t4_main.c revision 241733
1218792Snp/*-
2218792Snp * Copyright (c) 2011 Chelsio Communications, Inc.
3218792Snp * All rights reserved.
4218792Snp * Written by: Navdeep Parhar <np@FreeBSD.org>
5218792Snp *
6218792Snp * Redistribution and use in source and binary forms, with or without
7218792Snp * modification, are permitted provided that the following conditions
8218792Snp * are met:
9218792Snp * 1. Redistributions of source code must retain the above copyright
10218792Snp *    notice, this list of conditions and the following disclaimer.
11218792Snp * 2. Redistributions in binary form must reproduce the above copyright
12218792Snp *    notice, this list of conditions and the following disclaimer in the
13218792Snp *    documentation and/or other materials provided with the distribution.
14218792Snp *
15218792Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16218792Snp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17218792Snp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18218792Snp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19218792Snp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20218792Snp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21218792Snp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22218792Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23218792Snp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24218792Snp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25218792Snp * SUCH DAMAGE.
26218792Snp */
27218792Snp
28218792Snp#include <sys/cdefs.h>
29218792Snp__FBSDID("$FreeBSD: head/sys/dev/cxgbe/t4_main.c 241733 2012-10-19 13:26:40Z ed $");
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>
58218792Snp
59218792Snp#include "common/common.h"
60221474Snp#include "common/t4_msg.h"
61218792Snp#include "common/t4_regs.h"
62218792Snp#include "common/t4_regs_values.h"
63218792Snp#include "t4_ioctl.h"
64222509Snp#include "t4_l2t.h"
65218792Snp
66218792Snp/* T4 bus driver interface */
67218792Snpstatic int t4_probe(device_t);
68218792Snpstatic int t4_attach(device_t);
69218792Snpstatic int t4_detach(device_t);
70218792Snpstatic device_method_t t4_methods[] = {
71218792Snp	DEVMETHOD(device_probe,		t4_probe),
72218792Snp	DEVMETHOD(device_attach,	t4_attach),
73218792Snp	DEVMETHOD(device_detach,	t4_detach),
74218792Snp
75227843Smarius	DEVMETHOD_END
76218792Snp};
77218792Snpstatic driver_t t4_driver = {
78218792Snp	"t4nex",
79218792Snp	t4_methods,
80218792Snp	sizeof(struct adapter)
81218792Snp};
82218792Snp
83218792Snp
84218792Snp/* T4 port (cxgbe) interface */
85218792Snpstatic int cxgbe_probe(device_t);
86218792Snpstatic int cxgbe_attach(device_t);
87218792Snpstatic int cxgbe_detach(device_t);
88218792Snpstatic device_method_t cxgbe_methods[] = {
89218792Snp	DEVMETHOD(device_probe,		cxgbe_probe),
90218792Snp	DEVMETHOD(device_attach,	cxgbe_attach),
91218792Snp	DEVMETHOD(device_detach,	cxgbe_detach),
92218792Snp	{ 0, 0 }
93218792Snp};
94218792Snpstatic driver_t cxgbe_driver = {
95218792Snp	"cxgbe",
96218792Snp	cxgbe_methods,
97218792Snp	sizeof(struct port_info)
98218792Snp};
99218792Snp
100218792Snpstatic d_ioctl_t t4_ioctl;
101218792Snpstatic d_open_t t4_open;
102218792Snpstatic d_close_t t4_close;
103218792Snp
104218792Snpstatic struct cdevsw t4_cdevsw = {
105218792Snp       .d_version = D_VERSION,
106218792Snp       .d_flags = 0,
107218792Snp       .d_open = t4_open,
108218792Snp       .d_close = t4_close,
109218792Snp       .d_ioctl = t4_ioctl,
110218792Snp       .d_name = "t4nex",
111218792Snp};
112218792Snp
113218792Snp/* ifnet + media interface */
114218792Snpstatic void cxgbe_init(void *);
115218792Snpstatic int cxgbe_ioctl(struct ifnet *, unsigned long, caddr_t);
116218792Snpstatic int cxgbe_transmit(struct ifnet *, struct mbuf *);
117218792Snpstatic void cxgbe_qflush(struct ifnet *);
118218792Snpstatic int cxgbe_media_change(struct ifnet *);
119218792Snpstatic void cxgbe_media_status(struct ifnet *, struct ifmediareq *);
120218792Snp
121218792SnpMALLOC_DEFINE(M_CXGBE, "cxgbe", "Chelsio T4 Ethernet driver and services");
122218792Snp
123237263Snp/*
124237263Snp * Correct lock order when you need to acquire multiple locks is t4_list_lock,
125237263Snp * then ADAPTER_LOCK, then t4_uld_list_lock.
126237263Snp */
127228561Snpstatic struct mtx t4_list_lock;
128228561Snpstatic SLIST_HEAD(, adapter) t4_list;
129237263Snp#ifdef TCP_OFFLOAD
130228561Snpstatic struct mtx t4_uld_list_lock;
131228561Snpstatic SLIST_HEAD(, uld_info) t4_uld_list;
132228561Snp#endif
133218792Snp
134218792Snp/*
135228561Snp * Tunables.  See tweak_tunables() too.
136218792Snp */
137218792Snp
138218792Snp/*
139228561Snp * Number of queues for tx and rx, 10G and 1G, NIC and offload.
140218792Snp */
141228561Snp#define NTXQ_10G 16
142228561Snpstatic int t4_ntxq10g = -1;
143228561SnpTUNABLE_INT("hw.cxgbe.ntxq10g", &t4_ntxq10g);
144218792Snp
145228561Snp#define NRXQ_10G 8
146228561Snpstatic int t4_nrxq10g = -1;
147228561SnpTUNABLE_INT("hw.cxgbe.nrxq10g", &t4_nrxq10g);
148218792Snp
149228561Snp#define NTXQ_1G 4
150228561Snpstatic int t4_ntxq1g = -1;
151228561SnpTUNABLE_INT("hw.cxgbe.ntxq1g", &t4_ntxq1g);
152218792Snp
153228561Snp#define NRXQ_1G 2
154228561Snpstatic int t4_nrxq1g = -1;
155228561SnpTUNABLE_INT("hw.cxgbe.nrxq1g", &t4_nrxq1g);
156218792Snp
157237263Snp#ifdef TCP_OFFLOAD
158228561Snp#define NOFLDTXQ_10G 8
159228561Snpstatic int t4_nofldtxq10g = -1;
160228561SnpTUNABLE_INT("hw.cxgbe.nofldtxq10g", &t4_nofldtxq10g);
161228561Snp
162228561Snp#define NOFLDRXQ_10G 2
163228561Snpstatic int t4_nofldrxq10g = -1;
164228561SnpTUNABLE_INT("hw.cxgbe.nofldrxq10g", &t4_nofldrxq10g);
165228561Snp
166228561Snp#define NOFLDTXQ_1G 2
167228561Snpstatic int t4_nofldtxq1g = -1;
168228561SnpTUNABLE_INT("hw.cxgbe.nofldtxq1g", &t4_nofldtxq1g);
169228561Snp
170228561Snp#define NOFLDRXQ_1G 1
171228561Snpstatic int t4_nofldrxq1g = -1;
172228561SnpTUNABLE_INT("hw.cxgbe.nofldrxq1g", &t4_nofldrxq1g);
173228561Snp#endif
174228561Snp
175218792Snp/*
176218792Snp * Holdoff parameters for 10G and 1G ports.
177218792Snp */
178228561Snp#define TMR_IDX_10G 1
179228561Snpstatic int t4_tmr_idx_10g = TMR_IDX_10G;
180228561SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_10G", &t4_tmr_idx_10g);
181218792Snp
182234833Snp#define PKTC_IDX_10G (-1)
183228561Snpstatic int t4_pktc_idx_10g = PKTC_IDX_10G;
184228561SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_10G", &t4_pktc_idx_10g);
185218792Snp
186228561Snp#define TMR_IDX_1G 1
187228561Snpstatic int t4_tmr_idx_1g = TMR_IDX_1G;
188228561SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_1G", &t4_tmr_idx_1g);
189218792Snp
190234833Snp#define PKTC_IDX_1G (-1)
191228561Snpstatic int t4_pktc_idx_1g = PKTC_IDX_1G;
192228561SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_1G", &t4_pktc_idx_1g);
193218792Snp
194218792Snp/*
195218792Snp * Size (# of entries) of each tx and rx queue.
196218792Snp */
197228561Snpstatic unsigned int t4_qsize_txq = TX_EQ_QSIZE;
198228561SnpTUNABLE_INT("hw.cxgbe.qsize_txq", &t4_qsize_txq);
199218792Snp
200228561Snpstatic unsigned int t4_qsize_rxq = RX_IQ_QSIZE;
201228561SnpTUNABLE_INT("hw.cxgbe.qsize_rxq", &t4_qsize_rxq);
202218792Snp
203218792Snp/*
204228561Snp * Interrupt types allowed (bits 0, 1, 2 = INTx, MSI, MSI-X respectively).
205218792Snp */
206228561Snpstatic int t4_intr_types = INTR_MSIX | INTR_MSI | INTR_INTX;
207228561SnpTUNABLE_INT("hw.cxgbe.interrupt_types", &t4_intr_types);
208218792Snp
209218792Snp/*
210228561Snp * Configuration file.
211218792Snp */
212228561Snpstatic char t4_cfg_file[32] = "default";
213228561SnpTUNABLE_STR("hw.cxgbe.config_file", t4_cfg_file, sizeof(t4_cfg_file));
214218792Snp
215228561Snp/*
216228561Snp * ASIC features that will be used.  Disable the ones you don't want so that the
217228561Snp * chip resources aren't wasted on features that will not be used.
218228561Snp */
219228561Snpstatic int t4_linkcaps_allowed = 0;	/* No DCBX, PPP, etc. by default */
220228561SnpTUNABLE_INT("hw.cxgbe.linkcaps_allowed", &t4_linkcaps_allowed);
221221474Snp
222228561Snpstatic int t4_niccaps_allowed = FW_CAPS_CONFIG_NIC;
223228561SnpTUNABLE_INT("hw.cxgbe.niccaps_allowed", &t4_niccaps_allowed);
224228561Snp
225238028Snpstatic int t4_toecaps_allowed = -1;
226228561SnpTUNABLE_INT("hw.cxgbe.toecaps_allowed", &t4_toecaps_allowed);
227228561Snp
228228561Snpstatic int t4_rdmacaps_allowed = 0;
229228561SnpTUNABLE_INT("hw.cxgbe.rdmacaps_allowed", &t4_rdmacaps_allowed);
230228561Snp
231228561Snpstatic int t4_iscsicaps_allowed = 0;
232228561SnpTUNABLE_INT("hw.cxgbe.iscsicaps_allowed", &t4_iscsicaps_allowed);
233228561Snp
234228561Snpstatic int t4_fcoecaps_allowed = 0;
235228561SnpTUNABLE_INT("hw.cxgbe.fcoecaps_allowed", &t4_fcoecaps_allowed);
236228561Snp
237218792Snpstruct intrs_and_queues {
238219944Snp	int intr_type;		/* INTx, MSI, or MSI-X */
239218792Snp	int nirq;		/* Number of vectors */
240228561Snp	int intr_flags;
241218792Snp	int ntxq10g;		/* # of NIC txq's for each 10G port */
242218792Snp	int nrxq10g;		/* # of NIC rxq's for each 10G port */
243218792Snp	int ntxq1g;		/* # of NIC txq's for each 1G port */
244218792Snp	int nrxq1g;		/* # of NIC rxq's for each 1G port */
245237263Snp#ifdef TCP_OFFLOAD
246228561Snp	int nofldtxq10g;	/* # of TOE txq's for each 10G port */
247228561Snp	int nofldrxq10g;	/* # of TOE rxq's for each 10G port */
248228561Snp	int nofldtxq1g;		/* # of TOE txq's for each 1G port */
249228561Snp	int nofldrxq1g;		/* # of TOE rxq's for each 1G port */
250228561Snp#endif
251218792Snp};
252218792Snp
253221474Snpstruct filter_entry {
254221474Snp        uint32_t valid:1;	/* filter allocated and valid */
255221474Snp        uint32_t locked:1;	/* filter is administratively locked */
256221474Snp        uint32_t pending:1;	/* filter action is pending firmware reply */
257221474Snp	uint32_t smtidx:8;	/* Source MAC Table index for smac */
258222509Snp	struct l2t_entry *l2t;	/* Layer Two Table entry for dmac */
259221474Snp
260221474Snp        struct t4_filter_specification fs;
261221474Snp};
262221474Snp
263218792Snpenum {
264218792Snp	XGMAC_MTU	= (1 << 0),
265218792Snp	XGMAC_PROMISC	= (1 << 1),
266218792Snp	XGMAC_ALLMULTI	= (1 << 2),
267218792Snp	XGMAC_VLANEX	= (1 << 3),
268218792Snp	XGMAC_UCADDR	= (1 << 4),
269218792Snp	XGMAC_MCADDRS	= (1 << 5),
270218792Snp
271218792Snp	XGMAC_ALL	= 0xffff
272218792Snp};
273218792Snp
274218792Snpstatic int map_bars(struct adapter *);
275218792Snpstatic void setup_memwin(struct adapter *);
276218792Snpstatic int cfg_itype_and_nqueues(struct adapter *, int, int,
277218792Snp    struct intrs_and_queues *);
278218792Snpstatic int prep_firmware(struct adapter *);
279228561Snpstatic int upload_config_file(struct adapter *, const struct firmware *,
280228561Snp    uint32_t *, uint32_t *);
281228561Snpstatic int partition_resources(struct adapter *, const struct firmware *);
282228561Snpstatic int get_params__pre_init(struct adapter *);
283228561Snpstatic int get_params__post_init(struct adapter *);
284218792Snpstatic void t4_set_desc(struct adapter *);
285218792Snpstatic void build_medialist(struct port_info *);
286218792Snpstatic int update_mac_settings(struct port_info *, int);
287218792Snpstatic int cxgbe_init_locked(struct port_info *);
288218792Snpstatic int cxgbe_init_synchronized(struct port_info *);
289218792Snpstatic int cxgbe_uninit_locked(struct port_info *);
290218792Snpstatic int cxgbe_uninit_synchronized(struct port_info *);
291240453Snpstatic int setup_intr_handlers(struct adapter *);
292228561Snpstatic int adapter_full_init(struct adapter *);
293228561Snpstatic int adapter_full_uninit(struct adapter *);
294228561Snpstatic int port_full_init(struct port_info *);
295228561Snpstatic int port_full_uninit(struct port_info *);
296228561Snpstatic void quiesce_eq(struct adapter *, struct sge_eq *);
297228561Snpstatic void quiesce_iq(struct adapter *, struct sge_iq *);
298228561Snpstatic void quiesce_fl(struct adapter *, struct sge_fl *);
299218792Snpstatic int t4_alloc_irq(struct adapter *, struct irq *, int rid,
300228561Snp    driver_intr_t *, void *, char *);
301218792Snpstatic int t4_free_irq(struct adapter *, struct irq *);
302218792Snpstatic void reg_block_dump(struct adapter *, uint8_t *, unsigned int,
303218792Snp    unsigned int);
304218792Snpstatic void t4_get_regs(struct adapter *, struct t4_regdump *, uint8_t *);
305218792Snpstatic void cxgbe_tick(void *);
306237263Snpstatic void cxgbe_vlan_config(void *, struct ifnet *, uint16_t);
307228561Snpstatic int cpl_not_handled(struct sge_iq *, const struct rss_header *,
308228561Snp    struct mbuf *);
309237263Snpstatic int an_not_handled(struct sge_iq *, const struct rsp_ctrl *);
310239336Snpstatic int fw_msg_not_handled(struct adapter *, const __be64 *);
311218792Snpstatic int t4_sysctls(struct adapter *);
312218792Snpstatic int cxgbe_sysctls(struct port_info *);
313219436Snpstatic int sysctl_int_array(SYSCTL_HANDLER_ARGS);
314228561Snpstatic int sysctl_bitfield(SYSCTL_HANDLER_ARGS);
315218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS);
316218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS);
317218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS);
318218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS);
319218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS);
320231115Snp#ifdef SBUF_DRAIN
321228561Snpstatic int sysctl_cctrl(SYSCTL_HANDLER_ARGS);
322228561Snpstatic int sysctl_cpl_stats(SYSCTL_HANDLER_ARGS);
323228561Snpstatic int sysctl_ddp_stats(SYSCTL_HANDLER_ARGS);
324222551Snpstatic int sysctl_devlog(SYSCTL_HANDLER_ARGS);
325228561Snpstatic int sysctl_fcoe_stats(SYSCTL_HANDLER_ARGS);
326228561Snpstatic int sysctl_hw_sched(SYSCTL_HANDLER_ARGS);
327228561Snpstatic int sysctl_lb_stats(SYSCTL_HANDLER_ARGS);
328228561Snpstatic int sysctl_meminfo(SYSCTL_HANDLER_ARGS);
329228561Snpstatic int sysctl_path_mtus(SYSCTL_HANDLER_ARGS);
330228561Snpstatic int sysctl_pm_stats(SYSCTL_HANDLER_ARGS);
331228561Snpstatic int sysctl_rdma_stats(SYSCTL_HANDLER_ARGS);
332228561Snpstatic int sysctl_tcp_stats(SYSCTL_HANDLER_ARGS);
333228561Snpstatic int sysctl_tids(SYSCTL_HANDLER_ARGS);
334228561Snpstatic int sysctl_tp_err_stats(SYSCTL_HANDLER_ARGS);
335228561Snpstatic int sysctl_tx_rate(SYSCTL_HANDLER_ARGS);
336231115Snp#endif
337219286Snpstatic inline void txq_start(struct ifnet *, struct sge_txq *);
338221474Snpstatic uint32_t fconf_to_mode(uint32_t);
339221474Snpstatic uint32_t mode_to_fconf(uint32_t);
340221474Snpstatic uint32_t fspec_to_fconf(struct t4_filter_specification *);
341221474Snpstatic int get_filter_mode(struct adapter *, uint32_t *);
342221474Snpstatic int set_filter_mode(struct adapter *, uint32_t);
343222552Snpstatic inline uint64_t get_filter_hits(struct adapter *, uint32_t);
344221474Snpstatic int get_filter(struct adapter *, struct t4_filter *);
345221474Snpstatic int set_filter(struct adapter *, struct t4_filter *);
346221474Snpstatic int del_filter(struct adapter *, struct t4_filter *);
347222509Snpstatic void clear_filter(struct filter_entry *);
348221474Snpstatic int set_filter_wr(struct adapter *, int);
349221474Snpstatic int del_filter_wr(struct adapter *, int);
350222973Snpstatic int get_sge_context(struct adapter *, struct t4_sge_context *);
351228561Snpstatic int read_card_mem(struct adapter *, struct t4_mem_range *);
352241399Snpstatic int read_i2c(struct adapter *, struct t4_i2c_data *);
353237263Snp#ifdef TCP_OFFLOAD
354228561Snpstatic int toe_capability(struct port_info *, int);
355228561Snp#endif
356219392Snpstatic int t4_mod_event(module_t, int, void *);
357218792Snp
358218792Snpstruct t4_pciids {
359218792Snp	uint16_t device;
360218792Snp	char *desc;
361218792Snp} t4_pciids[] = {
362237587Snp	{0xa000, "Chelsio Terminator 4 FPGA"},
363237587Snp	{0x4400, "Chelsio T440-dbg"},
364237587Snp	{0x4401, "Chelsio T420-CR"},
365237587Snp	{0x4402, "Chelsio T422-CR"},
366237587Snp	{0x4403, "Chelsio T440-CR"},
367237587Snp	{0x4404, "Chelsio T420-BCH"},
368237587Snp	{0x4405, "Chelsio T440-BCH"},
369237587Snp	{0x4406, "Chelsio T440-CH"},
370237587Snp	{0x4407, "Chelsio T420-SO"},
371237587Snp	{0x4408, "Chelsio T420-CX"},
372237587Snp	{0x4409, "Chelsio T420-BT"},
373237587Snp	{0x440a, "Chelsio T404-BT"},
374218792Snp};
375218792Snp
376237263Snp#ifdef TCP_OFFLOAD
377237263Snp/*
378237263Snp * service_iq() has an iq and needs the fl.  Offset of fl from the iq should be
379237263Snp * exactly the same for both rxq and ofld_rxq.
380237263Snp */
381237263SnpCTASSERT(offsetof(struct sge_ofld_rxq, iq) == offsetof(struct sge_rxq, iq));
382228561SnpCTASSERT(offsetof(struct sge_ofld_rxq, fl) == offsetof(struct sge_rxq, fl));
383228561Snp#endif
384228561Snp
385239336Snp/* No easy way to include t4_msg.h before adapter.h so we check this way */
386240452SnpCTASSERT(nitems(((struct adapter *)0)->cpl_handler) == NUM_CPL_CMDS);
387240452SnpCTASSERT(nitems(((struct adapter *)0)->fw_msg_handler) == NUM_FW6_TYPES);
388239336Snp
389218792Snpstatic int
390218792Snpt4_probe(device_t dev)
391218792Snp{
392218792Snp	int i;
393218792Snp	uint16_t v = pci_get_vendor(dev);
394218792Snp	uint16_t d = pci_get_device(dev);
395237587Snp	uint8_t f = pci_get_function(dev);
396218792Snp
397218792Snp	if (v != PCI_VENDOR_ID_CHELSIO)
398218792Snp		return (ENXIO);
399218792Snp
400237587Snp	/* Attach only to PF0 of the FPGA */
401237587Snp	if (d == 0xa000 && f != 0)
402237587Snp		return (ENXIO);
403237587Snp
404240452Snp	for (i = 0; i < nitems(t4_pciids); i++) {
405237587Snp		if (d == t4_pciids[i].device) {
406218792Snp			device_set_desc(dev, t4_pciids[i].desc);
407218792Snp			return (BUS_PROBE_DEFAULT);
408218792Snp		}
409218792Snp	}
410218792Snp
411218792Snp	return (ENXIO);
412218792Snp}
413218792Snp
414218792Snpstatic int
415218792Snpt4_attach(device_t dev)
416218792Snp{
417218792Snp	struct adapter *sc;
418218792Snp	int rc = 0, i, n10g, n1g, rqidx, tqidx;
419218792Snp	struct intrs_and_queues iaq;
420218792Snp	struct sge *s;
421237263Snp#ifdef TCP_OFFLOAD
422228561Snp	int ofld_rqidx, ofld_tqidx;
423228561Snp#endif
424218792Snp
425218792Snp	sc = device_get_softc(dev);
426218792Snp	sc->dev = dev;
427218792Snp
428218792Snp	pci_enable_busmaster(dev);
429222085Snp	if (pci_find_cap(dev, PCIY_EXPRESS, &i) == 0) {
430228561Snp		uint32_t v;
431228561Snp
432222085Snp		pci_set_max_read_req(dev, 4096);
433240680Sgavin		v = pci_read_config(dev, i + PCIER_DEVICE_CTL, 2);
434240680Sgavin		v |= PCIEM_CTL_RELAXED_ORD_ENABLE;
435240680Sgavin		pci_write_config(dev, i + PCIER_DEVICE_CTL, v, 2);
436222085Snp	}
437222085Snp
438218792Snp	snprintf(sc->lockname, sizeof(sc->lockname), "%s",
439218792Snp	    device_get_nameunit(dev));
440218792Snp	mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF);
441228561Snp	mtx_lock(&t4_list_lock);
442228561Snp	SLIST_INSERT_HEAD(&t4_list, sc, link);
443228561Snp	mtx_unlock(&t4_list_lock);
444218792Snp
445228561Snp	mtx_init(&sc->sfl_lock, "starving freelists", 0, MTX_DEF);
446228561Snp	TAILQ_INIT(&sc->sfl);
447228561Snp	callout_init(&sc->sfl_callout, CALLOUT_MPSAFE);
448228561Snp
449218792Snp	rc = map_bars(sc);
450218792Snp	if (rc != 0)
451218792Snp		goto done; /* error message displayed already */
452218792Snp
453237587Snp	/*
454237587Snp	 * This is the real PF# to which we're attaching.  Works from within PCI
455237587Snp	 * passthrough environments too, where pci_get_function() could return a
456237587Snp	 * different PF# depending on the passthrough configuration.  We need to
457237587Snp	 * use the real PF# in all our communication with the firmware.
458237587Snp	 */
459237587Snp	sc->pf = G_SOURCEPF(t4_read_reg(sc, A_PL_WHOAMI));
460237587Snp	sc->mbox = sc->pf;
461237587Snp
462218792Snp	memset(sc->chan_map, 0xff, sizeof(sc->chan_map));
463237263Snp	sc->an_handler = an_not_handled;
464240452Snp	for (i = 0; i < nitems(sc->cpl_handler); i++)
465228561Snp		sc->cpl_handler[i] = cpl_not_handled;
466240452Snp	for (i = 0; i < nitems(sc->fw_msg_handler); i++)
467239336Snp		sc->fw_msg_handler[i] = fw_msg_not_handled;
468239338Snp	t4_register_cpl_handler(sc, CPL_SET_TCB_RPL, t4_filter_rpl);
469218792Snp
470218792Snp	/* Prepare the adapter for operation */
471218792Snp	rc = -t4_prep_adapter(sc);
472218792Snp	if (rc != 0) {
473218792Snp		device_printf(dev, "failed to prepare adapter: %d.\n", rc);
474218792Snp		goto done;
475218792Snp	}
476218792Snp
477228561Snp	/*
478228561Snp	 * Do this really early, with the memory windows set up even before the
479228561Snp	 * character device.  The userland tool's register i/o and mem read
480228561Snp	 * will work even in "recovery mode".
481228561Snp	 */
482228561Snp	setup_memwin(sc);
483218792Snp	sc->cdev = make_dev(&t4_cdevsw, device_get_unit(dev), UID_ROOT,
484218792Snp	    GID_WHEEL, 0600, "%s", device_get_nameunit(dev));
485218792Snp	sc->cdev->si_drv1 = sc;
486218792Snp
487228561Snp	/* Go no further if recovery mode has been requested. */
488228561Snp	if (TUNABLE_INT_FETCH("hw.cxgbe.sos", &i) && i != 0) {
489228561Snp		device_printf(dev, "recovery mode.\n");
490228561Snp		goto done;
491228561Snp	}
492228561Snp
493218792Snp	/* Prepare the firmware for operation */
494218792Snp	rc = prep_firmware(sc);
495218792Snp	if (rc != 0)
496218792Snp		goto done; /* error message displayed already */
497218792Snp
498228561Snp	rc = get_params__pre_init(sc);
499228561Snp	if (rc != 0)
500228561Snp		goto done; /* error message displayed already */
501222551Snp
502228561Snp	rc = t4_sge_init(sc);
503228561Snp	if (rc != 0)
504228561Snp		goto done; /* error message displayed already */
505218792Snp
506228561Snp	if (sc->flags & MASTER_PF) {
507228561Snp		/* get basic stuff going */
508228561Snp		rc = -t4_fw_initialize(sc, sc->mbox);
509228561Snp		if (rc != 0) {
510228561Snp			device_printf(dev, "early init failed: %d.\n", rc);
511228561Snp			goto done;
512228561Snp		}
513218792Snp	}
514218792Snp
515228561Snp	rc = get_params__post_init(sc);
516228561Snp	if (rc != 0)
517228561Snp		goto done; /* error message displayed already */
518218792Snp
519228561Snp	if (sc->flags & MASTER_PF) {
520239341Snp		uint16_t indsz = min(RX_COPY_THRESHOLD - 1, M_INDICATESIZE);
521218792Snp
522228561Snp		/* final tweaks to some settings */
523218792Snp
524228561Snp		t4_load_mtus(sc, sc->params.mtus, sc->params.a_wnd,
525228561Snp		    sc->params.b_wnd);
526239341Snp		/* 4K, 16K, 64K, 256K DDP "page sizes" */
527239341Snp		t4_write_reg(sc, A_ULP_RX_TDDP_PSZ, V_HPZ0(0) | V_HPZ1(2) |
528239341Snp		    V_HPZ2(4) | V_HPZ3(6));
529239341Snp		t4_set_reg_field(sc, A_ULP_RX_CTL, F_TDDPTAGTCB, F_TDDPTAGTCB);
530228561Snp		t4_set_reg_field(sc, A_TP_PARA_REG5,
531228561Snp		    V_INDICATESIZE(M_INDICATESIZE) |
532228561Snp		    F_REARMDDPOFFSET | F_RESETDDPOFFSET,
533239341Snp		    V_INDICATESIZE(indsz) |
534228561Snp		    F_REARMDDPOFFSET | F_RESETDDPOFFSET);
535228561Snp	} else {
536228561Snp		/*
537228561Snp		 * XXX: Verify that we can live with whatever the master driver
538228561Snp		 * has done so far, and hope that it doesn't change any global
539228561Snp		 * setting from underneath us in the future.
540228561Snp		 */
541218792Snp	}
542218792Snp
543228561Snp	t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &sc->filter_mode, 1,
544228561Snp	    A_TP_VLAN_PRI_MAP);
545218792Snp
546228561Snp	for (i = 0; i < NCHAN; i++)
547228561Snp		sc->params.tp.tx_modq[i] = i;
548218792Snp
549218792Snp	rc = t4_create_dma_tag(sc);
550218792Snp	if (rc != 0)
551218792Snp		goto done; /* error message displayed already */
552218792Snp
553218792Snp	/*
554218792Snp	 * First pass over all the ports - allocate VIs and initialize some
555218792Snp	 * basic parameters like mac address, port type, etc.  We also figure
556218792Snp	 * out whether a port is 10G or 1G and use that information when
557218792Snp	 * calculating how many interrupts to attempt to allocate.
558218792Snp	 */
559218792Snp	n10g = n1g = 0;
560218792Snp	for_each_port(sc, i) {
561218792Snp		struct port_info *pi;
562218792Snp
563218792Snp		pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK);
564218792Snp		sc->port[i] = pi;
565218792Snp
566218792Snp		/* These must be set before t4_port_init */
567218792Snp		pi->adapter = sc;
568218792Snp		pi->port_id = i;
569218792Snp
570218792Snp		/* Allocate the vi and initialize parameters like mac addr */
571218792Snp		rc = -t4_port_init(pi, sc->mbox, sc->pf, 0);
572218792Snp		if (rc != 0) {
573218792Snp			device_printf(dev, "unable to initialize port %d: %d\n",
574218792Snp			    i, rc);
575218792Snp			free(pi, M_CXGBE);
576222510Snp			sc->port[i] = NULL;
577222510Snp			goto done;
578218792Snp		}
579218792Snp
580218792Snp		snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d",
581218792Snp		    device_get_nameunit(dev), i);
582218792Snp		mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF);
583218792Snp
584218792Snp		if (is_10G_port(pi)) {
585218792Snp			n10g++;
586228561Snp			pi->tmr_idx = t4_tmr_idx_10g;
587228561Snp			pi->pktc_idx = t4_pktc_idx_10g;
588218792Snp		} else {
589218792Snp			n1g++;
590228561Snp			pi->tmr_idx = t4_tmr_idx_1g;
591228561Snp			pi->pktc_idx = t4_pktc_idx_1g;
592218792Snp		}
593218792Snp
594218792Snp		pi->xact_addr_filt = -1;
595218792Snp
596228561Snp		pi->qsize_rxq = t4_qsize_rxq;
597228561Snp		pi->qsize_txq = t4_qsize_txq;
598218792Snp
599218792Snp		pi->dev = device_add_child(dev, "cxgbe", -1);
600218792Snp		if (pi->dev == NULL) {
601218792Snp			device_printf(dev,
602218792Snp			    "failed to add device for port %d.\n", i);
603218792Snp			rc = ENXIO;
604218792Snp			goto done;
605218792Snp		}
606218792Snp		device_set_softc(pi->dev, pi);
607218792Snp	}
608218792Snp
609218792Snp	/*
610218792Snp	 * Interrupt type, # of interrupts, # of rx/tx queues, etc.
611218792Snp	 */
612218792Snp	rc = cfg_itype_and_nqueues(sc, n10g, n1g, &iaq);
613218792Snp	if (rc != 0)
614218792Snp		goto done; /* error message displayed already */
615218792Snp
616218792Snp	sc->intr_type = iaq.intr_type;
617218792Snp	sc->intr_count = iaq.nirq;
618228561Snp	sc->flags |= iaq.intr_flags;
619218792Snp
620218792Snp	s = &sc->sge;
621218792Snp	s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g;
622218792Snp	s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g;
623220873Snp	s->neq = s->ntxq + s->nrxq;	/* the free list in an rxq is an eq */
624228561Snp	s->neq += sc->params.nports + 1;/* ctrl queues: 1 per port + 1 mgmt */
625218792Snp	s->niq = s->nrxq + 1;		/* 1 extra for firmware event queue */
626222510Snp
627237263Snp#ifdef TCP_OFFLOAD
628228561Snp	if (is_offload(sc)) {
629228561Snp
630228561Snp		s->nofldrxq = n10g * iaq.nofldrxq10g + n1g * iaq.nofldrxq1g;
631228561Snp		s->nofldtxq = n10g * iaq.nofldtxq10g + n1g * iaq.nofldtxq1g;
632228561Snp		s->neq += s->nofldtxq + s->nofldrxq;
633228561Snp		s->niq += s->nofldrxq;
634228561Snp
635228561Snp		s->ofld_rxq = malloc(s->nofldrxq * sizeof(struct sge_ofld_rxq),
636228561Snp		    M_CXGBE, M_ZERO | M_WAITOK);
637228561Snp		s->ofld_txq = malloc(s->nofldtxq * sizeof(struct sge_wrq),
638228561Snp		    M_CXGBE, M_ZERO | M_WAITOK);
639228561Snp	}
640228561Snp#endif
641228561Snp
642228561Snp	s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_wrq), M_CXGBE,
643220873Snp	    M_ZERO | M_WAITOK);
644218792Snp	s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE,
645218792Snp	    M_ZERO | M_WAITOK);
646218792Snp	s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE,
647218792Snp	    M_ZERO | M_WAITOK);
648218792Snp	s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE,
649218792Snp	    M_ZERO | M_WAITOK);
650218792Snp	s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE,
651218792Snp	    M_ZERO | M_WAITOK);
652218792Snp
653218792Snp	sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE,
654218792Snp	    M_ZERO | M_WAITOK);
655218792Snp
656228561Snp	t4_init_l2t(sc, M_WAITOK);
657222509Snp
658218792Snp	/*
659218792Snp	 * Second pass over the ports.  This time we know the number of rx and
660218792Snp	 * tx queues that each port should get.
661218792Snp	 */
662218792Snp	rqidx = tqidx = 0;
663237263Snp#ifdef TCP_OFFLOAD
664228561Snp	ofld_rqidx = ofld_tqidx = 0;
665228561Snp#endif
666218792Snp	for_each_port(sc, i) {
667218792Snp		struct port_info *pi = sc->port[i];
668218792Snp
669218792Snp		if (pi == NULL)
670218792Snp			continue;
671218792Snp
672218792Snp		pi->first_rxq = rqidx;
673218792Snp		pi->first_txq = tqidx;
674228561Snp		if (is_10G_port(pi)) {
675228561Snp			pi->nrxq = iaq.nrxq10g;
676228561Snp			pi->ntxq = iaq.ntxq10g;
677228561Snp		} else {
678228561Snp			pi->nrxq = iaq.nrxq1g;
679228561Snp			pi->ntxq = iaq.ntxq1g;
680228561Snp		}
681218792Snp
682218792Snp		rqidx += pi->nrxq;
683218792Snp		tqidx += pi->ntxq;
684228561Snp
685237263Snp#ifdef TCP_OFFLOAD
686228561Snp		if (is_offload(sc)) {
687228561Snp			pi->first_ofld_rxq = ofld_rqidx;
688228561Snp			pi->first_ofld_txq = ofld_tqidx;
689228561Snp			if (is_10G_port(pi)) {
690228561Snp				pi->nofldrxq = iaq.nofldrxq10g;
691228561Snp				pi->nofldtxq = iaq.nofldtxq10g;
692228561Snp			} else {
693228561Snp				pi->nofldrxq = iaq.nofldrxq1g;
694228561Snp				pi->nofldtxq = iaq.nofldtxq1g;
695228561Snp			}
696228561Snp			ofld_rqidx += pi->nofldrxq;
697228561Snp			ofld_tqidx += pi->nofldtxq;
698228561Snp		}
699228561Snp#endif
700218792Snp	}
701218792Snp
702240453Snp	rc = setup_intr_handlers(sc);
703240453Snp	if (rc != 0) {
704240453Snp		device_printf(dev,
705240453Snp		    "failed to setup interrupt handlers: %d\n", rc);
706240453Snp		goto done;
707240453Snp	}
708240453Snp
709218792Snp	rc = bus_generic_attach(dev);
710218792Snp	if (rc != 0) {
711218792Snp		device_printf(dev,
712218792Snp		    "failed to attach all child ports: %d\n", rc);
713218792Snp		goto done;
714218792Snp	}
715218792Snp
716218792Snp	device_printf(dev,
717228561Snp	    "PCIe x%d, %d ports, %d %s interrupt%s, %d eq, %d iq\n",
718228561Snp	    sc->params.pci.width, sc->params.nports, sc->intr_count,
719228561Snp	    sc->intr_type == INTR_MSIX ? "MSI-X" :
720228561Snp	    (sc->intr_type == INTR_MSI ? "MSI" : "INTx"),
721228561Snp	    sc->intr_count > 1 ? "s" : "", sc->sge.neq, sc->sge.niq);
722228561Snp
723218792Snp	t4_set_desc(sc);
724218792Snp
725218792Snpdone:
726228561Snp	if (rc != 0 && sc->cdev) {
727228561Snp		/* cdev was created and so cxgbetool works; recover that way. */
728228561Snp		device_printf(dev,
729228561Snp		    "error during attach, adapter is now in recovery mode.\n");
730228561Snp		rc = 0;
731228561Snp	}
732228561Snp
733218792Snp	if (rc != 0)
734218792Snp		t4_detach(dev);
735228561Snp	else
736228561Snp		t4_sysctls(sc);
737218792Snp
738218792Snp	return (rc);
739218792Snp}
740218792Snp
741218792Snp/*
742218792Snp * Idempotent
743218792Snp */
744218792Snpstatic int
745218792Snpt4_detach(device_t dev)
746218792Snp{
747218792Snp	struct adapter *sc;
748218792Snp	struct port_info *pi;
749228561Snp	int i, rc;
750218792Snp
751218792Snp	sc = device_get_softc(dev);
752218792Snp
753228561Snp	if (sc->flags & FULL_INIT_DONE)
754228561Snp		t4_intr_disable(sc);
755228561Snp
756228561Snp	if (sc->cdev) {
757218792Snp		destroy_dev(sc->cdev);
758228561Snp		sc->cdev = NULL;
759228561Snp	}
760218792Snp
761228561Snp	rc = bus_generic_detach(dev);
762228561Snp	if (rc) {
763228561Snp		device_printf(dev,
764228561Snp		    "failed to detach child devices: %d\n", rc);
765228561Snp		return (rc);
766228561Snp	}
767228561Snp
768240453Snp	for (i = 0; i < sc->intr_count; i++)
769240453Snp		t4_free_irq(sc, &sc->irq[i]);
770240453Snp
771218792Snp	for (i = 0; i < MAX_NPORTS; i++) {
772218792Snp		pi = sc->port[i];
773218792Snp		if (pi) {
774218792Snp			t4_free_vi(pi->adapter, sc->mbox, sc->pf, 0, pi->viid);
775218792Snp			if (pi->dev)
776218792Snp				device_delete_child(dev, pi->dev);
777218792Snp
778218792Snp			mtx_destroy(&pi->pi_lock);
779218792Snp			free(pi, M_CXGBE);
780218792Snp		}
781218792Snp	}
782218792Snp
783228561Snp	if (sc->flags & FULL_INIT_DONE)
784228561Snp		adapter_full_uninit(sc);
785228561Snp
786218792Snp	if (sc->flags & FW_OK)
787218792Snp		t4_fw_bye(sc, sc->mbox);
788218792Snp
789219944Snp	if (sc->intr_type == INTR_MSI || sc->intr_type == INTR_MSIX)
790218792Snp		pci_release_msi(dev);
791218792Snp
792218792Snp	if (sc->regs_res)
793218792Snp		bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid,
794218792Snp		    sc->regs_res);
795218792Snp
796218792Snp	if (sc->msix_res)
797218792Snp		bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid,
798218792Snp		    sc->msix_res);
799218792Snp
800222509Snp	if (sc->l2t)
801222509Snp		t4_free_l2t(sc->l2t);
802222509Snp
803237263Snp#ifdef TCP_OFFLOAD
804228561Snp	free(sc->sge.ofld_rxq, M_CXGBE);
805228561Snp	free(sc->sge.ofld_txq, M_CXGBE);
806228561Snp#endif
807218792Snp	free(sc->irq, M_CXGBE);
808218792Snp	free(sc->sge.rxq, M_CXGBE);
809218792Snp	free(sc->sge.txq, M_CXGBE);
810220873Snp	free(sc->sge.ctrlq, M_CXGBE);
811218792Snp	free(sc->sge.iqmap, M_CXGBE);
812218792Snp	free(sc->sge.eqmap, M_CXGBE);
813221474Snp	free(sc->tids.ftid_tab, M_CXGBE);
814218792Snp	t4_destroy_dma_tag(sc);
815228561Snp	if (mtx_initialized(&sc->sc_lock)) {
816228561Snp		mtx_lock(&t4_list_lock);
817228561Snp		SLIST_REMOVE(&t4_list, sc, adapter, link);
818228561Snp		mtx_unlock(&t4_list_lock);
819228561Snp		mtx_destroy(&sc->sc_lock);
820228561Snp	}
821218792Snp
822228561Snp	if (mtx_initialized(&sc->sfl_lock))
823228561Snp		mtx_destroy(&sc->sfl_lock);
824228561Snp
825218792Snp	bzero(sc, sizeof(*sc));
826218792Snp
827218792Snp	return (0);
828218792Snp}
829218792Snp
830218792Snp
831218792Snpstatic int
832218792Snpcxgbe_probe(device_t dev)
833218792Snp{
834218792Snp	char buf[128];
835218792Snp	struct port_info *pi = device_get_softc(dev);
836218792Snp
837228561Snp	snprintf(buf, sizeof(buf), "port %d", pi->port_id);
838218792Snp	device_set_desc_copy(dev, buf);
839218792Snp
840218792Snp	return (BUS_PROBE_DEFAULT);
841218792Snp}
842218792Snp
843218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \
844218792Snp    IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \
845237831Snp    IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6)
846237819Snp#define T4_CAP_ENABLE (T4_CAP)
847218792Snp
848218792Snpstatic int
849218792Snpcxgbe_attach(device_t dev)
850218792Snp{
851218792Snp	struct port_info *pi = device_get_softc(dev);
852218792Snp	struct ifnet *ifp;
853218792Snp
854218792Snp	/* Allocate an ifnet and set it up */
855218792Snp	ifp = if_alloc(IFT_ETHER);
856218792Snp	if (ifp == NULL) {
857218792Snp		device_printf(dev, "Cannot allocate ifnet\n");
858218792Snp		return (ENOMEM);
859218792Snp	}
860218792Snp	pi->ifp = ifp;
861218792Snp	ifp->if_softc = pi;
862218792Snp
863218792Snp	callout_init(&pi->tick, CALLOUT_MPSAFE);
864218792Snp
865218792Snp	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
866218792Snp	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
867218792Snp
868218792Snp	ifp->if_init = cxgbe_init;
869218792Snp	ifp->if_ioctl = cxgbe_ioctl;
870218792Snp	ifp->if_transmit = cxgbe_transmit;
871218792Snp	ifp->if_qflush = cxgbe_qflush;
872218792Snp
873218792Snp	ifp->if_capabilities = T4_CAP;
874237263Snp#ifdef TCP_OFFLOAD
875228561Snp	if (is_offload(pi->adapter))
876228561Snp		ifp->if_capabilities |= IFCAP_TOE4;
877228561Snp#endif
878218792Snp	ifp->if_capenable = T4_CAP_ENABLE;
879237799Snp	ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO |
880237799Snp	    CSUM_UDP_IPV6 | CSUM_TCP_IPV6;
881218792Snp
882218792Snp	/* Initialize ifmedia for this port */
883218792Snp	ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change,
884218792Snp	    cxgbe_media_status);
885218792Snp	build_medialist(pi);
886218792Snp
887237263Snp	pi->vlan_c = EVENTHANDLER_REGISTER(vlan_config, cxgbe_vlan_config, ifp,
888237263Snp	    EVENTHANDLER_PRI_ANY);
889237263Snp
890218792Snp	ether_ifattach(ifp, pi->hw_addr);
891218792Snp
892237263Snp#ifdef TCP_OFFLOAD
893228561Snp	if (is_offload(pi->adapter)) {
894228561Snp		device_printf(dev,
895228561Snp		    "%d txq, %d rxq (NIC); %d txq, %d rxq (TOE)\n",
896228561Snp		    pi->ntxq, pi->nrxq, pi->nofldtxq, pi->nofldrxq);
897228561Snp	} else
898218792Snp#endif
899228561Snp		device_printf(dev, "%d txq, %d rxq\n", pi->ntxq, pi->nrxq);
900218792Snp
901218792Snp	cxgbe_sysctls(pi);
902218792Snp
903218792Snp	return (0);
904218792Snp}
905218792Snp
906218792Snpstatic int
907218792Snpcxgbe_detach(device_t dev)
908218792Snp{
909218792Snp	struct port_info *pi = device_get_softc(dev);
910218792Snp	struct adapter *sc = pi->adapter;
911228561Snp	struct ifnet *ifp = pi->ifp;
912218792Snp
913218792Snp	/* Tell if_ioctl and if_init that the port is going away */
914218792Snp	ADAPTER_LOCK(sc);
915218792Snp	SET_DOOMED(pi);
916218792Snp	wakeup(&sc->flags);
917218792Snp	while (IS_BUSY(sc))
918218792Snp		mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0);
919218792Snp	SET_BUSY(sc);
920218792Snp	ADAPTER_UNLOCK(sc);
921218792Snp
922237263Snp	if (pi->vlan_c)
923237263Snp		EVENTHANDLER_DEREGISTER(vlan_config, pi->vlan_c);
924237263Snp
925228561Snp	PORT_LOCK(pi);
926228561Snp	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
927228561Snp	callout_stop(&pi->tick);
928228561Snp	PORT_UNLOCK(pi);
929228561Snp	callout_drain(&pi->tick);
930218792Snp
931228561Snp	/* Let detach proceed even if these fail. */
932228561Snp	cxgbe_uninit_synchronized(pi);
933228561Snp	port_full_uninit(pi);
934219286Snp
935218792Snp	ifmedia_removeall(&pi->media);
936218792Snp	ether_ifdetach(pi->ifp);
937218792Snp	if_free(pi->ifp);
938218792Snp
939218792Snp	ADAPTER_LOCK(sc);
940218792Snp	CLR_BUSY(sc);
941218792Snp	wakeup_one(&sc->flags);
942218792Snp	ADAPTER_UNLOCK(sc);
943218792Snp
944218792Snp	return (0);
945218792Snp}
946218792Snp
947218792Snpstatic void
948218792Snpcxgbe_init(void *arg)
949218792Snp{
950218792Snp	struct port_info *pi = arg;
951218792Snp	struct adapter *sc = pi->adapter;
952218792Snp
953218792Snp	ADAPTER_LOCK(sc);
954218792Snp	cxgbe_init_locked(pi); /* releases adapter lock */
955218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
956218792Snp}
957218792Snp
958218792Snpstatic int
959218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
960218792Snp{
961218792Snp	int rc = 0, mtu, flags;
962218792Snp	struct port_info *pi = ifp->if_softc;
963218792Snp	struct adapter *sc = pi->adapter;
964218792Snp	struct ifreq *ifr = (struct ifreq *)data;
965218792Snp	uint32_t mask;
966218792Snp
967218792Snp	switch (cmd) {
968218792Snp	case SIOCSIFMTU:
969218792Snp		ADAPTER_LOCK(sc);
970218792Snp		rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
971218792Snp		if (rc) {
972218792Snpfail:
973218792Snp			ADAPTER_UNLOCK(sc);
974218792Snp			return (rc);
975218792Snp		}
976218792Snp
977218792Snp		mtu = ifr->ifr_mtu;
978218792Snp		if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) {
979218792Snp			rc = EINVAL;
980218792Snp		} else {
981218792Snp			ifp->if_mtu = mtu;
982218792Snp			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
983218792Snp				t4_update_fl_bufsize(ifp);
984218792Snp				PORT_LOCK(pi);
985218792Snp				rc = update_mac_settings(pi, XGMAC_MTU);
986218792Snp				PORT_UNLOCK(pi);
987218792Snp			}
988218792Snp		}
989218792Snp		ADAPTER_UNLOCK(sc);
990218792Snp		break;
991218792Snp
992218792Snp	case SIOCSIFFLAGS:
993218792Snp		ADAPTER_LOCK(sc);
994218792Snp		if (IS_DOOMED(pi)) {
995218792Snp			rc = ENXIO;
996218792Snp			goto fail;
997218792Snp		}
998218792Snp		if (ifp->if_flags & IFF_UP) {
999218792Snp			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1000218792Snp				flags = pi->if_flags;
1001218792Snp				if ((ifp->if_flags ^ flags) &
1002218792Snp				    (IFF_PROMISC | IFF_ALLMULTI)) {
1003218792Snp					if (IS_BUSY(sc)) {
1004218792Snp						rc = EBUSY;
1005218792Snp						goto fail;
1006218792Snp					}
1007218792Snp					PORT_LOCK(pi);
1008218792Snp					rc = update_mac_settings(pi,
1009218792Snp					    XGMAC_PROMISC | XGMAC_ALLMULTI);
1010218792Snp					PORT_UNLOCK(pi);
1011218792Snp				}
1012218792Snp				ADAPTER_UNLOCK(sc);
1013218792Snp			} else
1014218792Snp				rc = cxgbe_init_locked(pi);
1015218792Snp			pi->if_flags = ifp->if_flags;
1016218792Snp		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1017218792Snp			rc = cxgbe_uninit_locked(pi);
1018218792Snp		else
1019218792Snp			ADAPTER_UNLOCK(sc);
1020218792Snp
1021218792Snp		ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1022218792Snp		break;
1023218792Snp
1024218792Snp	case SIOCADDMULTI:
1025218792Snp	case SIOCDELMULTI: /* these two can be called with a mutex held :-( */
1026218792Snp		ADAPTER_LOCK(sc);
1027218792Snp		rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
1028218792Snp		if (rc)
1029218792Snp			goto fail;
1030218792Snp
1031218792Snp		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1032218792Snp			PORT_LOCK(pi);
1033218792Snp			rc = update_mac_settings(pi, XGMAC_MCADDRS);
1034218792Snp			PORT_UNLOCK(pi);
1035218792Snp		}
1036218792Snp		ADAPTER_UNLOCK(sc);
1037218792Snp		break;
1038218792Snp
1039218792Snp	case SIOCSIFCAP:
1040218792Snp		ADAPTER_LOCK(sc);
1041218792Snp		rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
1042218792Snp		if (rc)
1043218792Snp			goto fail;
1044218792Snp
1045218792Snp		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1046218792Snp		if (mask & IFCAP_TXCSUM) {
1047218792Snp			ifp->if_capenable ^= IFCAP_TXCSUM;
1048218792Snp			ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP);
1049218792Snp
1050237831Snp			if (IFCAP_TSO4 & ifp->if_capenable &&
1051218792Snp			    !(IFCAP_TXCSUM & ifp->if_capenable)) {
1052237799Snp				ifp->if_capenable &= ~IFCAP_TSO4;
1053218792Snp				if_printf(ifp,
1054237831Snp				    "tso4 disabled due to -txcsum.\n");
1055218792Snp			}
1056218792Snp		}
1057237799Snp		if (mask & IFCAP_TXCSUM_IPV6) {
1058237799Snp			ifp->if_capenable ^= IFCAP_TXCSUM_IPV6;
1059237799Snp			ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6);
1060237799Snp
1061237799Snp			if (IFCAP_TSO6 & ifp->if_capenable &&
1062237799Snp			    !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) {
1063237799Snp				ifp->if_capenable &= ~IFCAP_TSO6;
1064237799Snp				if_printf(ifp,
1065237799Snp				    "tso6 disabled due to -txcsum6.\n");
1066237799Snp			}
1067237799Snp		}
1068218792Snp		if (mask & IFCAP_RXCSUM)
1069218792Snp			ifp->if_capenable ^= IFCAP_RXCSUM;
1070237799Snp		if (mask & IFCAP_RXCSUM_IPV6)
1071237799Snp			ifp->if_capenable ^= IFCAP_RXCSUM_IPV6;
1072237799Snp
1073237799Snp		/*
1074237799Snp		 * Note that we leave CSUM_TSO alone (it is always set).  The
1075237799Snp		 * kernel takes both IFCAP_TSOx and CSUM_TSO into account before
1076237799Snp		 * sending a TSO request our way, so it's sufficient to toggle
1077237799Snp		 * IFCAP_TSOx only.
1078237799Snp		 */
1079218792Snp		if (mask & IFCAP_TSO4) {
1080237799Snp			if (!(IFCAP_TSO4 & ifp->if_capenable) &&
1081237799Snp			    !(IFCAP_TXCSUM & ifp->if_capenable)) {
1082237799Snp				if_printf(ifp, "enable txcsum first.\n");
1083237799Snp				rc = EAGAIN;
1084237799Snp				goto fail;
1085237799Snp			}
1086218792Snp			ifp->if_capenable ^= IFCAP_TSO4;
1087218792Snp		}
1088237799Snp		if (mask & IFCAP_TSO6) {
1089237799Snp			if (!(IFCAP_TSO6 & ifp->if_capenable) &&
1090237799Snp			    !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) {
1091237799Snp				if_printf(ifp, "enable txcsum6 first.\n");
1092237799Snp				rc = EAGAIN;
1093237799Snp				goto fail;
1094237799Snp			}
1095237799Snp			ifp->if_capenable ^= IFCAP_TSO6;
1096237799Snp		}
1097218792Snp		if (mask & IFCAP_LRO) {
1098237819Snp#if defined(INET) || defined(INET6)
1099218792Snp			int i;
1100218792Snp			struct sge_rxq *rxq;
1101218792Snp
1102218792Snp			ifp->if_capenable ^= IFCAP_LRO;
1103218792Snp			for_each_rxq(pi, i, rxq) {
1104218792Snp				if (ifp->if_capenable & IFCAP_LRO)
1105228561Snp					rxq->iq.flags |= IQ_LRO_ENABLED;
1106218792Snp				else
1107228561Snp					rxq->iq.flags &= ~IQ_LRO_ENABLED;
1108218792Snp			}
1109218792Snp#endif
1110218792Snp		}
1111237263Snp#ifdef TCP_OFFLOAD
1112228561Snp		if (mask & IFCAP_TOE) {
1113228561Snp			int enable = (ifp->if_capenable ^ mask) & IFCAP_TOE;
1114228561Snp
1115228561Snp			rc = toe_capability(pi, enable);
1116228561Snp			if (rc != 0)
1117228561Snp				goto fail;
1118228561Snp
1119228561Snp			ifp->if_capenable ^= mask;
1120218792Snp		}
1121218792Snp#endif
1122218792Snp		if (mask & IFCAP_VLAN_HWTAGGING) {
1123218792Snp			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
1124218792Snp			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1125218792Snp				PORT_LOCK(pi);
1126218792Snp				rc = update_mac_settings(pi, XGMAC_VLANEX);
1127218792Snp				PORT_UNLOCK(pi);
1128218792Snp			}
1129218792Snp		}
1130218792Snp		if (mask & IFCAP_VLAN_MTU) {
1131218792Snp			ifp->if_capenable ^= IFCAP_VLAN_MTU;
1132218792Snp
1133218792Snp			/* Need to find out how to disable auto-mtu-inflation */
1134218792Snp		}
1135218792Snp		if (mask & IFCAP_VLAN_HWTSO)
1136218792Snp			ifp->if_capenable ^= IFCAP_VLAN_HWTSO;
1137218792Snp		if (mask & IFCAP_VLAN_HWCSUM)
1138218792Snp			ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
1139218792Snp
1140218792Snp#ifdef VLAN_CAPABILITIES
1141218792Snp		VLAN_CAPABILITIES(ifp);
1142218792Snp#endif
1143218792Snp		ADAPTER_UNLOCK(sc);
1144218792Snp		break;
1145218792Snp
1146218792Snp	case SIOCSIFMEDIA:
1147218792Snp	case SIOCGIFMEDIA:
1148218792Snp		ifmedia_ioctl(ifp, ifr, &pi->media, cmd);
1149218792Snp		break;
1150218792Snp
1151218792Snp	default:
1152218792Snp		rc = ether_ioctl(ifp, cmd, data);
1153218792Snp	}
1154218792Snp
1155218792Snp	return (rc);
1156218792Snp}
1157218792Snp
1158218792Snpstatic int
1159218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m)
1160218792Snp{
1161218792Snp	struct port_info *pi = ifp->if_softc;
1162218792Snp	struct adapter *sc = pi->adapter;
1163218792Snp	struct sge_txq *txq = &sc->sge.txq[pi->first_txq];
1164218792Snp	struct buf_ring *br;
1165218792Snp	int rc;
1166218792Snp
1167218792Snp	M_ASSERTPKTHDR(m);
1168218792Snp
1169228561Snp	if (__predict_false(pi->link_cfg.link_ok == 0)) {
1170218792Snp		m_freem(m);
1171228561Snp		return (ENETDOWN);
1172218792Snp	}
1173218792Snp
1174218792Snp	if (m->m_flags & M_FLOWID)
1175218792Snp		txq += (m->m_pkthdr.flowid % pi->ntxq);
1176220873Snp	br = txq->br;
1177218792Snp
1178218792Snp	if (TXQ_TRYLOCK(txq) == 0) {
1179228561Snp		struct sge_eq *eq = &txq->eq;
1180228561Snp
1181218792Snp		/*
1182228561Snp		 * It is possible that t4_eth_tx finishes up and releases the
1183228561Snp		 * lock between the TRYLOCK above and the drbr_enqueue here.  We
1184228561Snp		 * need to make sure that this mbuf doesn't just sit there in
1185228561Snp		 * the drbr.
1186218792Snp		 */
1187218792Snp
1188228561Snp		rc = drbr_enqueue(ifp, br, m);
1189228561Snp		if (rc == 0 && callout_pending(&eq->tx_callout) == 0 &&
1190228561Snp		    !(eq->flags & EQ_DOOMED))
1191228561Snp			callout_reset(&eq->tx_callout, 1, t4_tx_callout, eq);
1192228561Snp		return (rc);
1193218792Snp	}
1194218792Snp
1195218792Snp	/*
1196218792Snp	 * txq->m is the mbuf that is held up due to a temporary shortage of
1197218792Snp	 * resources and it should be put on the wire first.  Then what's in
1198218792Snp	 * drbr and finally the mbuf that was just passed in to us.
1199218792Snp	 *
1200218792Snp	 * Return code should indicate the fate of the mbuf that was passed in
1201218792Snp	 * this time.
1202218792Snp	 */
1203218792Snp
1204218792Snp	TXQ_LOCK_ASSERT_OWNED(txq);
1205218792Snp	if (drbr_needs_enqueue(ifp, br) || txq->m) {
1206218792Snp
1207218792Snp		/* Queued for transmission. */
1208218792Snp
1209218792Snp		rc = drbr_enqueue(ifp, br, m);
1210218792Snp		m = txq->m ? txq->m : drbr_dequeue(ifp, br);
1211218792Snp		(void) t4_eth_tx(ifp, txq, m);
1212218792Snp		TXQ_UNLOCK(txq);
1213218792Snp		return (rc);
1214218792Snp	}
1215218792Snp
1216218792Snp	/* Direct transmission. */
1217218792Snp	rc = t4_eth_tx(ifp, txq, m);
1218218792Snp	if (rc != 0 && txq->m)
1219218792Snp		rc = 0;	/* held, will be transmitted soon (hopefully) */
1220218792Snp
1221218792Snp	TXQ_UNLOCK(txq);
1222218792Snp	return (rc);
1223218792Snp}
1224218792Snp
1225218792Snpstatic void
1226218792Snpcxgbe_qflush(struct ifnet *ifp)
1227218792Snp{
1228218792Snp	struct port_info *pi = ifp->if_softc;
1229220649Snp	struct sge_txq *txq;
1230220649Snp	int i;
1231220649Snp	struct mbuf *m;
1232218792Snp
1233228561Snp	/* queues do not exist if !PORT_INIT_DONE. */
1234228561Snp	if (pi->flags & PORT_INIT_DONE) {
1235220649Snp		for_each_txq(pi, i, txq) {
1236220649Snp			TXQ_LOCK(txq);
1237220649Snp			m_freem(txq->m);
1238228561Snp			txq->m = NULL;
1239220873Snp			while ((m = buf_ring_dequeue_sc(txq->br)) != NULL)
1240220649Snp				m_freem(m);
1241220649Snp			TXQ_UNLOCK(txq);
1242220649Snp		}
1243220649Snp	}
1244220649Snp	if_qflush(ifp);
1245218792Snp}
1246218792Snp
1247218792Snpstatic int
1248218792Snpcxgbe_media_change(struct ifnet *ifp)
1249218792Snp{
1250218792Snp	struct port_info *pi = ifp->if_softc;
1251218792Snp
1252218792Snp	device_printf(pi->dev, "%s unimplemented.\n", __func__);
1253218792Snp
1254218792Snp	return (EOPNOTSUPP);
1255218792Snp}
1256218792Snp
1257218792Snpstatic void
1258218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
1259218792Snp{
1260218792Snp	struct port_info *pi = ifp->if_softc;
1261218792Snp	struct ifmedia_entry *cur = pi->media.ifm_cur;
1262218792Snp	int speed = pi->link_cfg.speed;
1263218792Snp	int data = (pi->port_type << 8) | pi->mod_type;
1264218792Snp
1265218792Snp	if (cur->ifm_data != data) {
1266218792Snp		build_medialist(pi);
1267218792Snp		cur = pi->media.ifm_cur;
1268218792Snp	}
1269218792Snp
1270218792Snp	ifmr->ifm_status = IFM_AVALID;
1271218792Snp	if (!pi->link_cfg.link_ok)
1272218792Snp		return;
1273218792Snp
1274218792Snp	ifmr->ifm_status |= IFM_ACTIVE;
1275218792Snp
1276218792Snp	/* active and current will differ iff current media is autoselect. */
1277218792Snp	if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO)
1278218792Snp		return;
1279218792Snp
1280218792Snp	ifmr->ifm_active = IFM_ETHER | IFM_FDX;
1281218792Snp	if (speed == SPEED_10000)
1282218792Snp		ifmr->ifm_active |= IFM_10G_T;
1283218792Snp	else if (speed == SPEED_1000)
1284218792Snp		ifmr->ifm_active |= IFM_1000_T;
1285218792Snp	else if (speed == SPEED_100)
1286218792Snp		ifmr->ifm_active |= IFM_100_TX;
1287218792Snp	else if (speed == SPEED_10)
1288218792Snp		ifmr->ifm_active |= IFM_10_T;
1289218792Snp	else
1290218792Snp		KASSERT(0, ("%s: link up but speed unknown (%u)", __func__,
1291218792Snp			    speed));
1292218792Snp}
1293218792Snp
1294218792Snpvoid
1295218792Snpt4_fatal_err(struct adapter *sc)
1296218792Snp{
1297218792Snp	t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0);
1298218792Snp	t4_intr_disable(sc);
1299218792Snp	log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n",
1300218792Snp	    device_get_nameunit(sc->dev));
1301218792Snp}
1302218792Snp
1303218792Snpstatic int
1304218792Snpmap_bars(struct adapter *sc)
1305218792Snp{
1306218792Snp	sc->regs_rid = PCIR_BAR(0);
1307218792Snp	sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
1308218792Snp	    &sc->regs_rid, RF_ACTIVE);
1309218792Snp	if (sc->regs_res == NULL) {
1310218792Snp		device_printf(sc->dev, "cannot map registers.\n");
1311218792Snp		return (ENXIO);
1312218792Snp	}
1313218792Snp	sc->bt = rman_get_bustag(sc->regs_res);
1314218792Snp	sc->bh = rman_get_bushandle(sc->regs_res);
1315218792Snp	sc->mmio_len = rman_get_size(sc->regs_res);
1316218792Snp
1317218792Snp	sc->msix_rid = PCIR_BAR(4);
1318218792Snp	sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY,
1319218792Snp	    &sc->msix_rid, RF_ACTIVE);
1320218792Snp	if (sc->msix_res == NULL) {
1321218792Snp		device_printf(sc->dev, "cannot map MSI-X BAR.\n");
1322218792Snp		return (ENXIO);
1323218792Snp	}
1324218792Snp
1325218792Snp	return (0);
1326218792Snp}
1327218792Snp
1328218792Snpstatic void
1329218792Snpsetup_memwin(struct adapter *sc)
1330218792Snp{
1331237587Snp	uint32_t bar0;
1332218792Snp
1333237587Snp	/*
1334237587Snp	 * Read low 32b of bar0 indirectly via the hardware backdoor mechanism.
1335237587Snp	 * Works from within PCI passthrough environments too, where
1336237587Snp	 * rman_get_start() can return a different value.  We need to program
1337237587Snp	 * the memory window decoders with the actual addresses that will be
1338237587Snp	 * coming across the PCIe link.
1339237587Snp	 */
1340237587Snp	bar0 = t4_hw_pci_read_cfg4(sc, PCIR_BAR(0));
1341237587Snp	bar0 &= (uint32_t) PCIM_BAR_MEM_BASE;
1342218792Snp
1343218792Snp	t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 0),
1344218792Snp	    	     (bar0 + MEMWIN0_BASE) | V_BIR(0) |
1345218792Snp		     V_WINDOW(ilog2(MEMWIN0_APERTURE) - 10));
1346218792Snp
1347218792Snp	t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 1),
1348218792Snp		     (bar0 + MEMWIN1_BASE) | V_BIR(0) |
1349218792Snp		     V_WINDOW(ilog2(MEMWIN1_APERTURE) - 10));
1350218792Snp
1351218792Snp	t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2),
1352218792Snp		     (bar0 + MEMWIN2_BASE) | V_BIR(0) |
1353218792Snp		     V_WINDOW(ilog2(MEMWIN2_APERTURE) - 10));
1354237587Snp
1355237587Snp	/* flush */
1356237587Snp	t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2));
1357218792Snp}
1358218792Snp
1359218792Snpstatic int
1360218792Snpcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g,
1361218792Snp    struct intrs_and_queues *iaq)
1362218792Snp{
1363228561Snp	int rc, itype, navail, nrxq10g, nrxq1g, n;
1364228561Snp	int nofldrxq10g = 0, nofldrxq1g = 0;
1365218792Snp
1366218792Snp	bzero(iaq, sizeof(*iaq));
1367218792Snp
1368228561Snp	iaq->ntxq10g = t4_ntxq10g;
1369228561Snp	iaq->ntxq1g = t4_ntxq1g;
1370228561Snp	iaq->nrxq10g = nrxq10g = t4_nrxq10g;
1371228561Snp	iaq->nrxq1g = nrxq1g = t4_nrxq1g;
1372237263Snp#ifdef TCP_OFFLOAD
1373237463Snp	if (is_offload(sc)) {
1374237463Snp		iaq->nofldtxq10g = t4_nofldtxq10g;
1375237463Snp		iaq->nofldtxq1g = t4_nofldtxq1g;
1376237463Snp		iaq->nofldrxq10g = nofldrxq10g = t4_nofldrxq10g;
1377237463Snp		iaq->nofldrxq1g = nofldrxq1g = t4_nofldrxq1g;
1378237463Snp	}
1379228561Snp#endif
1380228561Snp
1381219944Snp	for (itype = INTR_MSIX; itype; itype >>= 1) {
1382218792Snp
1383228561Snp		if ((itype & t4_intr_types) == 0)
1384218792Snp			continue;	/* not allowed */
1385218792Snp
1386219944Snp		if (itype == INTR_MSIX)
1387218792Snp			navail = pci_msix_count(sc->dev);
1388219944Snp		else if (itype == INTR_MSI)
1389218792Snp			navail = pci_msi_count(sc->dev);
1390218792Snp		else
1391218792Snp			navail = 1;
1392228561Snprestart:
1393218792Snp		if (navail == 0)
1394218792Snp			continue;
1395218792Snp
1396218792Snp		iaq->intr_type = itype;
1397228561Snp		iaq->intr_flags = 0;
1398218792Snp
1399228561Snp		/*
1400228561Snp		 * Best option: an interrupt vector for errors, one for the
1401228561Snp		 * firmware event queue, and one each for each rxq (NIC as well
1402228561Snp		 * as offload).
1403228561Snp		 */
1404228561Snp		iaq->nirq = T4_EXTRA_INTR;
1405228561Snp		iaq->nirq += n10g * (nrxq10g + nofldrxq10g);
1406228561Snp		iaq->nirq += n1g * (nrxq1g + nofldrxq1g);
1407228561Snp		if (iaq->nirq <= navail &&
1408228561Snp		    (itype != INTR_MSI || powerof2(iaq->nirq))) {
1409228561Snp			iaq->intr_flags |= INTR_DIRECT;
1410228561Snp			goto allocate;
1411228561Snp		}
1412218792Snp
1413228561Snp		/*
1414228561Snp		 * Second best option: an interrupt vector for errors, one for
1415228561Snp		 * the firmware event queue, and one each for either NIC or
1416228561Snp		 * offload rxq's.
1417228561Snp		 */
1418228561Snp		iaq->nirq = T4_EXTRA_INTR;
1419228561Snp		iaq->nirq += n10g * max(nrxq10g, nofldrxq10g);
1420228561Snp		iaq->nirq += n1g * max(nrxq1g, nofldrxq1g);
1421228561Snp		if (iaq->nirq <= navail &&
1422228561Snp		    (itype != INTR_MSI || powerof2(iaq->nirq)))
1423228561Snp			goto allocate;
1424218792Snp
1425228561Snp		/*
1426228561Snp		 * Next best option: an interrupt vector for errors, one for the
1427228561Snp		 * firmware event queue, and at least one per port.  At this
1428228561Snp		 * point we know we'll have to downsize nrxq or nofldrxq to fit
1429228561Snp		 * what's available to us.
1430228561Snp		 */
1431228561Snp		iaq->nirq = T4_EXTRA_INTR;
1432228561Snp		iaq->nirq += n10g + n1g;
1433228561Snp		if (iaq->nirq <= navail) {
1434228561Snp			int leftover = navail - iaq->nirq;
1435218792Snp
1436228561Snp			if (n10g > 0) {
1437228561Snp				int target = max(nrxq10g, nofldrxq10g);
1438219944Snp
1439228561Snp				n = 1;
1440228561Snp				while (n < target && leftover >= n10g) {
1441228561Snp					leftover -= n10g;
1442228561Snp					iaq->nirq += n10g;
1443228561Snp					n++;
1444228561Snp				}
1445228561Snp				iaq->nrxq10g = min(n, nrxq10g);
1446237263Snp#ifdef TCP_OFFLOAD
1447237463Snp				if (is_offload(sc))
1448237463Snp					iaq->nofldrxq10g = min(n, nofldrxq10g);
1449228561Snp#endif
1450228561Snp			}
1451218792Snp
1452228561Snp			if (n1g > 0) {
1453228561Snp				int target = max(nrxq1g, nofldrxq1g);
1454219944Snp
1455228561Snp				n = 1;
1456228561Snp				while (n < target && leftover >= n1g) {
1457228561Snp					leftover -= n1g;
1458228561Snp					iaq->nirq += n1g;
1459228561Snp					n++;
1460219944Snp				}
1461228561Snp				iaq->nrxq1g = min(n, nrxq1g);
1462237263Snp#ifdef TCP_OFFLOAD
1463237463Snp				if (is_offload(sc))
1464237463Snp					iaq->nofldrxq1g = min(n, nofldrxq1g);
1465228561Snp#endif
1466219944Snp			}
1467219944Snp
1468228561Snp			if (itype != INTR_MSI || powerof2(iaq->nirq))
1469228561Snp				goto allocate;
1470218792Snp		}
1471218792Snp
1472228561Snp		/*
1473228561Snp		 * Least desirable option: one interrupt vector for everything.
1474228561Snp		 */
1475228561Snp		iaq->nirq = iaq->nrxq10g = iaq->nrxq1g = 1;
1476237263Snp#ifdef TCP_OFFLOAD
1477237463Snp		if (is_offload(sc))
1478237463Snp			iaq->nofldrxq10g = iaq->nofldrxq1g = 1;
1479228561Snp#endif
1480228561Snp
1481228561Snpallocate:
1482218792Snp		navail = iaq->nirq;
1483218792Snp		rc = 0;
1484219944Snp		if (itype == INTR_MSIX)
1485218792Snp			rc = pci_alloc_msix(sc->dev, &navail);
1486219944Snp		else if (itype == INTR_MSI)
1487218792Snp			rc = pci_alloc_msi(sc->dev, &navail);
1488218792Snp
1489218792Snp		if (rc == 0) {
1490218792Snp			if (navail == iaq->nirq)
1491218792Snp				return (0);
1492218792Snp
1493218792Snp			/*
1494218792Snp			 * Didn't get the number requested.  Use whatever number
1495218792Snp			 * the kernel is willing to allocate (it's in navail).
1496218792Snp			 */
1497228561Snp			device_printf(sc->dev, "fewer vectors than requested, "
1498228561Snp			    "type=%d, req=%d, rcvd=%d; will downshift req.\n",
1499228561Snp			    itype, iaq->nirq, navail);
1500218792Snp			pci_release_msi(sc->dev);
1501228561Snp			goto restart;
1502218792Snp		}
1503218792Snp
1504218792Snp		device_printf(sc->dev,
1505218792Snp		    "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n",
1506218792Snp		    itype, rc, iaq->nirq, navail);
1507218792Snp	}
1508218792Snp
1509218792Snp	device_printf(sc->dev,
1510218792Snp	    "failed to find a usable interrupt type.  "
1511228561Snp	    "allowed=%d, msi-x=%d, msi=%d, intx=1", t4_intr_types,
1512218792Snp	    pci_msix_count(sc->dev), pci_msi_count(sc->dev));
1513218792Snp
1514218792Snp	return (ENXIO);
1515218792Snp}
1516218792Snp
1517218792Snp/*
1518228561Snp * Install a compatible firmware (if required), establish contact with it (by
1519228561Snp * saying hello), and reset the device.  If we end up as the master driver,
1520228561Snp * partition adapter resources by providing a configuration file to the
1521228561Snp * firmware.
1522218792Snp */
1523218792Snpstatic int
1524218792Snpprep_firmware(struct adapter *sc)
1525218792Snp{
1526228561Snp	const struct firmware *fw = NULL, *cfg = NULL, *default_cfg;
1527218792Snp	int rc;
1528218792Snp	enum dev_state state;
1529218792Snp
1530228561Snp	default_cfg = firmware_get(T4_CFGNAME);
1531228561Snp
1532218792Snp	/* Check firmware version and install a different one if necessary */
1533218792Snp	rc = t4_check_fw_version(sc);
1534234831Snp	snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u",
1535234831Snp	    G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers),
1536234831Snp	    G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers),
1537234831Snp	    G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers),
1538234831Snp	    G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers));
1539228561Snp	if (rc != 0) {
1540219287Snp		uint32_t v = 0;
1541218792Snp
1542218792Snp		fw = firmware_get(T4_FWNAME);
1543219287Snp		if (fw != NULL) {
1544219287Snp			const struct fw_hdr *hdr = (const void *)fw->data;
1545219287Snp
1546219287Snp			v = ntohl(hdr->fw_ver);
1547219287Snp
1548219287Snp			/*
1549219287Snp			 * The firmware module will not be used if it isn't the
1550219287Snp			 * same major version as what the driver was compiled
1551228561Snp			 * with.
1552219287Snp			 */
1553219287Snp			if (G_FW_HDR_FW_VER_MAJOR(v) != FW_VERSION_MAJOR) {
1554219287Snp				device_printf(sc->dev,
1555219287Snp				    "Found firmware image but version %d "
1556219287Snp				    "can not be used with this driver (%d)\n",
1557219287Snp				    G_FW_HDR_FW_VER_MAJOR(v), FW_VERSION_MAJOR);
1558219287Snp
1559219287Snp				firmware_put(fw, FIRMWARE_UNLOAD);
1560219287Snp				fw = NULL;
1561219287Snp			}
1562218792Snp		}
1563218792Snp
1564228561Snp		if (fw == NULL && rc < 0) {
1565219287Snp			device_printf(sc->dev, "No usable firmware. "
1566228561Snp			    "card has %d.%d.%d, driver compiled with %d.%d.%d",
1567219287Snp			    G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers),
1568219287Snp			    G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers),
1569219287Snp			    G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers),
1570219287Snp			    FW_VERSION_MAJOR, FW_VERSION_MINOR,
1571228561Snp			    FW_VERSION_MICRO);
1572228561Snp			rc = EAGAIN;
1573228561Snp			goto done;
1574219287Snp		}
1575219287Snp
1576219287Snp		/*
1577219287Snp		 * Always upgrade, even for minor/micro/build mismatches.
1578219287Snp		 * Downgrade only for a major version mismatch or if
1579219287Snp		 * force_firmware_install was specified.
1580219287Snp		 */
1581228561Snp		if (fw != NULL && (rc < 0 || v > sc->params.fw_vers)) {
1582218792Snp			device_printf(sc->dev,
1583219287Snp			    "installing firmware %d.%d.%d.%d on card.\n",
1584219287Snp			    G_FW_HDR_FW_VER_MAJOR(v), G_FW_HDR_FW_VER_MINOR(v),
1585219287Snp			    G_FW_HDR_FW_VER_MICRO(v), G_FW_HDR_FW_VER_BUILD(v));
1586219287Snp
1587219287Snp			rc = -t4_load_fw(sc, fw->data, fw->datasize);
1588219287Snp			if (rc != 0) {
1589219287Snp				device_printf(sc->dev,
1590219287Snp				    "failed to install firmware: %d\n", rc);
1591228561Snp				goto done;
1592219287Snp			} else {
1593219287Snp				/* refresh */
1594219287Snp				(void) t4_check_fw_version(sc);
1595234831Snp				snprintf(sc->fw_version,
1596234831Snp				    sizeof(sc->fw_version), "%u.%u.%u.%u",
1597234831Snp				    G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers),
1598234831Snp				    G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers),
1599234831Snp				    G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers),
1600234831Snp				    G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers));
1601219287Snp			}
1602218792Snp		}
1603218792Snp	}
1604218792Snp
1605228561Snp	/* Contact firmware.  */
1606228561Snp	rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state);
1607218792Snp	if (rc < 0) {
1608218792Snp		rc = -rc;
1609218792Snp		device_printf(sc->dev,
1610218792Snp		    "failed to connect to the firmware: %d.\n", rc);
1611228561Snp		goto done;
1612218792Snp	}
1613228561Snp	if (rc == sc->mbox)
1614228561Snp		sc->flags |= MASTER_PF;
1615218792Snp
1616218792Snp	/* Reset device */
1617218792Snp	rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST);
1618218792Snp	if (rc != 0) {
1619218792Snp		device_printf(sc->dev, "firmware reset failed: %d.\n", rc);
1620218792Snp		if (rc != ETIMEDOUT && rc != EIO)
1621218792Snp			t4_fw_bye(sc, sc->mbox);
1622228561Snp		goto done;
1623218792Snp	}
1624218792Snp
1625228561Snp	/* Partition adapter resources as specified in the config file. */
1626228561Snp	if (sc->flags & MASTER_PF) {
1627228561Snp		if (strncmp(t4_cfg_file, "default", sizeof(t4_cfg_file))) {
1628228561Snp			char s[32];
1629228561Snp
1630228561Snp			snprintf(s, sizeof(s), "t4fw_cfg_%s", t4_cfg_file);
1631228561Snp			cfg = firmware_get(s);
1632228561Snp			if (cfg == NULL) {
1633228561Snp				device_printf(sc->dev,
1634228561Snp				    "unable to locate %s module, "
1635228561Snp				    "will use default config file.\n", s);
1636228561Snp			}
1637228561Snp		}
1638228561Snp
1639228561Snp		rc = partition_resources(sc, cfg ? cfg : default_cfg);
1640228561Snp		if (rc != 0)
1641228561Snp			goto done;	/* error message displayed already */
1642228561Snp	}
1643228561Snp
1644218792Snp	sc->flags |= FW_OK;
1645218792Snp
1646228561Snpdone:
1647228561Snp	if (fw != NULL)
1648228561Snp		firmware_put(fw, FIRMWARE_UNLOAD);
1649228561Snp	if (cfg != NULL)
1650228561Snp		firmware_put(cfg, FIRMWARE_UNLOAD);
1651228561Snp	if (default_cfg != NULL)
1652228561Snp		firmware_put(default_cfg, FIRMWARE_UNLOAD);
1653228561Snp
1654228561Snp	return (rc);
1655218792Snp}
1656218792Snp
1657228561Snp#define FW_PARAM_DEV(param) \
1658228561Snp	(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \
1659228561Snp	 V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
1660228561Snp#define FW_PARAM_PFVF(param) \
1661228561Snp	(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \
1662228561Snp	 V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param))
1663228561Snp
1664228561Snp/*
1665228561Snp * Upload configuration file to card's memory.
1666228561Snp */
1667218792Snpstatic int
1668228561Snpupload_config_file(struct adapter *sc, const struct firmware *fw, uint32_t *mt,
1669228561Snp    uint32_t *ma)
1670222551Snp{
1671228561Snp	int rc, i;
1672228561Snp	uint32_t param, val, mtype, maddr, bar, off, win, remaining;
1673228561Snp	const uint32_t *b;
1674222551Snp
1675228561Snp	/* Figure out where the firmware wants us to upload it. */
1676228561Snp	param = FW_PARAM_DEV(CF);
1677228561Snp	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, &param, &val);
1678222551Snp	if (rc != 0) {
1679228561Snp		/* Firmwares without config file support will fail this way */
1680222551Snp		device_printf(sc->dev,
1681228561Snp		    "failed to query config file location: %d.\n", rc);
1682222551Snp		return (rc);
1683222551Snp	}
1684228561Snp	*mt = mtype = G_FW_PARAMS_PARAM_Y(val);
1685228561Snp	*ma = maddr = G_FW_PARAMS_PARAM_Z(val) << 16;
1686222551Snp
1687228561Snp	if (maddr & 3) {
1688228561Snp		device_printf(sc->dev,
1689228561Snp		    "cannot upload config file (type %u, addr %x).\n",
1690228561Snp		    mtype, maddr);
1691228561Snp		return (EFAULT);
1692228561Snp	}
1693222551Snp
1694228561Snp	/* Translate mtype/maddr to an address suitable for the PCIe window */
1695228561Snp	val = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE);
1696228561Snp	val &= F_EDRAM0_ENABLE | F_EDRAM1_ENABLE | F_EXT_MEM_ENABLE;
1697228561Snp	switch (mtype) {
1698228561Snp	case FW_MEMTYPE_CF_EDC0:
1699228561Snp		if (!(val & F_EDRAM0_ENABLE))
1700228561Snp			goto err;
1701228561Snp		bar = t4_read_reg(sc, A_MA_EDRAM0_BAR);
1702228561Snp		maddr += G_EDRAM0_BASE(bar) << 20;
1703228561Snp		break;
1704228561Snp
1705228561Snp	case FW_MEMTYPE_CF_EDC1:
1706228561Snp		if (!(val & F_EDRAM1_ENABLE))
1707228561Snp			goto err;
1708228561Snp		bar = t4_read_reg(sc, A_MA_EDRAM1_BAR);
1709228561Snp		maddr += G_EDRAM1_BASE(bar) << 20;
1710228561Snp		break;
1711228561Snp
1712228561Snp	case FW_MEMTYPE_CF_EXTMEM:
1713228561Snp		if (!(val & F_EXT_MEM_ENABLE))
1714228561Snp			goto err;
1715228561Snp		bar = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR);
1716228561Snp		maddr += G_EXT_MEM_BASE(bar) << 20;
1717228561Snp		break;
1718228561Snp
1719228561Snp	default:
1720228561Snperr:
1721228561Snp		device_printf(sc->dev,
1722228561Snp		    "cannot upload config file (type %u, enabled %u).\n",
1723228561Snp		    mtype, val);
1724228561Snp		return (EFAULT);
1725228561Snp	}
1726228561Snp
1727228561Snp	/*
1728228561Snp	 * Position the PCIe window (we use memwin2) to the 16B aligned area
1729228561Snp	 * just at/before the upload location.
1730228561Snp	 */
1731228561Snp	win = maddr & ~0xf;
1732228561Snp	off = maddr - win;  /* offset from the start of the window. */
1733228561Snp	t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2), win);
1734228561Snp	t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2));
1735228561Snp
1736228561Snp	remaining = fw->datasize;
1737228561Snp	if (remaining > FLASH_CFG_MAX_SIZE ||
1738228561Snp	    remaining > MEMWIN2_APERTURE - off) {
1739228561Snp		device_printf(sc->dev, "cannot upload config file all at once "
1740228561Snp		    "(size %u, max %u, room %u).\n",
1741228561Snp		    remaining, FLASH_CFG_MAX_SIZE, MEMWIN2_APERTURE - off);
1742228561Snp		return (EFBIG);
1743228561Snp	}
1744228561Snp
1745228561Snp	/*
1746228561Snp	 * XXX: sheer laziness.  We deliberately added 4 bytes of useless
1747228561Snp	 * stuffing/comments at the end of the config file so it's ok to simply
1748228561Snp	 * throw away the last remaining bytes when the config file is not an
1749228561Snp	 * exact multiple of 4.
1750228561Snp	 */
1751228561Snp	b = fw->data;
1752228561Snp	for (i = 0; remaining >= 4; i += 4, remaining -= 4)
1753228561Snp		t4_write_reg(sc, MEMWIN2_BASE + off + i, *b++);
1754228561Snp
1755228561Snp	return (rc);
1756222551Snp}
1757222551Snp
1758228561Snp/*
1759228561Snp * Partition chip resources for use between various PFs, VFs, etc.  This is done
1760228561Snp * by uploading the firmware configuration file to the adapter and instructing
1761228561Snp * the firmware to process it.
1762228561Snp */
1763222551Snpstatic int
1764228561Snppartition_resources(struct adapter *sc, const struct firmware *cfg)
1765218792Snp{
1766218792Snp	int rc;
1767228561Snp	struct fw_caps_config_cmd caps;
1768228561Snp	uint32_t mtype, maddr, finicsum, cfcsum;
1769218792Snp
1770228561Snp	rc = cfg ? upload_config_file(sc, cfg, &mtype, &maddr) : ENOENT;
1771228561Snp	if (rc != 0) {
1772228561Snp		mtype = FW_MEMTYPE_CF_FLASH;
1773228561Snp		maddr = t4_flash_cfg_addr(sc);
1774228561Snp	}
1775228561Snp
1776228561Snp	bzero(&caps, sizeof(caps));
1777228561Snp	caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
1778218792Snp	    F_FW_CMD_REQUEST | F_FW_CMD_READ);
1779228561Snp	caps.cfvalid_to_len16 = htobe32(F_FW_CAPS_CONFIG_CMD_CFVALID |
1780228561Snp	    V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) |
1781228561Snp	    V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(maddr >> 16) | FW_LEN16(caps));
1782228561Snp	rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps);
1783228561Snp	if (rc != 0) {
1784228561Snp		device_printf(sc->dev,
1785228561Snp		    "failed to pre-process config file: %d.\n", rc);
1786218792Snp		return (rc);
1787228561Snp	}
1788218792Snp
1789228561Snp	finicsum = be32toh(caps.finicsum);
1790228561Snp	cfcsum = be32toh(caps.cfcsum);
1791228561Snp	if (finicsum != cfcsum) {
1792228561Snp		device_printf(sc->dev,
1793228561Snp		    "WARNING: config file checksum mismatch: %08x %08x\n",
1794228561Snp		    finicsum, cfcsum);
1795228561Snp	}
1796228561Snp	sc->cfcsum = cfcsum;
1797218792Snp
1798228561Snp#define LIMIT_CAPS(x) do { \
1799228561Snp	caps.x &= htobe16(t4_##x##_allowed); \
1800228561Snp	sc->x = htobe16(caps.x); \
1801228561Snp} while (0)
1802228561Snp
1803228561Snp	/*
1804228561Snp	 * Let the firmware know what features will (not) be used so it can tune
1805228561Snp	 * things accordingly.
1806228561Snp	 */
1807228561Snp	LIMIT_CAPS(linkcaps);
1808228561Snp	LIMIT_CAPS(niccaps);
1809228561Snp	LIMIT_CAPS(toecaps);
1810228561Snp	LIMIT_CAPS(rdmacaps);
1811228561Snp	LIMIT_CAPS(iscsicaps);
1812228561Snp	LIMIT_CAPS(fcoecaps);
1813228561Snp#undef LIMIT_CAPS
1814228561Snp
1815228561Snp	caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
1816218792Snp	    F_FW_CMD_REQUEST | F_FW_CMD_WRITE);
1817228561Snp	caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps));
1818228561Snp	rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), NULL);
1819228561Snp	if (rc != 0) {
1820228561Snp		device_printf(sc->dev,
1821228561Snp		    "failed to process config file: %d.\n", rc);
1822228561Snp		return (rc);
1823228561Snp	}
1824218792Snp
1825228561Snp	return (0);
1826218792Snp}
1827218792Snp
1828228561Snp/*
1829228561Snp * Retrieve parameters that are needed (or nice to have) prior to calling
1830228561Snp * t4_sge_init and t4_fw_initialize.
1831228561Snp */
1832218792Snpstatic int
1833228561Snpget_params__pre_init(struct adapter *sc)
1834218792Snp{
1835218792Snp	int rc;
1836228561Snp	uint32_t param[2], val[2];
1837228561Snp	struct fw_devlog_cmd cmd;
1838228561Snp	struct devlog_params *dlog = &sc->params.devlog;
1839218792Snp
1840228561Snp	param[0] = FW_PARAM_DEV(PORTVEC);
1841228561Snp	param[1] = FW_PARAM_DEV(CCLK);
1842228561Snp	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val);
1843218792Snp	if (rc != 0) {
1844218792Snp		device_printf(sc->dev,
1845228561Snp		    "failed to query parameters (pre_init): %d.\n", rc);
1846228561Snp		return (rc);
1847218792Snp	}
1848218792Snp
1849218792Snp	sc->params.portvec = val[0];
1850240452Snp	sc->params.nports = bitcount32(val[0]);
1851228561Snp	sc->params.vpd.cclk = val[1];
1852218792Snp
1853228561Snp	/* Read device log parameters. */
1854228561Snp	bzero(&cmd, sizeof(cmd));
1855228561Snp	cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) |
1856228561Snp	    F_FW_CMD_REQUEST | F_FW_CMD_READ);
1857228561Snp	cmd.retval_len16 = htobe32(FW_LEN16(cmd));
1858228561Snp	rc = -t4_wr_mbox(sc, sc->mbox, &cmd, sizeof(cmd), &cmd);
1859228561Snp	if (rc != 0) {
1860228561Snp		device_printf(sc->dev,
1861228561Snp		    "failed to get devlog parameters: %d.\n", rc);
1862228561Snp		bzero(dlog, sizeof (*dlog));
1863228561Snp		rc = 0;	/* devlog isn't critical for device operation */
1864228561Snp	} else {
1865228561Snp		val[0] = be32toh(cmd.memtype_devlog_memaddr16_devlog);
1866228561Snp		dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(val[0]);
1867228561Snp		dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(val[0]) << 4;
1868228561Snp		dlog->size = be32toh(cmd.memsize_devlog);
1869228561Snp	}
1870228561Snp
1871228561Snp	return (rc);
1872228561Snp}
1873228561Snp
1874228561Snp/*
1875228561Snp * Retrieve various parameters that are of interest to the driver.  The device
1876228561Snp * has been initialized by the firmware at this point.
1877228561Snp */
1878228561Snpstatic int
1879228561Snpget_params__post_init(struct adapter *sc)
1880228561Snp{
1881228561Snp	int rc;
1882228561Snp	uint32_t param[7], val[7];
1883228561Snp	struct fw_caps_config_cmd caps;
1884228561Snp
1885228561Snp	param[0] = FW_PARAM_PFVF(IQFLINT_START);
1886228561Snp	param[1] = FW_PARAM_PFVF(EQ_START);
1887228561Snp	param[2] = FW_PARAM_PFVF(FILTER_START);
1888228561Snp	param[3] = FW_PARAM_PFVF(FILTER_END);
1889228561Snp	rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 4, param, val);
1890228561Snp	if (rc != 0) {
1891228561Snp		device_printf(sc->dev,
1892228561Snp		    "failed to query parameters (post_init): %d.\n", rc);
1893228561Snp		return (rc);
1894228561Snp	}
1895228561Snp
1896228561Snp	sc->sge.iq_start = val[0];
1897228561Snp	sc->sge.eq_start = val[1];
1898228561Snp	sc->tids.ftid_base = val[2];
1899228561Snp	sc->tids.nftids = val[3] - val[2] + 1;
1900228561Snp
1901228561Snp	/* get capabilites */
1902228561Snp	bzero(&caps, sizeof(caps));
1903228561Snp	caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
1904228561Snp	    F_FW_CMD_REQUEST | F_FW_CMD_READ);
1905228561Snp	caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps));
1906228561Snp	rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps);
1907228561Snp	if (rc != 0) {
1908228561Snp		device_printf(sc->dev,
1909228561Snp		    "failed to get card capabilities: %d.\n", rc);
1910228561Snp		return (rc);
1911228561Snp	}
1912228561Snp
1913228561Snp	if (caps.toecaps) {
1914218792Snp		/* query offload-related parameters */
1915228561Snp		param[0] = FW_PARAM_DEV(NTID);
1916228561Snp		param[1] = FW_PARAM_PFVF(SERVER_START);
1917228561Snp		param[2] = FW_PARAM_PFVF(SERVER_END);
1918228561Snp		param[3] = FW_PARAM_PFVF(TDDP_START);
1919228561Snp		param[4] = FW_PARAM_PFVF(TDDP_END);
1920228561Snp		param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ);
1921228561Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val);
1922218792Snp		if (rc != 0) {
1923218792Snp			device_printf(sc->dev,
1924218792Snp			    "failed to query TOE parameters: %d.\n", rc);
1925228561Snp			return (rc);
1926218792Snp		}
1927218792Snp		sc->tids.ntids = val[0];
1928218792Snp		sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS);
1929218792Snp		sc->tids.stid_base = val[1];
1930218792Snp		sc->tids.nstids = val[2] - val[1] + 1;
1931218792Snp		sc->vres.ddp.start = val[3];
1932218792Snp		sc->vres.ddp.size = val[4] - val[3] + 1;
1933218792Snp		sc->params.ofldq_wr_cred = val[5];
1934218792Snp		sc->params.offload = 1;
1935218792Snp	}
1936228561Snp	if (caps.rdmacaps) {
1937228561Snp		param[0] = FW_PARAM_PFVF(STAG_START);
1938228561Snp		param[1] = FW_PARAM_PFVF(STAG_END);
1939228561Snp		param[2] = FW_PARAM_PFVF(RQ_START);
1940228561Snp		param[3] = FW_PARAM_PFVF(RQ_END);
1941228561Snp		param[4] = FW_PARAM_PFVF(PBL_START);
1942228561Snp		param[5] = FW_PARAM_PFVF(PBL_END);
1943228561Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val);
1944218792Snp		if (rc != 0) {
1945218792Snp			device_printf(sc->dev,
1946228561Snp			    "failed to query RDMA parameters(1): %d.\n", rc);
1947228561Snp			return (rc);
1948218792Snp		}
1949218792Snp		sc->vres.stag.start = val[0];
1950218792Snp		sc->vres.stag.size = val[1] - val[0] + 1;
1951218792Snp		sc->vres.rq.start = val[2];
1952218792Snp		sc->vres.rq.size = val[3] - val[2] + 1;
1953218792Snp		sc->vres.pbl.start = val[4];
1954218792Snp		sc->vres.pbl.size = val[5] - val[4] + 1;
1955228561Snp
1956228561Snp		param[0] = FW_PARAM_PFVF(SQRQ_START);
1957228561Snp		param[1] = FW_PARAM_PFVF(SQRQ_END);
1958228561Snp		param[2] = FW_PARAM_PFVF(CQ_START);
1959228561Snp		param[3] = FW_PARAM_PFVF(CQ_END);
1960228561Snp		param[4] = FW_PARAM_PFVF(OCQ_START);
1961228561Snp		param[5] = FW_PARAM_PFVF(OCQ_END);
1962228561Snp		rc = -t4_query_params(sc, 0, 0, 0, 6, param, val);
1963228561Snp		if (rc != 0) {
1964228561Snp			device_printf(sc->dev,
1965228561Snp			    "failed to query RDMA parameters(2): %d.\n", rc);
1966228561Snp			return (rc);
1967228561Snp		}
1968228561Snp		sc->vres.qp.start = val[0];
1969228561Snp		sc->vres.qp.size = val[1] - val[0] + 1;
1970228561Snp		sc->vres.cq.start = val[2];
1971228561Snp		sc->vres.cq.size = val[3] - val[2] + 1;
1972228561Snp		sc->vres.ocq.start = val[4];
1973228561Snp		sc->vres.ocq.size = val[5] - val[4] + 1;
1974218792Snp	}
1975228561Snp	if (caps.iscsicaps) {
1976228561Snp		param[0] = FW_PARAM_PFVF(ISCSI_START);
1977228561Snp		param[1] = FW_PARAM_PFVF(ISCSI_END);
1978228561Snp		rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val);
1979218792Snp		if (rc != 0) {
1980218792Snp			device_printf(sc->dev,
1981218792Snp			    "failed to query iSCSI parameters: %d.\n", rc);
1982228561Snp			return (rc);
1983218792Snp		}
1984218792Snp		sc->vres.iscsi.start = val[0];
1985218792Snp		sc->vres.iscsi.size = val[1] - val[0] + 1;
1986218792Snp	}
1987218792Snp
1988228561Snp	/* These are finalized by FW initialization, load their values now */
1989228561Snp	val[0] = t4_read_reg(sc, A_TP_TIMER_RESOLUTION);
1990228561Snp	sc->params.tp.tre = G_TIMERRESOLUTION(val[0]);
1991228561Snp	sc->params.tp.dack_re = G_DELAYEDACKRESOLUTION(val[0]);
1992228561Snp	t4_read_mtu_tbl(sc, sc->params.mtus, NULL);
1993228561Snp
1994218792Snp	return (rc);
1995218792Snp}
1996218792Snp
1997228561Snp#undef FW_PARAM_PFVF
1998228561Snp#undef FW_PARAM_DEV
1999228561Snp
2000218792Snpstatic void
2001218792Snpt4_set_desc(struct adapter *sc)
2002218792Snp{
2003218792Snp	char buf[128];
2004218792Snp	struct adapter_params *p = &sc->params;
2005218792Snp
2006228561Snp	snprintf(buf, sizeof(buf), "Chelsio %s %sNIC (rev %d), S/N:%s, E/C:%s",
2007228561Snp	    p->vpd.id, is_offload(sc) ? "R" : "", p->rev, p->vpd.sn, p->vpd.ec);
2008218792Snp
2009218792Snp	device_set_desc_copy(sc->dev, buf);
2010218792Snp}
2011218792Snp
2012218792Snpstatic void
2013218792Snpbuild_medialist(struct port_info *pi)
2014218792Snp{
2015218792Snp	struct ifmedia *media = &pi->media;
2016218792Snp	int data, m;
2017218792Snp
2018218792Snp	PORT_LOCK(pi);
2019218792Snp
2020218792Snp	ifmedia_removeall(media);
2021218792Snp
2022218792Snp	m = IFM_ETHER | IFM_FDX;
2023218792Snp	data = (pi->port_type << 8) | pi->mod_type;
2024218792Snp
2025218792Snp	switch(pi->port_type) {
2026218792Snp	case FW_PORT_TYPE_BT_XFI:
2027218792Snp		ifmedia_add(media, m | IFM_10G_T, data, NULL);
2028218792Snp		break;
2029218792Snp
2030218792Snp	case FW_PORT_TYPE_BT_XAUI:
2031218792Snp		ifmedia_add(media, m | IFM_10G_T, data, NULL);
2032218792Snp		/* fall through */
2033218792Snp
2034218792Snp	case FW_PORT_TYPE_BT_SGMII:
2035218792Snp		ifmedia_add(media, m | IFM_1000_T, data, NULL);
2036218792Snp		ifmedia_add(media, m | IFM_100_TX, data, NULL);
2037218792Snp		ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL);
2038218792Snp		ifmedia_set(media, IFM_ETHER | IFM_AUTO);
2039218792Snp		break;
2040218792Snp
2041218792Snp	case FW_PORT_TYPE_CX4:
2042218792Snp		ifmedia_add(media, m | IFM_10G_CX4, data, NULL);
2043218792Snp		ifmedia_set(media, m | IFM_10G_CX4);
2044218792Snp		break;
2045218792Snp
2046218792Snp	case FW_PORT_TYPE_SFP:
2047218792Snp	case FW_PORT_TYPE_FIBER_XFI:
2048218792Snp	case FW_PORT_TYPE_FIBER_XAUI:
2049218792Snp		switch (pi->mod_type) {
2050218792Snp
2051218792Snp		case FW_PORT_MOD_TYPE_LR:
2052218792Snp			ifmedia_add(media, m | IFM_10G_LR, data, NULL);
2053218792Snp			ifmedia_set(media, m | IFM_10G_LR);
2054218792Snp			break;
2055218792Snp
2056218792Snp		case FW_PORT_MOD_TYPE_SR:
2057218792Snp			ifmedia_add(media, m | IFM_10G_SR, data, NULL);
2058218792Snp			ifmedia_set(media, m | IFM_10G_SR);
2059218792Snp			break;
2060218792Snp
2061218792Snp		case FW_PORT_MOD_TYPE_LRM:
2062218792Snp			ifmedia_add(media, m | IFM_10G_LRM, data, NULL);
2063218792Snp			ifmedia_set(media, m | IFM_10G_LRM);
2064218792Snp			break;
2065218792Snp
2066218792Snp		case FW_PORT_MOD_TYPE_TWINAX_PASSIVE:
2067218792Snp		case FW_PORT_MOD_TYPE_TWINAX_ACTIVE:
2068218792Snp			ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL);
2069218792Snp			ifmedia_set(media, m | IFM_10G_TWINAX);
2070218792Snp			break;
2071218792Snp
2072218792Snp		case FW_PORT_MOD_TYPE_NONE:
2073218792Snp			m &= ~IFM_FDX;
2074218792Snp			ifmedia_add(media, m | IFM_NONE, data, NULL);
2075218792Snp			ifmedia_set(media, m | IFM_NONE);
2076218792Snp			break;
2077218792Snp
2078218792Snp		case FW_PORT_MOD_TYPE_NA:
2079218792Snp		case FW_PORT_MOD_TYPE_ER:
2080218792Snp		default:
2081218792Snp			ifmedia_add(media, m | IFM_UNKNOWN, data, NULL);
2082218792Snp			ifmedia_set(media, m | IFM_UNKNOWN);
2083218792Snp			break;
2084218792Snp		}
2085218792Snp		break;
2086218792Snp
2087218792Snp	case FW_PORT_TYPE_KX4:
2088218792Snp	case FW_PORT_TYPE_KX:
2089218792Snp	case FW_PORT_TYPE_KR:
2090218792Snp	default:
2091218792Snp		ifmedia_add(media, m | IFM_UNKNOWN, data, NULL);
2092218792Snp		ifmedia_set(media, m | IFM_UNKNOWN);
2093218792Snp		break;
2094218792Snp	}
2095218792Snp
2096218792Snp	PORT_UNLOCK(pi);
2097218792Snp}
2098218792Snp
2099231172Snp#define FW_MAC_EXACT_CHUNK	7
2100231172Snp
2101218792Snp/*
2102218792Snp * Program the port's XGMAC based on parameters in ifnet.  The caller also
2103218792Snp * indicates which parameters should be programmed (the rest are left alone).
2104218792Snp */
2105218792Snpstatic int
2106218792Snpupdate_mac_settings(struct port_info *pi, int flags)
2107218792Snp{
2108218792Snp	int rc;
2109218792Snp	struct ifnet *ifp = pi->ifp;
2110218792Snp	struct adapter *sc = pi->adapter;
2111218792Snp	int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1;
2112218792Snp
2113218792Snp	PORT_LOCK_ASSERT_OWNED(pi);
2114218792Snp	KASSERT(flags, ("%s: not told what to update.", __func__));
2115218792Snp
2116218792Snp	if (flags & XGMAC_MTU)
2117218792Snp		mtu = ifp->if_mtu;
2118218792Snp
2119218792Snp	if (flags & XGMAC_PROMISC)
2120218792Snp		promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0;
2121218792Snp
2122218792Snp	if (flags & XGMAC_ALLMULTI)
2123218792Snp		allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0;
2124218792Snp
2125218792Snp	if (flags & XGMAC_VLANEX)
2126218792Snp		vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0;
2127218792Snp
2128218792Snp	rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, mtu, promisc, allmulti, 1,
2129218792Snp	    vlanex, false);
2130218792Snp	if (rc) {
2131218792Snp		if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, rc);
2132218792Snp		return (rc);
2133218792Snp	}
2134218792Snp
2135218792Snp	if (flags & XGMAC_UCADDR) {
2136218792Snp		uint8_t ucaddr[ETHER_ADDR_LEN];
2137218792Snp
2138218792Snp		bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr));
2139218792Snp		rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt,
2140218792Snp		    ucaddr, true, true);
2141218792Snp		if (rc < 0) {
2142218792Snp			rc = -rc;
2143218792Snp			if_printf(ifp, "change_mac failed: %d\n", rc);
2144218792Snp			return (rc);
2145218792Snp		} else {
2146218792Snp			pi->xact_addr_filt = rc;
2147218792Snp			rc = 0;
2148218792Snp		}
2149218792Snp	}
2150218792Snp
2151218792Snp	if (flags & XGMAC_MCADDRS) {
2152231172Snp		const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK];
2153218792Snp		int del = 1;
2154218792Snp		uint64_t hash = 0;
2155218792Snp		struct ifmultiaddr *ifma;
2156231172Snp		int i = 0, j;
2157218792Snp
2158218792Snp		if_maddr_rlock(ifp);
2159218792Snp		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
2160238054Snp			if (ifma->ifma_addr->sa_family != AF_LINK)
2161218792Snp				continue;
2162231172Snp			mcaddr[i++] =
2163231172Snp			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2164218792Snp
2165231172Snp			if (i == FW_MAC_EXACT_CHUNK) {
2166231172Snp				rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid,
2167231172Snp				    del, i, mcaddr, NULL, &hash, 0);
2168231172Snp				if (rc < 0) {
2169231172Snp					rc = -rc;
2170231172Snp					for (j = 0; j < i; j++) {
2171231172Snp						if_printf(ifp,
2172231172Snp						    "failed to add mc address"
2173231172Snp						    " %02x:%02x:%02x:"
2174231172Snp						    "%02x:%02x:%02x rc=%d\n",
2175231172Snp						    mcaddr[j][0], mcaddr[j][1],
2176231172Snp						    mcaddr[j][2], mcaddr[j][3],
2177231172Snp						    mcaddr[j][4], mcaddr[j][5],
2178231172Snp						    rc);
2179231172Snp					}
2180231172Snp					goto mcfail;
2181231172Snp				}
2182231172Snp				del = 0;
2183231172Snp				i = 0;
2184231172Snp			}
2185231172Snp		}
2186231172Snp		if (i > 0) {
2187231172Snp			rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid,
2188231172Snp			    del, i, mcaddr, NULL, &hash, 0);
2189218792Snp			if (rc < 0) {
2190218792Snp				rc = -rc;
2191231172Snp				for (j = 0; j < i; j++) {
2192231172Snp					if_printf(ifp,
2193231172Snp					    "failed to add mc address"
2194231172Snp					    " %02x:%02x:%02x:"
2195231172Snp					    "%02x:%02x:%02x rc=%d\n",
2196231172Snp					    mcaddr[j][0], mcaddr[j][1],
2197231172Snp					    mcaddr[j][2], mcaddr[j][3],
2198231172Snp					    mcaddr[j][4], mcaddr[j][5],
2199231172Snp					    rc);
2200231172Snp				}
2201218792Snp				goto mcfail;
2202218792Snp			}
2203218792Snp		}
2204218792Snp
2205218792Snp		rc = -t4_set_addr_hash(sc, sc->mbox, pi->viid, 0, hash, 0);
2206218792Snp		if (rc != 0)
2207218792Snp			if_printf(ifp, "failed to set mc address hash: %d", rc);
2208218792Snpmcfail:
2209218792Snp		if_maddr_runlock(ifp);
2210218792Snp	}
2211218792Snp
2212218792Snp	return (rc);
2213218792Snp}
2214218792Snp
2215218792Snpstatic int
2216218792Snpcxgbe_init_locked(struct port_info *pi)
2217218792Snp{
2218218792Snp	struct adapter *sc = pi->adapter;
2219218792Snp	int rc = 0;
2220218792Snp
2221218792Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
2222218792Snp
2223218792Snp	while (!IS_DOOMED(pi) && IS_BUSY(sc)) {
2224218792Snp		if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4init", 0)) {
2225218792Snp			rc = EINTR;
2226218792Snp			goto done;
2227218792Snp		}
2228218792Snp	}
2229218792Snp	if (IS_DOOMED(pi)) {
2230218792Snp		rc = ENXIO;
2231218792Snp		goto done;
2232218792Snp	}
2233218792Snp	KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__));
2234218792Snp
2235218792Snp	/* Give up the adapter lock, port init code can sleep. */
2236218792Snp	SET_BUSY(sc);
2237218792Snp	ADAPTER_UNLOCK(sc);
2238218792Snp
2239218792Snp	rc = cxgbe_init_synchronized(pi);
2240218792Snp
2241218792Snpdone:
2242218792Snp	ADAPTER_LOCK(sc);
2243218792Snp	KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__));
2244218792Snp	CLR_BUSY(sc);
2245218792Snp	wakeup_one(&sc->flags);
2246218792Snp	ADAPTER_UNLOCK(sc);
2247218792Snp	return (rc);
2248218792Snp}
2249218792Snp
2250218792Snpstatic int
2251218792Snpcxgbe_init_synchronized(struct port_info *pi)
2252218792Snp{
2253218792Snp	struct adapter *sc = pi->adapter;
2254218792Snp	struct ifnet *ifp = pi->ifp;
2255228561Snp	int rc = 0;
2256218792Snp
2257218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
2258218792Snp
2259218792Snp	if (isset(&sc->open_device_map, pi->port_id)) {
2260218792Snp		KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING,
2261218792Snp		    ("mismatch between open_device_map and if_drv_flags"));
2262218792Snp		return (0);	/* already running */
2263218792Snp	}
2264218792Snp
2265228561Snp	if (!(sc->flags & FULL_INIT_DONE) &&
2266228561Snp	    ((rc = adapter_full_init(sc)) != 0))
2267218792Snp		return (rc);	/* error message displayed already */
2268218792Snp
2269228561Snp	if (!(pi->flags & PORT_INIT_DONE) &&
2270228561Snp	    ((rc = port_full_init(pi)) != 0))
2271228561Snp		return (rc); /* error message displayed already */
2272218792Snp
2273218792Snp	PORT_LOCK(pi);
2274218792Snp	rc = update_mac_settings(pi, XGMAC_ALL);
2275218792Snp	PORT_UNLOCK(pi);
2276218792Snp	if (rc)
2277218792Snp		goto done;	/* error message displayed already */
2278218792Snp
2279218792Snp	rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg);
2280218792Snp	if (rc != 0) {
2281218792Snp		if_printf(ifp, "start_link failed: %d\n", rc);
2282218792Snp		goto done;
2283218792Snp	}
2284218792Snp
2285218792Snp	rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true);
2286218792Snp	if (rc != 0) {
2287218792Snp		if_printf(ifp, "enable_vi failed: %d\n", rc);
2288218792Snp		goto done;
2289218792Snp	}
2290218792Snp
2291218792Snp	/* all ok */
2292218792Snp	setbit(&sc->open_device_map, pi->port_id);
2293218792Snp	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2294218792Snp
2295218792Snp	callout_reset(&pi->tick, hz, cxgbe_tick, pi);
2296218792Snpdone:
2297218792Snp	if (rc != 0)
2298218792Snp		cxgbe_uninit_synchronized(pi);
2299218792Snp
2300218792Snp	return (rc);
2301218792Snp}
2302218792Snp
2303218792Snpstatic int
2304218792Snpcxgbe_uninit_locked(struct port_info *pi)
2305218792Snp{
2306218792Snp	struct adapter *sc = pi->adapter;
2307218792Snp	int rc;
2308218792Snp
2309218792Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
2310218792Snp
2311218792Snp	while (!IS_DOOMED(pi) && IS_BUSY(sc)) {
2312218792Snp		if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4uninit", 0)) {
2313218792Snp			rc = EINTR;
2314218792Snp			goto done;
2315218792Snp		}
2316218792Snp	}
2317218792Snp	if (IS_DOOMED(pi)) {
2318218792Snp		rc = ENXIO;
2319218792Snp		goto done;
2320218792Snp	}
2321218792Snp	KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__));
2322218792Snp	SET_BUSY(sc);
2323218792Snp	ADAPTER_UNLOCK(sc);
2324218792Snp
2325218792Snp	rc = cxgbe_uninit_synchronized(pi);
2326218792Snp
2327218792Snp	ADAPTER_LOCK(sc);
2328218792Snp	KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__));
2329218792Snp	CLR_BUSY(sc);
2330218792Snp	wakeup_one(&sc->flags);
2331218792Snpdone:
2332218792Snp	ADAPTER_UNLOCK(sc);
2333218792Snp	return (rc);
2334218792Snp}
2335218792Snp
2336218792Snp/*
2337218792Snp * Idempotent.
2338218792Snp */
2339218792Snpstatic int
2340218792Snpcxgbe_uninit_synchronized(struct port_info *pi)
2341218792Snp{
2342218792Snp	struct adapter *sc = pi->adapter;
2343218792Snp	struct ifnet *ifp = pi->ifp;
2344218792Snp	int rc;
2345218792Snp
2346218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
2347218792Snp
2348218792Snp	/*
2349228561Snp	 * Disable the VI so that all its data in either direction is discarded
2350228561Snp	 * by the MPS.  Leave everything else (the queues, interrupts, and 1Hz
2351228561Snp	 * tick) intact as the TP can deliver negative advice or data that it's
2352228561Snp	 * holding in its RAM (for an offloaded connection) even after the VI is
2353228561Snp	 * disabled.
2354218792Snp	 */
2355228561Snp	rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false);
2356228561Snp	if (rc) {
2357228561Snp		if_printf(ifp, "disable_vi failed: %d\n", rc);
2358228561Snp		return (rc);
2359228561Snp	}
2360228561Snp
2361218792Snp	clrbit(&sc->open_device_map, pi->port_id);
2362228561Snp	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2363218792Snp
2364218792Snp	pi->link_cfg.link_ok = 0;
2365218792Snp	pi->link_cfg.speed = 0;
2366218792Snp	t4_os_link_changed(sc, pi->port_id, 0);
2367218792Snp
2368218792Snp	return (0);
2369218792Snp}
2370218792Snp
2371240453Snp/*
2372240453Snp * It is ok for this function to fail midway and return right away.  t4_detach
2373240453Snp * will walk the entire sc->irq list and clean up whatever is valid.
2374240453Snp */
2375218792Snpstatic int
2376240453Snpsetup_intr_handlers(struct adapter *sc)
2377218792Snp{
2378240453Snp	int rc, rid, p, q;
2379222510Snp	char s[8];
2380222510Snp	struct irq *irq;
2381228561Snp	struct port_info *pi;
2382228561Snp	struct sge_rxq *rxq;
2383237263Snp#ifdef TCP_OFFLOAD
2384228561Snp	struct sge_ofld_rxq *ofld_rxq;
2385228561Snp#endif
2386218792Snp
2387218792Snp	/*
2388218792Snp	 * Setup interrupts.
2389218792Snp	 */
2390222510Snp	irq = &sc->irq[0];
2391222510Snp	rid = sc->intr_type == INTR_INTX ? 0 : 1;
2392218792Snp	if (sc->intr_count == 1) {
2393228561Snp		KASSERT(!(sc->flags & INTR_DIRECT),
2394228561Snp		    ("%s: single interrupt && INTR_DIRECT?", __func__));
2395222510Snp
2396240453Snp		rc = t4_alloc_irq(sc, irq, rid, t4_intr_all, sc, "all");
2397240453Snp		if (rc != 0)
2398240453Snp			return (rc);
2399218792Snp	} else {
2400228561Snp		/* Multiple interrupts. */
2401228561Snp		KASSERT(sc->intr_count >= T4_EXTRA_INTR + sc->params.nports,
2402228561Snp		    ("%s: too few intr.", __func__));
2403228561Snp
2404228561Snp		/* The first one is always error intr */
2405240453Snp		rc = t4_alloc_irq(sc, irq, rid, t4_intr_err, sc, "err");
2406240453Snp		if (rc != 0)
2407240453Snp			return (rc);
2408222510Snp		irq++;
2409222510Snp		rid++;
2410218792Snp
2411228561Snp		/* The second one is always the firmware event queue */
2412240453Snp		rc = t4_alloc_irq(sc, irq, rid, t4_intr_evt, &sc->sge.fwq,
2413240453Snp		    "evt");
2414240453Snp		if (rc != 0)
2415240453Snp			return (rc);
2416228561Snp		irq++;
2417228561Snp		rid++;
2418222510Snp
2419228561Snp		/*
2420228561Snp		 * Note that if INTR_DIRECT is not set then either the NIC rx
2421228561Snp		 * queues or (exclusive or) the TOE rx queueus will be taking
2422228561Snp		 * direct interrupts.
2423228561Snp		 *
2424228561Snp		 * There is no need to check for is_offload(sc) as nofldrxq
2425228561Snp		 * will be 0 if offload is disabled.
2426228561Snp		 */
2427228561Snp		for_each_port(sc, p) {
2428228561Snp			pi = sc->port[p];
2429222510Snp
2430237263Snp#ifdef TCP_OFFLOAD
2431228561Snp			/*
2432228561Snp			 * Skip over the NIC queues if they aren't taking direct
2433228561Snp			 * interrupts.
2434228561Snp			 */
2435228561Snp			if (!(sc->flags & INTR_DIRECT) &&
2436228561Snp			    pi->nofldrxq > pi->nrxq)
2437228561Snp				goto ofld_queues;
2438228561Snp#endif
2439228561Snp			rxq = &sc->sge.rxq[pi->first_rxq];
2440228561Snp			for (q = 0; q < pi->nrxq; q++, rxq++) {
2441228561Snp				snprintf(s, sizeof(s), "%d.%d", p, q);
2442240453Snp				rc = t4_alloc_irq(sc, irq, rid, t4_intr, rxq,
2443240453Snp				    s);
2444240453Snp				if (rc != 0)
2445240453Snp					return (rc);
2446222510Snp				irq++;
2447222510Snp				rid++;
2448218792Snp			}
2449218792Snp
2450237263Snp#ifdef TCP_OFFLOAD
2451228561Snp			/*
2452228561Snp			 * Skip over the offload queues if they aren't taking
2453228561Snp			 * direct interrupts.
2454228561Snp			 */
2455228561Snp			if (!(sc->flags & INTR_DIRECT))
2456228561Snp				continue;
2457228561Snpofld_queues:
2458228561Snp			ofld_rxq = &sc->sge.ofld_rxq[pi->first_ofld_rxq];
2459228561Snp			for (q = 0; q < pi->nofldrxq; q++, ofld_rxq++) {
2460228561Snp				snprintf(s, sizeof(s), "%d,%d", p, q);
2461240453Snp				rc = t4_alloc_irq(sc, irq, rid, t4_intr,
2462240453Snp				    ofld_rxq, s);
2463240453Snp				if (rc != 0)
2464240453Snp					return (rc);
2465228561Snp				irq++;
2466228561Snp				rid++;
2467218792Snp			}
2468228561Snp#endif
2469218792Snp		}
2470218792Snp	}
2471218792Snp
2472240453Snp	return (0);
2473240453Snp}
2474240453Snp
2475240453Snpstatic int
2476240453Snpadapter_full_init(struct adapter *sc)
2477240453Snp{
2478240453Snp	int rc, i;
2479240453Snp
2480240453Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
2481240453Snp	KASSERT((sc->flags & FULL_INIT_DONE) == 0,
2482240453Snp	    ("%s: FULL_INIT_DONE already", __func__));
2483240453Snp
2484240453Snp	/*
2485240453Snp	 * queues that belong to the adapter (not any particular port).
2486240453Snp	 */
2487240453Snp	rc = t4_setup_adapter_queues(sc);
2488240453Snp	if (rc != 0)
2489240453Snp		goto done;
2490240453Snp
2491240453Snp	for (i = 0; i < nitems(sc->tq); i++) {
2492240453Snp		sc->tq[i] = taskqueue_create("t4 taskq", M_NOWAIT,
2493240453Snp		    taskqueue_thread_enqueue, &sc->tq[i]);
2494240453Snp		if (sc->tq[i] == NULL) {
2495240453Snp			device_printf(sc->dev,
2496240453Snp			    "failed to allocate task queue %d\n", i);
2497240453Snp			rc = ENOMEM;
2498240453Snp			goto done;
2499240453Snp		}
2500240453Snp		taskqueue_start_threads(&sc->tq[i], 1, PI_NET, "%s tq%d",
2501240453Snp		    device_get_nameunit(sc->dev), i);
2502240453Snp	}
2503240453Snp
2504218792Snp	t4_intr_enable(sc);
2505218792Snp	sc->flags |= FULL_INIT_DONE;
2506218792Snpdone:
2507218792Snp	if (rc != 0)
2508228561Snp		adapter_full_uninit(sc);
2509218792Snp
2510218792Snp	return (rc);
2511218792Snp}
2512218792Snp
2513218792Snpstatic int
2514228561Snpadapter_full_uninit(struct adapter *sc)
2515218792Snp{
2516218792Snp	int i;
2517218792Snp
2518218792Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
2519218792Snp
2520220873Snp	t4_teardown_adapter_queues(sc);
2521218792Snp
2522240452Snp	for (i = 0; i < nitems(sc->tq) && sc->tq[i]; i++) {
2523228561Snp		taskqueue_free(sc->tq[i]);
2524228561Snp		sc->tq[i] = NULL;
2525228561Snp	}
2526228561Snp
2527218792Snp	sc->flags &= ~FULL_INIT_DONE;
2528218792Snp
2529218792Snp	return (0);
2530218792Snp}
2531218792Snp
2532218792Snpstatic int
2533228561Snpport_full_init(struct port_info *pi)
2534228561Snp{
2535228561Snp	struct adapter *sc = pi->adapter;
2536228561Snp	struct ifnet *ifp = pi->ifp;
2537228561Snp	uint16_t *rss;
2538228561Snp	struct sge_rxq *rxq;
2539228561Snp	int rc, i;
2540228561Snp
2541228561Snp	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
2542228561Snp	KASSERT((pi->flags & PORT_INIT_DONE) == 0,
2543228561Snp	    ("%s: PORT_INIT_DONE already", __func__));
2544228561Snp
2545228561Snp	sysctl_ctx_init(&pi->ctx);
2546228561Snp	pi->flags |= PORT_SYSCTL_CTX;
2547228561Snp
2548228561Snp	/*
2549228561Snp	 * Allocate tx/rx/fl queues for this port.
2550228561Snp	 */
2551228561Snp	rc = t4_setup_port_queues(pi);
2552228561Snp	if (rc != 0)
2553228561Snp		goto done;	/* error message displayed already */
2554228561Snp
2555228561Snp	/*
2556228561Snp	 * Setup RSS for this port.
2557228561Snp	 */
2558228561Snp	rss = malloc(pi->nrxq * sizeof (*rss), M_CXGBE,
2559228561Snp	    M_ZERO | M_WAITOK);
2560228561Snp	for_each_rxq(pi, i, rxq) {
2561228561Snp		rss[i] = rxq->iq.abs_id;
2562228561Snp	}
2563228561Snp	rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0,
2564228561Snp	    pi->rss_size, rss, pi->nrxq);
2565228561Snp	free(rss, M_CXGBE);
2566228561Snp	if (rc != 0) {
2567228561Snp		if_printf(ifp, "rss_config failed: %d\n", rc);
2568228561Snp		goto done;
2569228561Snp	}
2570228561Snp
2571228561Snp	pi->flags |= PORT_INIT_DONE;
2572228561Snpdone:
2573228561Snp	if (rc != 0)
2574228561Snp		port_full_uninit(pi);
2575228561Snp
2576228561Snp	return (rc);
2577228561Snp}
2578228561Snp
2579228561Snp/*
2580228561Snp * Idempotent.
2581228561Snp */
2582228561Snpstatic int
2583228561Snpport_full_uninit(struct port_info *pi)
2584228561Snp{
2585228561Snp	struct adapter *sc = pi->adapter;
2586228561Snp	int i;
2587228561Snp	struct sge_rxq *rxq;
2588228561Snp	struct sge_txq *txq;
2589237263Snp#ifdef TCP_OFFLOAD
2590228561Snp	struct sge_ofld_rxq *ofld_rxq;
2591228561Snp	struct sge_wrq *ofld_txq;
2592228561Snp#endif
2593228561Snp
2594228561Snp	if (pi->flags & PORT_INIT_DONE) {
2595228561Snp
2596228561Snp		/* Need to quiesce queues.  XXX: ctrl queues? */
2597228561Snp
2598228561Snp		for_each_txq(pi, i, txq) {
2599228561Snp			quiesce_eq(sc, &txq->eq);
2600228561Snp		}
2601228561Snp
2602237263Snp#ifdef TCP_OFFLOAD
2603228561Snp		for_each_ofld_txq(pi, i, ofld_txq) {
2604228561Snp			quiesce_eq(sc, &ofld_txq->eq);
2605228561Snp		}
2606228561Snp#endif
2607228561Snp
2608228561Snp		for_each_rxq(pi, i, rxq) {
2609228561Snp			quiesce_iq(sc, &rxq->iq);
2610228561Snp			quiesce_fl(sc, &rxq->fl);
2611228561Snp		}
2612228561Snp
2613237263Snp#ifdef TCP_OFFLOAD
2614228561Snp		for_each_ofld_rxq(pi, i, ofld_rxq) {
2615228561Snp			quiesce_iq(sc, &ofld_rxq->iq);
2616228561Snp			quiesce_fl(sc, &ofld_rxq->fl);
2617228561Snp		}
2618228561Snp#endif
2619228561Snp	}
2620228561Snp
2621228561Snp	t4_teardown_port_queues(pi);
2622228561Snp	pi->flags &= ~PORT_INIT_DONE;
2623228561Snp
2624228561Snp	return (0);
2625228561Snp}
2626228561Snp
2627228561Snpstatic void
2628228561Snpquiesce_eq(struct adapter *sc, struct sge_eq *eq)
2629228561Snp{
2630228561Snp	EQ_LOCK(eq);
2631228561Snp	eq->flags |= EQ_DOOMED;
2632228561Snp
2633228561Snp	/*
2634228561Snp	 * Wait for the response to a credit flush if one's
2635228561Snp	 * pending.
2636228561Snp	 */
2637228561Snp	while (eq->flags & EQ_CRFLUSHED)
2638228561Snp		mtx_sleep(eq, &eq->eq_lock, 0, "crflush", 0);
2639228561Snp	EQ_UNLOCK(eq);
2640228561Snp
2641228561Snp	callout_drain(&eq->tx_callout);	/* XXX: iffy */
2642228561Snp	pause("callout", 10);		/* Still iffy */
2643228561Snp
2644228561Snp	taskqueue_drain(sc->tq[eq->tx_chan], &eq->tx_task);
2645228561Snp}
2646228561Snp
2647228561Snpstatic void
2648228561Snpquiesce_iq(struct adapter *sc, struct sge_iq *iq)
2649228561Snp{
2650228561Snp	(void) sc;	/* unused */
2651228561Snp
2652228561Snp	/* Synchronize with the interrupt handler */
2653228561Snp	while (!atomic_cmpset_int(&iq->state, IQS_IDLE, IQS_DISABLED))
2654228561Snp		pause("iqfree", 1);
2655228561Snp}
2656228561Snp
2657228561Snpstatic void
2658228561Snpquiesce_fl(struct adapter *sc, struct sge_fl *fl)
2659228561Snp{
2660228561Snp	mtx_lock(&sc->sfl_lock);
2661228561Snp	FL_LOCK(fl);
2662228561Snp	fl->flags |= FL_DOOMED;
2663228561Snp	FL_UNLOCK(fl);
2664228561Snp	mtx_unlock(&sc->sfl_lock);
2665228561Snp
2666228561Snp	callout_drain(&sc->sfl_callout);
2667228561Snp	KASSERT((fl->flags & FL_STARVING) == 0,
2668228561Snp	    ("%s: still starving", __func__));
2669228561Snp}
2670228561Snp
2671228561Snpstatic int
2672218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid,
2673228561Snp    driver_intr_t *handler, void *arg, char *name)
2674218792Snp{
2675218792Snp	int rc;
2676218792Snp
2677218792Snp	irq->rid = rid;
2678218792Snp	irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid,
2679218792Snp	    RF_SHAREABLE | RF_ACTIVE);
2680218792Snp	if (irq->res == NULL) {
2681218792Snp		device_printf(sc->dev,
2682218792Snp		    "failed to allocate IRQ for rid %d, name %s.\n", rid, name);
2683218792Snp		return (ENOMEM);
2684218792Snp	}
2685218792Snp
2686218792Snp	rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET,
2687218792Snp	    NULL, handler, arg, &irq->tag);
2688218792Snp	if (rc != 0) {
2689218792Snp		device_printf(sc->dev,
2690218792Snp		    "failed to setup interrupt for rid %d, name %s: %d\n",
2691218792Snp		    rid, name, rc);
2692218792Snp	} else if (name)
2693218792Snp		bus_describe_intr(sc->dev, irq->res, irq->tag, name);
2694218792Snp
2695218792Snp	return (rc);
2696218792Snp}
2697218792Snp
2698218792Snpstatic int
2699218792Snpt4_free_irq(struct adapter *sc, struct irq *irq)
2700218792Snp{
2701218792Snp	if (irq->tag)
2702218792Snp		bus_teardown_intr(sc->dev, irq->res, irq->tag);
2703218792Snp	if (irq->res)
2704218792Snp		bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res);
2705218792Snp
2706218792Snp	bzero(irq, sizeof(*irq));
2707218792Snp
2708218792Snp	return (0);
2709218792Snp}
2710218792Snp
2711218792Snpstatic void
2712218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start,
2713218792Snp    unsigned int end)
2714218792Snp{
2715218792Snp	uint32_t *p = (uint32_t *)(buf + start);
2716218792Snp
2717218792Snp	for ( ; start <= end; start += sizeof(uint32_t))
2718218792Snp		*p++ = t4_read_reg(sc, start);
2719218792Snp}
2720218792Snp
2721218792Snpstatic void
2722218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf)
2723218792Snp{
2724218792Snp	int i;
2725218792Snp	static const unsigned int reg_ranges[] = {
2726218792Snp		0x1008, 0x1108,
2727218792Snp		0x1180, 0x11b4,
2728218792Snp		0x11fc, 0x123c,
2729218792Snp		0x1300, 0x173c,
2730218792Snp		0x1800, 0x18fc,
2731218792Snp		0x3000, 0x30d8,
2732218792Snp		0x30e0, 0x5924,
2733218792Snp		0x5960, 0x59d4,
2734218792Snp		0x5a00, 0x5af8,
2735218792Snp		0x6000, 0x6098,
2736218792Snp		0x6100, 0x6150,
2737218792Snp		0x6200, 0x6208,
2738218792Snp		0x6240, 0x6248,
2739218792Snp		0x6280, 0x6338,
2740218792Snp		0x6370, 0x638c,
2741218792Snp		0x6400, 0x643c,
2742218792Snp		0x6500, 0x6524,
2743218792Snp		0x6a00, 0x6a38,
2744218792Snp		0x6a60, 0x6a78,
2745218792Snp		0x6b00, 0x6b84,
2746218792Snp		0x6bf0, 0x6c84,
2747218792Snp		0x6cf0, 0x6d84,
2748218792Snp		0x6df0, 0x6e84,
2749218792Snp		0x6ef0, 0x6f84,
2750218792Snp		0x6ff0, 0x7084,
2751218792Snp		0x70f0, 0x7184,
2752218792Snp		0x71f0, 0x7284,
2753218792Snp		0x72f0, 0x7384,
2754218792Snp		0x73f0, 0x7450,
2755218792Snp		0x7500, 0x7530,
2756218792Snp		0x7600, 0x761c,
2757218792Snp		0x7680, 0x76cc,
2758218792Snp		0x7700, 0x7798,
2759218792Snp		0x77c0, 0x77fc,
2760218792Snp		0x7900, 0x79fc,
2761218792Snp		0x7b00, 0x7c38,
2762218792Snp		0x7d00, 0x7efc,
2763218792Snp		0x8dc0, 0x8e1c,
2764218792Snp		0x8e30, 0x8e78,
2765218792Snp		0x8ea0, 0x8f6c,
2766218792Snp		0x8fc0, 0x9074,
2767218792Snp		0x90fc, 0x90fc,
2768218792Snp		0x9400, 0x9458,
2769218792Snp		0x9600, 0x96bc,
2770218792Snp		0x9800, 0x9808,
2771218792Snp		0x9820, 0x983c,
2772218792Snp		0x9850, 0x9864,
2773218792Snp		0x9c00, 0x9c6c,
2774218792Snp		0x9c80, 0x9cec,
2775218792Snp		0x9d00, 0x9d6c,
2776218792Snp		0x9d80, 0x9dec,
2777218792Snp		0x9e00, 0x9e6c,
2778218792Snp		0x9e80, 0x9eec,
2779218792Snp		0x9f00, 0x9f6c,
2780218792Snp		0x9f80, 0x9fec,
2781218792Snp		0xd004, 0xd03c,
2782218792Snp		0xdfc0, 0xdfe0,
2783218792Snp		0xe000, 0xea7c,
2784218792Snp		0xf000, 0x11190,
2785237439Snp		0x19040, 0x1906c,
2786237439Snp		0x19078, 0x19080,
2787237439Snp		0x1908c, 0x19124,
2788218792Snp		0x19150, 0x191b0,
2789218792Snp		0x191d0, 0x191e8,
2790218792Snp		0x19238, 0x1924c,
2791218792Snp		0x193f8, 0x19474,
2792218792Snp		0x19490, 0x194f8,
2793218792Snp		0x19800, 0x19f30,
2794218792Snp		0x1a000, 0x1a06c,
2795218792Snp		0x1a0b0, 0x1a120,
2796218792Snp		0x1a128, 0x1a138,
2797218792Snp		0x1a190, 0x1a1c4,
2798218792Snp		0x1a1fc, 0x1a1fc,
2799218792Snp		0x1e040, 0x1e04c,
2800237439Snp		0x1e284, 0x1e28c,
2801218792Snp		0x1e2c0, 0x1e2c0,
2802218792Snp		0x1e2e0, 0x1e2e0,
2803218792Snp		0x1e300, 0x1e384,
2804218792Snp		0x1e3c0, 0x1e3c8,
2805218792Snp		0x1e440, 0x1e44c,
2806237439Snp		0x1e684, 0x1e68c,
2807218792Snp		0x1e6c0, 0x1e6c0,
2808218792Snp		0x1e6e0, 0x1e6e0,
2809218792Snp		0x1e700, 0x1e784,
2810218792Snp		0x1e7c0, 0x1e7c8,
2811218792Snp		0x1e840, 0x1e84c,
2812237439Snp		0x1ea84, 0x1ea8c,
2813218792Snp		0x1eac0, 0x1eac0,
2814218792Snp		0x1eae0, 0x1eae0,
2815218792Snp		0x1eb00, 0x1eb84,
2816218792Snp		0x1ebc0, 0x1ebc8,
2817218792Snp		0x1ec40, 0x1ec4c,
2818237439Snp		0x1ee84, 0x1ee8c,
2819218792Snp		0x1eec0, 0x1eec0,
2820218792Snp		0x1eee0, 0x1eee0,
2821218792Snp		0x1ef00, 0x1ef84,
2822218792Snp		0x1efc0, 0x1efc8,
2823218792Snp		0x1f040, 0x1f04c,
2824237439Snp		0x1f284, 0x1f28c,
2825218792Snp		0x1f2c0, 0x1f2c0,
2826218792Snp		0x1f2e0, 0x1f2e0,
2827218792Snp		0x1f300, 0x1f384,
2828218792Snp		0x1f3c0, 0x1f3c8,
2829218792Snp		0x1f440, 0x1f44c,
2830237439Snp		0x1f684, 0x1f68c,
2831218792Snp		0x1f6c0, 0x1f6c0,
2832218792Snp		0x1f6e0, 0x1f6e0,
2833218792Snp		0x1f700, 0x1f784,
2834218792Snp		0x1f7c0, 0x1f7c8,
2835218792Snp		0x1f840, 0x1f84c,
2836237439Snp		0x1fa84, 0x1fa8c,
2837218792Snp		0x1fac0, 0x1fac0,
2838218792Snp		0x1fae0, 0x1fae0,
2839218792Snp		0x1fb00, 0x1fb84,
2840218792Snp		0x1fbc0, 0x1fbc8,
2841218792Snp		0x1fc40, 0x1fc4c,
2842237439Snp		0x1fe84, 0x1fe8c,
2843218792Snp		0x1fec0, 0x1fec0,
2844218792Snp		0x1fee0, 0x1fee0,
2845218792Snp		0x1ff00, 0x1ff84,
2846218792Snp		0x1ffc0, 0x1ffc8,
2847218792Snp		0x20000, 0x2002c,
2848218792Snp		0x20100, 0x2013c,
2849218792Snp		0x20190, 0x201c8,
2850218792Snp		0x20200, 0x20318,
2851218792Snp		0x20400, 0x20528,
2852218792Snp		0x20540, 0x20614,
2853218792Snp		0x21000, 0x21040,
2854218792Snp		0x2104c, 0x21060,
2855218792Snp		0x210c0, 0x210ec,
2856218792Snp		0x21200, 0x21268,
2857218792Snp		0x21270, 0x21284,
2858218792Snp		0x212fc, 0x21388,
2859218792Snp		0x21400, 0x21404,
2860218792Snp		0x21500, 0x21518,
2861218792Snp		0x2152c, 0x2153c,
2862218792Snp		0x21550, 0x21554,
2863218792Snp		0x21600, 0x21600,
2864218792Snp		0x21608, 0x21628,
2865218792Snp		0x21630, 0x2163c,
2866218792Snp		0x21700, 0x2171c,
2867218792Snp		0x21780, 0x2178c,
2868218792Snp		0x21800, 0x21c38,
2869218792Snp		0x21c80, 0x21d7c,
2870218792Snp		0x21e00, 0x21e04,
2871218792Snp		0x22000, 0x2202c,
2872218792Snp		0x22100, 0x2213c,
2873218792Snp		0x22190, 0x221c8,
2874218792Snp		0x22200, 0x22318,
2875218792Snp		0x22400, 0x22528,
2876218792Snp		0x22540, 0x22614,
2877218792Snp		0x23000, 0x23040,
2878218792Snp		0x2304c, 0x23060,
2879218792Snp		0x230c0, 0x230ec,
2880218792Snp		0x23200, 0x23268,
2881218792Snp		0x23270, 0x23284,
2882218792Snp		0x232fc, 0x23388,
2883218792Snp		0x23400, 0x23404,
2884218792Snp		0x23500, 0x23518,
2885218792Snp		0x2352c, 0x2353c,
2886218792Snp		0x23550, 0x23554,
2887218792Snp		0x23600, 0x23600,
2888218792Snp		0x23608, 0x23628,
2889218792Snp		0x23630, 0x2363c,
2890218792Snp		0x23700, 0x2371c,
2891218792Snp		0x23780, 0x2378c,
2892218792Snp		0x23800, 0x23c38,
2893218792Snp		0x23c80, 0x23d7c,
2894218792Snp		0x23e00, 0x23e04,
2895218792Snp		0x24000, 0x2402c,
2896218792Snp		0x24100, 0x2413c,
2897218792Snp		0x24190, 0x241c8,
2898218792Snp		0x24200, 0x24318,
2899218792Snp		0x24400, 0x24528,
2900218792Snp		0x24540, 0x24614,
2901218792Snp		0x25000, 0x25040,
2902218792Snp		0x2504c, 0x25060,
2903218792Snp		0x250c0, 0x250ec,
2904218792Snp		0x25200, 0x25268,
2905218792Snp		0x25270, 0x25284,
2906218792Snp		0x252fc, 0x25388,
2907218792Snp		0x25400, 0x25404,
2908218792Snp		0x25500, 0x25518,
2909218792Snp		0x2552c, 0x2553c,
2910218792Snp		0x25550, 0x25554,
2911218792Snp		0x25600, 0x25600,
2912218792Snp		0x25608, 0x25628,
2913218792Snp		0x25630, 0x2563c,
2914218792Snp		0x25700, 0x2571c,
2915218792Snp		0x25780, 0x2578c,
2916218792Snp		0x25800, 0x25c38,
2917218792Snp		0x25c80, 0x25d7c,
2918218792Snp		0x25e00, 0x25e04,
2919218792Snp		0x26000, 0x2602c,
2920218792Snp		0x26100, 0x2613c,
2921218792Snp		0x26190, 0x261c8,
2922218792Snp		0x26200, 0x26318,
2923218792Snp		0x26400, 0x26528,
2924218792Snp		0x26540, 0x26614,
2925218792Snp		0x27000, 0x27040,
2926218792Snp		0x2704c, 0x27060,
2927218792Snp		0x270c0, 0x270ec,
2928218792Snp		0x27200, 0x27268,
2929218792Snp		0x27270, 0x27284,
2930218792Snp		0x272fc, 0x27388,
2931218792Snp		0x27400, 0x27404,
2932218792Snp		0x27500, 0x27518,
2933218792Snp		0x2752c, 0x2753c,
2934218792Snp		0x27550, 0x27554,
2935218792Snp		0x27600, 0x27600,
2936218792Snp		0x27608, 0x27628,
2937218792Snp		0x27630, 0x2763c,
2938218792Snp		0x27700, 0x2771c,
2939218792Snp		0x27780, 0x2778c,
2940218792Snp		0x27800, 0x27c38,
2941218792Snp		0x27c80, 0x27d7c,
2942218792Snp		0x27e00, 0x27e04
2943218792Snp	};
2944218792Snp
2945218792Snp	regs->version = 4 | (sc->params.rev << 10);
2946240452Snp	for (i = 0; i < nitems(reg_ranges); i += 2)
2947218792Snp		reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]);
2948218792Snp}
2949218792Snp
2950218792Snpstatic void
2951218792Snpcxgbe_tick(void *arg)
2952218792Snp{
2953218792Snp	struct port_info *pi = arg;
2954218792Snp	struct ifnet *ifp = pi->ifp;
2955218792Snp	struct sge_txq *txq;
2956218792Snp	int i, drops;
2957218792Snp	struct port_stats *s = &pi->stats;
2958218792Snp
2959218792Snp	PORT_LOCK(pi);
2960218792Snp	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
2961218792Snp		PORT_UNLOCK(pi);
2962218792Snp		return;	/* without scheduling another callout */
2963218792Snp	}
2964218792Snp
2965218792Snp	t4_get_port_stats(pi->adapter, pi->tx_chan, s);
2966218792Snp
2967228561Snp	ifp->if_opackets = s->tx_frames - s->tx_pause;
2968228561Snp	ifp->if_ipackets = s->rx_frames - s->rx_pause;
2969228561Snp	ifp->if_obytes = s->tx_octets - s->tx_pause * 64;
2970228561Snp	ifp->if_ibytes = s->rx_octets - s->rx_pause * 64;
2971228561Snp	ifp->if_omcasts = s->tx_mcast_frames - s->tx_pause;
2972228561Snp	ifp->if_imcasts = s->rx_mcast_frames - s->rx_pause;
2973218792Snp	ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 +
2974239259Snp	    s->rx_ovflow3 + s->rx_trunc0 + s->rx_trunc1 + s->rx_trunc2 +
2975239259Snp	    s->rx_trunc3;
2976218792Snp
2977218792Snp	drops = s->tx_drop;
2978218792Snp	for_each_txq(pi, i, txq)
2979220873Snp		drops += txq->br->br_drops;
2980218792Snp	ifp->if_snd.ifq_drops = drops;
2981218792Snp
2982218792Snp	ifp->if_oerrors = s->tx_error_frames;
2983218792Snp	ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long +
2984218792Snp	    s->rx_fcs_err + s->rx_len_err;
2985218792Snp
2986218792Snp	callout_schedule(&pi->tick, hz);
2987218792Snp	PORT_UNLOCK(pi);
2988218792Snp}
2989218792Snp
2990237263Snpstatic void
2991237263Snpcxgbe_vlan_config(void *arg, struct ifnet *ifp, uint16_t vid)
2992237263Snp{
2993237263Snp	struct ifnet *vlan;
2994237263Snp
2995241494Snp	if (arg != ifp || ifp->if_type != IFT_ETHER)
2996237263Snp		return;
2997237263Snp
2998237263Snp	vlan = VLAN_DEVAT(ifp, vid);
2999237263Snp	VLAN_SETCOOKIE(vlan, ifp);
3000237263Snp}
3001237263Snp
3002218792Snpstatic int
3003228561Snpcpl_not_handled(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
3004228561Snp{
3005237263Snp
3006228561Snp#ifdef INVARIANTS
3007237263Snp	panic("%s: opcode 0x%02x on iq %p with payload %p",
3008228561Snp	    __func__, rss->opcode, iq, m);
3009228561Snp#else
3010239336Snp	log(LOG_ERR, "%s: opcode 0x%02x on iq %p with payload %p\n",
3011228561Snp	    __func__, rss->opcode, iq, m);
3012228561Snp	m_freem(m);
3013228561Snp#endif
3014228561Snp	return (EDOOFUS);
3015228561Snp}
3016228561Snp
3017228561Snpint
3018228561Snpt4_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h)
3019228561Snp{
3020228561Snp	uintptr_t *loc, new;
3021228561Snp
3022240452Snp	if (opcode >= nitems(sc->cpl_handler))
3023228561Snp		return (EINVAL);
3024228561Snp
3025228561Snp	new = h ? (uintptr_t)h : (uintptr_t)cpl_not_handled;
3026228561Snp	loc = (uintptr_t *) &sc->cpl_handler[opcode];
3027228561Snp	atomic_store_rel_ptr(loc, new);
3028228561Snp
3029228561Snp	return (0);
3030228561Snp}
3031228561Snp
3032228561Snpstatic int
3033237263Snpan_not_handled(struct sge_iq *iq, const struct rsp_ctrl *ctrl)
3034237263Snp{
3035237263Snp
3036237263Snp#ifdef INVARIANTS
3037237263Snp	panic("%s: async notification on iq %p (ctrl %p)", __func__, iq, ctrl);
3038237263Snp#else
3039239336Snp	log(LOG_ERR, "%s: async notification on iq %p (ctrl %p)\n",
3040237263Snp	    __func__, iq, ctrl);
3041237263Snp#endif
3042237263Snp	return (EDOOFUS);
3043237263Snp}
3044237263Snp
3045237263Snpint
3046237263Snpt4_register_an_handler(struct adapter *sc, an_handler_t h)
3047237263Snp{
3048237263Snp	uintptr_t *loc, new;
3049237263Snp
3050237263Snp	new = h ? (uintptr_t)h : (uintptr_t)an_not_handled;
3051237263Snp	loc = (uintptr_t *) &sc->an_handler;
3052237263Snp	atomic_store_rel_ptr(loc, new);
3053237263Snp
3054237263Snp	return (0);
3055237263Snp}
3056237263Snp
3057237263Snpstatic int
3058239336Snpfw_msg_not_handled(struct adapter *sc, const __be64 *rpl)
3059239336Snp{
3060241733Sed	const struct cpl_fw6_msg *cpl =
3061241733Sed	    __containerof(rpl, struct cpl_fw6_msg, data[0]);
3062239336Snp
3063239336Snp#ifdef INVARIANTS
3064239336Snp	panic("%s: fw_msg type %d", __func__, cpl->type);
3065239336Snp#else
3066239336Snp	log(LOG_ERR, "%s: fw_msg type %d\n", __func__, cpl->type);
3067239336Snp#endif
3068239336Snp	return (EDOOFUS);
3069239336Snp}
3070239336Snp
3071239336Snpint
3072239336Snpt4_register_fw_msg_handler(struct adapter *sc, int type, fw_msg_handler_t h)
3073239336Snp{
3074239336Snp	uintptr_t *loc, new;
3075239336Snp
3076240452Snp	if (type >= nitems(sc->fw_msg_handler))
3077239336Snp		return (EINVAL);
3078239336Snp
3079239336Snp	new = h ? (uintptr_t)h : (uintptr_t)fw_msg_not_handled;
3080239336Snp	loc = (uintptr_t *) &sc->fw_msg_handler[type];
3081239336Snp	atomic_store_rel_ptr(loc, new);
3082239336Snp
3083239336Snp	return (0);
3084239336Snp}
3085239336Snp
3086239336Snpstatic int
3087218792Snpt4_sysctls(struct adapter *sc)
3088218792Snp{
3089218792Snp	struct sysctl_ctx_list *ctx;
3090218792Snp	struct sysctl_oid *oid;
3091228561Snp	struct sysctl_oid_list *children, *c0;
3092228561Snp	static char *caps[] = {
3093228561Snp		"\20\1PPP\2QFC\3DCBX",			/* caps[0] linkcaps */
3094228561Snp		"\20\1NIC\2VM\3IDS\4UM\5UM_ISGL",	/* caps[1] niccaps */
3095228561Snp		"\20\1TOE",				/* caps[2] toecaps */
3096228561Snp		"\20\1RDDP\2RDMAC",			/* caps[3] rdmacaps */
3097228561Snp		"\20\1INITIATOR_PDU\2TARGET_PDU"	/* caps[4] iscsicaps */
3098228561Snp		    "\3INITIATOR_CNXOFLD\4TARGET_CNXOFLD"
3099228561Snp		    "\5INITIATOR_SSNOFLD\6TARGET_SSNOFLD",
3100228561Snp		"\20\1INITIATOR\2TARGET\3CTRL_OFLD"	/* caps[5] fcoecaps */
3101228561Snp	};
3102218792Snp
3103218792Snp	ctx = device_get_sysctl_ctx(sc->dev);
3104228561Snp
3105228561Snp	/*
3106228561Snp	 * dev.t4nex.X.
3107228561Snp	 */
3108218792Snp	oid = device_get_sysctl_tree(sc->dev);
3109228561Snp	c0 = children = SYSCTL_CHILDREN(oid);
3110218792Snp
3111218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD,
3112218792Snp	    &sc->params.nports, 0, "# of ports");
3113218792Snp
3114218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD,
3115218792Snp	    &sc->params.rev, 0, "chip hardware revision");
3116218792Snp
3117218792Snp	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version",
3118218792Snp	    CTLFLAG_RD, &sc->fw_version, 0, "firmware version");
3119218792Snp
3120228561Snp	SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "cf",
3121228561Snp	    CTLFLAG_RD, &t4_cfg_file, 0, "configuration file");
3122218792Snp
3123228561Snp	SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cfcsum", CTLFLAG_RD,
3124228561Snp	    &sc->cfcsum, 0, "config file checksum");
3125228561Snp
3126228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkcaps",
3127228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, caps[0], sc->linkcaps,
3128228561Snp	    sysctl_bitfield, "A", "available link capabilities");
3129228561Snp
3130228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "niccaps",
3131228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, caps[1], sc->niccaps,
3132228561Snp	    sysctl_bitfield, "A", "available NIC capabilities");
3133228561Snp
3134228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "toecaps",
3135228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, caps[2], sc->toecaps,
3136228561Snp	    sysctl_bitfield, "A", "available TCP offload capabilities");
3137228561Snp
3138228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdmacaps",
3139228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, caps[3], sc->rdmacaps,
3140228561Snp	    sysctl_bitfield, "A", "available RDMA capabilities");
3141228561Snp
3142228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "iscsicaps",
3143228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, caps[4], sc->iscsicaps,
3144228561Snp	    sysctl_bitfield, "A", "available iSCSI capabilities");
3145228561Snp
3146228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoecaps",
3147228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, caps[5], sc->fcoecaps,
3148228561Snp	    sysctl_bitfield, "A", "available FCoE capabilities");
3149228561Snp
3150218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD,
3151218792Snp	    &sc->params.vpd.cclk, 0, "core clock frequency (in KHz)");
3152218792Snp
3153219436Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers",
3154228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc->sge.timer_val,
3155228561Snp	    sizeof(sc->sge.timer_val), sysctl_int_array, "A",
3156228561Snp	    "interrupt holdoff timer values (us)");
3157218792Snp
3158219436Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts",
3159228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc->sge.counter_val,
3160228561Snp	    sizeof(sc->sge.counter_val), sysctl_int_array, "A",
3161228561Snp	    "interrupt holdoff packet counter values");
3162218792Snp
3163231115Snp#ifdef SBUF_DRAIN
3164228561Snp	/*
3165228561Snp	 * dev.t4nex.X.misc.  Marked CTLFLAG_SKIP to avoid information overload.
3166228561Snp	 */
3167228561Snp	oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "misc",
3168228561Snp	    CTLFLAG_RD | CTLFLAG_SKIP, NULL,
3169228561Snp	    "logs and miscellaneous information");
3170228561Snp	children = SYSCTL_CHILDREN(oid);
3171228561Snp
3172228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cctrl",
3173228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3174228561Snp	    sysctl_cctrl, "A", "congestion control");
3175228561Snp
3176228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats",
3177228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3178228561Snp	    sysctl_cpl_stats, "A", "CPL statistics");
3179228561Snp
3180228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ddp_stats",
3181228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3182228561Snp	    sysctl_ddp_stats, "A", "DDP statistics");
3183228561Snp
3184222551Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog",
3185222551Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3186228561Snp	    sysctl_devlog, "A", "firmware's device log");
3187222551Snp
3188228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoe_stats",
3189228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3190228561Snp	    sysctl_fcoe_stats, "A", "FCoE statistics");
3191228561Snp
3192228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hw_sched",
3193228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3194228561Snp	    sysctl_hw_sched, "A", "hardware scheduler ");
3195228561Snp
3196228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "l2t",
3197228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3198228561Snp	    sysctl_l2t, "A", "hardware L2 table");
3199228561Snp
3200228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats",
3201228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3202228561Snp	    sysctl_lb_stats, "A", "loopback statistics");
3203228561Snp
3204228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "meminfo",
3205228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3206228561Snp	    sysctl_meminfo, "A", "memory regions");
3207228561Snp
3208228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "path_mtus",
3209228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3210228561Snp	    sysctl_path_mtus, "A", "path MTUs");
3211228561Snp
3212228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pm_stats",
3213228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3214228561Snp	    sysctl_pm_stats, "A", "PM statistics");
3215228561Snp
3216228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_stats",
3217228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3218228561Snp	    sysctl_rdma_stats, "A", "RDMA statistics");
3219228561Snp
3220228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tcp_stats",
3221228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3222228561Snp	    sysctl_tcp_stats, "A", "TCP statistics");
3223228561Snp
3224228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tids",
3225228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3226228561Snp	    sysctl_tids, "A", "TID information");
3227228561Snp
3228228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_err_stats",
3229228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3230228561Snp	    sysctl_tp_err_stats, "A", "TP error statistics");
3231228561Snp
3232228561Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_rate",
3233228561Snp	    CTLTYPE_STRING | CTLFLAG_RD, sc, 0,
3234228561Snp	    sysctl_tx_rate, "A", "Tx rate");
3235231115Snp#endif
3236228561Snp
3237237263Snp#ifdef TCP_OFFLOAD
3238228561Snp	if (is_offload(sc)) {
3239228561Snp		/*
3240228561Snp		 * dev.t4nex.X.toe.
3241228561Snp		 */
3242228561Snp		oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "toe", CTLFLAG_RD,
3243228561Snp		    NULL, "TOE parameters");
3244228561Snp		children = SYSCTL_CHILDREN(oid);
3245228561Snp
3246228561Snp		sc->tt.sndbuf = 256 * 1024;
3247228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "sndbuf", CTLFLAG_RW,
3248228561Snp		    &sc->tt.sndbuf, 0, "max hardware send buffer size");
3249228561Snp
3250228561Snp		sc->tt.ddp = 0;
3251228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp", CTLFLAG_RW,
3252228561Snp		    &sc->tt.ddp, 0, "DDP allowed");
3253239341Snp
3254239341Snp		sc->tt.indsz = G_INDICATESIZE(t4_read_reg(sc, A_TP_PARA_REG5));
3255228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "indsz", CTLFLAG_RW,
3256228561Snp		    &sc->tt.indsz, 0, "DDP max indicate size allowed");
3257239341Snp
3258239341Snp		sc->tt.ddp_thres =
3259239341Snp		    G_RXCOALESCESIZE(t4_read_reg(sc, A_TP_PARA_REG2));
3260228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp_thres", CTLFLAG_RW,
3261228561Snp		    &sc->tt.ddp_thres, 0, "DDP threshold");
3262228561Snp	}
3263228561Snp#endif
3264228561Snp
3265228561Snp
3266218792Snp	return (0);
3267218792Snp}
3268218792Snp
3269218792Snpstatic int
3270218792Snpcxgbe_sysctls(struct port_info *pi)
3271218792Snp{
3272218792Snp	struct sysctl_ctx_list *ctx;
3273218792Snp	struct sysctl_oid *oid;
3274218792Snp	struct sysctl_oid_list *children;
3275218792Snp
3276218792Snp	ctx = device_get_sysctl_ctx(pi->dev);
3277218792Snp
3278218792Snp	/*
3279218792Snp	 * dev.cxgbe.X.
3280218792Snp	 */
3281218792Snp	oid = device_get_sysctl_tree(pi->dev);
3282218792Snp	children = SYSCTL_CHILDREN(oid);
3283218792Snp
3284218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD,
3285218792Snp	    &pi->nrxq, 0, "# of rx queues");
3286218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD,
3287218792Snp	    &pi->ntxq, 0, "# of tx queues");
3288218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD,
3289218792Snp	    &pi->first_rxq, 0, "index of first rx queue");
3290218792Snp	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD,
3291218792Snp	    &pi->first_txq, 0, "index of first tx queue");
3292218792Snp
3293237263Snp#ifdef TCP_OFFLOAD
3294228561Snp	if (is_offload(pi->adapter)) {
3295228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldrxq", CTLFLAG_RD,
3296228561Snp		    &pi->nofldrxq, 0,
3297228561Snp		    "# of rx queues for offloaded TCP connections");
3298228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldtxq", CTLFLAG_RD,
3299228561Snp		    &pi->nofldtxq, 0,
3300228561Snp		    "# of tx queues for offloaded TCP connections");
3301228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_rxq",
3302228561Snp		    CTLFLAG_RD, &pi->first_ofld_rxq, 0,
3303228561Snp		    "index of first TOE rx queue");
3304228561Snp		SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_txq",
3305228561Snp		    CTLFLAG_RD, &pi->first_ofld_txq, 0,
3306228561Snp		    "index of first TOE tx queue");
3307228561Snp	}
3308228561Snp#endif
3309228561Snp
3310218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx",
3311218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I",
3312218792Snp	    "holdoff timer index");
3313218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx",
3314218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I",
3315218792Snp	    "holdoff packet counter index");
3316218792Snp
3317218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq",
3318218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I",
3319218792Snp	    "rx queue size");
3320218792Snp	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq",
3321218792Snp	    CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I",
3322218792Snp	    "tx queue size");
3323218792Snp
3324218792Snp	/*
3325218792Snp	 * dev.cxgbe.X.stats.
3326218792Snp	 */
3327218792Snp	oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD,
3328218792Snp	    NULL, "port statistics");
3329218792Snp	children = SYSCTL_CHILDREN(oid);
3330218792Snp
3331218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \
3332218792Snp	SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \
3333218792Snp	    CTLTYPE_U64 | CTLFLAG_RD, pi->adapter, reg, \
3334218792Snp	    sysctl_handle_t4_reg64, "QU", desc)
3335218792Snp
3336218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames",
3337218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L));
3338218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames",
3339218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L));
3340218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames",
3341218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L));
3342218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames",
3343218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L));
3344218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames",
3345218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L));
3346218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames",
3347218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L));
3348218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_64",
3349218792Snp	    "# of tx frames in this range",
3350218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L));
3351218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127",
3352218792Snp	    "# of tx frames in this range",
3353218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L));
3354218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255",
3355218792Snp	    "# of tx frames in this range",
3356218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L));
3357218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511",
3358218792Snp	    "# of tx frames in this range",
3359218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L));
3360218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023",
3361218792Snp	    "# of tx frames in this range",
3362218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L));
3363218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518",
3364218792Snp	    "# of tx frames in this range",
3365218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L));
3366218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max",
3367218792Snp	    "# of tx frames in this range",
3368218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L));
3369218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames",
3370218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L));
3371218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted",
3372218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L));
3373218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted",
3374218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L));
3375218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted",
3376218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L));
3377218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted",
3378218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L));
3379218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted",
3380218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L));
3381218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted",
3382218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L));
3383218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted",
3384218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L));
3385218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted",
3386218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L));
3387218792Snp	SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted",
3388218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L));
3389218792Snp
3390218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames",
3391218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L));
3392218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames",
3393218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L));
3394218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames",
3395218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L));
3396218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames",
3397218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L));
3398218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames",
3399218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L));
3400218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU",
3401218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L));
3402218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames",
3403218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L));
3404218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err",
3405218792Snp	    "# of frames received with bad FCS",
3406218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L));
3407218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_len_err",
3408218792Snp	    "# of frames received with length error",
3409218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L));
3410218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors",
3411218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L));
3412218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received",
3413218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L));
3414218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_64",
3415218792Snp	    "# of rx frames in this range",
3416218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L));
3417218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127",
3418218792Snp	    "# of rx frames in this range",
3419218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L));
3420218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255",
3421218792Snp	    "# of rx frames in this range",
3422218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L));
3423218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511",
3424218792Snp	    "# of rx frames in this range",
3425218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L));
3426218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023",
3427218792Snp	    "# of rx frames in this range",
3428218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L));
3429218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518",
3430218792Snp	    "# of rx frames in this range",
3431218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L));
3432218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max",
3433218792Snp	    "# of rx frames in this range",
3434218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L));
3435218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received",
3436218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L));
3437218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received",
3438218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L));
3439218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received",
3440218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L));
3441218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received",
3442218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L));
3443218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received",
3444218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L));
3445218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received",
3446218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L));
3447218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received",
3448218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L));
3449218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received",
3450218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L));
3451218792Snp	SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received",
3452218792Snp	    PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L));
3453218792Snp
3454218792Snp#undef SYSCTL_ADD_T4_REG64
3455218792Snp
3456218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \
3457218792Snp	SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \
3458218792Snp	    &pi->stats.name, desc)
3459218792Snp
3460218792Snp	/* We get these from port_stats and they may be stale by upto 1s */
3461218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0,
3462218792Snp	    "# drops due to buffer-group 0 overflows");
3463218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1,
3464218792Snp	    "# drops due to buffer-group 1 overflows");
3465218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2,
3466218792Snp	    "# drops due to buffer-group 2 overflows");
3467218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3,
3468218792Snp	    "# drops due to buffer-group 3 overflows");
3469218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc0,
3470218792Snp	    "# of buffer-group 0 truncated packets");
3471218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc1,
3472218792Snp	    "# of buffer-group 1 truncated packets");
3473218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc2,
3474218792Snp	    "# of buffer-group 2 truncated packets");
3475218792Snp	SYSCTL_ADD_T4_PORTSTAT(rx_trunc3,
3476218792Snp	    "# of buffer-group 3 truncated packets");
3477218792Snp
3478218792Snp#undef SYSCTL_ADD_T4_PORTSTAT
3479218792Snp
3480218792Snp	return (0);
3481218792Snp}
3482218792Snp
3483218792Snpstatic int
3484219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS)
3485219436Snp{
3486219436Snp	int rc, *i;
3487219436Snp	struct sbuf sb;
3488219436Snp
3489219436Snp	sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND);
3490219436Snp	for (i = arg1; arg2; arg2 -= sizeof(int), i++)
3491219436Snp		sbuf_printf(&sb, "%d ", *i);
3492219436Snp	sbuf_trim(&sb);
3493219436Snp	sbuf_finish(&sb);
3494219436Snp	rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
3495219436Snp	sbuf_delete(&sb);
3496219436Snp	return (rc);
3497219436Snp}
3498219436Snp
3499219436Snpstatic int
3500228561Snpsysctl_bitfield(SYSCTL_HANDLER_ARGS)
3501228561Snp{
3502228561Snp	int rc;
3503228561Snp	struct sbuf *sb;
3504228561Snp
3505228561Snp	rc = sysctl_wire_old_buffer(req, 0);
3506228561Snp	if (rc != 0)
3507228561Snp		return(rc);
3508228561Snp
3509228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 128, req);
3510228561Snp	if (sb == NULL)
3511228561Snp		return (ENOMEM);
3512228561Snp
3513228561Snp	sbuf_printf(sb, "%b", (int)arg2, (char *)arg1);
3514228561Snp	rc = sbuf_finish(sb);
3515228561Snp	sbuf_delete(sb);
3516228561Snp
3517228561Snp	return (rc);
3518228561Snp}
3519228561Snp
3520228561Snpstatic int
3521218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS)
3522218792Snp{
3523218792Snp	struct port_info *pi = arg1;
3524218792Snp	struct adapter *sc = pi->adapter;
3525218792Snp	int idx, rc, i;
3526218792Snp
3527218792Snp	idx = pi->tmr_idx;
3528218792Snp
3529218792Snp	rc = sysctl_handle_int(oidp, &idx, 0, req);
3530218792Snp	if (rc != 0 || req->newptr == NULL)
3531218792Snp		return (rc);
3532218792Snp
3533218792Snp	if (idx < 0 || idx >= SGE_NTIMERS)
3534218792Snp		return (EINVAL);
3535218792Snp
3536218792Snp	ADAPTER_LOCK(sc);
3537218792Snp	rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
3538218792Snp	if (rc == 0) {
3539228561Snp		struct sge_rxq *rxq;
3540228561Snp		uint8_t v;
3541228561Snp
3542228561Snp		v = V_QINTR_TIMER_IDX(idx) | V_QINTR_CNT_EN(pi->pktc_idx != -1);
3543218792Snp		for_each_rxq(pi, i, rxq) {
3544228561Snp#ifdef atomic_store_rel_8
3545228561Snp			atomic_store_rel_8(&rxq->iq.intr_params, v);
3546228561Snp#else
3547228561Snp			rxq->iq.intr_params = v;
3548228561Snp#endif
3549218792Snp		}
3550218792Snp		pi->tmr_idx = idx;
3551218792Snp	}
3552218792Snp
3553218792Snp	ADAPTER_UNLOCK(sc);
3554218792Snp	return (rc);
3555218792Snp}
3556218792Snp
3557218792Snpstatic int
3558218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS)
3559218792Snp{
3560218792Snp	struct port_info *pi = arg1;
3561218792Snp	struct adapter *sc = pi->adapter;
3562218792Snp	int idx, rc;
3563218792Snp
3564218792Snp	idx = pi->pktc_idx;
3565218792Snp
3566218792Snp	rc = sysctl_handle_int(oidp, &idx, 0, req);
3567218792Snp	if (rc != 0 || req->newptr == NULL)
3568218792Snp		return (rc);
3569218792Snp
3570218792Snp	if (idx < -1 || idx >= SGE_NCOUNTERS)
3571218792Snp		return (EINVAL);
3572218792Snp
3573218792Snp	ADAPTER_LOCK(sc);
3574218792Snp	rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
3575228561Snp	if (rc == 0 && pi->flags & PORT_INIT_DONE)
3576228561Snp		rc = EBUSY; /* cannot be changed once the queues are created */
3577218792Snp
3578218792Snp	if (rc == 0)
3579218792Snp		pi->pktc_idx = idx;
3580218792Snp
3581218792Snp	ADAPTER_UNLOCK(sc);
3582218792Snp	return (rc);
3583218792Snp}
3584218792Snp
3585218792Snpstatic int
3586218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS)
3587218792Snp{
3588218792Snp	struct port_info *pi = arg1;
3589218792Snp	struct adapter *sc = pi->adapter;
3590218792Snp	int qsize, rc;
3591218792Snp
3592218792Snp	qsize = pi->qsize_rxq;
3593218792Snp
3594218792Snp	rc = sysctl_handle_int(oidp, &qsize, 0, req);
3595218792Snp	if (rc != 0 || req->newptr == NULL)
3596218792Snp		return (rc);
3597218792Snp
3598218792Snp	if (qsize < 128 || (qsize & 7))
3599218792Snp		return (EINVAL);
3600218792Snp
3601218792Snp	ADAPTER_LOCK(sc);
3602218792Snp	rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
3603228561Snp	if (rc == 0 && pi->flags & PORT_INIT_DONE)
3604228561Snp		rc = EBUSY; /* cannot be changed once the queues are created */
3605218792Snp
3606218792Snp	if (rc == 0)
3607218792Snp		pi->qsize_rxq = qsize;
3608218792Snp
3609218792Snp	ADAPTER_UNLOCK(sc);
3610218792Snp	return (rc);
3611218792Snp}
3612218792Snp
3613218792Snpstatic int
3614218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS)
3615218792Snp{
3616218792Snp	struct port_info *pi = arg1;
3617218792Snp	struct adapter *sc = pi->adapter;
3618218792Snp	int qsize, rc;
3619218792Snp
3620218792Snp	qsize = pi->qsize_txq;
3621218792Snp
3622218792Snp	rc = sysctl_handle_int(oidp, &qsize, 0, req);
3623218792Snp	if (rc != 0 || req->newptr == NULL)
3624218792Snp		return (rc);
3625218792Snp
3626218792Snp	if (qsize < 128)
3627218792Snp		return (EINVAL);
3628218792Snp
3629218792Snp	ADAPTER_LOCK(sc);
3630218792Snp	rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
3631228561Snp	if (rc == 0 && pi->flags & PORT_INIT_DONE)
3632228561Snp		rc = EBUSY; /* cannot be changed once the queues are created */
3633218792Snp
3634218792Snp	if (rc == 0)
3635218792Snp		pi->qsize_txq = qsize;
3636218792Snp
3637218792Snp	ADAPTER_UNLOCK(sc);
3638218792Snp	return (rc);
3639218792Snp}
3640218792Snp
3641218792Snpstatic int
3642218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS)
3643218792Snp{
3644218792Snp	struct adapter *sc = arg1;
3645218792Snp	int reg = arg2;
3646218792Snp	uint64_t val;
3647218792Snp
3648218792Snp	val = t4_read_reg64(sc, reg);
3649218792Snp
3650218792Snp	return (sysctl_handle_64(oidp, &val, 0, req));
3651218792Snp}
3652218792Snp
3653231115Snp#ifdef SBUF_DRAIN
3654228561Snpstatic int
3655228561Snpsysctl_cctrl(SYSCTL_HANDLER_ARGS)
3656228561Snp{
3657228561Snp	struct adapter *sc = arg1;
3658228561Snp	struct sbuf *sb;
3659228561Snp	int rc, i;
3660228561Snp	uint16_t incr[NMTUS][NCCTRL_WIN];
3661228561Snp	static const char *dec_fac[] = {
3662228561Snp		"0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875",
3663228561Snp		"0.9375"
3664228561Snp	};
3665228561Snp
3666228561Snp	rc = sysctl_wire_old_buffer(req, 0);
3667228561Snp	if (rc != 0)
3668228561Snp		return (rc);
3669228561Snp
3670228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
3671228561Snp	if (sb == NULL)
3672228561Snp		return (ENOMEM);
3673228561Snp
3674228561Snp	t4_read_cong_tbl(sc, incr);
3675228561Snp
3676228561Snp	for (i = 0; i < NCCTRL_WIN; ++i) {
3677228561Snp		sbuf_printf(sb, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i,
3678228561Snp		    incr[0][i], incr[1][i], incr[2][i], incr[3][i], incr[4][i],
3679228561Snp		    incr[5][i], incr[6][i], incr[7][i]);
3680228561Snp		sbuf_printf(sb, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n",
3681228561Snp		    incr[8][i], incr[9][i], incr[10][i], incr[11][i],
3682228561Snp		    incr[12][i], incr[13][i], incr[14][i], incr[15][i],
3683228561Snp		    sc->params.a_wnd[i], dec_fac[sc->params.b_wnd[i]]);
3684228561Snp	}
3685228561Snp
3686228561Snp	rc = sbuf_finish(sb);
3687228561Snp	sbuf_delete(sb);
3688228561Snp
3689228561Snp	return (rc);
3690228561Snp}
3691228561Snp
3692228561Snpstatic int
3693228561Snpsysctl_cpl_stats(SYSCTL_HANDLER_ARGS)
3694228561Snp{
3695228561Snp	struct adapter *sc = arg1;
3696228561Snp	struct sbuf *sb;
3697228561Snp	int rc;
3698228561Snp	struct tp_cpl_stats stats;
3699228561Snp
3700228561Snp	rc = sysctl_wire_old_buffer(req, 0);
3701228561Snp	if (rc != 0)
3702228561Snp		return (rc);
3703228561Snp
3704228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
3705228561Snp	if (sb == NULL)
3706228561Snp		return (ENOMEM);
3707228561Snp
3708228561Snp	t4_tp_get_cpl_stats(sc, &stats);
3709228561Snp
3710228561Snp	sbuf_printf(sb, "                 channel 0  channel 1  channel 2  "
3711228561Snp	    "channel 3\n");
3712228561Snp	sbuf_printf(sb, "CPL requests:   %10u %10u %10u %10u\n",
3713228561Snp		   stats.req[0], stats.req[1], stats.req[2], stats.req[3]);
3714228561Snp	sbuf_printf(sb, "CPL responses:  %10u %10u %10u %10u",
3715228561Snp		   stats.rsp[0], stats.rsp[1], stats.rsp[2], stats.rsp[3]);
3716228561Snp
3717228561Snp	rc = sbuf_finish(sb);
3718228561Snp	sbuf_delete(sb);
3719228561Snp
3720228561Snp	return (rc);
3721228561Snp}
3722228561Snp
3723228561Snpstatic int
3724228561Snpsysctl_ddp_stats(SYSCTL_HANDLER_ARGS)
3725228561Snp{
3726228561Snp	struct adapter *sc = arg1;
3727228561Snp	struct sbuf *sb;
3728228561Snp	int rc;
3729228561Snp	struct tp_usm_stats stats;
3730228561Snp
3731228561Snp	rc = sysctl_wire_old_buffer(req, 0);
3732228561Snp	if (rc != 0)
3733228561Snp		return(rc);
3734228561Snp
3735228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
3736228561Snp	if (sb == NULL)
3737228561Snp		return (ENOMEM);
3738228561Snp
3739228561Snp	t4_get_usm_stats(sc, &stats);
3740228561Snp
3741228561Snp	sbuf_printf(sb, "Frames: %u\n", stats.frames);
3742228561Snp	sbuf_printf(sb, "Octets: %ju\n", stats.octets);
3743228561Snp	sbuf_printf(sb, "Drops:  %u", stats.drops);
3744228561Snp
3745228561Snp	rc = sbuf_finish(sb);
3746228561Snp	sbuf_delete(sb);
3747228561Snp
3748228561Snp	return (rc);
3749228561Snp}
3750228561Snp
3751222551Snpconst char *devlog_level_strings[] = {
3752222551Snp	[FW_DEVLOG_LEVEL_EMERG]		= "EMERG",
3753222551Snp	[FW_DEVLOG_LEVEL_CRIT]		= "CRIT",
3754222551Snp	[FW_DEVLOG_LEVEL_ERR]		= "ERR",
3755222551Snp	[FW_DEVLOG_LEVEL_NOTICE]	= "NOTICE",
3756222551Snp	[FW_DEVLOG_LEVEL_INFO]		= "INFO",
3757222551Snp	[FW_DEVLOG_LEVEL_DEBUG]		= "DEBUG"
3758222551Snp};
3759222551Snp
3760222551Snpconst char *devlog_facility_strings[] = {
3761222551Snp	[FW_DEVLOG_FACILITY_CORE]	= "CORE",
3762222551Snp	[FW_DEVLOG_FACILITY_SCHED]	= "SCHED",
3763222551Snp	[FW_DEVLOG_FACILITY_TIMER]	= "TIMER",
3764222551Snp	[FW_DEVLOG_FACILITY_RES]	= "RES",
3765222551Snp	[FW_DEVLOG_FACILITY_HW]		= "HW",
3766222551Snp	[FW_DEVLOG_FACILITY_FLR]	= "FLR",
3767222551Snp	[FW_DEVLOG_FACILITY_DMAQ]	= "DMAQ",
3768222551Snp	[FW_DEVLOG_FACILITY_PHY]	= "PHY",
3769222551Snp	[FW_DEVLOG_FACILITY_MAC]	= "MAC",
3770222551Snp	[FW_DEVLOG_FACILITY_PORT]	= "PORT",
3771222551Snp	[FW_DEVLOG_FACILITY_VI]		= "VI",
3772222551Snp	[FW_DEVLOG_FACILITY_FILTER]	= "FILTER",
3773222551Snp	[FW_DEVLOG_FACILITY_ACL]	= "ACL",
3774222551Snp	[FW_DEVLOG_FACILITY_TM]		= "TM",
3775222551Snp	[FW_DEVLOG_FACILITY_QFC]	= "QFC",
3776222551Snp	[FW_DEVLOG_FACILITY_DCB]	= "DCB",
3777222551Snp	[FW_DEVLOG_FACILITY_ETH]	= "ETH",
3778222551Snp	[FW_DEVLOG_FACILITY_OFLD]	= "OFLD",
3779222551Snp	[FW_DEVLOG_FACILITY_RI]		= "RI",
3780222551Snp	[FW_DEVLOG_FACILITY_ISCSI]	= "ISCSI",
3781222551Snp	[FW_DEVLOG_FACILITY_FCOE]	= "FCOE",
3782222551Snp	[FW_DEVLOG_FACILITY_FOISCSI]	= "FOISCSI",
3783222551Snp	[FW_DEVLOG_FACILITY_FOFCOE]	= "FOFCOE"
3784222551Snp};
3785222551Snp
3786222551Snpstatic int
3787222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS)
3788222551Snp{
3789222551Snp	struct adapter *sc = arg1;
3790222551Snp	struct devlog_params *dparams = &sc->params.devlog;
3791222551Snp	struct fw_devlog_e *buf, *e;
3792222551Snp	int i, j, rc, nentries, first = 0;
3793222551Snp	struct sbuf *sb;
3794222551Snp	uint64_t ftstamp = UINT64_MAX;
3795222551Snp
3796222551Snp	if (dparams->start == 0)
3797222551Snp		return (ENXIO);
3798222551Snp
3799222551Snp	nentries = dparams->size / sizeof(struct fw_devlog_e);
3800222551Snp
3801222551Snp	buf = malloc(dparams->size, M_CXGBE, M_NOWAIT);
3802222551Snp	if (buf == NULL)
3803222551Snp		return (ENOMEM);
3804222551Snp
3805222551Snp	rc = -t4_mem_read(sc, dparams->memtype, dparams->start, dparams->size,
3806222551Snp	    (void *)buf);
3807222551Snp	if (rc != 0)
3808222551Snp		goto done;
3809222551Snp
3810222551Snp	for (i = 0; i < nentries; i++) {
3811222551Snp		e = &buf[i];
3812222551Snp
3813222551Snp		if (e->timestamp == 0)
3814222551Snp			break;	/* end */
3815222551Snp
3816222551Snp		e->timestamp = be64toh(e->timestamp);
3817222551Snp		e->seqno = be32toh(e->seqno);
3818222551Snp		for (j = 0; j < 8; j++)
3819222551Snp			e->params[j] = be32toh(e->params[j]);
3820222551Snp
3821222551Snp		if (e->timestamp < ftstamp) {
3822222551Snp			ftstamp = e->timestamp;
3823222551Snp			first = i;
3824222551Snp		}
3825222551Snp	}
3826222551Snp
3827222551Snp	if (buf[first].timestamp == 0)
3828222551Snp		goto done;	/* nothing in the log */
3829222551Snp
3830222551Snp	rc = sysctl_wire_old_buffer(req, 0);
3831222551Snp	if (rc != 0)
3832222551Snp		goto done;
3833222551Snp
3834222551Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
3835228561Snp	if (sb == NULL) {
3836228561Snp		rc = ENOMEM;
3837228561Snp		goto done;
3838228561Snp	}
3839228561Snp	sbuf_printf(sb, "%10s  %15s  %8s  %8s  %s\n",
3840222551Snp	    "Seq#", "Tstamp", "Level", "Facility", "Message");
3841222551Snp
3842222551Snp	i = first;
3843222551Snp	do {
3844222551Snp		e = &buf[i];
3845222551Snp		if (e->timestamp == 0)
3846222551Snp			break;	/* end */
3847222551Snp
3848222551Snp		sbuf_printf(sb, "%10d  %15ju  %8s  %8s  ",
3849222551Snp		    e->seqno, e->timestamp,
3850240452Snp		    (e->level < nitems(devlog_level_strings) ?
3851222551Snp			devlog_level_strings[e->level] : "UNKNOWN"),
3852240452Snp		    (e->facility < nitems(devlog_facility_strings) ?
3853222551Snp			devlog_facility_strings[e->facility] : "UNKNOWN"));
3854222551Snp		sbuf_printf(sb, e->fmt, e->params[0], e->params[1],
3855222551Snp		    e->params[2], e->params[3], e->params[4],
3856222551Snp		    e->params[5], e->params[6], e->params[7]);
3857222551Snp
3858222551Snp		if (++i == nentries)
3859222551Snp			i = 0;
3860222551Snp	} while (i != first);
3861222551Snp
3862222551Snp	rc = sbuf_finish(sb);
3863222551Snp	sbuf_delete(sb);
3864222551Snpdone:
3865222551Snp	free(buf, M_CXGBE);
3866222551Snp	return (rc);
3867222551Snp}
3868222551Snp
3869228561Snpstatic int
3870228561Snpsysctl_fcoe_stats(SYSCTL_HANDLER_ARGS)
3871228561Snp{
3872228561Snp	struct adapter *sc = arg1;
3873228561Snp	struct sbuf *sb;
3874228561Snp	int rc;
3875228561Snp	struct tp_fcoe_stats stats[4];
3876228561Snp
3877228561Snp	rc = sysctl_wire_old_buffer(req, 0);
3878228561Snp	if (rc != 0)
3879228561Snp		return (rc);
3880228561Snp
3881228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
3882228561Snp	if (sb == NULL)
3883228561Snp		return (ENOMEM);
3884228561Snp
3885228561Snp	t4_get_fcoe_stats(sc, 0, &stats[0]);
3886228561Snp	t4_get_fcoe_stats(sc, 1, &stats[1]);
3887228561Snp	t4_get_fcoe_stats(sc, 2, &stats[2]);
3888228561Snp	t4_get_fcoe_stats(sc, 3, &stats[3]);
3889228561Snp
3890228561Snp	sbuf_printf(sb, "                   channel 0        channel 1        "
3891228561Snp	    "channel 2        channel 3\n");
3892228561Snp	sbuf_printf(sb, "octetsDDP:  %16ju %16ju %16ju %16ju\n",
3893228561Snp	    stats[0].octetsDDP, stats[1].octetsDDP, stats[2].octetsDDP,
3894228561Snp	    stats[3].octetsDDP);
3895228561Snp	sbuf_printf(sb, "framesDDP:  %16u %16u %16u %16u\n", stats[0].framesDDP,
3896228561Snp	    stats[1].framesDDP, stats[2].framesDDP, stats[3].framesDDP);
3897228561Snp	sbuf_printf(sb, "framesDrop: %16u %16u %16u %16u",
3898228561Snp	    stats[0].framesDrop, stats[1].framesDrop, stats[2].framesDrop,
3899228561Snp	    stats[3].framesDrop);
3900228561Snp
3901228561Snp	rc = sbuf_finish(sb);
3902228561Snp	sbuf_delete(sb);
3903228561Snp
3904228561Snp	return (rc);
3905228561Snp}
3906228561Snp
3907228561Snpstatic int
3908228561Snpsysctl_hw_sched(SYSCTL_HANDLER_ARGS)
3909228561Snp{
3910228561Snp	struct adapter *sc = arg1;
3911228561Snp	struct sbuf *sb;
3912228561Snp	int rc, i;
3913228561Snp	unsigned int map, kbps, ipg, mode;
3914228561Snp	unsigned int pace_tab[NTX_SCHED];
3915228561Snp
3916228561Snp	rc = sysctl_wire_old_buffer(req, 0);
3917228561Snp	if (rc != 0)
3918228561Snp		return (rc);
3919228561Snp
3920228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
3921228561Snp	if (sb == NULL)
3922228561Snp		return (ENOMEM);
3923228561Snp
3924228561Snp	map = t4_read_reg(sc, A_TP_TX_MOD_QUEUE_REQ_MAP);
3925228561Snp	mode = G_TIMERMODE(t4_read_reg(sc, A_TP_MOD_CONFIG));
3926228561Snp	t4_read_pace_tbl(sc, pace_tab);
3927228561Snp
3928228561Snp	sbuf_printf(sb, "Scheduler  Mode   Channel  Rate (Kbps)   "
3929228561Snp	    "Class IPG (0.1 ns)   Flow IPG (us)");
3930228561Snp
3931228561Snp	for (i = 0; i < NTX_SCHED; ++i, map >>= 2) {
3932228561Snp		t4_get_tx_sched(sc, i, &kbps, &ipg);
3933228561Snp		sbuf_printf(sb, "\n    %u      %-5s     %u     ", i,
3934228561Snp		    (mode & (1 << i)) ? "flow" : "class", map & 3);
3935228561Snp		if (kbps)
3936228561Snp			sbuf_printf(sb, "%9u     ", kbps);
3937228561Snp		else
3938228561Snp			sbuf_printf(sb, " disabled     ");
3939228561Snp
3940228561Snp		if (ipg)
3941228561Snp			sbuf_printf(sb, "%13u        ", ipg);
3942228561Snp		else
3943228561Snp			sbuf_printf(sb, "     disabled        ");
3944228561Snp
3945228561Snp		if (pace_tab[i])
3946228561Snp			sbuf_printf(sb, "%10u", pace_tab[i]);
3947228561Snp		else
3948228561Snp			sbuf_printf(sb, "  disabled");
3949228561Snp	}
3950228561Snp
3951228561Snp	rc = sbuf_finish(sb);
3952228561Snp	sbuf_delete(sb);
3953228561Snp
3954228561Snp	return (rc);
3955228561Snp}
3956228561Snp
3957228561Snpstatic int
3958228561Snpsysctl_lb_stats(SYSCTL_HANDLER_ARGS)
3959228561Snp{
3960228561Snp	struct adapter *sc = arg1;
3961228561Snp	struct sbuf *sb;
3962228561Snp	int rc, i, j;
3963228561Snp	uint64_t *p0, *p1;
3964228561Snp	struct lb_port_stats s[2];
3965228561Snp	static const char *stat_name[] = {
3966228561Snp		"OctetsOK:", "FramesOK:", "BcastFrames:", "McastFrames:",
3967228561Snp		"UcastFrames:", "ErrorFrames:", "Frames64:", "Frames65To127:",
3968228561Snp		"Frames128To255:", "Frames256To511:", "Frames512To1023:",
3969228561Snp		"Frames1024To1518:", "Frames1519ToMax:", "FramesDropped:",
3970228561Snp		"BG0FramesDropped:", "BG1FramesDropped:", "BG2FramesDropped:",
3971228561Snp		"BG3FramesDropped:", "BG0FramesTrunc:", "BG1FramesTrunc:",
3972228561Snp		"BG2FramesTrunc:", "BG3FramesTrunc:"
3973228561Snp	};
3974228561Snp
3975228561Snp	rc = sysctl_wire_old_buffer(req, 0);
3976228561Snp	if (rc != 0)
3977228561Snp		return (rc);
3978228561Snp
3979228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
3980228561Snp	if (sb == NULL)
3981228561Snp		return (ENOMEM);
3982228561Snp
3983228561Snp	memset(s, 0, sizeof(s));
3984228561Snp
3985228561Snp	for (i = 0; i < 4; i += 2) {
3986228561Snp		t4_get_lb_stats(sc, i, &s[0]);
3987228561Snp		t4_get_lb_stats(sc, i + 1, &s[1]);
3988228561Snp
3989228561Snp		p0 = &s[0].octets;
3990228561Snp		p1 = &s[1].octets;
3991228561Snp		sbuf_printf(sb, "%s                       Loopback %u"
3992228561Snp		    "           Loopback %u", i == 0 ? "" : "\n", i, i + 1);
3993228561Snp
3994240452Snp		for (j = 0; j < nitems(stat_name); j++)
3995228561Snp			sbuf_printf(sb, "\n%-17s %20ju %20ju", stat_name[j],
3996228561Snp				   *p0++, *p1++);
3997228561Snp	}
3998228561Snp
3999228561Snp	rc = sbuf_finish(sb);
4000228561Snp	sbuf_delete(sb);
4001228561Snp
4002228561Snp	return (rc);
4003228561Snp}
4004228561Snp
4005228561Snpstruct mem_desc {
4006228561Snp	unsigned int base;
4007228561Snp	unsigned int limit;
4008228561Snp	unsigned int idx;
4009228561Snp};
4010228561Snp
4011228561Snpstatic int
4012228561Snpmem_desc_cmp(const void *a, const void *b)
4013228561Snp{
4014228561Snp	return ((const struct mem_desc *)a)->base -
4015228561Snp	       ((const struct mem_desc *)b)->base;
4016228561Snp}
4017228561Snp
4018228561Snpstatic void
4019228561Snpmem_region_show(struct sbuf *sb, const char *name, unsigned int from,
4020228561Snp    unsigned int to)
4021228561Snp{
4022228561Snp	unsigned int size;
4023228561Snp
4024228561Snp	size = to - from + 1;
4025228561Snp	if (size == 0)
4026228561Snp		return;
4027228561Snp
4028228561Snp	/* XXX: need humanize_number(3) in libkern for a more readable 'size' */
4029228561Snp	sbuf_printf(sb, "%-15s %#x-%#x [%u]\n", name, from, to, size);
4030228561Snp}
4031228561Snp
4032228561Snpstatic int
4033228561Snpsysctl_meminfo(SYSCTL_HANDLER_ARGS)
4034228561Snp{
4035228561Snp	struct adapter *sc = arg1;
4036228561Snp	struct sbuf *sb;
4037228561Snp	int rc, i, n;
4038228561Snp	uint32_t lo, hi;
4039228561Snp	static const char *memory[] = { "EDC0:", "EDC1:", "MC:" };
4040228561Snp	static const char *region[] = {
4041228561Snp		"DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:",
4042228561Snp		"Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:",
4043228561Snp		"Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:",
4044228561Snp		"TDDP region:", "TPT region:", "STAG region:", "RQ region:",
4045228561Snp		"RQUDP region:", "PBL region:", "TXPBL region:", "ULPRX state:",
4046228561Snp		"ULPTX state:", "On-chip queues:"
4047228561Snp	};
4048228561Snp	struct mem_desc avail[3];
4049240452Snp	struct mem_desc mem[nitems(region) + 3];	/* up to 3 holes */
4050228561Snp	struct mem_desc *md = mem;
4051228561Snp
4052228561Snp	rc = sysctl_wire_old_buffer(req, 0);
4053228561Snp	if (rc != 0)
4054228561Snp		return (rc);
4055228561Snp
4056228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
4057228561Snp	if (sb == NULL)
4058228561Snp		return (ENOMEM);
4059228561Snp
4060240452Snp	for (i = 0; i < nitems(mem); i++) {
4061228561Snp		mem[i].limit = 0;
4062228561Snp		mem[i].idx = i;
4063228561Snp	}
4064228561Snp
4065228561Snp	/* Find and sort the populated memory ranges */
4066228561Snp	i = 0;
4067228561Snp	lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE);
4068228561Snp	if (lo & F_EDRAM0_ENABLE) {
4069228561Snp		hi = t4_read_reg(sc, A_MA_EDRAM0_BAR);
4070228561Snp		avail[i].base = G_EDRAM0_BASE(hi) << 20;
4071228561Snp		avail[i].limit = avail[i].base + (G_EDRAM0_SIZE(hi) << 20);
4072228561Snp		avail[i].idx = 0;
4073228561Snp		i++;
4074228561Snp	}
4075228561Snp	if (lo & F_EDRAM1_ENABLE) {
4076228561Snp		hi = t4_read_reg(sc, A_MA_EDRAM1_BAR);
4077228561Snp		avail[i].base = G_EDRAM1_BASE(hi) << 20;
4078228561Snp		avail[i].limit = avail[i].base + (G_EDRAM1_SIZE(hi) << 20);
4079228561Snp		avail[i].idx = 1;
4080228561Snp		i++;
4081228561Snp	}
4082228561Snp	if (lo & F_EXT_MEM_ENABLE) {
4083228561Snp		hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR);
4084228561Snp		avail[i].base = G_EXT_MEM_BASE(hi) << 20;
4085228561Snp		avail[i].limit = avail[i].base + (G_EXT_MEM_SIZE(hi) << 20);
4086228561Snp		avail[i].idx = 2;
4087228561Snp		i++;
4088228561Snp	}
4089228561Snp	if (!i)                                    /* no memory available */
4090228561Snp		return 0;
4091228561Snp	qsort(avail, i, sizeof(struct mem_desc), mem_desc_cmp);
4092228561Snp
4093228561Snp	(md++)->base = t4_read_reg(sc, A_SGE_DBQ_CTXT_BADDR);
4094228561Snp	(md++)->base = t4_read_reg(sc, A_SGE_IMSG_CTXT_BADDR);
4095228561Snp	(md++)->base = t4_read_reg(sc, A_SGE_FLM_CACHE_BADDR);
4096228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_TCB_BASE);
4097228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_MM_BASE);
4098228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_TIMER_BASE);
4099228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_MM_RX_FLST_BASE);
4100228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_MM_TX_FLST_BASE);
4101228561Snp	(md++)->base = t4_read_reg(sc, A_TP_CMM_MM_PS_FLST_BASE);
4102228561Snp
4103228561Snp	/* the next few have explicit upper bounds */
4104228561Snp	md->base = t4_read_reg(sc, A_TP_PMM_TX_BASE);
4105228561Snp	md->limit = md->base - 1 +
4106228561Snp		    t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE) *
4107228561Snp		    G_PMTXMAXPAGE(t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE));
4108228561Snp	md++;
4109228561Snp
4110228561Snp	md->base = t4_read_reg(sc, A_TP_PMM_RX_BASE);
4111228561Snp	md->limit = md->base - 1 +
4112228561Snp		    t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) *
4113228561Snp		    G_PMRXMAXPAGE(t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE));
4114228561Snp	md++;
4115228561Snp
4116228561Snp	if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) {
4117228561Snp		hi = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4;
4118228561Snp		md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE);
4119228561Snp		md->limit = (sc->tids.ntids - hi) * 16 + md->base - 1;
4120228561Snp	} else {
4121228561Snp		md->base = 0;
4122240452Snp		md->idx = nitems(region);  /* hide it */
4123228561Snp	}
4124228561Snp	md++;
4125228561Snp
4126228561Snp#define ulp_region(reg) \
4127228561Snp	md->base = t4_read_reg(sc, A_ULP_ ## reg ## _LLIMIT);\
4128228561Snp	(md++)->limit = t4_read_reg(sc, A_ULP_ ## reg ## _ULIMIT)
4129228561Snp
4130228561Snp	ulp_region(RX_ISCSI);
4131228561Snp	ulp_region(RX_TDDP);
4132228561Snp	ulp_region(TX_TPT);
4133228561Snp	ulp_region(RX_STAG);
4134228561Snp	ulp_region(RX_RQ);
4135228561Snp	ulp_region(RX_RQUDP);
4136228561Snp	ulp_region(RX_PBL);
4137228561Snp	ulp_region(TX_PBL);
4138228561Snp#undef ulp_region
4139228561Snp
4140228561Snp	md->base = t4_read_reg(sc, A_ULP_RX_CTX_BASE);
4141228561Snp	md->limit = md->base + sc->tids.ntids - 1;
4142228561Snp	md++;
4143228561Snp	md->base = t4_read_reg(sc, A_ULP_TX_ERR_TABLE_BASE);
4144228561Snp	md->limit = md->base + sc->tids.ntids - 1;
4145228561Snp	md++;
4146228561Snp
4147228561Snp	md->base = sc->vres.ocq.start;
4148228561Snp	if (sc->vres.ocq.size)
4149228561Snp		md->limit = md->base + sc->vres.ocq.size - 1;
4150228561Snp	else
4151240452Snp		md->idx = nitems(region);  /* hide it */
4152228561Snp	md++;
4153228561Snp
4154228561Snp	/* add any address-space holes, there can be up to 3 */
4155228561Snp	for (n = 0; n < i - 1; n++)
4156228561Snp		if (avail[n].limit < avail[n + 1].base)
4157228561Snp			(md++)->base = avail[n].limit;
4158228561Snp	if (avail[n].limit)
4159228561Snp		(md++)->base = avail[n].limit;
4160228561Snp
4161228561Snp	n = md - mem;
4162228561Snp	qsort(mem, n, sizeof(struct mem_desc), mem_desc_cmp);
4163228561Snp
4164228561Snp	for (lo = 0; lo < i; lo++)
4165228561Snp		mem_region_show(sb, memory[avail[lo].idx], avail[lo].base,
4166228561Snp				avail[lo].limit - 1);
4167228561Snp
4168228561Snp	sbuf_printf(sb, "\n");
4169228561Snp	for (i = 0; i < n; i++) {
4170240452Snp		if (mem[i].idx >= nitems(region))
4171228561Snp			continue;                        /* skip holes */
4172228561Snp		if (!mem[i].limit)
4173228561Snp			mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0;
4174228561Snp		mem_region_show(sb, region[mem[i].idx], mem[i].base,
4175228561Snp				mem[i].limit);
4176228561Snp	}
4177228561Snp
4178228561Snp	sbuf_printf(sb, "\n");
4179228561Snp	lo = t4_read_reg(sc, A_CIM_SDRAM_BASE_ADDR);
4180228561Snp	hi = t4_read_reg(sc, A_CIM_SDRAM_ADDR_SIZE) + lo - 1;
4181228561Snp	mem_region_show(sb, "uP RAM:", lo, hi);
4182228561Snp
4183228561Snp	lo = t4_read_reg(sc, A_CIM_EXTMEM2_BASE_ADDR);
4184228561Snp	hi = t4_read_reg(sc, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1;
4185228561Snp	mem_region_show(sb, "uP Extmem2:", lo, hi);
4186228561Snp
4187228561Snp	lo = t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE);
4188228561Snp	sbuf_printf(sb, "\n%u Rx pages of size %uKiB for %u channels\n",
4189228561Snp		   G_PMRXMAXPAGE(lo),
4190228561Snp		   t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) >> 10,
4191228561Snp		   (lo & F_PMRXNUMCHN) ? 2 : 1);
4192228561Snp
4193228561Snp	lo = t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE);
4194228561Snp	hi = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE);
4195228561Snp	sbuf_printf(sb, "%u Tx pages of size %u%ciB for %u channels\n",
4196228561Snp		   G_PMTXMAXPAGE(lo),
4197228561Snp		   hi >= (1 << 20) ? (hi >> 20) : (hi >> 10),
4198228561Snp		   hi >= (1 << 20) ? 'M' : 'K', 1 << G_PMTXNUMCHN(lo));
4199228561Snp	sbuf_printf(sb, "%u p-structs\n",
4200228561Snp		   t4_read_reg(sc, A_TP_CMM_MM_MAX_PSTRUCT));
4201228561Snp
4202228561Snp	for (i = 0; i < 4; i++) {
4203228561Snp		lo = t4_read_reg(sc, A_MPS_RX_PG_RSV0 + i * 4);
4204228561Snp		sbuf_printf(sb, "\nPort %d using %u pages out of %u allocated",
4205228561Snp			   i, G_USED(lo), G_ALLOC(lo));
4206228561Snp	}
4207228561Snp	for (i = 0; i < 4; i++) {
4208228561Snp		lo = t4_read_reg(sc, A_MPS_RX_PG_RSV4 + i * 4);
4209228561Snp		sbuf_printf(sb,
4210228561Snp			   "\nLoopback %d using %u pages out of %u allocated",
4211228561Snp			   i, G_USED(lo), G_ALLOC(lo));
4212228561Snp	}
4213228561Snp
4214228561Snp	rc = sbuf_finish(sb);
4215228561Snp	sbuf_delete(sb);
4216228561Snp
4217228561Snp	return (rc);
4218228561Snp}
4219228561Snp
4220228561Snpstatic int
4221228561Snpsysctl_path_mtus(SYSCTL_HANDLER_ARGS)
4222228561Snp{
4223228561Snp	struct adapter *sc = arg1;
4224228561Snp	struct sbuf *sb;
4225228561Snp	int rc;
4226228561Snp	uint16_t mtus[NMTUS];
4227228561Snp
4228228561Snp	rc = sysctl_wire_old_buffer(req, 0);
4229228561Snp	if (rc != 0)
4230228561Snp		return (rc);
4231228561Snp
4232228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
4233228561Snp	if (sb == NULL)
4234228561Snp		return (ENOMEM);
4235228561Snp
4236228561Snp	t4_read_mtu_tbl(sc, mtus, NULL);
4237228561Snp
4238228561Snp	sbuf_printf(sb, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u",
4239228561Snp	    mtus[0], mtus[1], mtus[2], mtus[3], mtus[4], mtus[5], mtus[6],
4240228561Snp	    mtus[7], mtus[8], mtus[9], mtus[10], mtus[11], mtus[12], mtus[13],
4241228561Snp	    mtus[14], mtus[15]);
4242228561Snp
4243228561Snp	rc = sbuf_finish(sb);
4244228561Snp	sbuf_delete(sb);
4245228561Snp
4246228561Snp	return (rc);
4247228561Snp}
4248228561Snp
4249228561Snpstatic int
4250228561Snpsysctl_pm_stats(SYSCTL_HANDLER_ARGS)
4251228561Snp{
4252228561Snp	struct adapter *sc = arg1;
4253228561Snp	struct sbuf *sb;
4254228561Snp	int rc, i;
4255228561Snp	uint32_t tx_cnt[PM_NSTATS], rx_cnt[PM_NSTATS];
4256228561Snp	uint64_t tx_cyc[PM_NSTATS], rx_cyc[PM_NSTATS];
4257228561Snp	static const char *pm_stats[] = {
4258228561Snp		"Read:", "Write bypass:", "Write mem:", "Flush:", "FIFO wait:"
4259228561Snp	};
4260228561Snp
4261228561Snp	rc = sysctl_wire_old_buffer(req, 0);
4262228561Snp	if (rc != 0)
4263228561Snp		return (rc);
4264228561Snp
4265228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
4266228561Snp	if (sb == NULL)
4267228561Snp		return (ENOMEM);
4268228561Snp
4269228561Snp	t4_pmtx_get_stats(sc, tx_cnt, tx_cyc);
4270228561Snp	t4_pmrx_get_stats(sc, rx_cnt, rx_cyc);
4271228561Snp
4272228561Snp	sbuf_printf(sb, "                Tx count            Tx cycles    "
4273228561Snp	    "Rx count            Rx cycles");
4274228561Snp	for (i = 0; i < PM_NSTATS; i++)
4275228561Snp		sbuf_printf(sb, "\n%-13s %10u %20ju  %10u %20ju",
4276228561Snp		    pm_stats[i], tx_cnt[i], tx_cyc[i], rx_cnt[i], rx_cyc[i]);
4277228561Snp
4278228561Snp	rc = sbuf_finish(sb);
4279228561Snp	sbuf_delete(sb);
4280228561Snp
4281228561Snp	return (rc);
4282228561Snp}
4283228561Snp
4284228561Snpstatic int
4285228561Snpsysctl_rdma_stats(SYSCTL_HANDLER_ARGS)
4286228561Snp{
4287228561Snp	struct adapter *sc = arg1;
4288228561Snp	struct sbuf *sb;
4289228561Snp	int rc;
4290228561Snp	struct tp_rdma_stats stats;
4291228561Snp
4292228561Snp	rc = sysctl_wire_old_buffer(req, 0);
4293228561Snp	if (rc != 0)
4294228561Snp		return (rc);
4295228561Snp
4296228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
4297228561Snp	if (sb == NULL)
4298228561Snp		return (ENOMEM);
4299228561Snp
4300228561Snp	t4_tp_get_rdma_stats(sc, &stats);
4301228561Snp	sbuf_printf(sb, "NoRQEModDefferals: %u\n", stats.rqe_dfr_mod);
4302228561Snp	sbuf_printf(sb, "NoRQEPktDefferals: %u", stats.rqe_dfr_pkt);
4303228561Snp
4304228561Snp	rc = sbuf_finish(sb);
4305228561Snp	sbuf_delete(sb);
4306228561Snp
4307228561Snp	return (rc);
4308228561Snp}
4309228561Snp
4310228561Snpstatic int
4311228561Snpsysctl_tcp_stats(SYSCTL_HANDLER_ARGS)
4312228561Snp{
4313228561Snp	struct adapter *sc = arg1;
4314228561Snp	struct sbuf *sb;
4315228561Snp	int rc;
4316228561Snp	struct tp_tcp_stats v4, v6;
4317228561Snp
4318228561Snp	rc = sysctl_wire_old_buffer(req, 0);
4319228561Snp	if (rc != 0)
4320228561Snp		return (rc);
4321228561Snp
4322228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
4323228561Snp	if (sb == NULL)
4324228561Snp		return (ENOMEM);
4325228561Snp
4326228561Snp	t4_tp_get_tcp_stats(sc, &v4, &v6);
4327228561Snp	sbuf_printf(sb,
4328228561Snp	    "                                IP                 IPv6\n");
4329228561Snp	sbuf_printf(sb, "OutRsts:      %20u %20u\n",
4330228561Snp	    v4.tcpOutRsts, v6.tcpOutRsts);
4331228561Snp	sbuf_printf(sb, "InSegs:       %20ju %20ju\n",
4332228561Snp	    v4.tcpInSegs, v6.tcpInSegs);
4333228561Snp	sbuf_printf(sb, "OutSegs:      %20ju %20ju\n",
4334228561Snp	    v4.tcpOutSegs, v6.tcpOutSegs);
4335228561Snp	sbuf_printf(sb, "RetransSegs:  %20ju %20ju",
4336228561Snp	    v4.tcpRetransSegs, v6.tcpRetransSegs);
4337228561Snp
4338228561Snp	rc = sbuf_finish(sb);
4339228561Snp	sbuf_delete(sb);
4340228561Snp
4341228561Snp	return (rc);
4342228561Snp}
4343228561Snp
4344228561Snpstatic int
4345228561Snpsysctl_tids(SYSCTL_HANDLER_ARGS)
4346228561Snp{
4347228561Snp	struct adapter *sc = arg1;
4348228561Snp	struct sbuf *sb;
4349228561Snp	int rc;
4350228561Snp	struct tid_info *t = &sc->tids;
4351228561Snp
4352228561Snp	rc = sysctl_wire_old_buffer(req, 0);
4353228561Snp	if (rc != 0)
4354228561Snp		return (rc);
4355228561Snp
4356228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
4357228561Snp	if (sb == NULL)
4358228561Snp		return (ENOMEM);
4359228561Snp
4360228561Snp	if (t->natids) {
4361228561Snp		sbuf_printf(sb, "ATID range: 0-%u, in use: %u\n", t->natids - 1,
4362228561Snp		    t->atids_in_use);
4363228561Snp	}
4364228561Snp
4365228561Snp	if (t->ntids) {
4366228561Snp		if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) {
4367228561Snp			uint32_t b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4;
4368228561Snp
4369228561Snp			if (b) {
4370228561Snp				sbuf_printf(sb, "TID range: 0-%u, %u-%u", b - 1,
4371228561Snp				    t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4,
4372228561Snp				    t->ntids - 1);
4373228561Snp			} else {
4374228561Snp				sbuf_printf(sb, "TID range: %u-%u",
4375228561Snp				    t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4,
4376228561Snp				    t->ntids - 1);
4377228561Snp			}
4378228561Snp		} else
4379228561Snp			sbuf_printf(sb, "TID range: 0-%u", t->ntids - 1);
4380228561Snp		sbuf_printf(sb, ", in use: %u\n",
4381228561Snp		    atomic_load_acq_int(&t->tids_in_use));
4382228561Snp	}
4383228561Snp
4384228561Snp	if (t->nstids) {
4385228561Snp		sbuf_printf(sb, "STID range: %u-%u, in use: %u\n", t->stid_base,
4386228561Snp		    t->stid_base + t->nstids - 1, t->stids_in_use);
4387228561Snp	}
4388228561Snp
4389228561Snp	if (t->nftids) {
4390228561Snp		sbuf_printf(sb, "FTID range: %u-%u\n", t->ftid_base,
4391228561Snp		    t->ftid_base + t->nftids - 1);
4392228561Snp	}
4393228561Snp
4394228561Snp	sbuf_printf(sb, "HW TID usage: %u IP users, %u IPv6 users",
4395228561Snp	    t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV4),
4396228561Snp	    t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV6));
4397228561Snp
4398228561Snp	rc = sbuf_finish(sb);
4399228561Snp	sbuf_delete(sb);
4400228561Snp
4401228561Snp	return (rc);
4402228561Snp}
4403228561Snp
4404228561Snpstatic int
4405228561Snpsysctl_tp_err_stats(SYSCTL_HANDLER_ARGS)
4406228561Snp{
4407228561Snp	struct adapter *sc = arg1;
4408228561Snp	struct sbuf *sb;
4409228561Snp	int rc;
4410228561Snp	struct tp_err_stats stats;
4411228561Snp
4412228561Snp	rc = sysctl_wire_old_buffer(req, 0);
4413228561Snp	if (rc != 0)
4414228561Snp		return (rc);
4415228561Snp
4416228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
4417228561Snp	if (sb == NULL)
4418228561Snp		return (ENOMEM);
4419228561Snp
4420228561Snp	t4_tp_get_err_stats(sc, &stats);
4421228561Snp
4422228561Snp	sbuf_printf(sb, "                 channel 0  channel 1  channel 2  "
4423228561Snp		      "channel 3\n");
4424228561Snp	sbuf_printf(sb, "macInErrs:      %10u %10u %10u %10u\n",
4425228561Snp	    stats.macInErrs[0], stats.macInErrs[1], stats.macInErrs[2],
4426228561Snp	    stats.macInErrs[3]);
4427228561Snp	sbuf_printf(sb, "hdrInErrs:      %10u %10u %10u %10u\n",
4428228561Snp	    stats.hdrInErrs[0], stats.hdrInErrs[1], stats.hdrInErrs[2],
4429228561Snp	    stats.hdrInErrs[3]);
4430228561Snp	sbuf_printf(sb, "tcpInErrs:      %10u %10u %10u %10u\n",
4431228561Snp	    stats.tcpInErrs[0], stats.tcpInErrs[1], stats.tcpInErrs[2],
4432228561Snp	    stats.tcpInErrs[3]);
4433228561Snp	sbuf_printf(sb, "tcp6InErrs:     %10u %10u %10u %10u\n",
4434228561Snp	    stats.tcp6InErrs[0], stats.tcp6InErrs[1], stats.tcp6InErrs[2],
4435228561Snp	    stats.tcp6InErrs[3]);
4436228561Snp	sbuf_printf(sb, "tnlCongDrops:   %10u %10u %10u %10u\n",
4437228561Snp	    stats.tnlCongDrops[0], stats.tnlCongDrops[1], stats.tnlCongDrops[2],
4438228561Snp	    stats.tnlCongDrops[3]);
4439228561Snp	sbuf_printf(sb, "tnlTxDrops:     %10u %10u %10u %10u\n",
4440228561Snp	    stats.tnlTxDrops[0], stats.tnlTxDrops[1], stats.tnlTxDrops[2],
4441228561Snp	    stats.tnlTxDrops[3]);
4442228561Snp	sbuf_printf(sb, "ofldVlanDrops:  %10u %10u %10u %10u\n",
4443228561Snp	    stats.ofldVlanDrops[0], stats.ofldVlanDrops[1],
4444228561Snp	    stats.ofldVlanDrops[2], stats.ofldVlanDrops[3]);
4445228561Snp	sbuf_printf(sb, "ofldChanDrops:  %10u %10u %10u %10u\n\n",
4446228561Snp	    stats.ofldChanDrops[0], stats.ofldChanDrops[1],
4447228561Snp	    stats.ofldChanDrops[2], stats.ofldChanDrops[3]);
4448228561Snp	sbuf_printf(sb, "ofldNoNeigh:    %u\nofldCongDefer:  %u",
4449228561Snp	    stats.ofldNoNeigh, stats.ofldCongDefer);
4450228561Snp
4451228561Snp	rc = sbuf_finish(sb);
4452228561Snp	sbuf_delete(sb);
4453228561Snp
4454228561Snp	return (rc);
4455228561Snp}
4456228561Snp
4457228561Snpstatic int
4458228561Snpsysctl_tx_rate(SYSCTL_HANDLER_ARGS)
4459228561Snp{
4460228561Snp	struct adapter *sc = arg1;
4461228561Snp	struct sbuf *sb;
4462228561Snp	int rc;
4463228561Snp	u64 nrate[NCHAN], orate[NCHAN];
4464228561Snp
4465228561Snp	rc = sysctl_wire_old_buffer(req, 0);
4466228561Snp	if (rc != 0)
4467228561Snp		return (rc);
4468228561Snp
4469228561Snp	sb = sbuf_new_for_sysctl(NULL, NULL, 256, req);
4470228561Snp	if (sb == NULL)
4471228561Snp		return (ENOMEM);
4472228561Snp
4473228561Snp	t4_get_chan_txrate(sc, nrate, orate);
4474228561Snp	sbuf_printf(sb, "              channel 0   channel 1   channel 2   "
4475228561Snp		 "channel 3\n");
4476228561Snp	sbuf_printf(sb, "NIC B/s:     %10ju  %10ju  %10ju  %10ju\n",
4477228561Snp	    nrate[0], nrate[1], nrate[2], nrate[3]);
4478228561Snp	sbuf_printf(sb, "Offload B/s: %10ju  %10ju  %10ju  %10ju",
4479228561Snp	    orate[0], orate[1], orate[2], orate[3]);
4480228561Snp
4481228561Snp	rc = sbuf_finish(sb);
4482228561Snp	sbuf_delete(sb);
4483228561Snp
4484228561Snp	return (rc);
4485228561Snp}
4486231115Snp#endif
4487228561Snp
4488219286Snpstatic inline void
4489219286Snptxq_start(struct ifnet *ifp, struct sge_txq *txq)
4490219286Snp{
4491219286Snp	struct buf_ring *br;
4492219286Snp	struct mbuf *m;
4493219286Snp
4494219286Snp	TXQ_LOCK_ASSERT_OWNED(txq);
4495219286Snp
4496220873Snp	br = txq->br;
4497219286Snp	m = txq->m ? txq->m : drbr_dequeue(ifp, br);
4498219286Snp	if (m)
4499219286Snp		t4_eth_tx(ifp, txq, m);
4500219286Snp}
4501219286Snp
4502219286Snpvoid
4503228561Snpt4_tx_callout(void *arg)
4504219286Snp{
4505228561Snp	struct sge_eq *eq = arg;
4506228561Snp	struct adapter *sc;
4507219286Snp
4508228561Snp	if (EQ_TRYLOCK(eq) == 0)
4509228561Snp		goto reschedule;
4510228561Snp
4511228561Snp	if (eq->flags & EQ_STALLED && !can_resume_tx(eq)) {
4512228561Snp		EQ_UNLOCK(eq);
4513228561Snpreschedule:
4514228561Snp		if (__predict_true(!(eq->flags && EQ_DOOMED)))
4515228561Snp			callout_schedule(&eq->tx_callout, 1);
4516228561Snp		return;
4517228561Snp	}
4518228561Snp
4519228561Snp	EQ_LOCK_ASSERT_OWNED(eq);
4520228561Snp
4521228561Snp	if (__predict_true((eq->flags & EQ_DOOMED) == 0)) {
4522228561Snp
4523228561Snp		if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) {
4524228561Snp			struct sge_txq *txq = arg;
4525228561Snp			struct port_info *pi = txq->ifp->if_softc;
4526228561Snp
4527228561Snp			sc = pi->adapter;
4528228561Snp		} else {
4529228561Snp			struct sge_wrq *wrq = arg;
4530228561Snp
4531228561Snp			sc = wrq->adapter;
4532228561Snp		}
4533228561Snp
4534228561Snp		taskqueue_enqueue(sc->tq[eq->tx_chan], &eq->tx_task);
4535228561Snp	}
4536228561Snp
4537228561Snp	EQ_UNLOCK(eq);
4538228561Snp}
4539228561Snp
4540228561Snpvoid
4541228561Snpt4_tx_task(void *arg, int count)
4542228561Snp{
4543228561Snp	struct sge_eq *eq = arg;
4544228561Snp
4545228561Snp	EQ_LOCK(eq);
4546228561Snp	if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) {
4547228561Snp		struct sge_txq *txq = arg;
4548220649Snp		txq_start(txq->ifp, txq);
4549228561Snp	} else {
4550228561Snp		struct sge_wrq *wrq = arg;
4551228561Snp		t4_wrq_tx_locked(wrq->adapter, wrq, NULL);
4552228561Snp	}
4553228561Snp	EQ_UNLOCK(eq);
4554219286Snp}
4555219286Snp
4556221474Snpstatic uint32_t
4557221474Snpfconf_to_mode(uint32_t fconf)
4558221474Snp{
4559221474Snp	uint32_t mode;
4560221474Snp
4561221474Snp	mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR |
4562221474Snp	    T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT;
4563221474Snp
4564221474Snp	if (fconf & F_FRAGMENTATION)
4565221474Snp		mode |= T4_FILTER_IP_FRAGMENT;
4566221474Snp
4567221474Snp	if (fconf & F_MPSHITTYPE)
4568221474Snp		mode |= T4_FILTER_MPS_HIT_TYPE;
4569221474Snp
4570221474Snp	if (fconf & F_MACMATCH)
4571221474Snp		mode |= T4_FILTER_MAC_IDX;
4572221474Snp
4573221474Snp	if (fconf & F_ETHERTYPE)
4574221474Snp		mode |= T4_FILTER_ETH_TYPE;
4575221474Snp
4576221474Snp	if (fconf & F_PROTOCOL)
4577221474Snp		mode |= T4_FILTER_IP_PROTO;
4578221474Snp
4579221474Snp	if (fconf & F_TOS)
4580221474Snp		mode |= T4_FILTER_IP_TOS;
4581221474Snp
4582221474Snp	if (fconf & F_VLAN)
4583228561Snp		mode |= T4_FILTER_VLAN;
4584221474Snp
4585221474Snp	if (fconf & F_VNIC_ID)
4586228561Snp		mode |= T4_FILTER_VNIC;
4587221474Snp
4588221474Snp	if (fconf & F_PORT)
4589221474Snp		mode |= T4_FILTER_PORT;
4590221474Snp
4591221474Snp	if (fconf & F_FCOE)
4592221474Snp		mode |= T4_FILTER_FCoE;
4593221474Snp
4594221474Snp	return (mode);
4595221474Snp}
4596221474Snp
4597221474Snpstatic uint32_t
4598221474Snpmode_to_fconf(uint32_t mode)
4599221474Snp{
4600221474Snp	uint32_t fconf = 0;
4601221474Snp
4602221474Snp	if (mode & T4_FILTER_IP_FRAGMENT)
4603221474Snp		fconf |= F_FRAGMENTATION;
4604221474Snp
4605221474Snp	if (mode & T4_FILTER_MPS_HIT_TYPE)
4606221474Snp		fconf |= F_MPSHITTYPE;
4607221474Snp
4608221474Snp	if (mode & T4_FILTER_MAC_IDX)
4609221474Snp		fconf |= F_MACMATCH;
4610221474Snp
4611221474Snp	if (mode & T4_FILTER_ETH_TYPE)
4612221474Snp		fconf |= F_ETHERTYPE;
4613221474Snp
4614221474Snp	if (mode & T4_FILTER_IP_PROTO)
4615221474Snp		fconf |= F_PROTOCOL;
4616221474Snp
4617221474Snp	if (mode & T4_FILTER_IP_TOS)
4618221474Snp		fconf |= F_TOS;
4619221474Snp
4620228561Snp	if (mode & T4_FILTER_VLAN)
4621221474Snp		fconf |= F_VLAN;
4622221474Snp
4623228561Snp	if (mode & T4_FILTER_VNIC)
4624221474Snp		fconf |= F_VNIC_ID;
4625221474Snp
4626221474Snp	if (mode & T4_FILTER_PORT)
4627221474Snp		fconf |= F_PORT;
4628221474Snp
4629221474Snp	if (mode & T4_FILTER_FCoE)
4630221474Snp		fconf |= F_FCOE;
4631221474Snp
4632221474Snp	return (fconf);
4633221474Snp}
4634221474Snp
4635221474Snpstatic uint32_t
4636221474Snpfspec_to_fconf(struct t4_filter_specification *fs)
4637221474Snp{
4638221474Snp	uint32_t fconf = 0;
4639221474Snp
4640221474Snp	if (fs->val.frag || fs->mask.frag)
4641221474Snp		fconf |= F_FRAGMENTATION;
4642221474Snp
4643221474Snp	if (fs->val.matchtype || fs->mask.matchtype)
4644221474Snp		fconf |= F_MPSHITTYPE;
4645221474Snp
4646221474Snp	if (fs->val.macidx || fs->mask.macidx)
4647221474Snp		fconf |= F_MACMATCH;
4648221474Snp
4649221474Snp	if (fs->val.ethtype || fs->mask.ethtype)
4650221474Snp		fconf |= F_ETHERTYPE;
4651221474Snp
4652221474Snp	if (fs->val.proto || fs->mask.proto)
4653221474Snp		fconf |= F_PROTOCOL;
4654221474Snp
4655221474Snp	if (fs->val.tos || fs->mask.tos)
4656221474Snp		fconf |= F_TOS;
4657221474Snp
4658228561Snp	if (fs->val.vlan_vld || fs->mask.vlan_vld)
4659221474Snp		fconf |= F_VLAN;
4660221474Snp
4661228561Snp	if (fs->val.vnic_vld || fs->mask.vnic_vld)
4662221474Snp		fconf |= F_VNIC_ID;
4663221474Snp
4664221474Snp	if (fs->val.iport || fs->mask.iport)
4665221474Snp		fconf |= F_PORT;
4666221474Snp
4667221474Snp	if (fs->val.fcoe || fs->mask.fcoe)
4668221474Snp		fconf |= F_FCOE;
4669221474Snp
4670221474Snp	return (fconf);
4671221474Snp}
4672221474Snp
4673221474Snpstatic int
4674221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode)
4675221474Snp{
4676221474Snp	uint32_t fconf;
4677221474Snp
4678221474Snp	t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1,
4679221474Snp	    A_TP_VLAN_PRI_MAP);
4680221474Snp
4681228561Snp	if (sc->filter_mode != fconf) {
4682228561Snp		log(LOG_WARNING, "%s: cached filter mode out of sync %x %x.\n",
4683228561Snp		    device_get_nameunit(sc->dev), sc->filter_mode, fconf);
4684228561Snp		sc->filter_mode = fconf;
4685228561Snp	}
4686221474Snp
4687228561Snp	*mode = fconf_to_mode(sc->filter_mode);
4688228561Snp
4689221474Snp	return (0);
4690221474Snp}
4691221474Snp
4692221474Snpstatic int
4693221474Snpset_filter_mode(struct adapter *sc, uint32_t mode)
4694221474Snp{
4695221474Snp	uint32_t fconf;
4696221474Snp	int rc;
4697221474Snp
4698221474Snp	fconf = mode_to_fconf(mode);
4699221474Snp
4700221474Snp	ADAPTER_LOCK(sc);
4701221474Snp	if (IS_BUSY(sc)) {
4702221474Snp		rc = EAGAIN;
4703221474Snp		goto done;
4704221474Snp	}
4705221474Snp
4706221474Snp	if (sc->tids.ftids_in_use > 0) {
4707221474Snp		rc = EBUSY;
4708221474Snp		goto done;
4709221474Snp	}
4710221474Snp
4711237263Snp#ifdef TCP_OFFLOAD
4712228561Snp	if (sc->offload_map) {
4713228561Snp		rc = EBUSY;
4714228561Snp		goto done;
4715228561Snp	}
4716228561Snp#endif
4717228561Snp
4718228561Snp#ifdef notyet
4719221474Snp	rc = -t4_set_filter_mode(sc, fconf);
4720228561Snp	if (rc == 0)
4721228561Snp		sc->filter_mode = fconf;
4722228561Snp#else
4723228561Snp	rc = ENOTSUP;
4724228561Snp#endif
4725228561Snp
4726221474Snpdone:
4727221474Snp	ADAPTER_UNLOCK(sc);
4728221474Snp	return (rc);
4729221474Snp}
4730221474Snp
4731222552Snpstatic inline uint64_t
4732222552Snpget_filter_hits(struct adapter *sc, uint32_t fid)
4733222552Snp{
4734222552Snp	uint32_t tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE);
4735222552Snp	uint64_t hits;
4736222552Snp
4737222552Snp	t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0),
4738222552Snp	    tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE);
4739222552Snp	t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0));
4740222552Snp	hits = t4_read_reg64(sc, MEMWIN0_BASE + 16);
4741222552Snp
4742222552Snp	return (be64toh(hits));
4743222552Snp}
4744222552Snp
4745221474Snpstatic int
4746221474Snpget_filter(struct adapter *sc, struct t4_filter *t)
4747221474Snp{
4748221474Snp	int i, nfilters = sc->tids.nftids;
4749221474Snp	struct filter_entry *f;
4750221474Snp
4751221474Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
4752221474Snp
4753221474Snp	if (IS_BUSY(sc))
4754221474Snp		return (EAGAIN);
4755221474Snp
4756221474Snp	if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL ||
4757221474Snp	    t->idx >= nfilters) {
4758221474Snp		t->idx = 0xffffffff;
4759221474Snp		return (0);
4760221474Snp	}
4761221474Snp
4762221474Snp	f = &sc->tids.ftid_tab[t->idx];
4763221474Snp	for (i = t->idx; i < nfilters; i++, f++) {
4764221474Snp		if (f->valid) {
4765221474Snp			t->idx = i;
4766222509Snp			t->l2tidx = f->l2t ? f->l2t->idx : 0;
4767222509Snp			t->smtidx = f->smtidx;
4768222552Snp			if (f->fs.hitcnts)
4769222552Snp				t->hits = get_filter_hits(sc, t->idx);
4770222552Snp			else
4771222552Snp				t->hits = UINT64_MAX;
4772221474Snp			t->fs = f->fs;
4773221474Snp
4774221474Snp			return (0);
4775221474Snp		}
4776221474Snp	}
4777221474Snp
4778221474Snp	t->idx = 0xffffffff;
4779221474Snp	return (0);
4780221474Snp}
4781221474Snp
4782221474Snpstatic int
4783221474Snpset_filter(struct adapter *sc, struct t4_filter *t)
4784221474Snp{
4785221474Snp	unsigned int nfilters, nports;
4786221474Snp	struct filter_entry *f;
4787221474Snp	int i;
4788221474Snp
4789221474Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
4790221474Snp
4791221474Snp	nfilters = sc->tids.nftids;
4792221474Snp	nports = sc->params.nports;
4793221474Snp
4794221474Snp	if (nfilters == 0)
4795221474Snp		return (ENOTSUP);
4796221474Snp
4797221474Snp	if (!(sc->flags & FULL_INIT_DONE))
4798221474Snp		return (EAGAIN);
4799221474Snp
4800221474Snp	if (t->idx >= nfilters)
4801221474Snp		return (EINVAL);
4802221474Snp
4803221474Snp	/* Validate against the global filter mode */
4804228561Snp	if ((sc->filter_mode | fspec_to_fconf(&t->fs)) != sc->filter_mode)
4805221474Snp		return (E2BIG);
4806221474Snp
4807221474Snp	if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports)
4808221474Snp		return (EINVAL);
4809221474Snp
4810221474Snp	if (t->fs.val.iport >= nports)
4811221474Snp		return (EINVAL);
4812221474Snp
4813221474Snp	/* Can't specify an iq if not steering to it */
4814221474Snp	if (!t->fs.dirsteer && t->fs.iq)
4815221474Snp		return (EINVAL);
4816221474Snp
4817221474Snp	/* IPv6 filter idx must be 4 aligned */
4818221474Snp	if (t->fs.type == 1 &&
4819221474Snp	    ((t->idx & 0x3) || t->idx + 4 >= nfilters))
4820221474Snp		return (EINVAL);
4821221474Snp
4822221474Snp	if (sc->tids.ftid_tab == NULL) {
4823221474Snp		KASSERT(sc->tids.ftids_in_use == 0,
4824221474Snp		    ("%s: no memory allocated but filters_in_use > 0",
4825221474Snp		    __func__));
4826221474Snp
4827221474Snp		sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) *
4828221474Snp		    nfilters, M_CXGBE, M_NOWAIT | M_ZERO);
4829221474Snp		if (sc->tids.ftid_tab == NULL)
4830221474Snp			return (ENOMEM);
4831221474Snp	}
4832221474Snp
4833221474Snp	for (i = 0; i < 4; i++) {
4834221474Snp		f = &sc->tids.ftid_tab[t->idx + i];
4835221474Snp
4836221474Snp		if (f->pending || f->valid)
4837221474Snp			return (EBUSY);
4838221474Snp		if (f->locked)
4839221474Snp			return (EPERM);
4840221474Snp
4841221474Snp		if (t->fs.type == 0)
4842221474Snp			break;
4843221474Snp	}
4844221474Snp
4845221474Snp	f = &sc->tids.ftid_tab[t->idx];
4846221474Snp	f->fs = t->fs;
4847221474Snp
4848221474Snp	return set_filter_wr(sc, t->idx);
4849221474Snp}
4850221474Snp
4851221474Snpstatic int
4852221474Snpdel_filter(struct adapter *sc, struct t4_filter *t)
4853221474Snp{
4854221474Snp	unsigned int nfilters;
4855221474Snp	struct filter_entry *f;
4856221474Snp
4857221474Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
4858221474Snp
4859221474Snp	if (IS_BUSY(sc))
4860221474Snp		return (EAGAIN);
4861221474Snp
4862221474Snp	nfilters = sc->tids.nftids;
4863221474Snp
4864221474Snp	if (nfilters == 0)
4865221474Snp		return (ENOTSUP);
4866221474Snp
4867221474Snp	if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 ||
4868221474Snp	    t->idx >= nfilters)
4869221474Snp		return (EINVAL);
4870221474Snp
4871221474Snp	if (!(sc->flags & FULL_INIT_DONE))
4872221474Snp		return (EAGAIN);
4873221474Snp
4874221474Snp	f = &sc->tids.ftid_tab[t->idx];
4875221474Snp
4876221474Snp	if (f->pending)
4877221474Snp		return (EBUSY);
4878221474Snp	if (f->locked)
4879221474Snp		return (EPERM);
4880221474Snp
4881221474Snp	if (f->valid) {
4882221474Snp		t->fs = f->fs;	/* extra info for the caller */
4883221474Snp		return del_filter_wr(sc, t->idx);
4884221474Snp	}
4885221474Snp
4886221474Snp	return (0);
4887221474Snp}
4888221474Snp
4889221474Snpstatic void
4890222509Snpclear_filter(struct filter_entry *f)
4891221474Snp{
4892222509Snp	if (f->l2t)
4893222509Snp		t4_l2t_release(f->l2t);
4894222509Snp
4895221474Snp	bzero(f, sizeof (*f));
4896221474Snp}
4897221474Snp
4898221474Snpstatic int
4899221474Snpset_filter_wr(struct adapter *sc, int fidx)
4900221474Snp{
4901221474Snp	struct filter_entry *f = &sc->tids.ftid_tab[fidx];
4902237263Snp	struct wrqe *wr;
4903221474Snp	struct fw_filter_wr *fwr;
4904221474Snp	unsigned int ftid;
4905221474Snp
4906221474Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
4907221474Snp
4908222509Snp	if (f->fs.newdmac || f->fs.newvlan) {
4909222509Snp		/* This filter needs an L2T entry; allocate one. */
4910222509Snp		f->l2t = t4_l2t_alloc_switching(sc->l2t);
4911222509Snp		if (f->l2t == NULL)
4912222509Snp			return (EAGAIN);
4913222509Snp		if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport,
4914222509Snp		    f->fs.dmac)) {
4915222509Snp			t4_l2t_release(f->l2t);
4916222509Snp			f->l2t = NULL;
4917222509Snp			return (ENOMEM);
4918222509Snp		}
4919222509Snp	}
4920221474Snp
4921221474Snp	ftid = sc->tids.ftid_base + fidx;
4922221474Snp
4923237263Snp	wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq);
4924237263Snp	if (wr == NULL)
4925221474Snp		return (ENOMEM);
4926221474Snp
4927237263Snp	fwr = wrtod(wr);
4928221474Snp	bzero(fwr, sizeof (*fwr));
4929221474Snp
4930221474Snp	fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR));
4931221474Snp	fwr->len16_pkd = htobe32(FW_LEN16(*fwr));
4932221474Snp	fwr->tid_to_iq =
4933221474Snp	    htobe32(V_FW_FILTER_WR_TID(ftid) |
4934221474Snp		V_FW_FILTER_WR_RQTYPE(f->fs.type) |
4935221474Snp		V_FW_FILTER_WR_NOREPLY(0) |
4936221474Snp		V_FW_FILTER_WR_IQ(f->fs.iq));
4937221474Snp	fwr->del_filter_to_l2tix =
4938221474Snp	    htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) |
4939221474Snp		V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) |
4940221474Snp		V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) |
4941221474Snp		V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) |
4942221474Snp		V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) |
4943221474Snp		V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) |
4944221474Snp		V_FW_FILTER_WR_DMAC(f->fs.newdmac) |
4945221474Snp		V_FW_FILTER_WR_SMAC(f->fs.newsmac) |
4946221474Snp		V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT ||
4947221474Snp		    f->fs.newvlan == VLAN_REWRITE) |
4948221474Snp		V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE ||
4949221474Snp		    f->fs.newvlan == VLAN_REWRITE) |
4950221474Snp		V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) |
4951221474Snp		V_FW_FILTER_WR_TXCHAN(f->fs.eport) |
4952221474Snp		V_FW_FILTER_WR_PRIO(f->fs.prio) |
4953222509Snp		V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0));
4954221474Snp	fwr->ethtype = htobe16(f->fs.val.ethtype);
4955221474Snp	fwr->ethtypem = htobe16(f->fs.mask.ethtype);
4956221474Snp	fwr->frag_to_ovlan_vldm =
4957221474Snp	    (V_FW_FILTER_WR_FRAG(f->fs.val.frag) |
4958221474Snp		V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) |
4959228561Snp		V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) |
4960228561Snp		V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.vnic_vld) |
4961228561Snp		V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) |
4962228561Snp		V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.vnic_vld));
4963221474Snp	fwr->smac_sel = 0;
4964221474Snp	fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) |
4965228561Snp	    V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id));
4966221474Snp	fwr->maci_to_matchtypem =
4967221474Snp	    htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) |
4968221474Snp		V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) |
4969221474Snp		V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) |
4970221474Snp		V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) |
4971221474Snp		V_FW_FILTER_WR_PORT(f->fs.val.iport) |
4972221474Snp		V_FW_FILTER_WR_PORTM(f->fs.mask.iport) |
4973221474Snp		V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) |
4974221474Snp		V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype));
4975221474Snp	fwr->ptcl = f->fs.val.proto;
4976221474Snp	fwr->ptclm = f->fs.mask.proto;
4977221474Snp	fwr->ttyp = f->fs.val.tos;
4978221474Snp	fwr->ttypm = f->fs.mask.tos;
4979228561Snp	fwr->ivlan = htobe16(f->fs.val.vlan);
4980228561Snp	fwr->ivlanm = htobe16(f->fs.mask.vlan);
4981228561Snp	fwr->ovlan = htobe16(f->fs.val.vnic);
4982228561Snp	fwr->ovlanm = htobe16(f->fs.mask.vnic);
4983221474Snp	bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip));
4984221474Snp	bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm));
4985221474Snp	bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip));
4986221474Snp	bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm));
4987221474Snp	fwr->lp = htobe16(f->fs.val.dport);
4988221474Snp	fwr->lpm = htobe16(f->fs.mask.dport);
4989221474Snp	fwr->fp = htobe16(f->fs.val.sport);
4990221474Snp	fwr->fpm = htobe16(f->fs.mask.sport);
4991221474Snp	if (f->fs.newsmac)
4992221474Snp		bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma));
4993221474Snp
4994221474Snp	f->pending = 1;
4995221474Snp	sc->tids.ftids_in_use++;
4996228561Snp
4997237263Snp	t4_wrq_tx(sc, wr);
4998228561Snp	return (0);
4999221474Snp}
5000221474Snp
5001221474Snpstatic int
5002221474Snpdel_filter_wr(struct adapter *sc, int fidx)
5003221474Snp{
5004221474Snp	struct filter_entry *f = &sc->tids.ftid_tab[fidx];
5005237263Snp	struct wrqe *wr;
5006221474Snp	struct fw_filter_wr *fwr;
5007228561Snp	unsigned int ftid;
5008221474Snp
5009221474Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
5010221474Snp
5011221474Snp	ftid = sc->tids.ftid_base + fidx;
5012221474Snp
5013237263Snp	wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq);
5014237263Snp	if (wr == NULL)
5015221474Snp		return (ENOMEM);
5016237263Snp	fwr = wrtod(wr);
5017221474Snp	bzero(fwr, sizeof (*fwr));
5018221474Snp
5019228561Snp	t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id);
5020221474Snp
5021221474Snp	f->pending = 1;
5022237263Snp	t4_wrq_tx(sc, wr);
5023228561Snp	return (0);
5024221474Snp}
5025221474Snp
5026239338Snpint
5027239338Snpt4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m)
5028221474Snp{
5029228561Snp	struct adapter *sc = iq->adapter;
5030228561Snp	const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1);
5031221474Snp	unsigned int idx = GET_TID(rpl);
5032221474Snp
5033228561Snp	KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__,
5034228561Snp	    rss->opcode));
5035228561Snp
5036221474Snp	if (idx >= sc->tids.ftid_base &&
5037221474Snp	    (idx -= sc->tids.ftid_base) < sc->tids.nftids) {
5038221474Snp		unsigned int rc = G_COOKIE(rpl->cookie);
5039221474Snp		struct filter_entry *f = &sc->tids.ftid_tab[idx];
5040221474Snp
5041231120Snp		ADAPTER_LOCK(sc);
5042228561Snp		if (rc == FW_FILTER_WR_FLT_ADDED) {
5043221474Snp			f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff;
5044221474Snp			f->pending = 0;  /* asynchronous setup completed */
5045221474Snp			f->valid = 1;
5046231120Snp		} else {
5047231120Snp			if (rc != FW_FILTER_WR_FLT_DELETED) {
5048231120Snp				/* Add or delete failed, display an error */
5049231120Snp				log(LOG_ERR,
5050231120Snp				    "filter %u setup failed with error %u\n",
5051231120Snp				    idx, rc);
5052231120Snp			}
5053228561Snp
5054231120Snp			clear_filter(f);
5055231120Snp			sc->tids.ftids_in_use--;
5056221474Snp		}
5057228561Snp		ADAPTER_UNLOCK(sc);
5058221474Snp	}
5059228561Snp
5060228561Snp	return (0);
5061221474Snp}
5062221474Snp
5063222973Snpstatic int
5064222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt)
5065222973Snp{
5066222973Snp	int rc = EINVAL;
5067222973Snp
5068222973Snp	if (cntxt->cid > M_CTXTQID)
5069222973Snp		return (rc);
5070222973Snp
5071222973Snp	if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS &&
5072222973Snp	    cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM)
5073222973Snp		return (rc);
5074222973Snp
5075222973Snp	if (sc->flags & FW_OK) {
5076222973Snp		ADAPTER_LOCK(sc);	/* Avoid parallel t4_wr_mbox */
5077222973Snp		rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id,
5078222973Snp		    &cntxt->data[0]);
5079222973Snp		ADAPTER_UNLOCK(sc);
5080222973Snp	}
5081222973Snp
5082222973Snp	if (rc != 0) {
5083222973Snp		/* Read via firmware failed or wasn't even attempted */
5084222973Snp
5085222973Snp		rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id,
5086222973Snp		    &cntxt->data[0]);
5087222973Snp	}
5088222973Snp
5089222973Snp	return (rc);
5090222973Snp}
5091222973Snp
5092228561Snpstatic int
5093228561Snpread_card_mem(struct adapter *sc, struct t4_mem_range *mr)
5094228561Snp{
5095228561Snp	uint32_t base, size, lo, hi, win, off, remaining, i, n;
5096228561Snp	uint32_t *buf, *b;
5097228561Snp	int rc;
5098228561Snp
5099228561Snp	/* reads are in multiples of 32 bits */
5100228561Snp	if (mr->addr & 3 || mr->len & 3 || mr->len == 0)
5101228561Snp		return (EINVAL);
5102228561Snp
5103228561Snp	/*
5104228561Snp	 * We don't want to deal with potential holes so we mandate that the
5105228561Snp	 * requested region must lie entirely within one of the 3 memories.
5106228561Snp	 */
5107228561Snp	lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE);
5108228561Snp	if (lo & F_EDRAM0_ENABLE) {
5109228561Snp		hi = t4_read_reg(sc, A_MA_EDRAM0_BAR);
5110228561Snp		base = G_EDRAM0_BASE(hi) << 20;
5111228561Snp		size = G_EDRAM0_SIZE(hi) << 20;
5112228561Snp		if (size > 0 &&
5113228561Snp		    mr->addr >= base && mr->addr < base + size &&
5114228561Snp		    mr->addr + mr->len <= base + size)
5115228561Snp			goto proceed;
5116228561Snp	}
5117228561Snp	if (lo & F_EDRAM1_ENABLE) {
5118228561Snp		hi = t4_read_reg(sc, A_MA_EDRAM1_BAR);
5119228561Snp		base = G_EDRAM1_BASE(hi) << 20;
5120228561Snp		size = G_EDRAM1_SIZE(hi) << 20;
5121228561Snp		if (size > 0 &&
5122228561Snp		    mr->addr >= base && mr->addr < base + size &&
5123228561Snp		    mr->addr + mr->len <= base + size)
5124228561Snp			goto proceed;
5125228561Snp	}
5126228561Snp	if (lo & F_EXT_MEM_ENABLE) {
5127228561Snp		hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR);
5128228561Snp		base = G_EXT_MEM_BASE(hi) << 20;
5129228561Snp		size = G_EXT_MEM_SIZE(hi) << 20;
5130228561Snp		if (size > 0 &&
5131228561Snp		    mr->addr >= base && mr->addr < base + size &&
5132228561Snp		    mr->addr + mr->len <= base + size)
5133228561Snp			goto proceed;
5134228561Snp	}
5135228561Snp	return (ENXIO);
5136228561Snp
5137228561Snpproceed:
5138228561Snp	buf = b = malloc(mr->len, M_CXGBE, M_WAITOK);
5139228561Snp
5140228561Snp	/*
5141228561Snp	 * Position the PCIe window (we use memwin2) to the 16B aligned area
5142228561Snp	 * just at/before the requested region.
5143228561Snp	 */
5144228561Snp	win = mr->addr & ~0xf;
5145228561Snp	off = mr->addr - win;  /* offset of the requested region in the win */
5146228561Snp	remaining = mr->len;
5147228561Snp
5148228561Snp	while (remaining) {
5149228561Snp		t4_write_reg(sc,
5150228561Snp		    PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2), win);
5151228561Snp		t4_read_reg(sc,
5152228561Snp		    PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2));
5153228561Snp
5154228561Snp		/* number of bytes that we'll copy in the inner loop */
5155228561Snp		n = min(remaining, MEMWIN2_APERTURE - off);
5156228561Snp
5157228561Snp		for (i = 0; i < n; i += 4, remaining -= 4)
5158228561Snp			*b++ = t4_read_reg(sc, MEMWIN2_BASE + off + i);
5159228561Snp
5160228561Snp		win += MEMWIN2_APERTURE;
5161228561Snp		off = 0;
5162228561Snp	}
5163228561Snp
5164228561Snp	rc = copyout(buf, mr->data, mr->len);
5165228561Snp	free(buf, M_CXGBE);
5166228561Snp
5167228561Snp	return (rc);
5168228561Snp}
5169228561Snp
5170241399Snpstatic int
5171241399Snpread_i2c(struct adapter *sc, struct t4_i2c_data *i2cd)
5172241399Snp{
5173241399Snp	int rc;
5174241399Snp
5175241399Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);	/* for mbox */
5176241399Snp
5177241399Snp	if (i2cd->len == 0 || i2cd->port_id >= sc->params.nports)
5178241399Snp		return (EINVAL);
5179241399Snp
5180241399Snp	if (i2cd->len > 1) {
5181241399Snp		/* XXX: need fw support for longer reads in one go */
5182241399Snp		return (ENOTSUP);
5183241399Snp	}
5184241399Snp
5185241399Snp	rc = -t4_i2c_rd(sc, sc->mbox, i2cd->port_id, i2cd->dev_addr,
5186241399Snp	    i2cd->offset, &i2cd->data[0]);
5187241399Snp
5188241399Snp	return (rc);
5189241399Snp}
5190241399Snp
5191218792Snpint
5192218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap)
5193218792Snp{
5194222102Snp	int i;
5195218792Snp
5196222102Snp	return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0);
5197218792Snp}
5198218792Snp
5199218792Snpint
5200218792Snpt4_os_pci_save_state(struct adapter *sc)
5201218792Snp{
5202218792Snp	device_t dev;
5203218792Snp	struct pci_devinfo *dinfo;
5204218792Snp
5205218792Snp	dev = sc->dev;
5206218792Snp	dinfo = device_get_ivars(dev);
5207218792Snp
5208218792Snp	pci_cfg_save(dev, dinfo, 0);
5209218792Snp	return (0);
5210218792Snp}
5211218792Snp
5212218792Snpint
5213218792Snpt4_os_pci_restore_state(struct adapter *sc)
5214218792Snp{
5215218792Snp	device_t dev;
5216218792Snp	struct pci_devinfo *dinfo;
5217218792Snp
5218218792Snp	dev = sc->dev;
5219218792Snp	dinfo = device_get_ivars(dev);
5220218792Snp
5221218792Snp	pci_cfg_restore(dev, dinfo);
5222218792Snp	return (0);
5223218792Snp}
5224219299Snp
5225218792Snpvoid
5226218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx)
5227218792Snp{
5228218792Snp	struct port_info *pi = sc->port[idx];
5229218792Snp	static const char *mod_str[] = {
5230220232Snp		NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM"
5231218792Snp	};
5232218792Snp
5233218792Snp	if (pi->mod_type == FW_PORT_MOD_TYPE_NONE)
5234218792Snp		if_printf(pi->ifp, "transceiver unplugged.\n");
5235220232Snp	else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN)
5236220232Snp		if_printf(pi->ifp, "unknown transceiver inserted.\n");
5237220232Snp	else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED)
5238220232Snp		if_printf(pi->ifp, "unsupported transceiver inserted.\n");
5239240452Snp	else if (pi->mod_type > 0 && pi->mod_type < nitems(mod_str)) {
5240218792Snp		if_printf(pi->ifp, "%s transceiver inserted.\n",
5241218792Snp		    mod_str[pi->mod_type]);
5242219299Snp	} else {
5243219299Snp		if_printf(pi->ifp, "transceiver (type %d) inserted.\n",
5244219299Snp		    pi->mod_type);
5245219299Snp	}
5246218792Snp}
5247218792Snp
5248218792Snpvoid
5249218792Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat)
5250218792Snp{
5251218792Snp	struct port_info *pi = sc->port[idx];
5252218792Snp	struct ifnet *ifp = pi->ifp;
5253218792Snp
5254218792Snp	if (link_stat) {
5255218792Snp		ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed);
5256218792Snp		if_link_state_change(ifp, LINK_STATE_UP);
5257218792Snp	} else
5258218792Snp		if_link_state_change(ifp, LINK_STATE_DOWN);
5259218792Snp}
5260218792Snp
5261228561Snpvoid
5262228561Snpt4_iterate(void (*func)(struct adapter *, void *), void *arg)
5263228561Snp{
5264228561Snp	struct adapter *sc;
5265228561Snp
5266228561Snp	mtx_lock(&t4_list_lock);
5267228561Snp	SLIST_FOREACH(sc, &t4_list, link) {
5268228561Snp		/*
5269228561Snp		 * func should not make any assumptions about what state sc is
5270228561Snp		 * in - the only guarantee is that sc->sc_lock is a valid lock.
5271228561Snp		 */
5272228561Snp		func(sc, arg);
5273228561Snp	}
5274228561Snp	mtx_unlock(&t4_list_lock);
5275228561Snp}
5276228561Snp
5277218792Snpstatic int
5278218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td)
5279218792Snp{
5280218792Snp       return (0);
5281218792Snp}
5282218792Snp
5283218792Snpstatic int
5284218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td)
5285218792Snp{
5286218792Snp       return (0);
5287218792Snp}
5288218792Snp
5289218792Snpstatic int
5290218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag,
5291218792Snp    struct thread *td)
5292218792Snp{
5293218792Snp	int rc;
5294218792Snp	struct adapter *sc = dev->si_drv1;
5295218792Snp
5296218792Snp	rc = priv_check(td, PRIV_DRIVER);
5297218792Snp	if (rc != 0)
5298218792Snp		return (rc);
5299218792Snp
5300218792Snp	switch (cmd) {
5301220410Snp	case CHELSIO_T4_GETREG: {
5302220410Snp		struct t4_reg *edata = (struct t4_reg *)data;
5303220410Snp
5304218792Snp		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
5305218792Snp			return (EFAULT);
5306220410Snp
5307220410Snp		if (edata->size == 4)
5308220410Snp			edata->val = t4_read_reg(sc, edata->addr);
5309220410Snp		else if (edata->size == 8)
5310220410Snp			edata->val = t4_read_reg64(sc, edata->addr);
5311220410Snp		else
5312220410Snp			return (EINVAL);
5313220410Snp
5314218792Snp		break;
5315218792Snp	}
5316220410Snp	case CHELSIO_T4_SETREG: {
5317220410Snp		struct t4_reg *edata = (struct t4_reg *)data;
5318220410Snp
5319218792Snp		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
5320218792Snp			return (EFAULT);
5321220410Snp
5322220410Snp		if (edata->size == 4) {
5323220410Snp			if (edata->val & 0xffffffff00000000)
5324220410Snp				return (EINVAL);
5325220410Snp			t4_write_reg(sc, edata->addr, (uint32_t) edata->val);
5326220410Snp		} else if (edata->size == 8)
5327220410Snp			t4_write_reg64(sc, edata->addr, edata->val);
5328220410Snp		else
5329220410Snp			return (EINVAL);
5330218792Snp		break;
5331218792Snp	}
5332218792Snp	case CHELSIO_T4_REGDUMP: {
5333218792Snp		struct t4_regdump *regs = (struct t4_regdump *)data;
5334218792Snp		int reglen = T4_REGDUMP_SIZE;
5335218792Snp		uint8_t *buf;
5336218792Snp
5337218792Snp		if (regs->len < reglen) {
5338218792Snp			regs->len = reglen; /* hint to the caller */
5339218792Snp			return (ENOBUFS);
5340218792Snp		}
5341218792Snp
5342218792Snp		regs->len = reglen;
5343218792Snp		buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO);
5344218792Snp		t4_get_regs(sc, regs, buf);
5345218792Snp		rc = copyout(buf, regs->data, reglen);
5346218792Snp		free(buf, M_CXGBE);
5347218792Snp		break;
5348218792Snp	}
5349221474Snp	case CHELSIO_T4_GET_FILTER_MODE:
5350221474Snp		rc = get_filter_mode(sc, (uint32_t *)data);
5351221474Snp		break;
5352221474Snp	case CHELSIO_T4_SET_FILTER_MODE:
5353221474Snp		rc = set_filter_mode(sc, *(uint32_t *)data);
5354221474Snp		break;
5355221474Snp	case CHELSIO_T4_GET_FILTER:
5356221474Snp		ADAPTER_LOCK(sc);
5357221474Snp		rc = get_filter(sc, (struct t4_filter *)data);
5358221474Snp		ADAPTER_UNLOCK(sc);
5359221474Snp		break;
5360221474Snp	case CHELSIO_T4_SET_FILTER:
5361221474Snp		ADAPTER_LOCK(sc);
5362221474Snp		rc = set_filter(sc, (struct t4_filter *)data);
5363221474Snp		ADAPTER_UNLOCK(sc);
5364221474Snp		break;
5365221474Snp	case CHELSIO_T4_DEL_FILTER:
5366221474Snp		ADAPTER_LOCK(sc);
5367221474Snp		rc = del_filter(sc, (struct t4_filter *)data);
5368221474Snp		ADAPTER_UNLOCK(sc);
5369221474Snp		break;
5370222973Snp	case CHELSIO_T4_GET_SGE_CONTEXT:
5371222973Snp		rc = get_sge_context(sc, (struct t4_sge_context *)data);
5372222973Snp		break;
5373228561Snp	case CHELSIO_T4_LOAD_FW: {
5374228561Snp		struct t4_data *fw = (struct t4_data *)data;
5375228561Snp		uint8_t *fw_data;
5376228561Snp
5377228561Snp		if (sc->flags & FULL_INIT_DONE)
5378228561Snp			return (EBUSY);
5379228561Snp
5380228561Snp		fw_data = malloc(fw->len, M_CXGBE, M_NOWAIT);
5381228561Snp		if (fw_data == NULL)
5382228561Snp			return (ENOMEM);
5383228561Snp
5384228561Snp		rc = copyin(fw->data, fw_data, fw->len);
5385228561Snp		if (rc == 0)
5386228561Snp			rc = -t4_load_fw(sc, fw_data, fw->len);
5387228561Snp
5388228561Snp		free(fw_data, M_CXGBE);
5389228561Snp		break;
5390228561Snp	}
5391228561Snp	case CHELSIO_T4_GET_MEM:
5392228561Snp		rc = read_card_mem(sc, (struct t4_mem_range *)data);
5393228561Snp		break;
5394241399Snp	case CHELSIO_T4_GET_I2C:
5395241399Snp		ADAPTER_LOCK(sc);
5396241399Snp		rc = read_i2c(sc, (struct t4_i2c_data *)data);
5397241399Snp		ADAPTER_UNLOCK(sc);
5398241399Snp		break;
5399241409Snp	case CHELSIO_T4_CLEAR_STATS: {
5400241409Snp		u_int port_id = *(uint32_t *)data;
5401241409Snp
5402241409Snp		if (port_id >= sc->params.nports)
5403241409Snp			return (EINVAL);
5404241409Snp
5405241409Snp		t4_clr_port_stats(sc, port_id);
5406241409Snp		break;
5407241409Snp	}
5408218792Snp	default:
5409218792Snp		rc = EINVAL;
5410218792Snp	}
5411218792Snp
5412218792Snp	return (rc);
5413218792Snp}
5414218792Snp
5415237263Snp#ifdef TCP_OFFLOAD
5416219392Snpstatic int
5417228561Snptoe_capability(struct port_info *pi, int enable)
5418228561Snp{
5419228561Snp	int rc;
5420228561Snp	struct adapter *sc = pi->adapter;
5421228561Snp
5422228561Snp	ADAPTER_LOCK_ASSERT_OWNED(sc);
5423228561Snp
5424228561Snp	if (!is_offload(sc))
5425228561Snp		return (ENODEV);
5426228561Snp
5427228561Snp	if (enable) {
5428237263Snp		if (!(sc->flags & FULL_INIT_DONE)) {
5429237263Snp			log(LOG_WARNING,
5430237263Snp			    "You must enable a cxgbe interface first\n");
5431237263Snp			return (EAGAIN);
5432237263Snp		}
5433237263Snp
5434228561Snp		if (isset(&sc->offload_map, pi->port_id))
5435228561Snp			return (0);
5436228561Snp
5437237263Snp		if (!(sc->flags & TOM_INIT_DONE)) {
5438237263Snp			rc = t4_activate_uld(sc, ULD_TOM);
5439237263Snp			if (rc == EAGAIN) {
5440237263Snp				log(LOG_WARNING,
5441237263Snp				    "You must kldload t4_tom.ko before trying "
5442237263Snp				    "to enable TOE on a cxgbe interface.\n");
5443237263Snp			}
5444228561Snp			if (rc != 0)
5445228561Snp				return (rc);
5446237263Snp			KASSERT(sc->tom_softc != NULL,
5447237263Snp			    ("%s: TOM activated but softc NULL", __func__));
5448237263Snp			KASSERT(sc->flags & TOM_INIT_DONE,
5449237263Snp			    ("%s: TOM activated but flag not set", __func__));
5450228561Snp		}
5451228561Snp
5452228561Snp		setbit(&sc->offload_map, pi->port_id);
5453228561Snp	} else {
5454228561Snp		if (!isset(&sc->offload_map, pi->port_id))
5455228561Snp			return (0);
5456228561Snp
5457237263Snp		KASSERT(sc->flags & TOM_INIT_DONE,
5458237263Snp		    ("%s: TOM never initialized?", __func__));
5459228561Snp		clrbit(&sc->offload_map, pi->port_id);
5460228561Snp	}
5461228561Snp
5462228561Snp	return (0);
5463228561Snp}
5464228561Snp
5465228561Snp/*
5466228561Snp * Add an upper layer driver to the global list.
5467228561Snp */
5468228561Snpint
5469228561Snpt4_register_uld(struct uld_info *ui)
5470228561Snp{
5471228561Snp	int rc = 0;
5472228561Snp	struct uld_info *u;
5473228561Snp
5474228561Snp	mtx_lock(&t4_uld_list_lock);
5475228561Snp	SLIST_FOREACH(u, &t4_uld_list, link) {
5476228561Snp	    if (u->uld_id == ui->uld_id) {
5477228561Snp		    rc = EEXIST;
5478228561Snp		    goto done;
5479228561Snp	    }
5480228561Snp	}
5481228561Snp
5482228561Snp	SLIST_INSERT_HEAD(&t4_uld_list, ui, link);
5483228561Snp	ui->refcount = 0;
5484228561Snpdone:
5485228561Snp	mtx_unlock(&t4_uld_list_lock);
5486228561Snp	return (rc);
5487228561Snp}
5488228561Snp
5489228561Snpint
5490228561Snpt4_unregister_uld(struct uld_info *ui)
5491228561Snp{
5492228561Snp	int rc = EINVAL;
5493228561Snp	struct uld_info *u;
5494228561Snp
5495228561Snp	mtx_lock(&t4_uld_list_lock);
5496228561Snp
5497228561Snp	SLIST_FOREACH(u, &t4_uld_list, link) {
5498228561Snp	    if (u == ui) {
5499228561Snp		    if (ui->refcount > 0) {
5500228561Snp			    rc = EBUSY;
5501228561Snp			    goto done;
5502228561Snp		    }
5503228561Snp
5504228561Snp		    SLIST_REMOVE(&t4_uld_list, ui, uld_info, link);
5505228561Snp		    rc = 0;
5506228561Snp		    goto done;
5507228561Snp	    }
5508228561Snp	}
5509228561Snpdone:
5510228561Snp	mtx_unlock(&t4_uld_list_lock);
5511228561Snp	return (rc);
5512228561Snp}
5513228561Snp
5514237263Snpint
5515237263Snpt4_activate_uld(struct adapter *sc, int id)
5516228561Snp{
5517228561Snp	int rc = EAGAIN;
5518228561Snp	struct uld_info *ui;
5519228561Snp
5520228561Snp	mtx_lock(&t4_uld_list_lock);
5521228561Snp
5522228561Snp	SLIST_FOREACH(ui, &t4_uld_list, link) {
5523228561Snp		if (ui->uld_id == id) {
5524237263Snp			rc = ui->activate(sc);
5525237263Snp			if (rc == 0)
5526228561Snp				ui->refcount++;
5527228561Snp			goto done;
5528228561Snp		}
5529228561Snp	}
5530228561Snpdone:
5531228561Snp	mtx_unlock(&t4_uld_list_lock);
5532228561Snp
5533228561Snp	return (rc);
5534228561Snp}
5535228561Snp
5536237263Snpint
5537237263Snpt4_deactivate_uld(struct adapter *sc, int id)
5538228561Snp{
5539237263Snp	int rc = EINVAL;
5540237263Snp	struct uld_info *ui;
5541228561Snp
5542228561Snp	mtx_lock(&t4_uld_list_lock);
5543228561Snp
5544237263Snp	SLIST_FOREACH(ui, &t4_uld_list, link) {
5545237263Snp		if (ui->uld_id == id) {
5546237263Snp			rc = ui->deactivate(sc);
5547237263Snp			if (rc == 0)
5548237263Snp				ui->refcount--;
5549237263Snp			goto done;
5550237263Snp		}
5551228561Snp	}
5552228561Snpdone:
5553228561Snp	mtx_unlock(&t4_uld_list_lock);
5554228561Snp
5555228561Snp	return (rc);
5556228561Snp}
5557228561Snp#endif
5558228561Snp
5559228561Snp/*
5560228561Snp * Come up with reasonable defaults for some of the tunables, provided they're
5561228561Snp * not set by the user (in which case we'll use the values as is).
5562228561Snp */
5563228561Snpstatic void
5564228561Snptweak_tunables(void)
5565228561Snp{
5566228561Snp	int nc = mp_ncpus;	/* our snapshot of the number of CPUs */
5567228561Snp
5568228561Snp	if (t4_ntxq10g < 1)
5569228561Snp		t4_ntxq10g = min(nc, NTXQ_10G);
5570228561Snp
5571228561Snp	if (t4_ntxq1g < 1)
5572228561Snp		t4_ntxq1g = min(nc, NTXQ_1G);
5573228561Snp
5574228561Snp	if (t4_nrxq10g < 1)
5575228561Snp		t4_nrxq10g = min(nc, NRXQ_10G);
5576228561Snp
5577228561Snp	if (t4_nrxq1g < 1)
5578228561Snp		t4_nrxq1g = min(nc, NRXQ_1G);
5579228561Snp
5580237263Snp#ifdef TCP_OFFLOAD
5581228561Snp	if (t4_nofldtxq10g < 1)
5582228561Snp		t4_nofldtxq10g = min(nc, NOFLDTXQ_10G);
5583228561Snp
5584228561Snp	if (t4_nofldtxq1g < 1)
5585228561Snp		t4_nofldtxq1g = min(nc, NOFLDTXQ_1G);
5586228561Snp
5587228561Snp	if (t4_nofldrxq10g < 1)
5588228561Snp		t4_nofldrxq10g = min(nc, NOFLDRXQ_10G);
5589228561Snp
5590228561Snp	if (t4_nofldrxq1g < 1)
5591228561Snp		t4_nofldrxq1g = min(nc, NOFLDRXQ_1G);
5592238028Snp
5593238028Snp	if (t4_toecaps_allowed == -1)
5594238028Snp		t4_toecaps_allowed = FW_CAPS_CONFIG_TOE;
5595238028Snp#else
5596238028Snp	if (t4_toecaps_allowed == -1)
5597238028Snp		t4_toecaps_allowed = 0;
5598228561Snp#endif
5599228561Snp
5600228561Snp	if (t4_tmr_idx_10g < 0 || t4_tmr_idx_10g >= SGE_NTIMERS)
5601228561Snp		t4_tmr_idx_10g = TMR_IDX_10G;
5602228561Snp
5603228561Snp	if (t4_pktc_idx_10g < -1 || t4_pktc_idx_10g >= SGE_NCOUNTERS)
5604228561Snp		t4_pktc_idx_10g = PKTC_IDX_10G;
5605228561Snp
5606228561Snp	if (t4_tmr_idx_1g < 0 || t4_tmr_idx_1g >= SGE_NTIMERS)
5607228561Snp		t4_tmr_idx_1g = TMR_IDX_1G;
5608228561Snp
5609228561Snp	if (t4_pktc_idx_1g < -1 || t4_pktc_idx_1g >= SGE_NCOUNTERS)
5610228561Snp		t4_pktc_idx_1g = PKTC_IDX_1G;
5611228561Snp
5612228561Snp	if (t4_qsize_txq < 128)
5613228561Snp		t4_qsize_txq = 128;
5614228561Snp
5615228561Snp	if (t4_qsize_rxq < 128)
5616228561Snp		t4_qsize_rxq = 128;
5617228561Snp	while (t4_qsize_rxq & 7)
5618228561Snp		t4_qsize_rxq++;
5619228561Snp
5620228561Snp	t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX;
5621228561Snp}
5622228561Snp
5623228561Snpstatic int
5624219392Snpt4_mod_event(module_t mod, int cmd, void *arg)
5625219392Snp{
5626228561Snp	int rc = 0;
5627219392Snp
5628228561Snp	switch (cmd) {
5629228561Snp	case MOD_LOAD:
5630219392Snp		t4_sge_modload();
5631228561Snp		mtx_init(&t4_list_lock, "T4 adapters", 0, MTX_DEF);
5632228561Snp		SLIST_INIT(&t4_list);
5633237263Snp#ifdef TCP_OFFLOAD
5634228561Snp		mtx_init(&t4_uld_list_lock, "T4 ULDs", 0, MTX_DEF);
5635228561Snp		SLIST_INIT(&t4_uld_list);
5636228561Snp#endif
5637228561Snp		tweak_tunables();
5638228561Snp		break;
5639219392Snp
5640228561Snp	case MOD_UNLOAD:
5641237263Snp#ifdef TCP_OFFLOAD
5642228561Snp		mtx_lock(&t4_uld_list_lock);
5643228561Snp		if (!SLIST_EMPTY(&t4_uld_list)) {
5644228561Snp			rc = EBUSY;
5645228561Snp			mtx_unlock(&t4_uld_list_lock);
5646228561Snp			break;
5647228561Snp		}
5648228561Snp		mtx_unlock(&t4_uld_list_lock);
5649228561Snp		mtx_destroy(&t4_uld_list_lock);
5650228561Snp#endif
5651228561Snp		mtx_lock(&t4_list_lock);
5652228561Snp		if (!SLIST_EMPTY(&t4_list)) {
5653228561Snp			rc = EBUSY;
5654228561Snp			mtx_unlock(&t4_list_lock);
5655228561Snp			break;
5656228561Snp		}
5657228561Snp		mtx_unlock(&t4_list_lock);
5658228561Snp		mtx_destroy(&t4_list_lock);
5659228561Snp		break;
5660228561Snp	}
5661228561Snp
5662228561Snp	return (rc);
5663219392Snp}
5664219392Snp
5665218792Snpstatic devclass_t t4_devclass;
5666218792Snpstatic devclass_t cxgbe_devclass;
5667218792Snp
5668219392SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, t4_mod_event, 0);
5669218792SnpMODULE_VERSION(t4nex, 1);
5670218792Snp
5671218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0);
5672218792SnpMODULE_VERSION(cxgbe, 1);
5673