xref: /freebsd/sys/dev/cxgb/cxgb_main.c (revision 762d32354a18517c28933ddc29f9d3d855e450b1)
1b6d90eb7SKip Macy /**************************************************************************
24d846d26SWarner Losh SPDX-License-Identifier: BSD-2-Clause
3b6d90eb7SKip Macy 
4f2d8ff04SGeorge V. Neville-Neil Copyright (c) 2007-2009, Chelsio Inc.
5b6d90eb7SKip Macy All rights reserved.
6b6d90eb7SKip Macy 
7b6d90eb7SKip Macy Redistribution and use in source and binary forms, with or without
8b6d90eb7SKip Macy modification, are permitted provided that the following conditions are met:
9b6d90eb7SKip Macy 
10b6d90eb7SKip Macy  1. Redistributions of source code must retain the above copyright notice,
11b6d90eb7SKip Macy     this list of conditions and the following disclaimer.
12b6d90eb7SKip Macy 
13d722cab4SKip Macy  2. Neither the name of the Chelsio Corporation nor the names of its
14b6d90eb7SKip Macy     contributors may be used to endorse or promote products derived from
15b6d90eb7SKip Macy     this software without specific prior written permission.
16b6d90eb7SKip Macy 
17b6d90eb7SKip Macy THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18b6d90eb7SKip Macy AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19b6d90eb7SKip Macy IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20b6d90eb7SKip Macy ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21b6d90eb7SKip Macy LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22b6d90eb7SKip Macy CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23b6d90eb7SKip Macy SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24b6d90eb7SKip Macy INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25b6d90eb7SKip Macy CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26b6d90eb7SKip Macy ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27b6d90eb7SKip Macy POSSIBILITY OF SUCH DAMAGE.
28b6d90eb7SKip Macy 
29b6d90eb7SKip Macy ***************************************************************************/
30b6d90eb7SKip Macy 
31b6d90eb7SKip Macy #include <sys/cdefs.h>
3209fe6320SNavdeep Parhar #include "opt_inet.h"
3309fe6320SNavdeep Parhar 
34b6d90eb7SKip Macy #include <sys/param.h>
35b6d90eb7SKip Macy #include <sys/systm.h>
36b6d90eb7SKip Macy #include <sys/kernel.h>
37b6d90eb7SKip Macy #include <sys/bus.h>
38b6d90eb7SKip Macy #include <sys/module.h>
39b6d90eb7SKip Macy #include <sys/conf.h>
40b6d90eb7SKip Macy #include <machine/bus.h>
41b6d90eb7SKip Macy #include <machine/resource.h>
428e10660fSKip Macy #include <sys/ktr.h>
43b6d90eb7SKip Macy #include <sys/rman.h>
44b6d90eb7SKip Macy #include <sys/ioccom.h>
45b6d90eb7SKip Macy #include <sys/mbuf.h>
46b6d90eb7SKip Macy #include <sys/linker.h>
47b6d90eb7SKip Macy #include <sys/firmware.h>
48b6d90eb7SKip Macy #include <sys/socket.h>
49b6d90eb7SKip Macy #include <sys/sockio.h>
50b6d90eb7SKip Macy #include <sys/smp.h>
51b6d90eb7SKip Macy #include <sys/sysctl.h>
528090c9f5SKip Macy #include <sys/syslog.h>
53b6d90eb7SKip Macy #include <sys/queue.h>
54b6d90eb7SKip Macy #include <sys/taskqueue.h>
558090c9f5SKip Macy #include <sys/proc.h>
56b6d90eb7SKip Macy 
57b6d90eb7SKip Macy #include <net/bpf.h>
587790c8c1SConrad Meyer #include <net/debugnet.h>
59b6d90eb7SKip Macy #include <net/ethernet.h>
60b6d90eb7SKip Macy #include <net/if.h>
6176039bc8SGleb Smirnoff #include <net/if_var.h>
62b6d90eb7SKip Macy #include <net/if_arp.h>
63b6d90eb7SKip Macy #include <net/if_dl.h>
64b6d90eb7SKip Macy #include <net/if_media.h>
65b6d90eb7SKip Macy #include <net/if_types.h>
664af83c8cSKip Macy #include <net/if_vlan_var.h>
67b6d90eb7SKip Macy 
68b6d90eb7SKip Macy #include <netinet/in_systm.h>
69b6d90eb7SKip Macy #include <netinet/in.h>
70b6d90eb7SKip Macy #include <netinet/if_ether.h>
71b6d90eb7SKip Macy #include <netinet/ip.h>
72b6d90eb7SKip Macy #include <netinet/ip.h>
73b6d90eb7SKip Macy #include <netinet/tcp.h>
74b6d90eb7SKip Macy #include <netinet/udp.h>
75b6d90eb7SKip Macy 
76b6d90eb7SKip Macy #include <dev/pci/pcireg.h>
77b6d90eb7SKip Macy #include <dev/pci/pcivar.h>
78b6d90eb7SKip Macy 
7910faa568SKip Macy #include <cxgb_include.h>
80b6d90eb7SKip Macy 
81b6d90eb7SKip Macy #ifdef PRIV_SUPPORTED
82b6d90eb7SKip Macy #include <sys/priv.h>
83b6d90eb7SKip Macy #endif
84b6d90eb7SKip Macy 
85e3503bc9SGeorge V. Neville-Neil static int cxgb_setup_interrupts(adapter_t *);
86e3503bc9SGeorge V. Neville-Neil static void cxgb_teardown_interrupts(adapter_t *);
87b6d90eb7SKip Macy static void cxgb_init(void *);
88b302b77cSNavdeep Parhar static int cxgb_init_locked(struct port_info *);
89b302b77cSNavdeep Parhar static int cxgb_uninit_locked(struct port_info *);
903f345a5dSKip Macy static int cxgb_uninit_synchronized(struct port_info *);
91954712e8SJustin Hibbits static int cxgb_ioctl(if_t, unsigned long, caddr_t);
92954712e8SJustin Hibbits static int cxgb_media_change(if_t);
93837f41b0SGeorge V. Neville-Neil static int cxgb_ifm_type(int);
942975f787SNavdeep Parhar static void cxgb_build_medialist(struct port_info *);
95954712e8SJustin Hibbits static void cxgb_media_status(if_t, struct ifmediareq *);
96954712e8SJustin Hibbits static uint64_t cxgb_get_counter(if_t, ift_counter);
97b6d90eb7SKip Macy static int setup_sge_qsets(adapter_t *);
98b6d90eb7SKip Macy static void cxgb_async_intr(void *);
99bb38cd2fSKip Macy static void cxgb_tick_handler(void *, int);
100b6d90eb7SKip Macy static void cxgb_tick(void *);
101bd1a9fbaSNavdeep Parhar static void link_check_callout(void *);
102bd1a9fbaSNavdeep Parhar static void check_link_status(void *, int);
103b6d90eb7SKip Macy static void setup_rss(adapter_t *sc);
104d6da8362SNavdeep Parhar static int alloc_filters(struct adapter *);
105d6da8362SNavdeep Parhar static int setup_hw_filters(struct adapter *);
106d6da8362SNavdeep Parhar static int set_filter(struct adapter *, int, const struct filter_info *);
107d6da8362SNavdeep Parhar static inline void mk_set_tcb_field(struct cpl_set_tcb_field *, unsigned int,
108d6da8362SNavdeep Parhar     unsigned int, u64, u64);
109d6da8362SNavdeep Parhar static inline void set_tcb_field_ulp(struct cpl_set_tcb_field *, unsigned int,
110d6da8362SNavdeep Parhar     unsigned int, u64, u64);
11109fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
11209fe6320SNavdeep Parhar static int cpl_not_handled(struct sge_qset *, struct rsp_desc *, struct mbuf *);
11309fe6320SNavdeep Parhar #endif
114b6d90eb7SKip Macy 
115b6d90eb7SKip Macy /* Attachment glue for the PCI controller end of the device.  Each port of
116b6d90eb7SKip Macy  * the device is attached separately, as defined later.
117b6d90eb7SKip Macy  */
118b6d90eb7SKip Macy static int cxgb_controller_probe(device_t);
119b6d90eb7SKip Macy static int cxgb_controller_attach(device_t);
120b6d90eb7SKip Macy static int cxgb_controller_detach(device_t);
121b6d90eb7SKip Macy static void cxgb_free(struct adapter *);
122b6d90eb7SKip Macy static __inline void reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
123b6d90eb7SKip Macy     unsigned int end);
1241ffd6e58SKip Macy static void cxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf);
125b6d90eb7SKip Macy static int cxgb_get_regs_len(void);
1267ac2e6c3SKip Macy static void touch_bars(device_t dev);
127c01f2b83SNavdeep Parhar static void cxgb_update_mac_settings(struct port_info *p);
12809fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
12909fe6320SNavdeep Parhar static int toe_capability(struct port_info *, int);
13009fe6320SNavdeep Parhar #endif
131b6d90eb7SKip Macy 
1320dc34160SWarner Losh /* Table for probing the cards.  The desc field isn't actually used */
1330dc34160SWarner Losh struct cxgb_ident {
1340dc34160SWarner Losh 	uint16_t	vendor;
1350dc34160SWarner Losh 	uint16_t	device;
1360dc34160SWarner Losh 	int		index;
1370dc34160SWarner Losh 	char		*desc;
1380dc34160SWarner Losh } cxgb_identifiers[] = {
1390dc34160SWarner Losh 	{PCI_VENDOR_ID_CHELSIO, 0x0020, 0, "PE9000"},
1400dc34160SWarner Losh 	{PCI_VENDOR_ID_CHELSIO, 0x0021, 1, "T302E"},
1410dc34160SWarner Losh 	{PCI_VENDOR_ID_CHELSIO, 0x0022, 2, "T310E"},
1420dc34160SWarner Losh 	{PCI_VENDOR_ID_CHELSIO, 0x0023, 3, "T320X"},
1430dc34160SWarner Losh 	{PCI_VENDOR_ID_CHELSIO, 0x0024, 1, "T302X"},
1440dc34160SWarner Losh 	{PCI_VENDOR_ID_CHELSIO, 0x0025, 3, "T320E"},
1450dc34160SWarner Losh 	{PCI_VENDOR_ID_CHELSIO, 0x0026, 2, "T310X"},
1460dc34160SWarner Losh 	{PCI_VENDOR_ID_CHELSIO, 0x0030, 2, "T3B10"},
1470dc34160SWarner Losh 	{PCI_VENDOR_ID_CHELSIO, 0x0031, 3, "T3B20"},
1480dc34160SWarner Losh 	{PCI_VENDOR_ID_CHELSIO, 0x0032, 1, "T3B02"},
1490dc34160SWarner Losh 	{PCI_VENDOR_ID_CHELSIO, 0x0033, 4, "T3B04"},
1500dc34160SWarner Losh 	{PCI_VENDOR_ID_CHELSIO, 0x0035, 6, "T3C10"},
1510dc34160SWarner Losh 	{PCI_VENDOR_ID_CHELSIO, 0x0036, 3, "S320E-CR"},
1520dc34160SWarner Losh 	{PCI_VENDOR_ID_CHELSIO, 0x0037, 7, "N320E-G2"},
1530dc34160SWarner Losh 	{0, 0, 0, NULL}
1540dc34160SWarner Losh };
1550dc34160SWarner Losh 
156b6d90eb7SKip Macy static device_method_t cxgb_controller_methods[] = {
157b6d90eb7SKip Macy 	DEVMETHOD(device_probe,		cxgb_controller_probe),
158b6d90eb7SKip Macy 	DEVMETHOD(device_attach,	cxgb_controller_attach),
159b6d90eb7SKip Macy 	DEVMETHOD(device_detach,	cxgb_controller_detach),
160b6d90eb7SKip Macy 
1614b7ec270SMarius Strobl 	DEVMETHOD_END
162b6d90eb7SKip Macy };
163b6d90eb7SKip Macy 
164b6d90eb7SKip Macy static driver_t cxgb_controller_driver = {
165b6d90eb7SKip Macy 	"cxgbc",
166b6d90eb7SKip Macy 	cxgb_controller_methods,
167b6d90eb7SKip Macy 	sizeof(struct adapter)
168b6d90eb7SKip Macy };
169b6d90eb7SKip Macy 
17009fe6320SNavdeep Parhar static int cxgbc_mod_event(module_t, int, void *);
171c54f3323SJohn Baldwin 
172c54f3323SJohn Baldwin DRIVER_MODULE(cxgbc, pci, cxgb_controller_driver, cxgbc_mod_event, NULL);
1730dc34160SWarner Losh MODULE_PNP_INFO("U16:vendor;U16:device", pci, cxgbc, cxgb_identifiers,
1740dc34160SWarner Losh     nitems(cxgb_identifiers) - 1);
17509fe6320SNavdeep Parhar MODULE_VERSION(cxgbc, 1);
1765ada8664SKonstantin Belousov MODULE_DEPEND(cxgbc, firmware, 1, 1, 1);
177b6d90eb7SKip Macy 
178b6d90eb7SKip Macy /*
179b6d90eb7SKip Macy  * Attachment glue for the ports.  Attachment is done directly to the
180b6d90eb7SKip Macy  * controller device.
181b6d90eb7SKip Macy  */
182b6d90eb7SKip Macy static int cxgb_port_probe(device_t);
183b6d90eb7SKip Macy static int cxgb_port_attach(device_t);
184b6d90eb7SKip Macy static int cxgb_port_detach(device_t);
185b6d90eb7SKip Macy 
186b6d90eb7SKip Macy static device_method_t cxgb_port_methods[] = {
187b6d90eb7SKip Macy 	DEVMETHOD(device_probe,		cxgb_port_probe),
188b6d90eb7SKip Macy 	DEVMETHOD(device_attach,	cxgb_port_attach),
189b6d90eb7SKip Macy 	DEVMETHOD(device_detach,	cxgb_port_detach),
190b6d90eb7SKip Macy 	{ 0, 0 }
191b6d90eb7SKip Macy };
192b6d90eb7SKip Macy 
193b6d90eb7SKip Macy static driver_t cxgb_port_driver = {
194b6d90eb7SKip Macy 	"cxgb",
195b6d90eb7SKip Macy 	cxgb_port_methods,
196b6d90eb7SKip Macy 	0
197b6d90eb7SKip Macy };
198b6d90eb7SKip Macy 
199b6d90eb7SKip Macy static d_ioctl_t cxgb_extension_ioctl;
200ef72318fSKip Macy static d_open_t cxgb_extension_open;
201ef72318fSKip Macy static d_close_t cxgb_extension_close;
202ef72318fSKip Macy 
203ef72318fSKip Macy static struct cdevsw cxgb_cdevsw = {
204ef72318fSKip Macy        .d_version =    D_VERSION,
205ef72318fSKip Macy        .d_flags =      0,
206ef72318fSKip Macy        .d_open =       cxgb_extension_open,
207ef72318fSKip Macy        .d_close =      cxgb_extension_close,
208ef72318fSKip Macy        .d_ioctl =      cxgb_extension_ioctl,
209ef72318fSKip Macy        .d_name =       "cxgb",
210ef72318fSKip Macy };
211b6d90eb7SKip Macy 
212c54f3323SJohn Baldwin DRIVER_MODULE(cxgb, cxgbc, cxgb_port_driver, 0, 0);
21309fe6320SNavdeep Parhar MODULE_VERSION(cxgb, 1);
21409fe6320SNavdeep Parhar 
2157790c8c1SConrad Meyer DEBUGNET_DEFINE(cxgb);
216eb07d67eSMark Johnston 
21709fe6320SNavdeep Parhar static struct mtx t3_list_lock;
21809fe6320SNavdeep Parhar static SLIST_HEAD(, adapter) t3_list;
21909fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
22009fe6320SNavdeep Parhar static struct mtx t3_uld_list_lock;
22109fe6320SNavdeep Parhar static SLIST_HEAD(, uld_info) t3_uld_list;
22209fe6320SNavdeep Parhar #endif
223b6d90eb7SKip Macy 
224b6d90eb7SKip Macy /*
225b6d90eb7SKip Macy  * The driver uses the best interrupt scheme available on a platform in the
226b6d90eb7SKip Macy  * order MSI-X, MSI, legacy pin interrupts.  This parameter determines which
227b6d90eb7SKip Macy  * of these schemes the driver may consider as follows:
228b6d90eb7SKip Macy  *
229b6d90eb7SKip Macy  * msi = 2: choose from among all three options
230b6d90eb7SKip Macy  * msi = 1 : only consider MSI and pin interrupts
231b6d90eb7SKip Macy  * msi = 0: force pin interrupts
232b6d90eb7SKip Macy  */
233693d746cSKip Macy static int msi_allowed = 2;
234cebf6b9fSKip Macy 
2357029da5cSPawel Biernacki SYSCTL_NODE(_hw, OID_AUTO, cxgb, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
2367029da5cSPawel Biernacki     "CXGB driver parameters");
237deceab87SMatthew D Fleming SYSCTL_INT(_hw_cxgb, OID_AUTO, msi_allowed, CTLFLAG_RDTUN, &msi_allowed, 0,
238b6d90eb7SKip Macy     "MSI-X, MSI, INTx selector");
239d722cab4SKip Macy 
24064c43db5SKip Macy /*
241d722cab4SKip Macy  * The driver uses an auto-queue algorithm by default.
242a02573bcSKip Macy  * To disable it and force a single queue-set per port, use multiq = 0
24364c43db5SKip Macy  */
244a02573bcSKip Macy static int multiq = 1;
245deceab87SMatthew D Fleming SYSCTL_INT(_hw_cxgb, OID_AUTO, multiq, CTLFLAG_RDTUN, &multiq, 0,
246a02573bcSKip Macy     "use min(ncpus/ports, 8) queue-sets per port");
247f001b63dSKip Macy 
248404825a7SKip Macy /*
249a02573bcSKip Macy  * By default the driver will not update the firmware unless
250a02573bcSKip Macy  * it was compiled against a newer version
251a02573bcSKip Macy  *
252404825a7SKip Macy  */
253404825a7SKip Macy static int force_fw_update = 0;
254deceab87SMatthew D Fleming SYSCTL_INT(_hw_cxgb, OID_AUTO, force_fw_update, CTLFLAG_RDTUN, &force_fw_update, 0,
255404825a7SKip Macy     "update firmware even if up to date");
256f001b63dSKip Macy 
25797ae3bc3SNavdeep Parhar int cxgb_use_16k_clusters = -1;
25897ae3bc3SNavdeep Parhar SYSCTL_INT(_hw_cxgb, OID_AUTO, use_16k_clusters, CTLFLAG_RDTUN,
259f001b63dSKip Macy     &cxgb_use_16k_clusters, 0, "use 16kB clusters for the jumbo queue ");
260f001b63dSKip Macy 
2613a2c6562SNavdeep Parhar static int nfilters = -1;
2623a2c6562SNavdeep Parhar SYSCTL_INT(_hw_cxgb, OID_AUTO, nfilters, CTLFLAG_RDTUN,
2633a2c6562SNavdeep Parhar     &nfilters, 0, "max number of entries in the filter table");
26402c7d9a6SGeorge V. Neville-Neil 
265b6d90eb7SKip Macy enum {
266b6d90eb7SKip Macy 	MAX_TXQ_ENTRIES      = 16384,
267b6d90eb7SKip Macy 	MAX_CTRL_TXQ_ENTRIES = 1024,
268b6d90eb7SKip Macy 	MAX_RSPQ_ENTRIES     = 16384,
269b6d90eb7SKip Macy 	MAX_RX_BUFFERS       = 16384,
270b6d90eb7SKip Macy 	MAX_RX_JUMBO_BUFFERS = 16384,
271b6d90eb7SKip Macy 	MIN_TXQ_ENTRIES      = 4,
272b6d90eb7SKip Macy 	MIN_CTRL_TXQ_ENTRIES = 4,
273b6d90eb7SKip Macy 	MIN_RSPQ_ENTRIES     = 32,
2745c5df3daSKip Macy 	MIN_FL_ENTRIES       = 32,
2755c5df3daSKip Macy 	MIN_FL_JUMBO_ENTRIES = 32
276b6d90eb7SKip Macy };
277b6d90eb7SKip Macy 
278ac3a6d9cSKip Macy struct filter_info {
279ac3a6d9cSKip Macy 	u32 sip;
280ac3a6d9cSKip Macy 	u32 sip_mask;
281ac3a6d9cSKip Macy 	u32 dip;
282ac3a6d9cSKip Macy 	u16 sport;
283ac3a6d9cSKip Macy 	u16 dport;
284ac3a6d9cSKip Macy 	u32 vlan:12;
285ac3a6d9cSKip Macy 	u32 vlan_prio:3;
286ac3a6d9cSKip Macy 	u32 mac_hit:1;
287ac3a6d9cSKip Macy 	u32 mac_idx:4;
288ac3a6d9cSKip Macy 	u32 mac_vld:1;
289ac3a6d9cSKip Macy 	u32 pkt_type:2;
290ac3a6d9cSKip Macy 	u32 report_filter_id:1;
291ac3a6d9cSKip Macy 	u32 pass:1;
292ac3a6d9cSKip Macy 	u32 rss:1;
293ac3a6d9cSKip Macy 	u32 qset:3;
294ac3a6d9cSKip Macy 	u32 locked:1;
295ac3a6d9cSKip Macy 	u32 valid:1;
296ac3a6d9cSKip Macy };
297ac3a6d9cSKip Macy 
298ac3a6d9cSKip Macy enum { FILTER_NO_VLAN_PRI = 7 };
299ac3a6d9cSKip Macy 
3001ffd6e58SKip Macy #define EEPROM_MAGIC 0x38E2F10C
3011ffd6e58SKip Macy 
302b6d90eb7SKip Macy #define PORT_MASK ((1 << MAX_NPORTS) - 1)
303b6d90eb7SKip Macy 
304b6d90eb7SKip Macy 
305ac3a6d9cSKip Macy static int set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset);
306ac3a6d9cSKip Macy 
3078e10660fSKip Macy 
3088090c9f5SKip Macy static __inline char
t3rev2char(struct adapter * adapter)309ac3a6d9cSKip Macy t3rev2char(struct adapter *adapter)
310ac3a6d9cSKip Macy {
311ac3a6d9cSKip Macy 	char rev = 'z';
312ac3a6d9cSKip Macy 
313ac3a6d9cSKip Macy 	switch(adapter->params.rev) {
314ac3a6d9cSKip Macy 	case T3_REV_A:
315ac3a6d9cSKip Macy 		rev = 'a';
316ac3a6d9cSKip Macy 		break;
317ac3a6d9cSKip Macy 	case T3_REV_B:
318ac3a6d9cSKip Macy 	case T3_REV_B2:
319ac3a6d9cSKip Macy 		rev = 'b';
320ac3a6d9cSKip Macy 		break;
321ac3a6d9cSKip Macy 	case T3_REV_C:
322ac3a6d9cSKip Macy 		rev = 'c';
323ac3a6d9cSKip Macy 		break;
324ac3a6d9cSKip Macy 	}
325ac3a6d9cSKip Macy 	return rev;
326ac3a6d9cSKip Macy }
327ac3a6d9cSKip Macy 
328b6d90eb7SKip Macy static struct cxgb_ident *
cxgb_get_ident(device_t dev)329b6d90eb7SKip Macy cxgb_get_ident(device_t dev)
330b6d90eb7SKip Macy {
331b6d90eb7SKip Macy 	struct cxgb_ident *id;
332b6d90eb7SKip Macy 
333b6d90eb7SKip Macy 	for (id = cxgb_identifiers; id->desc != NULL; id++) {
334b6d90eb7SKip Macy 		if ((id->vendor == pci_get_vendor(dev)) &&
335b6d90eb7SKip Macy 		    (id->device == pci_get_device(dev))) {
336b6d90eb7SKip Macy 			return (id);
337b6d90eb7SKip Macy 		}
338b6d90eb7SKip Macy 	}
339b6d90eb7SKip Macy 	return (NULL);
340b6d90eb7SKip Macy }
341b6d90eb7SKip Macy 
342b6d90eb7SKip Macy static const struct adapter_info *
cxgb_get_adapter_info(device_t dev)343b6d90eb7SKip Macy cxgb_get_adapter_info(device_t dev)
344b6d90eb7SKip Macy {
345b6d90eb7SKip Macy 	struct cxgb_ident *id;
346b6d90eb7SKip Macy 	const struct adapter_info *ai;
347b6d90eb7SKip Macy 
348b6d90eb7SKip Macy 	id = cxgb_get_ident(dev);
349b6d90eb7SKip Macy 	if (id == NULL)
350b6d90eb7SKip Macy 		return (NULL);
351b6d90eb7SKip Macy 
352b6d90eb7SKip Macy 	ai = t3_get_adapter_info(id->index);
353b6d90eb7SKip Macy 
354b6d90eb7SKip Macy 	return (ai);
355b6d90eb7SKip Macy }
356b6d90eb7SKip Macy 
357b6d90eb7SKip Macy static int
cxgb_controller_probe(device_t dev)358b6d90eb7SKip Macy cxgb_controller_probe(device_t dev)
359b6d90eb7SKip Macy {
360b6d90eb7SKip Macy 	const struct adapter_info *ai;
361796bcf18SMark Johnston 	const char *ports;
362ef72318fSKip Macy 	int nports;
363b6d90eb7SKip Macy 
364b6d90eb7SKip Macy 	ai = cxgb_get_adapter_info(dev);
365b6d90eb7SKip Macy 	if (ai == NULL)
366b6d90eb7SKip Macy 		return (ENXIO);
367b6d90eb7SKip Macy 
368ef72318fSKip Macy 	nports = ai->nports0 + ai->nports1;
369ef72318fSKip Macy 	if (nports == 1)
370b6d90eb7SKip Macy 		ports = "port";
371b6d90eb7SKip Macy 	else
372b6d90eb7SKip Macy 		ports = "ports";
373b6d90eb7SKip Macy 
374796bcf18SMark Johnston 	device_set_descf(dev, "%s, %d %s", ai->desc, nports, ports);
375b6d90eb7SKip Macy 	return (BUS_PROBE_DEFAULT);
376b6d90eb7SKip Macy }
377b6d90eb7SKip Macy 
378404825a7SKip Macy #define FW_FNAME "cxgb_t3fw"
3790c1ff9c6SGeorge V. Neville-Neil #define TPEEPROM_NAME "cxgb_t3%c_tp_eeprom"
3800c1ff9c6SGeorge V. Neville-Neil #define TPSRAM_NAME "cxgb_t3%c_protocol_sram"
381ac3a6d9cSKip Macy 
382b6d90eb7SKip Macy static int
upgrade_fw(adapter_t * sc)383d722cab4SKip Macy upgrade_fw(adapter_t *sc)
384b6d90eb7SKip Macy {
385b6d90eb7SKip Macy 	const struct firmware *fw;
386b6d90eb7SKip Macy 	int status;
387a9da6d23SNavdeep Parhar 	u32 vers;
388b6d90eb7SKip Macy 
389404825a7SKip Macy 	if ((fw = firmware_get(FW_FNAME)) == NULL)  {
390404825a7SKip Macy 		device_printf(sc->dev, "Could not find firmware image %s\n", FW_FNAME);
391d722cab4SKip Macy 		return (ENOENT);
392ac3a6d9cSKip Macy 	} else
393a9da6d23SNavdeep Parhar 		device_printf(sc->dev, "installing firmware on card\n");
394b6d90eb7SKip Macy 	status = t3_load_fw(sc, (const uint8_t *)fw->data, fw->datasize);
395b6d90eb7SKip Macy 
396a9da6d23SNavdeep Parhar 	if (status != 0) {
397a9da6d23SNavdeep Parhar 		device_printf(sc->dev, "failed to install firmware: %d\n",
398a9da6d23SNavdeep Parhar 		    status);
399a9da6d23SNavdeep Parhar 	} else {
400a9da6d23SNavdeep Parhar 		t3_get_fw_version(sc, &vers);
401a9da6d23SNavdeep Parhar 		snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d.%d",
402a9da6d23SNavdeep Parhar 		    G_FW_VERSION_MAJOR(vers), G_FW_VERSION_MINOR(vers),
403a9da6d23SNavdeep Parhar 		    G_FW_VERSION_MICRO(vers));
404a9da6d23SNavdeep Parhar 	}
405ac3a6d9cSKip Macy 
406b6d90eb7SKip Macy 	firmware_put(fw, FIRMWARE_UNLOAD);
407b6d90eb7SKip Macy 
408b6d90eb7SKip Macy 	return (status);
409b6d90eb7SKip Macy }
410b6d90eb7SKip Macy 
4113cf138bbSGeorge V. Neville-Neil /*
4123cf138bbSGeorge V. Neville-Neil  * The cxgb_controller_attach function is responsible for the initial
4133cf138bbSGeorge V. Neville-Neil  * bringup of the device.  Its responsibilities include:
4143cf138bbSGeorge V. Neville-Neil  *
4153cf138bbSGeorge V. Neville-Neil  *  1. Determine if the device supports MSI or MSI-X.
4163cf138bbSGeorge V. Neville-Neil  *  2. Allocate bus resources so that we can access the Base Address Register
4173cf138bbSGeorge V. Neville-Neil  *  3. Create and initialize mutexes for the controller and its control
4183cf138bbSGeorge V. Neville-Neil  *     logic such as SGE and MDIO.
4193cf138bbSGeorge V. Neville-Neil  *  4. Call hardware specific setup routine for the adapter as a whole.
4203cf138bbSGeorge V. Neville-Neil  *  5. Allocate the BAR for doing MSI-X.
4213cf138bbSGeorge V. Neville-Neil  *  6. Setup the line interrupt iff MSI-X is not supported.
4223cf138bbSGeorge V. Neville-Neil  *  7. Create the driver's taskq.
423c2009a4cSGeorge V. Neville-Neil  *  8. Start one task queue service thread.
424c2009a4cSGeorge V. Neville-Neil  *  9. Check if the firmware and SRAM are up-to-date.  They will be
425c2009a4cSGeorge V. Neville-Neil  *     auto-updated later (before FULL_INIT_DONE), if required.
4263cf138bbSGeorge V. Neville-Neil  * 10. Create a child device for each MAC (port)
4273cf138bbSGeorge V. Neville-Neil  * 11. Initialize T3 private state.
4283cf138bbSGeorge V. Neville-Neil  * 12. Trigger the LED
4293cf138bbSGeorge V. Neville-Neil  * 13. Setup offload iff supported.
4303cf138bbSGeorge V. Neville-Neil  * 14. Reset/restart the tick callout.
4313cf138bbSGeorge V. Neville-Neil  * 15. Attach sysctls
4323cf138bbSGeorge V. Neville-Neil  *
4333cf138bbSGeorge V. Neville-Neil  * NOTE: Any modification or deviation from this list MUST be reflected in
4343cf138bbSGeorge V. Neville-Neil  * the above comment.  Failure to do so will result in problems on various
4353cf138bbSGeorge V. Neville-Neil  * error conditions including link flapping.
4363cf138bbSGeorge V. Neville-Neil  */
437b6d90eb7SKip Macy static int
cxgb_controller_attach(device_t dev)438b6d90eb7SKip Macy cxgb_controller_attach(device_t dev)
439b6d90eb7SKip Macy {
440b6d90eb7SKip Macy 	device_t child;
441b6d90eb7SKip Macy 	const struct adapter_info *ai;
442b6d90eb7SKip Macy 	struct adapter *sc;
4432de1fa86SKip Macy 	int i, error = 0;
444b6d90eb7SKip Macy 	uint32_t vers;
445693d746cSKip Macy 	int port_qsets = 1;
4462de1fa86SKip Macy 	int msi_needed, reg;
4475197f3abSGeorge V. Neville-Neil 
448b6d90eb7SKip Macy 	sc = device_get_softc(dev);
449b6d90eb7SKip Macy 	sc->dev = dev;
450d722cab4SKip Macy 	sc->msi_count = 0;
4512de1fa86SKip Macy 	ai = cxgb_get_adapter_info(dev);
452b6d90eb7SKip Macy 
45309fe6320SNavdeep Parhar 	snprintf(sc->lockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb controller lock %d",
45409fe6320SNavdeep Parhar 	    device_get_unit(dev));
45509fe6320SNavdeep Parhar 	ADAPTER_LOCK_INIT(sc, sc->lockbuf);
45609fe6320SNavdeep Parhar 
45709fe6320SNavdeep Parhar 	snprintf(sc->reglockbuf, ADAPTER_LOCK_NAME_LEN, "SGE reg lock %d",
45809fe6320SNavdeep Parhar 	    device_get_unit(dev));
45909fe6320SNavdeep Parhar 	snprintf(sc->mdiolockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb mdio lock %d",
46009fe6320SNavdeep Parhar 	    device_get_unit(dev));
46109fe6320SNavdeep Parhar 	snprintf(sc->elmerlockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb elmer lock %d",
46209fe6320SNavdeep Parhar 	    device_get_unit(dev));
46309fe6320SNavdeep Parhar 
46409fe6320SNavdeep Parhar 	MTX_INIT(&sc->sge.reg_lock, sc->reglockbuf, NULL, MTX_SPIN);
46509fe6320SNavdeep Parhar 	MTX_INIT(&sc->mdio_lock, sc->mdiolockbuf, NULL, MTX_DEF);
46609fe6320SNavdeep Parhar 	MTX_INIT(&sc->elmer_lock, sc->elmerlockbuf, NULL, MTX_DEF);
46709fe6320SNavdeep Parhar 
46809fe6320SNavdeep Parhar 	mtx_lock(&t3_list_lock);
46909fe6320SNavdeep Parhar 	SLIST_INSERT_HEAD(&t3_list, sc, link);
47009fe6320SNavdeep Parhar 	mtx_unlock(&t3_list_lock);
47109fe6320SNavdeep Parhar 
472fc01c613SKip Macy 	/* find the PCIe link width and set max read request to 4KB*/
4733b0a4aefSJohn Baldwin 	if (pci_find_cap(dev, PCIY_EXPRESS, &reg) == 0) {
474b739a509SJohn Baldwin 		uint16_t lnk;
475fc01c613SKip Macy 
476389c8bd5SGavin Atkinson 		lnk = pci_read_config(dev, reg + PCIER_LINK_STA, 2);
477389c8bd5SGavin Atkinson 		sc->link_width = (lnk & PCIEM_LINK_STA_WIDTH) >> 4;
478b739a509SJohn Baldwin 		if (sc->link_width < 8 &&
479b739a509SJohn Baldwin 		    (ai->caps & SUPPORTED_10000baseT_Full)) {
480fc01c613SKip Macy 			device_printf(sc->dev,
481ac6b4cf1SKip Macy 			    "PCIe x%d Link, expect reduced performance\n",
482fc01c613SKip Macy 			    sc->link_width);
483fc01c613SKip Macy 		}
484e83ec3e5SNavdeep Parhar 
485b739a509SJohn Baldwin 		pci_set_max_read_req(dev, 4096);
486b739a509SJohn Baldwin 	}
487b739a509SJohn Baldwin 
4887ac2e6c3SKip Macy 	touch_bars(dev);
489b6d90eb7SKip Macy 	pci_enable_busmaster(dev);
490b6d90eb7SKip Macy 	/*
491b6d90eb7SKip Macy 	 * Allocate the registers and make them available to the driver.
492b6d90eb7SKip Macy 	 * The registers that we care about for NIC mode are in BAR 0
493b6d90eb7SKip Macy 	 */
494b6d90eb7SKip Macy 	sc->regs_rid = PCIR_BAR(0);
495b6d90eb7SKip Macy 	if ((sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
496b6d90eb7SKip Macy 	    &sc->regs_rid, RF_ACTIVE)) == NULL) {
4978e10660fSKip Macy 		device_printf(dev, "Cannot allocate BAR region 0\n");
49809fe6320SNavdeep Parhar 		error = ENXIO;
49909fe6320SNavdeep Parhar 		goto out;
500b6d90eb7SKip Macy 	}
501b6d90eb7SKip Macy 
502b6d90eb7SKip Macy 	sc->bt = rman_get_bustag(sc->regs_res);
503b6d90eb7SKip Macy 	sc->bh = rman_get_bushandle(sc->regs_res);
504b6d90eb7SKip Macy 	sc->mmio_len = rman_get_size(sc->regs_res);
505b6d90eb7SKip Macy 
506c01f2b83SNavdeep Parhar 	for (i = 0; i < MAX_NPORTS; i++)
507c01f2b83SNavdeep Parhar 		sc->port[i].adapter = sc;
508c01f2b83SNavdeep Parhar 
50924cdd067SKip Macy 	if (t3_prep_adapter(sc, ai, 1) < 0) {
510ef72318fSKip Macy 		printf("prep adapter failed\n");
51124cdd067SKip Macy 		error = ENODEV;
51224cdd067SKip Macy 		goto out;
51324cdd067SKip Macy 	}
514c3286cd2SNavdeep Parhar 
515c3286cd2SNavdeep Parhar 	sc->udbs_rid = PCIR_BAR(2);
516c3286cd2SNavdeep Parhar 	sc->udbs_res = NULL;
517c3286cd2SNavdeep Parhar 	if (is_offload(sc) &&
518c3286cd2SNavdeep Parhar 	    ((sc->udbs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
519c3286cd2SNavdeep Parhar 		   &sc->udbs_rid, RF_ACTIVE)) == NULL)) {
520c3286cd2SNavdeep Parhar 		device_printf(dev, "Cannot allocate BAR region 1\n");
521c3286cd2SNavdeep Parhar 		error = ENXIO;
522c3286cd2SNavdeep Parhar 		goto out;
523c3286cd2SNavdeep Parhar 	}
524c3286cd2SNavdeep Parhar 
525b6d90eb7SKip Macy         /* Allocate the BAR for doing MSI-X.  If it succeeds, try to allocate
526b6d90eb7SKip Macy 	 * enough messages for the queue sets.  If that fails, try falling
527b6d90eb7SKip Macy 	 * back to MSI.  If that fails, then try falling back to the legacy
528b6d90eb7SKip Macy 	 * interrupt pin model.
529b6d90eb7SKip Macy 	 */
530b6d90eb7SKip Macy 	sc->msix_regs_rid = 0x20;
531b6d90eb7SKip Macy 	if ((msi_allowed >= 2) &&
532b6d90eb7SKip Macy 	    (sc->msix_regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
533b6d90eb7SKip Macy 	    &sc->msix_regs_rid, RF_ACTIVE)) != NULL) {
534b6d90eb7SKip Macy 
535e3503bc9SGeorge V. Neville-Neil 		if (multiq)
536e3503bc9SGeorge V. Neville-Neil 			port_qsets = min(SGE_QSETS/sc->params.nports, mp_ncpus);
537e3503bc9SGeorge V. Neville-Neil 		msi_needed = sc->msi_count = sc->params.nports * port_qsets + 1;
538693d746cSKip Macy 
539e3503bc9SGeorge V. Neville-Neil 		if (pci_msix_count(dev) == 0 ||
540e3503bc9SGeorge V. Neville-Neil 		    (error = pci_alloc_msix(dev, &sc->msi_count)) != 0 ||
541e3503bc9SGeorge V. Neville-Neil 		    sc->msi_count != msi_needed) {
542e3503bc9SGeorge V. Neville-Neil 			device_printf(dev, "alloc msix failed - "
543e3503bc9SGeorge V. Neville-Neil 				      "msi_count=%d, msi_needed=%d, err=%d; "
544e3503bc9SGeorge V. Neville-Neil 				      "will try MSI\n", sc->msi_count,
545d722cab4SKip Macy 				      msi_needed, error);
546d722cab4SKip Macy 			sc->msi_count = 0;
547e3503bc9SGeorge V. Neville-Neil 			port_qsets = 1;
548b6d90eb7SKip Macy 			pci_release_msi(dev);
549b6d90eb7SKip Macy 			bus_release_resource(dev, SYS_RES_MEMORY,
550b6d90eb7SKip Macy 			    sc->msix_regs_rid, sc->msix_regs_res);
551b6d90eb7SKip Macy 			sc->msix_regs_res = NULL;
552b6d90eb7SKip Macy 		} else {
553b6d90eb7SKip Macy 			sc->flags |= USING_MSIX;
554e3503bc9SGeorge V. Neville-Neil 			sc->cxgb_intr = cxgb_async_intr;
555e3503bc9SGeorge V. Neville-Neil 			device_printf(dev,
556e3503bc9SGeorge V. Neville-Neil 				      "using MSI-X interrupts (%u vectors)\n",
557e3503bc9SGeorge V. Neville-Neil 				      sc->msi_count);
558b6d90eb7SKip Macy 		}
559b6d90eb7SKip Macy 	}
560b6d90eb7SKip Macy 
561d722cab4SKip Macy 	if ((msi_allowed >= 1) && (sc->msi_count == 0)) {
562d722cab4SKip Macy 		sc->msi_count = 1;
563e3503bc9SGeorge V. Neville-Neil 		if ((error = pci_alloc_msi(dev, &sc->msi_count)) != 0) {
564e3503bc9SGeorge V. Neville-Neil 			device_printf(dev, "alloc msi failed - "
565e3503bc9SGeorge V. Neville-Neil 				      "err=%d; will try INTx\n", error);
566d722cab4SKip Macy 			sc->msi_count = 0;
567e3503bc9SGeorge V. Neville-Neil 			port_qsets = 1;
568b6d90eb7SKip Macy 			pci_release_msi(dev);
569b6d90eb7SKip Macy 		} else {
570b6d90eb7SKip Macy 			sc->flags |= USING_MSI;
571f0a542f8SKip Macy 			sc->cxgb_intr = t3_intr_msi;
572e3503bc9SGeorge V. Neville-Neil 			device_printf(dev, "using MSI interrupts\n");
573b6d90eb7SKip Macy 		}
574b6d90eb7SKip Macy 	}
575d722cab4SKip Macy 	if (sc->msi_count == 0) {
576693d746cSKip Macy 		device_printf(dev, "using line interrupts\n");
577f0a542f8SKip Macy 		sc->cxgb_intr = t3b_intr;
578b6d90eb7SKip Macy 	}
579b6d90eb7SKip Macy 
580b6d90eb7SKip Macy 	/* Create a private taskqueue thread for handling driver events */
581b6d90eb7SKip Macy 	sc->tq = taskqueue_create("cxgb_taskq", M_NOWAIT,
582b6d90eb7SKip Macy 	    taskqueue_thread_enqueue, &sc->tq);
583b6d90eb7SKip Macy 	if (sc->tq == NULL) {
584b6d90eb7SKip Macy 		device_printf(dev, "failed to allocate controller task queue\n");
585b6d90eb7SKip Macy 		goto out;
586b6d90eb7SKip Macy 	}
587b6d90eb7SKip Macy 
588b6d90eb7SKip Macy 	taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq",
589b6d90eb7SKip Macy 	    device_get_nameunit(dev));
590bb38cd2fSKip Macy 	TASK_INIT(&sc->tick_task, 0, cxgb_tick_handler, sc);
591b6d90eb7SKip Macy 
592b6d90eb7SKip Macy 
593b6d90eb7SKip Macy 	/* Create a periodic callout for checking adapter status */
594fd90e2edSJung-uk Kim 	callout_init(&sc->cxgb_tick_ch, 1);
595b6d90eb7SKip Macy 
596f2d8ff04SGeorge V. Neville-Neil 	if (t3_check_fw_version(sc) < 0 || force_fw_update) {
597b6d90eb7SKip Macy 		/*
598b6d90eb7SKip Macy 		 * Warn user that a firmware update will be attempted in init.
599b6d90eb7SKip Macy 		 */
600d722cab4SKip Macy 		device_printf(dev, "firmware needs to be updated to version %d.%d.%d\n",
601d722cab4SKip Macy 		    FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
602b6d90eb7SKip Macy 		sc->flags &= ~FW_UPTODATE;
603b6d90eb7SKip Macy 	} else {
604b6d90eb7SKip Macy 		sc->flags |= FW_UPTODATE;
605b6d90eb7SKip Macy 	}
606b6d90eb7SKip Macy 
607f2d8ff04SGeorge V. Neville-Neil 	if (t3_check_tpsram_version(sc) < 0) {
608ac3a6d9cSKip Macy 		/*
609ac3a6d9cSKip Macy 		 * Warn user that a firmware update will be attempted in init.
610ac3a6d9cSKip Macy 		 */
611ac3a6d9cSKip Macy 		device_printf(dev, "SRAM needs to be updated to version %c-%d.%d.%d\n",
612ac3a6d9cSKip Macy 		    t3rev2char(sc), TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
613ac3a6d9cSKip Macy 		sc->flags &= ~TPS_UPTODATE;
614ac3a6d9cSKip Macy 	} else {
615ac3a6d9cSKip Macy 		sc->flags |= TPS_UPTODATE;
616ac3a6d9cSKip Macy 	}
617ac3a6d9cSKip Macy 
618b6d90eb7SKip Macy 	/*
619b6d90eb7SKip Macy 	 * Create a child device for each MAC.  The ethernet attachment
620b6d90eb7SKip Macy 	 * will be done in these children.
621b6d90eb7SKip Macy 	 */
622693d746cSKip Macy 	for (i = 0; i < (sc)->params.nports; i++) {
6237ac2e6c3SKip Macy 		struct port_info *pi;
6247ac2e6c3SKip Macy 
625b6d90eb7SKip Macy 		if ((child = device_add_child(dev, "cxgb", -1)) == NULL) {
626b6d90eb7SKip Macy 			device_printf(dev, "failed to add child port\n");
627b6d90eb7SKip Macy 			error = EINVAL;
628b6d90eb7SKip Macy 			goto out;
629b6d90eb7SKip Macy 		}
6307ac2e6c3SKip Macy 		pi = &sc->port[i];
6317ac2e6c3SKip Macy 		pi->adapter = sc;
6327ac2e6c3SKip Macy 		pi->nqsets = port_qsets;
6337ac2e6c3SKip Macy 		pi->first_qset = i*port_qsets;
6347ac2e6c3SKip Macy 		pi->port_id = i;
6357ac2e6c3SKip Macy 		pi->tx_chan = i >= ai->nports0;
6367ac2e6c3SKip Macy 		pi->txpkt_intf = pi->tx_chan ? 2 * (i - ai->nports0) + 1 : 2 * i;
6377ac2e6c3SKip Macy 		sc->rxpkt_map[pi->txpkt_intf] = i;
6388090c9f5SKip Macy 		sc->port[i].tx_chan = i >= ai->nports0;
639ac3a6d9cSKip Macy 		sc->portdev[i] = child;
6407ac2e6c3SKip Macy 		device_set_softc(child, pi);
641b6d90eb7SKip Macy 	}
64218250ec6SJohn Baldwin 	bus_attach_children(dev);
643b6d90eb7SKip Macy 
644b6d90eb7SKip Macy 	/* initialize sge private state */
645ef72318fSKip Macy 	t3_sge_init_adapter(sc);
646b6d90eb7SKip Macy 
647b6d90eb7SKip Macy 	t3_led_ready(sc);
648b6d90eb7SKip Macy 
649b6d90eb7SKip Macy 	error = t3_get_fw_version(sc, &vers);
650b6d90eb7SKip Macy 	if (error)
651b6d90eb7SKip Macy 		goto out;
652b6d90eb7SKip Macy 
653d722cab4SKip Macy 	snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d.%d",
654d722cab4SKip Macy 	    G_FW_VERSION_MAJOR(vers), G_FW_VERSION_MINOR(vers),
655d722cab4SKip Macy 	    G_FW_VERSION_MICRO(vers));
656b6d90eb7SKip Macy 
657796bcf18SMark Johnston 	device_set_descf(dev, "%s %sNIC\t E/C: %s S/N: %s",
6587ead19d4SNavdeep Parhar 	    ai->desc, is_offload(sc) ? "R" : "",
6595197f3abSGeorge V. Neville-Neil 	    sc->params.vpd.ec, sc->params.vpd.sn);
6605197f3abSGeorge V. Neville-Neil 
6610bbdea77SGeorge V. Neville-Neil 	snprintf(&sc->port_types[0], sizeof(sc->port_types), "%x%x%x%x",
6620bbdea77SGeorge V. Neville-Neil 		 sc->params.vpd.port_type[0], sc->params.vpd.port_type[1],
6630bbdea77SGeorge V. Neville-Neil 		 sc->params.vpd.port_type[2], sc->params.vpd.port_type[3]);
6640bbdea77SGeorge V. Neville-Neil 
6658e10660fSKip Macy 	device_printf(sc->dev, "Firmware Version %s\n", &sc->fw_version[0]);
666bd1a9fbaSNavdeep Parhar 	callout_reset(&sc->cxgb_tick_ch, hz, cxgb_tick, sc);
6678090c9f5SKip Macy 	t3_add_attach_sysctls(sc);
66809fe6320SNavdeep Parhar 
66909fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
67009fe6320SNavdeep Parhar 	for (i = 0; i < NUM_CPL_HANDLERS; i++)
67109fe6320SNavdeep Parhar 		sc->cpl_handler[i] = cpl_not_handled;
67209fe6320SNavdeep Parhar #endif
673ec9a9cf1SJohn Baldwin 
674ec9a9cf1SJohn Baldwin 	t3_intr_clear(sc);
675ec9a9cf1SJohn Baldwin 	error = cxgb_setup_interrupts(sc);
676b6d90eb7SKip Macy out:
677b6d90eb7SKip Macy 	if (error)
678b6d90eb7SKip Macy 		cxgb_free(sc);
679b6d90eb7SKip Macy 
680b6d90eb7SKip Macy 	return (error);
681b6d90eb7SKip Macy }
682b6d90eb7SKip Macy 
6833cf138bbSGeorge V. Neville-Neil /*
684c2009a4cSGeorge V. Neville-Neil  * The cxgb_controller_detach routine is called with the device is
6853cf138bbSGeorge V. Neville-Neil  * unloaded from the system.
6863cf138bbSGeorge V. Neville-Neil  */
6873cf138bbSGeorge V. Neville-Neil 
688b6d90eb7SKip Macy static int
cxgb_controller_detach(device_t dev)689b6d90eb7SKip Macy cxgb_controller_detach(device_t dev)
690b6d90eb7SKip Macy {
691b6d90eb7SKip Macy 	struct adapter *sc;
692b6d90eb7SKip Macy 
693b6d90eb7SKip Macy 	sc = device_get_softc(dev);
694b6d90eb7SKip Macy 
695b6d90eb7SKip Macy 	cxgb_free(sc);
696b6d90eb7SKip Macy 
697b6d90eb7SKip Macy 	return (0);
698b6d90eb7SKip Macy }
699b6d90eb7SKip Macy 
7003cf138bbSGeorge V. Neville-Neil /*
7013cf138bbSGeorge V. Neville-Neil  * The cxgb_free() is called by the cxgb_controller_detach() routine
7023cf138bbSGeorge V. Neville-Neil  * to tear down the structures that were built up in
7033cf138bbSGeorge V. Neville-Neil  * cxgb_controller_attach(), and should be the final piece of work
704c2009a4cSGeorge V. Neville-Neil  * done when fully unloading the driver.
7053cf138bbSGeorge V. Neville-Neil  *
7063cf138bbSGeorge V. Neville-Neil  *
7073cf138bbSGeorge V. Neville-Neil  *  1. Shutting down the threads started by the cxgb_controller_attach()
7083cf138bbSGeorge V. Neville-Neil  *     routine.
7093cf138bbSGeorge V. Neville-Neil  *  2. Stopping the lower level device and all callouts (cxgb_down_locked()).
7103cf138bbSGeorge V. Neville-Neil  *  3. Detaching all of the port devices created during the
7113cf138bbSGeorge V. Neville-Neil  *     cxgb_controller_attach() routine.
7123cf138bbSGeorge V. Neville-Neil  *  4. Removing the device children created via cxgb_controller_attach().
713e3503bc9SGeorge V. Neville-Neil  *  5. Releasing PCI resources associated with the device.
7143cf138bbSGeorge V. Neville-Neil  *  6. Turning off the offload support, iff it was turned on.
7153cf138bbSGeorge V. Neville-Neil  *  7. Destroying the mutexes created in cxgb_controller_attach().
7163cf138bbSGeorge V. Neville-Neil  *
7173cf138bbSGeorge V. Neville-Neil  */
718b6d90eb7SKip Macy static void
cxgb_free(struct adapter * sc)719b6d90eb7SKip Macy cxgb_free(struct adapter *sc)
720b6d90eb7SKip Macy {
7217eeb16ceSNavdeep Parhar 	int i, nqsets = 0;
722b6d90eb7SKip Macy 
7238e10660fSKip Macy 	ADAPTER_LOCK(sc);
7248e10660fSKip Macy 	sc->flags |= CXGB_SHUTDOWN;
7258e10660fSKip Macy 	ADAPTER_UNLOCK(sc);
7268e10660fSKip Macy 
7273cf138bbSGeorge V. Neville-Neil 	/*
7283f345a5dSKip Macy 	 * Make sure all child devices are gone.
7293cf138bbSGeorge V. Neville-Neil 	 */
730e9d38570SJohn Baldwin 	bus_detach_children(sc->dev);
7313cf138bbSGeorge V. Neville-Neil 	for (i = 0; i < (sc)->params.nports; i++) {
732c2009a4cSGeorge V. Neville-Neil 		if (sc->portdev[i] &&
733c2009a4cSGeorge V. Neville-Neil 		    device_delete_child(sc->dev, sc->portdev[i]) != 0)
7343cf138bbSGeorge V. Neville-Neil 			device_printf(sc->dev, "failed to delete child port\n");
7357eeb16ceSNavdeep Parhar 		nqsets += sc->port[i].nqsets;
7363cf138bbSGeorge V. Neville-Neil 	}
737d722cab4SKip Macy 
7383f345a5dSKip Macy 	/*
7393f345a5dSKip Macy 	 * At this point, it is as if cxgb_port_detach has run on all ports, and
7403f345a5dSKip Macy 	 * cxgb_down has run on the adapter.  All interrupts have been silenced,
7413f345a5dSKip Macy 	 * all open devices have been closed.
7423f345a5dSKip Macy 	 */
7433f345a5dSKip Macy 	KASSERT(sc->open_device_map == 0, ("%s: device(s) still open (%x)",
7443f345a5dSKip Macy 					   __func__, sc->open_device_map));
7453f345a5dSKip Macy 	for (i = 0; i < sc->params.nports; i++) {
7463f345a5dSKip Macy 		KASSERT(sc->port[i].ifp == NULL, ("%s: port %i undead!",
7473f345a5dSKip Macy 						  __func__, i));
7483f345a5dSKip Macy 	}
749e3503bc9SGeorge V. Neville-Neil 
7503f345a5dSKip Macy 	/*
7513f345a5dSKip Macy 	 * Finish off the adapter's callouts.
7523f345a5dSKip Macy 	 */
7533f345a5dSKip Macy 	callout_drain(&sc->cxgb_tick_ch);
7543f345a5dSKip Macy 	callout_drain(&sc->sge_timer_ch);
7553f345a5dSKip Macy 
7563f345a5dSKip Macy 	/*
7573f345a5dSKip Macy 	 * Release resources grabbed under FULL_INIT_DONE by cxgb_up.  The
7583f345a5dSKip Macy 	 * sysctls are cleaned up by the kernel linker.
7593f345a5dSKip Macy 	 */
7603f345a5dSKip Macy 	if (sc->flags & FULL_INIT_DONE) {
7617eeb16ceSNavdeep Parhar  		t3_free_sge_resources(sc, nqsets);
7623f345a5dSKip Macy  		sc->flags &= ~FULL_INIT_DONE;
7633f345a5dSKip Macy  	}
7643f345a5dSKip Macy 
7653f345a5dSKip Macy 	/*
7663f345a5dSKip Macy 	 * Release all interrupt resources.
7673f345a5dSKip Macy 	 */
7683f345a5dSKip Macy 	cxgb_teardown_interrupts(sc);
769d722cab4SKip Macy 	if (sc->flags & (USING_MSI | USING_MSIX)) {
770d722cab4SKip Macy 		device_printf(sc->dev, "releasing msi message(s)\n");
771d722cab4SKip Macy 		pci_release_msi(sc->dev);
772d722cab4SKip Macy 	} else {
773d722cab4SKip Macy 		device_printf(sc->dev, "no msi message to release\n");
774d722cab4SKip Macy 	}
775e3503bc9SGeorge V. Neville-Neil 
776d722cab4SKip Macy 	if (sc->msix_regs_res != NULL) {
777d722cab4SKip Macy 		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid,
778d722cab4SKip Macy 		    sc->msix_regs_res);
779d722cab4SKip Macy 	}
780d722cab4SKip Macy 
7813f345a5dSKip Macy 	/*
7823f345a5dSKip Macy 	 * Free the adapter's taskqueue.
7833f345a5dSKip Macy 	 */
7848e10660fSKip Macy 	if (sc->tq != NULL) {
7857ac2e6c3SKip Macy 		taskqueue_free(sc->tq);
7868e10660fSKip Macy 		sc->tq = NULL;
7878e10660fSKip Macy 	}
7888e10660fSKip Macy 
789ac3a6d9cSKip Macy 	free(sc->filters, M_DEVBUF);
790b6d90eb7SKip Macy 	t3_sge_free(sc);
791b6d90eb7SKip Macy 
7928e10660fSKip Macy 	if (sc->udbs_res != NULL)
7938e10660fSKip Macy 		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->udbs_rid,
7948e10660fSKip Macy 		    sc->udbs_res);
7958e10660fSKip Macy 
796b6d90eb7SKip Macy 	if (sc->regs_res != NULL)
797b6d90eb7SKip Macy 		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->regs_rid,
798b6d90eb7SKip Macy 		    sc->regs_res);
799b6d90eb7SKip Macy 
800bb38cd2fSKip Macy 	MTX_DESTROY(&sc->mdio_lock);
801bb38cd2fSKip Macy 	MTX_DESTROY(&sc->sge.reg_lock);
802bb38cd2fSKip Macy 	MTX_DESTROY(&sc->elmer_lock);
80309fe6320SNavdeep Parhar 	mtx_lock(&t3_list_lock);
80409fe6320SNavdeep Parhar 	SLIST_REMOVE(&t3_list, sc, adapter, link);
80509fe6320SNavdeep Parhar 	mtx_unlock(&t3_list_lock);
806bb38cd2fSKip Macy 	ADAPTER_LOCK_DEINIT(sc);
807b6d90eb7SKip Macy }
808b6d90eb7SKip Macy 
809b6d90eb7SKip Macy /**
810b6d90eb7SKip Macy  *	setup_sge_qsets - configure SGE Tx/Rx/response queues
811b6d90eb7SKip Macy  *	@sc: the controller softc
812b6d90eb7SKip Macy  *
813b6d90eb7SKip Macy  *	Determines how many sets of SGE queues to use and initializes them.
814b6d90eb7SKip Macy  *	We support multiple queue sets per port if we have MSI-X, otherwise
815b6d90eb7SKip Macy  *	just one queue set per port.
816b6d90eb7SKip Macy  */
817b6d90eb7SKip Macy static int
setup_sge_qsets(adapter_t * sc)818b6d90eb7SKip Macy setup_sge_qsets(adapter_t *sc)
819b6d90eb7SKip Macy {
8205c5df3daSKip Macy 	int i, j, err, irq_idx = 0, qset_idx = 0;
821d722cab4SKip Macy 	u_int ntxq = SGE_TXQ_PER_SET;
822b6d90eb7SKip Macy 
823b6d90eb7SKip Macy 	if ((err = t3_sge_alloc(sc)) != 0) {
824693d746cSKip Macy 		device_printf(sc->dev, "t3_sge_alloc returned %d\n", err);
825b6d90eb7SKip Macy 		return (err);
826b6d90eb7SKip Macy 	}
827b6d90eb7SKip Macy 
828b6d90eb7SKip Macy 	if (sc->params.rev > 0 && !(sc->flags & USING_MSI))
829b6d90eb7SKip Macy 		irq_idx = -1;
830b6d90eb7SKip Macy 
8315c5df3daSKip Macy 	for (i = 0; i < (sc)->params.nports; i++) {
832b6d90eb7SKip Macy 		struct port_info *pi = &sc->port[i];
833b6d90eb7SKip Macy 
8347ac2e6c3SKip Macy 		for (j = 0; j < pi->nqsets; j++, qset_idx++) {
835693d746cSKip Macy 			err = t3_sge_alloc_qset(sc, qset_idx, (sc)->params.nports,
836b6d90eb7SKip Macy 			    (sc->flags & USING_MSIX) ? qset_idx + 1 : irq_idx,
837b6d90eb7SKip Macy 			    &sc->params.sge.qset[qset_idx], ntxq, pi);
838b6d90eb7SKip Macy 			if (err) {
8397eeb16ceSNavdeep Parhar 				t3_free_sge_resources(sc, qset_idx);
8407eeb16ceSNavdeep Parhar 				device_printf(sc->dev,
8417eeb16ceSNavdeep Parhar 				    "t3_sge_alloc_qset failed with %d\n", err);
842b6d90eb7SKip Macy 				return (err);
843b6d90eb7SKip Macy 			}
844b6d90eb7SKip Macy 		}
845b6d90eb7SKip Macy 	}
846b6d90eb7SKip Macy 
8473948ad29SConrad Meyer 	sc->nqsets = qset_idx;
8483948ad29SConrad Meyer 
849b6d90eb7SKip Macy 	return (0);
850b6d90eb7SKip Macy }
851b6d90eb7SKip Macy 
852ef72318fSKip Macy static void
cxgb_teardown_interrupts(adapter_t * sc)853e3503bc9SGeorge V. Neville-Neil cxgb_teardown_interrupts(adapter_t *sc)
854ef72318fSKip Macy {
855e3503bc9SGeorge V. Neville-Neil 	int i;
856ef72318fSKip Macy 
857e3503bc9SGeorge V. Neville-Neil 	for (i = 0; i < SGE_QSETS; i++) {
858e3503bc9SGeorge V. Neville-Neil 		if (sc->msix_intr_tag[i] == NULL) {
859ef72318fSKip Macy 
860e3503bc9SGeorge V. Neville-Neil 			/* Should have been setup fully or not at all */
861e3503bc9SGeorge V. Neville-Neil 			KASSERT(sc->msix_irq_res[i] == NULL &&
862e3503bc9SGeorge V. Neville-Neil 				sc->msix_irq_rid[i] == 0,
863e3503bc9SGeorge V. Neville-Neil 				("%s: half-done interrupt (%d).", __func__, i));
864e3503bc9SGeorge V. Neville-Neil 
865e3503bc9SGeorge V. Neville-Neil 			continue;
866e3503bc9SGeorge V. Neville-Neil 		}
867e3503bc9SGeorge V. Neville-Neil 
868ef72318fSKip Macy 		bus_teardown_intr(sc->dev, sc->msix_irq_res[i],
869ef72318fSKip Macy 				  sc->msix_intr_tag[i]);
870e3503bc9SGeorge V. Neville-Neil 		bus_release_resource(sc->dev, SYS_RES_IRQ, sc->msix_irq_rid[i],
871e3503bc9SGeorge V. Neville-Neil 				     sc->msix_irq_res[i]);
872e3503bc9SGeorge V. Neville-Neil 
873e3503bc9SGeorge V. Neville-Neil 		sc->msix_irq_res[i] = sc->msix_intr_tag[i] = NULL;
874e3503bc9SGeorge V. Neville-Neil 		sc->msix_irq_rid[i] = 0;
875ef72318fSKip Macy 	}
876e3503bc9SGeorge V. Neville-Neil 
877e3503bc9SGeorge V. Neville-Neil 	if (sc->intr_tag) {
878e3503bc9SGeorge V. Neville-Neil 		KASSERT(sc->irq_res != NULL,
879e3503bc9SGeorge V. Neville-Neil 			("%s: half-done interrupt.", __func__));
880e3503bc9SGeorge V. Neville-Neil 
881e3503bc9SGeorge V. Neville-Neil 		bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag);
882e3503bc9SGeorge V. Neville-Neil 		bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
883e3503bc9SGeorge V. Neville-Neil 				     sc->irq_res);
884e3503bc9SGeorge V. Neville-Neil 
885e3503bc9SGeorge V. Neville-Neil 		sc->irq_res = sc->intr_tag = NULL;
886e3503bc9SGeorge V. Neville-Neil 		sc->irq_rid = 0;
887ef72318fSKip Macy 	}
888ef72318fSKip Macy }
889ef72318fSKip Macy 
890b6d90eb7SKip Macy static int
cxgb_setup_interrupts(adapter_t * sc)891e3503bc9SGeorge V. Neville-Neil cxgb_setup_interrupts(adapter_t *sc)
892b6d90eb7SKip Macy {
893e3503bc9SGeorge V. Neville-Neil 	struct resource *res;
894e3503bc9SGeorge V. Neville-Neil 	void *tag;
895e3503bc9SGeorge V. Neville-Neil 	int i, rid, err, intr_flag = sc->flags & (USING_MSI | USING_MSIX);
896b6d90eb7SKip Macy 
897e3503bc9SGeorge V. Neville-Neil 	sc->irq_rid = intr_flag ? 1 : 0;
898e3503bc9SGeorge V. Neville-Neil 	sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &sc->irq_rid,
899e3503bc9SGeorge V. Neville-Neil 					     RF_SHAREABLE | RF_ACTIVE);
900e3503bc9SGeorge V. Neville-Neil 	if (sc->irq_res == NULL) {
901e3503bc9SGeorge V. Neville-Neil 		device_printf(sc->dev, "Cannot allocate interrupt (%x, %u)\n",
902e3503bc9SGeorge V. Neville-Neil 			      intr_flag, sc->irq_rid);
903e3503bc9SGeorge V. Neville-Neil 		err = EINVAL;
904e3503bc9SGeorge V. Neville-Neil 		sc->irq_rid = 0;
905e3503bc9SGeorge V. Neville-Neil 	} else {
906e3503bc9SGeorge V. Neville-Neil 		err = bus_setup_intr(sc->dev, sc->irq_res,
907e83ec3e5SNavdeep Parhar 		    INTR_MPSAFE | INTR_TYPE_NET, NULL,
908e3503bc9SGeorge V. Neville-Neil 		    sc->cxgb_intr, sc, &sc->intr_tag);
909a02573bcSKip Macy 
910e3503bc9SGeorge V. Neville-Neil 		if (err) {
911e3503bc9SGeorge V. Neville-Neil 			device_printf(sc->dev,
912e3503bc9SGeorge V. Neville-Neil 				      "Cannot set up interrupt (%x, %u, %d)\n",
913e3503bc9SGeorge V. Neville-Neil 				      intr_flag, sc->irq_rid, err);
914e3503bc9SGeorge V. Neville-Neil 			bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
915e3503bc9SGeorge V. Neville-Neil 					     sc->irq_res);
916e3503bc9SGeorge V. Neville-Neil 			sc->irq_res = sc->intr_tag = NULL;
917e3503bc9SGeorge V. Neville-Neil 			sc->irq_rid = 0;
918b6d90eb7SKip Macy 		}
919b6d90eb7SKip Macy 	}
920693d746cSKip Macy 
921e3503bc9SGeorge V. Neville-Neil 	/* That's all for INTx or MSI */
922e3503bc9SGeorge V. Neville-Neil 	if (!(intr_flag & USING_MSIX) || err)
923e3503bc9SGeorge V. Neville-Neil 		return (err);
924e3503bc9SGeorge V. Neville-Neil 
925ec9a9cf1SJohn Baldwin 	bus_describe_intr(sc->dev, sc->irq_res, sc->intr_tag, "err");
926e3503bc9SGeorge V. Neville-Neil 	for (i = 0; i < sc->msi_count - 1; i++) {
927e3503bc9SGeorge V. Neville-Neil 		rid = i + 2;
928e3503bc9SGeorge V. Neville-Neil 		res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &rid,
929e3503bc9SGeorge V. Neville-Neil 					     RF_SHAREABLE | RF_ACTIVE);
930e3503bc9SGeorge V. Neville-Neil 		if (res == NULL) {
931e3503bc9SGeorge V. Neville-Neil 			device_printf(sc->dev, "Cannot allocate interrupt "
932e3503bc9SGeorge V. Neville-Neil 				      "for message %d\n", rid);
933e3503bc9SGeorge V. Neville-Neil 			err = EINVAL;
934e3503bc9SGeorge V. Neville-Neil 			break;
935b6d90eb7SKip Macy 		}
936b6d90eb7SKip Macy 
937e3503bc9SGeorge V. Neville-Neil 		err = bus_setup_intr(sc->dev, res, INTR_MPSAFE | INTR_TYPE_NET,
938e83ec3e5SNavdeep Parhar 				     NULL, t3_intr_msix, &sc->sge.qs[i], &tag);
939e3503bc9SGeorge V. Neville-Neil 		if (err) {
940e3503bc9SGeorge V. Neville-Neil 			device_printf(sc->dev, "Cannot set up interrupt "
941e3503bc9SGeorge V. Neville-Neil 				      "for message %d (%d)\n", rid, err);
942e3503bc9SGeorge V. Neville-Neil 			bus_release_resource(sc->dev, SYS_RES_IRQ, rid, res);
943e3503bc9SGeorge V. Neville-Neil 			break;
944e3503bc9SGeorge V. Neville-Neil 		}
945e3503bc9SGeorge V. Neville-Neil 
946e3503bc9SGeorge V. Neville-Neil 		sc->msix_irq_rid[i] = rid;
947e3503bc9SGeorge V. Neville-Neil 		sc->msix_irq_res[i] = res;
948e3503bc9SGeorge V. Neville-Neil 		sc->msix_intr_tag[i] = tag;
949ec9a9cf1SJohn Baldwin 		bus_describe_intr(sc->dev, res, tag, "qs%d", i);
950e3503bc9SGeorge V. Neville-Neil 	}
951e3503bc9SGeorge V. Neville-Neil 
952e3503bc9SGeorge V. Neville-Neil 	if (err)
953e3503bc9SGeorge V. Neville-Neil 		cxgb_teardown_interrupts(sc);
954e3503bc9SGeorge V. Neville-Neil 
955e3503bc9SGeorge V. Neville-Neil 	return (err);
956e3503bc9SGeorge V. Neville-Neil }
957e3503bc9SGeorge V. Neville-Neil 
958e3503bc9SGeorge V. Neville-Neil 
959b6d90eb7SKip Macy static int
cxgb_port_probe(device_t dev)960b6d90eb7SKip Macy cxgb_port_probe(device_t dev)
961b6d90eb7SKip Macy {
962b6d90eb7SKip Macy 	struct port_info *p;
9638e10660fSKip Macy 	const char *desc;
964b6d90eb7SKip Macy 
965b6d90eb7SKip Macy 	p = device_get_softc(dev);
9668e10660fSKip Macy 	desc = p->phy.desc;
967796bcf18SMark Johnston 	device_set_descf(dev, "Port %d %s", p->port_id, desc);
968b6d90eb7SKip Macy 	return (0);
969b6d90eb7SKip Macy }
970b6d90eb7SKip Macy 
971b6d90eb7SKip Macy 
972b6d90eb7SKip Macy static int
cxgb_makedev(struct port_info * pi)973b6d90eb7SKip Macy cxgb_makedev(struct port_info *pi)
974b6d90eb7SKip Macy {
975b6d90eb7SKip Macy 
976954712e8SJustin Hibbits 	pi->port_cdev = make_dev(&cxgb_cdevsw, if_getdunit(pi->ifp),
97706eace63SNavdeep Parhar 	    UID_ROOT, GID_WHEEL, 0600, "%s", if_name(pi->ifp));
978b6d90eb7SKip Macy 
979b6d90eb7SKip Macy 	if (pi->port_cdev == NULL)
980b6d90eb7SKip Macy 		return (ENOMEM);
981b6d90eb7SKip Macy 
982b6d90eb7SKip Macy 	pi->port_cdev->si_drv1 = (void *)pi;
983b6d90eb7SKip Macy 
984b6d90eb7SKip Macy 	return (0);
985b6d90eb7SKip Macy }
986b6d90eb7SKip Macy 
987e83ec3e5SNavdeep Parhar #define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \
988f9c6e164SNavdeep Parhar     IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \
9890a704909SNavdeep Parhar     IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6)
9903e7cc3caSNavdeep Parhar #define CXGB_CAP_ENABLE CXGB_CAP
991b6d90eb7SKip Macy 
992b6d90eb7SKip Macy static int
cxgb_port_attach(device_t dev)993b6d90eb7SKip Macy cxgb_port_attach(device_t dev)
994b6d90eb7SKip Macy {
995b6d90eb7SKip Macy 	struct port_info *p;
996954712e8SJustin Hibbits 	if_t ifp;
9972975f787SNavdeep Parhar 	int err;
9988e10660fSKip Macy 	struct adapter *sc;
9998e10660fSKip Macy 
1000b6d90eb7SKip Macy 	p = device_get_softc(dev);
10018e10660fSKip Macy 	sc = p->adapter;
1002bb38cd2fSKip Macy 	snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d",
10036b68e276SKip Macy 	    device_get_unit(device_get_parent(dev)), p->port_id);
1004bb38cd2fSKip Macy 	PORT_LOCK_INIT(p, p->lockbuf);
1005b6d90eb7SKip Macy 
1006fd90e2edSJung-uk Kim 	callout_init(&p->link_check_ch, 1);
1007bd1a9fbaSNavdeep Parhar 	TASK_INIT(&p->link_check_task, 0, check_link_status, p);
1008bd1a9fbaSNavdeep Parhar 
1009b6d90eb7SKip Macy 	/* Allocate an ifnet object and set it up */
1010b6d90eb7SKip Macy 	ifp = p->ifp = if_alloc(IFT_ETHER);
1011b6d90eb7SKip Macy 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1012954712e8SJustin Hibbits 	if_setinitfn(ifp, cxgb_init);
1013954712e8SJustin Hibbits 	if_setsoftc(ifp, p);
1014954712e8SJustin Hibbits 	if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
1015954712e8SJustin Hibbits 	if_setioctlfn(ifp, cxgb_ioctl);
1016954712e8SJustin Hibbits 	if_settransmitfn(ifp, cxgb_transmit);
1017954712e8SJustin Hibbits 	if_setqflushfn(ifp, cxgb_qflush);
1018954712e8SJustin Hibbits 	if_setgetcounterfn(ifp, cxgb_get_counter);
1019b6d90eb7SKip Macy 
1020954712e8SJustin Hibbits 	if_setcapabilities(ifp, CXGB_CAP);
102109fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
102209fe6320SNavdeep Parhar 	if (is_offload(sc))
1023954712e8SJustin Hibbits 		if_setcapabilitiesbit(ifp, IFCAP_TOE4, 0);
102409fe6320SNavdeep Parhar #endif
1025954712e8SJustin Hibbits 	if_setcapenable(ifp, CXGB_CAP_ENABLE);
1026954712e8SJustin Hibbits 	if_sethwassist(ifp, CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO |
1027954712e8SJustin Hibbits 	    CSUM_UDP_IPV6 | CSUM_TCP_IPV6);
1028954712e8SJustin Hibbits 	if_sethwtsomax(ifp, IP_MAXPACKET);
1029954712e8SJustin Hibbits 	if_sethwtsomaxsegcount(ifp, 36);
1030954712e8SJustin Hibbits 	if_sethwtsomaxsegsize(ifp, 65536);
1031e83ec3e5SNavdeep Parhar 
1032ac3a6d9cSKip Macy 	/*
1033e83ec3e5SNavdeep Parhar 	 * Disable TSO on 4-port - it isn't supported by the firmware.
1034ac3a6d9cSKip Macy 	 */
1035e83ec3e5SNavdeep Parhar 	if (sc->params.nports > 2) {
1036954712e8SJustin Hibbits 		if_setcapabilitiesbit(ifp, 0, IFCAP_TSO | IFCAP_VLAN_HWTSO);
1037954712e8SJustin Hibbits 		if_setcapenablebit(ifp, 0, IFCAP_TSO | IFCAP_VLAN_HWTSO);
1038954712e8SJustin Hibbits 		if_sethwassistbits(ifp, 0, CSUM_TSO);
1039ac3a6d9cSKip Macy 	}
1040b6d90eb7SKip Macy 
1041f2daf899SScottD 	/* Create a list of media supported by this port */
1042f2daf899SScottD 	ifmedia_init(&p->media, IFM_IMASK, cxgb_media_change,
1043f2daf899SScottD 	    cxgb_media_status);
1044f2daf899SScottD 	cxgb_build_medialist(p);
1045f2daf899SScottD 
1046b6d90eb7SKip Macy 	ether_ifattach(ifp, p->hw_addr);
10473cf138bbSGeorge V. Neville-Neil 
10487790c8c1SConrad Meyer 	/* Attach driver debugnet methods. */
10497790c8c1SConrad Meyer 	DEBUGNET_SET(ifp, cxgb);
1050eb07d67eSMark Johnston 
1051e83ec3e5SNavdeep Parhar #ifdef DEFAULT_JUMBO
1052e83ec3e5SNavdeep Parhar 	if (sc->params.nports <= 2)
1053954712e8SJustin Hibbits 		if_setmtu(ifp, ETHERMTU_JUMBO);
1054e83ec3e5SNavdeep Parhar #endif
1055b6d90eb7SKip Macy 	if ((err = cxgb_makedev(p)) != 0) {
1056b6d90eb7SKip Macy 		printf("makedev failed %d\n", err);
1057b6d90eb7SKip Macy 		return (err);
1058b6d90eb7SKip Macy 	}
10592975f787SNavdeep Parhar 
1060ef72318fSKip Macy 	t3_sge_init_port(p);
1061f2d8ff04SGeorge V. Neville-Neil 
10623cf138bbSGeorge V. Neville-Neil 	return (err);
1063b6d90eb7SKip Macy }
1064b6d90eb7SKip Macy 
10653cf138bbSGeorge V. Neville-Neil /*
10663cf138bbSGeorge V. Neville-Neil  * cxgb_port_detach() is called via the device_detach methods when
1067e9d38570SJohn Baldwin  * cxgb_free() calls the bus_detach_children.  It is responsible for
10683cf138bbSGeorge V. Neville-Neil  * removing the device from the view of the kernel, i.e. from all
10693cf138bbSGeorge V. Neville-Neil  * interfaces lists etc.  This routine is only called when the driver is
10703cf138bbSGeorge V. Neville-Neil  * being unloaded, not when the link goes down.
10713cf138bbSGeorge V. Neville-Neil  */
1072b6d90eb7SKip Macy static int
cxgb_port_detach(device_t dev)1073b6d90eb7SKip Macy cxgb_port_detach(device_t dev)
1074b6d90eb7SKip Macy {
1075b6d90eb7SKip Macy 	struct port_info *p;
10763cf138bbSGeorge V. Neville-Neil 	struct adapter *sc;
10773f345a5dSKip Macy 	int i;
1078b6d90eb7SKip Macy 
1079b6d90eb7SKip Macy 	p = device_get_softc(dev);
10803cf138bbSGeorge V. Neville-Neil 	sc = p->adapter;
10813cf138bbSGeorge V. Neville-Neil 
1082b302b77cSNavdeep Parhar 	/* Tell cxgb_ioctl and if_init that the port is going away */
1083b302b77cSNavdeep Parhar 	ADAPTER_LOCK(sc);
1084b302b77cSNavdeep Parhar 	SET_DOOMED(p);
1085b302b77cSNavdeep Parhar 	wakeup(&sc->flags);
1086b302b77cSNavdeep Parhar 	while (IS_BUSY(sc))
1087b302b77cSNavdeep Parhar 		mtx_sleep(&sc->flags, &sc->lock, 0, "cxgbdtch", 0);
1088b302b77cSNavdeep Parhar 	SET_BUSY(sc);
1089b302b77cSNavdeep Parhar 	ADAPTER_UNLOCK(sc);
10903f345a5dSKip Macy 
10913cf138bbSGeorge V. Neville-Neil 	if (p->port_cdev != NULL)
10923cf138bbSGeorge V. Neville-Neil 		destroy_dev(p->port_cdev);
10933cf138bbSGeorge V. Neville-Neil 
10943f345a5dSKip Macy 	cxgb_uninit_synchronized(p);
10953cf138bbSGeorge V. Neville-Neil 	ether_ifdetach(p->ifp);
1096d722cab4SKip Macy 
10973f345a5dSKip Macy 	for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) {
10983f345a5dSKip Macy 		struct sge_qset *qs = &sc->sge.qs[i];
10993f345a5dSKip Macy 		struct sge_txq *txq = &qs->txq[TXQ_ETH];
1100d722cab4SKip Macy 
11013f345a5dSKip Macy 		callout_drain(&txq->txq_watchdog);
11023f345a5dSKip Macy 		callout_drain(&txq->txq_timer);
11033cf138bbSGeorge V. Neville-Neil 	}
11043cf138bbSGeorge V. Neville-Neil 
11057ac2e6c3SKip Macy 	PORT_LOCK_DEINIT(p);
1106b6d90eb7SKip Macy 	if_free(p->ifp);
11073f345a5dSKip Macy 	p->ifp = NULL;
1108b6d90eb7SKip Macy 
1109b302b77cSNavdeep Parhar 	ADAPTER_LOCK(sc);
1110b302b77cSNavdeep Parhar 	CLR_BUSY(sc);
1111b302b77cSNavdeep Parhar 	wakeup_one(&sc->flags);
1112b302b77cSNavdeep Parhar 	ADAPTER_UNLOCK(sc);
1113b6d90eb7SKip Macy 	return (0);
1114b6d90eb7SKip Macy }
1115b6d90eb7SKip Macy 
1116b6d90eb7SKip Macy void
t3_fatal_err(struct adapter * sc)1117b6d90eb7SKip Macy t3_fatal_err(struct adapter *sc)
1118b6d90eb7SKip Macy {
1119b6d90eb7SKip Macy 	u_int fw_status[4];
1120b6d90eb7SKip Macy 
11215c5df3daSKip Macy 	if (sc->flags & FULL_INIT_DONE) {
11225c5df3daSKip Macy 		t3_sge_stop(sc);
11235c5df3daSKip Macy 		t3_write_reg(sc, A_XGM_TX_CTRL, 0);
11245c5df3daSKip Macy 		t3_write_reg(sc, A_XGM_RX_CTRL, 0);
11255c5df3daSKip Macy 		t3_write_reg(sc, XGM_REG(A_XGM_TX_CTRL, 1), 0);
11265c5df3daSKip Macy 		t3_write_reg(sc, XGM_REG(A_XGM_RX_CTRL, 1), 0);
11275c5df3daSKip Macy 		t3_intr_disable(sc);
11285c5df3daSKip Macy 	}
1129b6d90eb7SKip Macy 	device_printf(sc->dev,"encountered fatal error, operation suspended\n");
1130b6d90eb7SKip Macy 	if (!t3_cim_ctl_blk_read(sc, 0xa0, 4, fw_status))
1131b6d90eb7SKip Macy 		device_printf(sc->dev, "FW_ status: 0x%x, 0x%x, 0x%x, 0x%x\n",
1132b6d90eb7SKip Macy 		    fw_status[0], fw_status[1], fw_status[2], fw_status[3]);
1133b6d90eb7SKip Macy }
1134b6d90eb7SKip Macy 
1135b6d90eb7SKip Macy int
t3_os_find_pci_capability(adapter_t * sc,int cap)1136b6d90eb7SKip Macy t3_os_find_pci_capability(adapter_t *sc, int cap)
1137b6d90eb7SKip Macy {
1138*762d3235SNavdeep Parhar 	int rc, reg = 0;
1139b6d90eb7SKip Macy 
1140*762d3235SNavdeep Parhar 	rc = pci_find_cap(sc->dev, cap, &reg);
1141*762d3235SNavdeep Parhar 	return (rc == 0 ? reg : 0);
1142b6d90eb7SKip Macy }
1143b6d90eb7SKip Macy 
1144b6d90eb7SKip Macy int
t3_os_pci_save_state(struct adapter * sc)1145b6d90eb7SKip Macy t3_os_pci_save_state(struct adapter *sc)
1146b6d90eb7SKip Macy {
1147*762d3235SNavdeep Parhar 	pci_save_state(sc->dev);
1148b6d90eb7SKip Macy 	return (0);
1149b6d90eb7SKip Macy }
1150b6d90eb7SKip Macy 
1151b6d90eb7SKip Macy int
t3_os_pci_restore_state(struct adapter * sc)1152b6d90eb7SKip Macy t3_os_pci_restore_state(struct adapter *sc)
1153b6d90eb7SKip Macy {
1154*762d3235SNavdeep Parhar 	pci_restore_state(sc->dev);
1155b6d90eb7SKip Macy 	return (0);
1156b6d90eb7SKip Macy }
1157b6d90eb7SKip Macy 
1158b6d90eb7SKip Macy /**
1159b6d90eb7SKip Macy  *	t3_os_link_changed - handle link status changes
1160c01f2b83SNavdeep Parhar  *	@sc: the adapter associated with the link change
1161c01f2b83SNavdeep Parhar  *	@port_id: the port index whose link status has changed
116219905d6dSKip Macy  *	@link_status: the new status of the link
1163b6d90eb7SKip Macy  *	@speed: the new speed setting
1164b6d90eb7SKip Macy  *	@duplex: the new duplex setting
1165b6d90eb7SKip Macy  *	@fc: the new flow-control setting
1166b6d90eb7SKip Macy  *
1167b6d90eb7SKip Macy  *	This is the OS-dependent handler for link status changes.  The OS
1168b6d90eb7SKip Macy  *	neutral handler takes care of most of the processing for these events,
1169b6d90eb7SKip Macy  *	then calls this handler for any OS-specific processing.
1170b6d90eb7SKip Macy  */
1171b6d90eb7SKip Macy void
t3_os_link_changed(adapter_t * adapter,int port_id,int link_status,int speed,int duplex,int fc,int mac_was_reset)1172b6d90eb7SKip Macy t3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed,
1173c01f2b83SNavdeep Parhar      int duplex, int fc, int mac_was_reset)
1174b6d90eb7SKip Macy {
1175b6d90eb7SKip Macy 	struct port_info *pi = &adapter->port[port_id];
1176954712e8SJustin Hibbits 	if_t ifp = pi->ifp;
11773f345a5dSKip Macy 
11783f345a5dSKip Macy 	/* no race with detach, so ifp should always be good */
11793f345a5dSKip Macy 	KASSERT(ifp, ("%s: if detached.", __func__));
1180b6d90eb7SKip Macy 
1181c01f2b83SNavdeep Parhar 	/* Reapply mac settings if they were lost due to a reset */
1182c01f2b83SNavdeep Parhar 	if (mac_was_reset) {
1183c01f2b83SNavdeep Parhar 		PORT_LOCK(pi);
1184c01f2b83SNavdeep Parhar 		cxgb_update_mac_settings(pi);
1185c01f2b83SNavdeep Parhar 		PORT_UNLOCK(pi);
1186c01f2b83SNavdeep Parhar 	}
1187c01f2b83SNavdeep Parhar 
1188d722cab4SKip Macy 	if (link_status) {
1189954712e8SJustin Hibbits 		if_setbaudrate(ifp, IF_Mbps(speed));
11903f345a5dSKip Macy 		if_link_state_change(ifp, LINK_STATE_UP);
11910bbdea77SGeorge V. Neville-Neil 	} else
11923f345a5dSKip Macy 		if_link_state_change(ifp, LINK_STATE_DOWN);
1193d722cab4SKip Macy }
1194b6d90eb7SKip Macy 
11959b4de886SKip Macy /**
11969b4de886SKip Macy  *	t3_os_phymod_changed - handle PHY module changes
11979b4de886SKip Macy  *	@phy: the PHY reporting the module change
11989b4de886SKip Macy  *	@mod_type: new module type
11999b4de886SKip Macy  *
12009b4de886SKip Macy  *	This is the OS-dependent handler for PHY module changes.  It is
12019b4de886SKip Macy  *	invoked when a PHY module is removed or inserted for any OS-specific
12029b4de886SKip Macy  *	processing.
12039b4de886SKip Macy  */
t3_os_phymod_changed(struct adapter * adap,int port_id)12049b4de886SKip Macy void t3_os_phymod_changed(struct adapter *adap, int port_id)
12059b4de886SKip Macy {
12069b4de886SKip Macy 	static const char *mod_str[] = {
1207cd5c70b2SNavdeep Parhar 		NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX-L", "unknown"
12089b4de886SKip Macy 	};
12099b4de886SKip Macy 	struct port_info *pi = &adap->port[port_id];
12102975f787SNavdeep Parhar 	int mod = pi->phy.modtype;
12119b4de886SKip Macy 
12122975f787SNavdeep Parhar 	if (mod != pi->media.ifm_cur->ifm_data)
12132975f787SNavdeep Parhar 		cxgb_build_medialist(pi);
12142975f787SNavdeep Parhar 
12152975f787SNavdeep Parhar 	if (mod == phy_modtype_none)
12162975f787SNavdeep Parhar 		if_printf(pi->ifp, "PHY module unplugged\n");
12179b4de886SKip Macy 	else {
12182975f787SNavdeep Parhar 		KASSERT(mod < ARRAY_SIZE(mod_str),
12192975f787SNavdeep Parhar 			("invalid PHY module type %d", mod));
12202975f787SNavdeep Parhar 		if_printf(pi->ifp, "%s PHY module inserted\n", mod_str[mod]);
12219b4de886SKip Macy 	}
12229b4de886SKip Macy }
12239b4de886SKip Macy 
1224b6d90eb7SKip Macy void
t3_os_set_hw_addr(adapter_t * adapter,int port_idx,u8 hw_addr[])1225b6d90eb7SKip Macy t3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[])
1226b6d90eb7SKip Macy {
1227b6d90eb7SKip Macy 
1228b6d90eb7SKip Macy 	/*
1229b6d90eb7SKip Macy 	 * The ifnet might not be allocated before this gets called,
1230b6d90eb7SKip Macy 	 * as this is called early on in attach by t3_prep_adapter
1231b6d90eb7SKip Macy 	 * save the address off in the port structure
1232b6d90eb7SKip Macy 	 */
1233b6d90eb7SKip Macy 	if (cxgb_debug)
1234b6d90eb7SKip Macy 		printf("set_hw_addr on idx %d addr %6D\n", port_idx, hw_addr, ":");
1235b6d90eb7SKip Macy 	bcopy(hw_addr, adapter->port[port_idx].hw_addr, ETHER_ADDR_LEN);
1236b6d90eb7SKip Macy }
1237b6d90eb7SKip Macy 
12383f345a5dSKip Macy /*
12393f345a5dSKip Macy  * Programs the XGMAC based on the settings in the ifnet.  These settings
12403f345a5dSKip Macy  * include MTU, MAC address, mcast addresses, etc.
1241b6d90eb7SKip Macy  */
1242b6d90eb7SKip Macy static void
cxgb_update_mac_settings(struct port_info * p)12433f345a5dSKip Macy cxgb_update_mac_settings(struct port_info *p)
1244b6d90eb7SKip Macy {
1245954712e8SJustin Hibbits 	if_t ifp = p->ifp;
1246b6d90eb7SKip Macy 	struct t3_rx_mode rm;
1247b6d90eb7SKip Macy 	struct cmac *mac = &p->mac;
12484af83c8cSKip Macy 	int mtu, hwtagging;
1249b6d90eb7SKip Macy 
12503f345a5dSKip Macy 	PORT_LOCK_ASSERT_OWNED(p);
1251b6d90eb7SKip Macy 
1252954712e8SJustin Hibbits 	bcopy(if_getlladdr(ifp), p->hw_addr, ETHER_ADDR_LEN);
12534af83c8cSKip Macy 
1254954712e8SJustin Hibbits 	mtu = if_getmtu(ifp);
1255954712e8SJustin Hibbits 	if (if_getcapenable(ifp) & IFCAP_VLAN_MTU)
12564af83c8cSKip Macy 		mtu += ETHER_VLAN_ENCAP_LEN;
12574af83c8cSKip Macy 
1258954712e8SJustin Hibbits 	hwtagging = (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0;
12594af83c8cSKip Macy 
12604af83c8cSKip Macy 	t3_mac_set_mtu(mac, mtu);
12614af83c8cSKip Macy 	t3_set_vlan_accel(p->adapter, 1 << p->tx_chan, hwtagging);
1262b6d90eb7SKip Macy 	t3_mac_set_address(mac, 0, p->hw_addr);
12633f345a5dSKip Macy 	t3_init_rx_mode(&rm, p);
1264b6d90eb7SKip Macy 	t3_mac_set_rx_mode(mac, &rm);
1265b6d90eb7SKip Macy }
1266b6d90eb7SKip Macy 
12678e10660fSKip Macy 
12688e10660fSKip Macy static int
await_mgmt_replies(struct adapter * adap,unsigned long init_cnt,unsigned long n)12698e10660fSKip Macy await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
12708e10660fSKip Macy 			      unsigned long n)
12718e10660fSKip Macy {
12728e10660fSKip Macy 	int attempts = 5;
12738e10660fSKip Macy 
12748e10660fSKip Macy 	while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
12758e10660fSKip Macy 		if (!--attempts)
12768e10660fSKip Macy 			return (ETIMEDOUT);
12778e10660fSKip Macy 		t3_os_sleep(10);
12788e10660fSKip Macy 	}
12798e10660fSKip Macy 	return 0;
12808e10660fSKip Macy }
12818e10660fSKip Macy 
12828e10660fSKip Macy static int
init_tp_parity(struct adapter * adap)12838e10660fSKip Macy init_tp_parity(struct adapter *adap)
12848e10660fSKip Macy {
12858e10660fSKip Macy 	int i;
12868e10660fSKip Macy 	struct mbuf *m;
12878e10660fSKip Macy 	struct cpl_set_tcb_field *greq;
12888e10660fSKip Macy 	unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts;
12898e10660fSKip Macy 
12908e10660fSKip Macy 	t3_tp_set_offload_mode(adap, 1);
12918e10660fSKip Macy 
12928e10660fSKip Macy 	for (i = 0; i < 16; i++) {
12938e10660fSKip Macy 		struct cpl_smt_write_req *req;
12948e10660fSKip Macy 
12958e10660fSKip Macy 		m = m_gethdr(M_WAITOK, MT_DATA);
12968e10660fSKip Macy 		req = mtod(m, struct cpl_smt_write_req *);
12978e10660fSKip Macy 		m->m_len = m->m_pkthdr.len = sizeof(*req);
12988e10660fSKip Macy 		memset(req, 0, sizeof(*req));
12993f345a5dSKip Macy 		req->wr.wrh_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
13008e10660fSKip Macy 		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
13018e10660fSKip Macy 		req->iff = i;
13028e10660fSKip Macy 		t3_mgmt_tx(adap, m);
13038e10660fSKip Macy 	}
13048e10660fSKip Macy 
13058e10660fSKip Macy 	for (i = 0; i < 2048; i++) {
13068e10660fSKip Macy 		struct cpl_l2t_write_req *req;
13078e10660fSKip Macy 
13088e10660fSKip Macy 		m = m_gethdr(M_WAITOK, MT_DATA);
13098e10660fSKip Macy 		req = mtod(m, struct cpl_l2t_write_req *);
13108e10660fSKip Macy 		m->m_len = m->m_pkthdr.len = sizeof(*req);
13118e10660fSKip Macy 		memset(req, 0, sizeof(*req));
13123f345a5dSKip Macy 		req->wr.wrh_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
13138e10660fSKip Macy 		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
13148e10660fSKip Macy 		req->params = htonl(V_L2T_W_IDX(i));
13158e10660fSKip Macy 		t3_mgmt_tx(adap, m);
13168e10660fSKip Macy 	}
13178e10660fSKip Macy 
13188e10660fSKip Macy 	for (i = 0; i < 2048; i++) {
13198e10660fSKip Macy 		struct cpl_rte_write_req *req;
13208e10660fSKip Macy 
13218e10660fSKip Macy 		m = m_gethdr(M_WAITOK, MT_DATA);
13228e10660fSKip Macy 		req = mtod(m, struct cpl_rte_write_req *);
13238e10660fSKip Macy 		m->m_len = m->m_pkthdr.len = sizeof(*req);
13248e10660fSKip Macy 		memset(req, 0, sizeof(*req));
13253f345a5dSKip Macy 		req->wr.wrh_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
13268e10660fSKip Macy 		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
13278e10660fSKip Macy 		req->l2t_idx = htonl(V_L2T_W_IDX(i));
13288e10660fSKip Macy 		t3_mgmt_tx(adap, m);
13298e10660fSKip Macy 	}
13308e10660fSKip Macy 
13318e10660fSKip Macy 	m = m_gethdr(M_WAITOK, MT_DATA);
13328e10660fSKip Macy 	greq = mtod(m, struct cpl_set_tcb_field *);
13338e10660fSKip Macy 	m->m_len = m->m_pkthdr.len = sizeof(*greq);
13348e10660fSKip Macy 	memset(greq, 0, sizeof(*greq));
13353f345a5dSKip Macy 	greq->wr.wrh_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
13368e10660fSKip Macy 	OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0));
13378e10660fSKip Macy 	greq->mask = htobe64(1);
13388e10660fSKip Macy 	t3_mgmt_tx(adap, m);
13398e10660fSKip Macy 
13408e10660fSKip Macy 	i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
13418e10660fSKip Macy 	t3_tp_set_offload_mode(adap, 0);
13428e10660fSKip Macy 	return (i);
13438e10660fSKip Macy }
13448e10660fSKip Macy 
1345b6d90eb7SKip Macy /**
1346b6d90eb7SKip Macy  *	setup_rss - configure Receive Side Steering (per-queue connection demux)
1347b6d90eb7SKip Macy  *	@adap: the adapter
1348b6d90eb7SKip Macy  *
1349b6d90eb7SKip Macy  *	Sets up RSS to distribute packets to multiple receive queues.  We
1350b6d90eb7SKip Macy  *	configure the RSS CPU lookup table to distribute to the number of HW
1351b6d90eb7SKip Macy  *	receive queues, and the response queue lookup table to narrow that
1352b6d90eb7SKip Macy  *	down to the response queues actually configured for each port.
1353b6d90eb7SKip Macy  *	We always configure the RSS mapping for two ports since the mapping
1354b6d90eb7SKip Macy  *	table has plenty of entries.
1355b6d90eb7SKip Macy  */
1356b6d90eb7SKip Macy static void
setup_rss(adapter_t * adap)1357b6d90eb7SKip Macy setup_rss(adapter_t *adap)
1358b6d90eb7SKip Macy {
1359b6d90eb7SKip Macy 	int i;
1360ac3a6d9cSKip Macy 	u_int nq[2];
1361b6d90eb7SKip Macy 	uint8_t cpus[SGE_QSETS + 1];
1362b6d90eb7SKip Macy 	uint16_t rspq_map[RSS_TABLE_SIZE];
13635c5df3daSKip Macy 
1364b6d90eb7SKip Macy 	for (i = 0; i < SGE_QSETS; ++i)
1365b6d90eb7SKip Macy 		cpus[i] = i;
1366b6d90eb7SKip Macy 	cpus[SGE_QSETS] = 0xff;
1367b6d90eb7SKip Macy 
13687ac2e6c3SKip Macy 	nq[0] = nq[1] = 0;
13697ac2e6c3SKip Macy 	for_each_port(adap, i) {
13707ac2e6c3SKip Macy 		const struct port_info *pi = adap2pinfo(adap, i);
13717ac2e6c3SKip Macy 
13727ac2e6c3SKip Macy 		nq[pi->tx_chan] += pi->nqsets;
13737ac2e6c3SKip Macy 	}
1374b6d90eb7SKip Macy 	for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
13758e10660fSKip Macy 		rspq_map[i] = nq[0] ? i % nq[0] : 0;
13768e10660fSKip Macy 		rspq_map[i + RSS_TABLE_SIZE / 2] = nq[1] ? i % nq[1] + nq[0] : 0;
1377b6d90eb7SKip Macy 	}
13786b2eaa83SJohn Baldwin 
1379ac3a6d9cSKip Macy 	/* Calculate the reverse RSS map table */
13806b2eaa83SJohn Baldwin 	for (i = 0; i < SGE_QSETS; ++i)
13816b2eaa83SJohn Baldwin 		adap->rrss_map[i] = 0xff;
1382ac3a6d9cSKip Macy 	for (i = 0; i < RSS_TABLE_SIZE; ++i)
1383ac3a6d9cSKip Macy 		if (adap->rrss_map[rspq_map[i]] == 0xff)
1384ac3a6d9cSKip Macy 			adap->rrss_map[rspq_map[i]] = i;
1385b6d90eb7SKip Macy 
1386b6d90eb7SKip Macy 	t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
1387ac3a6d9cSKip Macy 		      F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | F_OFDMAPEN |
13888e10660fSKip Macy 	              F_RRCPLMAPEN | V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ,
13898e10660fSKip Macy 	              cpus, rspq_map);
1390ac3a6d9cSKip Macy 
1391b6d90eb7SKip Macy }
1392b6d90eb7SKip Macy static void
send_pktsched_cmd(struct adapter * adap,int sched,int qidx,int lo,int hi,int port)1393b6d90eb7SKip Macy send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
1394b6d90eb7SKip Macy 			      int hi, int port)
1395b6d90eb7SKip Macy {
1396b6d90eb7SKip Macy 	struct mbuf *m;
1397b6d90eb7SKip Macy 	struct mngt_pktsched_wr *req;
1398b6d90eb7SKip Macy 
1399c6499eccSGleb Smirnoff 	m = m_gethdr(M_NOWAIT, MT_DATA);
140020fe52b8SKip Macy 	if (m) {
1401d722cab4SKip Macy 		req = mtod(m, struct mngt_pktsched_wr *);
14023f345a5dSKip Macy 		req->wr.wrh_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
1403b6d90eb7SKip Macy 		req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
1404b6d90eb7SKip Macy 		req->sched = sched;
1405b6d90eb7SKip Macy 		req->idx = qidx;
1406b6d90eb7SKip Macy 		req->min = lo;
1407b6d90eb7SKip Macy 		req->max = hi;
1408b6d90eb7SKip Macy 		req->binding = port;
1409b6d90eb7SKip Macy 		m->m_len = m->m_pkthdr.len = sizeof(*req);
1410b6d90eb7SKip Macy 		t3_mgmt_tx(adap, m);
1411b6d90eb7SKip Macy 	}
141220fe52b8SKip Macy }
1413b6d90eb7SKip Macy 
1414b6d90eb7SKip Macy static void
bind_qsets(adapter_t * sc)1415b6d90eb7SKip Macy bind_qsets(adapter_t *sc)
1416b6d90eb7SKip Macy {
1417b6d90eb7SKip Macy 	int i, j;
1418b6d90eb7SKip Macy 
1419b6d90eb7SKip Macy 	for (i = 0; i < (sc)->params.nports; ++i) {
1420b6d90eb7SKip Macy 		const struct port_info *pi = adap2pinfo(sc, i);
1421b6d90eb7SKip Macy 
14225c5df3daSKip Macy 		for (j = 0; j < pi->nqsets; ++j) {
1423b6d90eb7SKip Macy 			send_pktsched_cmd(sc, 1, pi->first_qset + j, -1,
14245c5df3daSKip Macy 					  -1, pi->tx_chan);
14255c5df3daSKip Macy 
14265c5df3daSKip Macy 		}
1427b6d90eb7SKip Macy 	}
1428b6d90eb7SKip Macy }
1429b6d90eb7SKip Macy 
1430ac3a6d9cSKip Macy static void
update_tpeeprom(struct adapter * adap)1431ac3a6d9cSKip Macy update_tpeeprom(struct adapter *adap)
1432ac3a6d9cSKip Macy {
1433ac3a6d9cSKip Macy 	const struct firmware *tpeeprom;
14342de1fa86SKip Macy 
1435ac3a6d9cSKip Macy 	uint32_t version;
1436ac3a6d9cSKip Macy 	unsigned int major, minor;
1437ac3a6d9cSKip Macy 	int ret, len;
1438f2d8ff04SGeorge V. Neville-Neil 	char rev, name[32];
1439ac3a6d9cSKip Macy 
1440ac3a6d9cSKip Macy 	t3_seeprom_read(adap, TP_SRAM_OFFSET, &version);
1441ac3a6d9cSKip Macy 
1442ac3a6d9cSKip Macy 	major = G_TP_VERSION_MAJOR(version);
1443ac3a6d9cSKip Macy 	minor = G_TP_VERSION_MINOR(version);
1444ac3a6d9cSKip Macy 	if (major == TP_VERSION_MAJOR  && minor == TP_VERSION_MINOR)
1445ac3a6d9cSKip Macy 		return;
1446ac3a6d9cSKip Macy 
1447ac3a6d9cSKip Macy 	rev = t3rev2char(adap);
1448f2d8ff04SGeorge V. Neville-Neil 	snprintf(name, sizeof(name), TPEEPROM_NAME, rev);
1449ac3a6d9cSKip Macy 
1450f2d8ff04SGeorge V. Neville-Neil 	tpeeprom = firmware_get(name);
1451ac3a6d9cSKip Macy 	if (tpeeprom == NULL) {
14520c1ff9c6SGeorge V. Neville-Neil 		device_printf(adap->dev,
14530c1ff9c6SGeorge V. Neville-Neil 			      "could not load TP EEPROM: unable to load %s\n",
14540c1ff9c6SGeorge V. Neville-Neil 			      name);
1455ac3a6d9cSKip Macy 		return;
1456ac3a6d9cSKip Macy 	}
1457ac3a6d9cSKip Macy 
1458ac3a6d9cSKip Macy 	len = tpeeprom->datasize - 4;
1459ac3a6d9cSKip Macy 
1460ac3a6d9cSKip Macy 	ret = t3_check_tpsram(adap, tpeeprom->data, tpeeprom->datasize);
1461ac3a6d9cSKip Macy 	if (ret)
1462ac3a6d9cSKip Macy 		goto release_tpeeprom;
1463ac3a6d9cSKip Macy 
1464ac3a6d9cSKip Macy 	if (len != TP_SRAM_LEN) {
14650c1ff9c6SGeorge V. Neville-Neil 		device_printf(adap->dev,
14660c1ff9c6SGeorge V. Neville-Neil 			      "%s length is wrong len=%d expected=%d\n", name,
14670c1ff9c6SGeorge V. Neville-Neil 			      len, TP_SRAM_LEN);
1468ac3a6d9cSKip Macy 		return;
1469ac3a6d9cSKip Macy 	}
1470ac3a6d9cSKip Macy 
1471ac3a6d9cSKip Macy 	ret = set_eeprom(&adap->port[0], tpeeprom->data, tpeeprom->datasize,
1472ac3a6d9cSKip Macy 	    TP_SRAM_OFFSET);
1473ac3a6d9cSKip Macy 
1474ac3a6d9cSKip Macy 	if (!ret) {
1475ac3a6d9cSKip Macy 		device_printf(adap->dev,
1476ac3a6d9cSKip Macy 			"Protocol SRAM image updated in EEPROM to %d.%d.%d\n",
1477ac3a6d9cSKip Macy 			 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1478ac3a6d9cSKip Macy 	} else
14790c1ff9c6SGeorge V. Neville-Neil 		device_printf(adap->dev,
14800c1ff9c6SGeorge V. Neville-Neil 			      "Protocol SRAM image update in EEPROM failed\n");
1481ac3a6d9cSKip Macy 
1482ac3a6d9cSKip Macy release_tpeeprom:
1483ac3a6d9cSKip Macy 	firmware_put(tpeeprom, FIRMWARE_UNLOAD);
1484ac3a6d9cSKip Macy 
1485ac3a6d9cSKip Macy 	return;
1486ac3a6d9cSKip Macy }
1487ac3a6d9cSKip Macy 
1488ac3a6d9cSKip Macy static int
update_tpsram(struct adapter * adap)1489ac3a6d9cSKip Macy update_tpsram(struct adapter *adap)
1490ac3a6d9cSKip Macy {
1491ac3a6d9cSKip Macy 	const struct firmware *tpsram;
1492ac3a6d9cSKip Macy 	int ret;
1493f2d8ff04SGeorge V. Neville-Neil 	char rev, name[32];
1494ac3a6d9cSKip Macy 
1495ac3a6d9cSKip Macy 	rev = t3rev2char(adap);
1496f2d8ff04SGeorge V. Neville-Neil 	snprintf(name, sizeof(name), TPSRAM_NAME, rev);
1497ac3a6d9cSKip Macy 
1498ac3a6d9cSKip Macy 	update_tpeeprom(adap);
1499ac3a6d9cSKip Macy 
1500f2d8ff04SGeorge V. Neville-Neil 	tpsram = firmware_get(name);
1501ac3a6d9cSKip Macy 	if (tpsram == NULL){
150264a37133SKip Macy 		device_printf(adap->dev, "could not load TP SRAM\n");
1503ac3a6d9cSKip Macy 		return (EINVAL);
1504ac3a6d9cSKip Macy 	} else
150564a37133SKip Macy 		device_printf(adap->dev, "updating TP SRAM\n");
1506ac3a6d9cSKip Macy 
1507ac3a6d9cSKip Macy 	ret = t3_check_tpsram(adap, tpsram->data, tpsram->datasize);
1508ac3a6d9cSKip Macy 	if (ret)
1509ac3a6d9cSKip Macy 		goto release_tpsram;
1510ac3a6d9cSKip Macy 
1511ac3a6d9cSKip Macy 	ret = t3_set_proto_sram(adap, tpsram->data);
1512ac3a6d9cSKip Macy 	if (ret)
1513ac3a6d9cSKip Macy 		device_printf(adap->dev, "loading protocol SRAM failed\n");
1514ac3a6d9cSKip Macy 
1515ac3a6d9cSKip Macy release_tpsram:
1516ac3a6d9cSKip Macy 	firmware_put(tpsram, FIRMWARE_UNLOAD);
1517ac3a6d9cSKip Macy 
1518ac3a6d9cSKip Macy 	return ret;
1519ac3a6d9cSKip Macy }
1520ac3a6d9cSKip Macy 
1521d722cab4SKip Macy /**
1522d722cab4SKip Macy  *	cxgb_up - enable the adapter
1523d722cab4SKip Macy  *	@adap: adapter being enabled
1524d722cab4SKip Macy  *
1525d722cab4SKip Macy  *	Called when the first port is enabled, this function performs the
1526d722cab4SKip Macy  *	actions necessary to make an adapter operational, such as completing
1527d722cab4SKip Macy  *	the initialization of HW modules, and enabling interrupts.
1528d722cab4SKip Macy  */
1529d722cab4SKip Macy static int
cxgb_up(struct adapter * sc)1530d722cab4SKip Macy cxgb_up(struct adapter *sc)
1531d722cab4SKip Macy {
1532d722cab4SKip Macy 	int err = 0;
15333a2c6562SNavdeep Parhar 	unsigned int mxf = t3_mc5_size(&sc->mc5) - MC5_MIN_TIDS;
1534d722cab4SKip Macy 
15353f345a5dSKip Macy 	KASSERT(sc->open_device_map == 0, ("%s: device(s) already open (%x)",
15363f345a5dSKip Macy 					   __func__, sc->open_device_map));
15373f345a5dSKip Macy 
1538d722cab4SKip Macy 	if ((sc->flags & FULL_INIT_DONE) == 0) {
1539d722cab4SKip Macy 
1540b302b77cSNavdeep Parhar 		ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1541b302b77cSNavdeep Parhar 
1542d722cab4SKip Macy 		if ((sc->flags & FW_UPTODATE) == 0)
1543ac3a6d9cSKip Macy 			if ((err = upgrade_fw(sc)))
1544d722cab4SKip Macy 				goto out;
15453f345a5dSKip Macy 
1546ac3a6d9cSKip Macy 		if ((sc->flags & TPS_UPTODATE) == 0)
1547ac3a6d9cSKip Macy 			if ((err = update_tpsram(sc)))
1548ac3a6d9cSKip Macy 				goto out;
15493f345a5dSKip Macy 
15503a2c6562SNavdeep Parhar 		if (is_offload(sc) && nfilters != 0) {
1551d6da8362SNavdeep Parhar 			sc->params.mc5.nservers = 0;
15523a2c6562SNavdeep Parhar 
15533a2c6562SNavdeep Parhar 			if (nfilters < 0)
15543a2c6562SNavdeep Parhar 				sc->params.mc5.nfilters = mxf;
15553a2c6562SNavdeep Parhar 			else
15563a2c6562SNavdeep Parhar 				sc->params.mc5.nfilters = min(nfilters, mxf);
1557d6da8362SNavdeep Parhar 		}
1558d6da8362SNavdeep Parhar 
1559d722cab4SKip Macy 		err = t3_init_hw(sc, 0);
1560d722cab4SKip Macy 		if (err)
1561d722cab4SKip Macy 			goto out;
1562d722cab4SKip Macy 
15638e10660fSKip Macy 		t3_set_reg_field(sc, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT);
1564d722cab4SKip Macy 		t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
1565d722cab4SKip Macy 
1566d722cab4SKip Macy 		err = setup_sge_qsets(sc);
1567d722cab4SKip Macy 		if (err)
1568d722cab4SKip Macy 			goto out;
1569d722cab4SKip Macy 
1570d6da8362SNavdeep Parhar 		alloc_filters(sc);
1571d722cab4SKip Macy 		setup_rss(sc);
1572e3503bc9SGeorge V. Neville-Neil 
15738090c9f5SKip Macy 		t3_add_configured_sysctls(sc);
1574d722cab4SKip Macy 		sc->flags |= FULL_INIT_DONE;
1575d722cab4SKip Macy 	}
1576d722cab4SKip Macy 
1577d722cab4SKip Macy 	t3_intr_clear(sc);
1578d722cab4SKip Macy 	t3_sge_start(sc);
1579d722cab4SKip Macy 	t3_intr_enable(sc);
1580d722cab4SKip Macy 
15818e10660fSKip Macy 	if (sc->params.rev >= T3_REV_C && !(sc->flags & TP_PARITY_INIT) &&
15828e10660fSKip Macy 	    is_offload(sc) && init_tp_parity(sc) == 0)
15838e10660fSKip Macy 		sc->flags |= TP_PARITY_INIT;
15848e10660fSKip Macy 
15858e10660fSKip Macy 	if (sc->flags & TP_PARITY_INIT) {
15863f345a5dSKip Macy 		t3_write_reg(sc, A_TP_INT_CAUSE, F_CMCACHEPERR | F_ARPLUTPERR);
15878e10660fSKip Macy 		t3_write_reg(sc, A_TP_INT_ENABLE, 0x7fbfffff);
15888e10660fSKip Macy 	}
15898e10660fSKip Macy 
15905c5df3daSKip Macy 	if (!(sc->flags & QUEUES_BOUND)) {
1591d722cab4SKip Macy 		bind_qsets(sc);
1592d6da8362SNavdeep Parhar 		setup_hw_filters(sc);
1593d722cab4SKip Macy 		sc->flags |= QUEUES_BOUND;
1594ac3a6d9cSKip Macy 	}
15953f345a5dSKip Macy 
15963f345a5dSKip Macy 	t3_sge_reset_adapter(sc);
1597d722cab4SKip Macy out:
1598d722cab4SKip Macy 	return (err);
1599d722cab4SKip Macy }
1600d722cab4SKip Macy 
1601d722cab4SKip Macy /*
16023f345a5dSKip Macy  * Called when the last open device is closed.  Does NOT undo all of cxgb_up's
16033f345a5dSKip Macy  * work.  Specifically, the resources grabbed under FULL_INIT_DONE are released
16043f345a5dSKip Macy  * during controller_detach, not here.
1605d722cab4SKip Macy  */
1606d722cab4SKip Macy static void
cxgb_down(struct adapter * sc)16073f345a5dSKip Macy cxgb_down(struct adapter *sc)
1608d722cab4SKip Macy {
1609d722cab4SKip Macy 	t3_sge_stop(sc);
1610d722cab4SKip Macy 	t3_intr_disable(sc);
1611d722cab4SKip Macy }
1612d722cab4SKip Macy 
16133f345a5dSKip Macy /*
16143f345a5dSKip Macy  * if_init for cxgb ports.
16153f345a5dSKip Macy  */
1616b6d90eb7SKip Macy static void
cxgb_init(void * arg)1617b6d90eb7SKip Macy cxgb_init(void *arg)
1618b6d90eb7SKip Macy {
1619b6d90eb7SKip Macy 	struct port_info *p = arg;
1620b302b77cSNavdeep Parhar 	struct adapter *sc = p->adapter;
1621b6d90eb7SKip Macy 
1622b302b77cSNavdeep Parhar 	ADAPTER_LOCK(sc);
1623b302b77cSNavdeep Parhar 	cxgb_init_locked(p); /* releases adapter lock */
1624b302b77cSNavdeep Parhar 	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
16253f345a5dSKip Macy }
16263f345a5dSKip Macy 
16273f345a5dSKip Macy static int
cxgb_init_locked(struct port_info * p)1628b302b77cSNavdeep Parhar cxgb_init_locked(struct port_info *p)
16293f345a5dSKip Macy {
16303f345a5dSKip Macy 	struct adapter *sc = p->adapter;
1631954712e8SJustin Hibbits 	if_t ifp = p->ifp;
16323f345a5dSKip Macy 	struct cmac *mac = &p->mac;
163361cb6c90SNavdeep Parhar 	int i, rc = 0, may_sleep = 0, gave_up_lock = 0;
1634b302b77cSNavdeep Parhar 
1635b302b77cSNavdeep Parhar 	ADAPTER_LOCK_ASSERT_OWNED(sc);
1636b302b77cSNavdeep Parhar 
1637b302b77cSNavdeep Parhar 	while (!IS_DOOMED(p) && IS_BUSY(sc)) {
163861cb6c90SNavdeep Parhar 		gave_up_lock = 1;
1639b302b77cSNavdeep Parhar 		if (mtx_sleep(&sc->flags, &sc->lock, PCATCH, "cxgbinit", 0)) {
1640b302b77cSNavdeep Parhar 			rc = EINTR;
1641b302b77cSNavdeep Parhar 			goto done;
1642b302b77cSNavdeep Parhar 		}
1643b302b77cSNavdeep Parhar 	}
1644b302b77cSNavdeep Parhar 	if (IS_DOOMED(p)) {
1645b302b77cSNavdeep Parhar 		rc = ENXIO;
1646b302b77cSNavdeep Parhar 		goto done;
1647b302b77cSNavdeep Parhar 	}
1648b302b77cSNavdeep Parhar 	KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__));
1649b302b77cSNavdeep Parhar 
1650b302b77cSNavdeep Parhar 	/*
1651b302b77cSNavdeep Parhar 	 * The code that runs during one-time adapter initialization can sleep
1652b302b77cSNavdeep Parhar 	 * so it's important not to hold any locks across it.
1653b302b77cSNavdeep Parhar 	 */
1654b302b77cSNavdeep Parhar 	may_sleep = sc->flags & FULL_INIT_DONE ? 0 : 1;
1655b302b77cSNavdeep Parhar 
1656b302b77cSNavdeep Parhar 	if (may_sleep) {
1657b302b77cSNavdeep Parhar 		SET_BUSY(sc);
165861cb6c90SNavdeep Parhar 		gave_up_lock = 1;
1659b302b77cSNavdeep Parhar 		ADAPTER_UNLOCK(sc);
1660b302b77cSNavdeep Parhar 	}
16613f345a5dSKip Macy 
166209fe6320SNavdeep Parhar 	if (sc->open_device_map == 0 && ((rc = cxgb_up(sc)) != 0))
1663b302b77cSNavdeep Parhar 			goto done;
16643f345a5dSKip Macy 
16653f345a5dSKip Macy 	PORT_LOCK(p);
1666b302b77cSNavdeep Parhar 	if (isset(&sc->open_device_map, p->port_id) &&
1667954712e8SJustin Hibbits 	    (if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
1668b302b77cSNavdeep Parhar 		PORT_UNLOCK(p);
1669b302b77cSNavdeep Parhar 		goto done;
1670b302b77cSNavdeep Parhar 	}
16710bbdea77SGeorge V. Neville-Neil 	t3_port_intr_enable(sc, p->port_id);
16723f345a5dSKip Macy 	if (!mac->multiport)
1673c01f2b83SNavdeep Parhar 		t3_mac_init(mac);
16743f345a5dSKip Macy 	cxgb_update_mac_settings(p);
16753f345a5dSKip Macy 	t3_link_start(&p->phy, mac, &p->link_config);
16763f345a5dSKip Macy 	t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
1677954712e8SJustin Hibbits 	if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
16783f345a5dSKip Macy 	PORT_UNLOCK(p);
16793f345a5dSKip Macy 
16803f345a5dSKip Macy 	for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) {
16813f345a5dSKip Macy 		struct sge_qset *qs = &sc->sge.qs[i];
16823f345a5dSKip Macy 		struct sge_txq *txq = &qs->txq[TXQ_ETH];
16833f345a5dSKip Macy 
16843f345a5dSKip Macy 		callout_reset_on(&txq->txq_watchdog, hz, cxgb_tx_watchdog, qs,
16853f345a5dSKip Macy 				 txq->txq_watchdog.c_cpu);
1686b6d90eb7SKip Macy 	}
1687b6d90eb7SKip Macy 
16883f345a5dSKip Macy 	/* all ok */
16893f345a5dSKip Macy 	setbit(&sc->open_device_map, p->port_id);
1690bd1a9fbaSNavdeep Parhar 	callout_reset(&p->link_check_ch,
1691bd1a9fbaSNavdeep Parhar 	    p->phy.caps & SUPPORTED_LINK_IRQ ?  hz * 3 : hz / 4,
1692bd1a9fbaSNavdeep Parhar 	    link_check_callout, p);
1693b6d90eb7SKip Macy 
1694b302b77cSNavdeep Parhar done:
1695b302b77cSNavdeep Parhar 	if (may_sleep) {
1696b302b77cSNavdeep Parhar 		ADAPTER_LOCK(sc);
1697b302b77cSNavdeep Parhar 		KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__));
1698b302b77cSNavdeep Parhar 		CLR_BUSY(sc);
1699b302b77cSNavdeep Parhar 	}
170061cb6c90SNavdeep Parhar 	if (gave_up_lock)
170161cb6c90SNavdeep Parhar 		wakeup_one(&sc->flags);
1702b302b77cSNavdeep Parhar 	ADAPTER_UNLOCK(sc);
1703b302b77cSNavdeep Parhar 	return (rc);
1704b302b77cSNavdeep Parhar }
1705b302b77cSNavdeep Parhar 
1706b302b77cSNavdeep Parhar static int
cxgb_uninit_locked(struct port_info * p)1707b302b77cSNavdeep Parhar cxgb_uninit_locked(struct port_info *p)
1708b302b77cSNavdeep Parhar {
1709b302b77cSNavdeep Parhar 	struct adapter *sc = p->adapter;
1710b302b77cSNavdeep Parhar 	int rc;
1711b302b77cSNavdeep Parhar 
1712b302b77cSNavdeep Parhar 	ADAPTER_LOCK_ASSERT_OWNED(sc);
1713b302b77cSNavdeep Parhar 
1714b302b77cSNavdeep Parhar 	while (!IS_DOOMED(p) && IS_BUSY(sc)) {
1715b302b77cSNavdeep Parhar 		if (mtx_sleep(&sc->flags, &sc->lock, PCATCH, "cxgbunin", 0)) {
1716b302b77cSNavdeep Parhar 			rc = EINTR;
1717b302b77cSNavdeep Parhar 			goto done;
1718b302b77cSNavdeep Parhar 		}
1719b302b77cSNavdeep Parhar 	}
1720b302b77cSNavdeep Parhar 	if (IS_DOOMED(p)) {
1721b302b77cSNavdeep Parhar 		rc = ENXIO;
1722b302b77cSNavdeep Parhar 		goto done;
1723b302b77cSNavdeep Parhar 	}
1724b302b77cSNavdeep Parhar 	KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__));
1725b302b77cSNavdeep Parhar 	SET_BUSY(sc);
1726b302b77cSNavdeep Parhar 	ADAPTER_UNLOCK(sc);
1727b302b77cSNavdeep Parhar 
1728b302b77cSNavdeep Parhar 	rc = cxgb_uninit_synchronized(p);
1729b302b77cSNavdeep Parhar 
1730b302b77cSNavdeep Parhar 	ADAPTER_LOCK(sc);
1731b302b77cSNavdeep Parhar 	KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__));
1732b302b77cSNavdeep Parhar 	CLR_BUSY(sc);
1733b302b77cSNavdeep Parhar 	wakeup_one(&sc->flags);
1734b302b77cSNavdeep Parhar done:
1735b302b77cSNavdeep Parhar 	ADAPTER_UNLOCK(sc);
1736b302b77cSNavdeep Parhar 	return (rc);
1737b6d90eb7SKip Macy }
1738b6d90eb7SKip Macy 
17393f345a5dSKip Macy /*
17403f345a5dSKip Macy  * Called on "ifconfig down", and from port_detach
17413f345a5dSKip Macy  */
17423f345a5dSKip Macy static int
cxgb_uninit_synchronized(struct port_info * pi)17433f345a5dSKip Macy cxgb_uninit_synchronized(struct port_info *pi)
1744b6d90eb7SKip Macy {
17453f345a5dSKip Macy 	struct adapter *sc = pi->adapter;
1746954712e8SJustin Hibbits 	if_t ifp = pi->ifp;
1747b6d90eb7SKip Macy 
17483f345a5dSKip Macy 	/*
1749b302b77cSNavdeep Parhar 	 * taskqueue_drain may cause a deadlock if the adapter lock is held.
1750b302b77cSNavdeep Parhar 	 */
1751b302b77cSNavdeep Parhar 	ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1752b302b77cSNavdeep Parhar 
1753b302b77cSNavdeep Parhar 	/*
17543f345a5dSKip Macy 	 * Clear this port's bit from the open device map, and then drain all
17553f345a5dSKip Macy 	 * the tasks that can access/manipulate this port's port_info or ifp.
17566bccea7cSRebecca Cran 	 * We disable this port's interrupts here and so the slow/ext
17573f345a5dSKip Macy 	 * interrupt tasks won't be enqueued.  The tick task will continue to
17583f345a5dSKip Macy 	 * be enqueued every second but the runs after this drain will not see
17593f345a5dSKip Macy 	 * this port in the open device map.
17603f345a5dSKip Macy 	 *
17613f345a5dSKip Macy 	 * A well behaved task must take open_device_map into account and ignore
17623f345a5dSKip Macy 	 * ports that are not open.
17633f345a5dSKip Macy 	 */
17643f345a5dSKip Macy 	clrbit(&sc->open_device_map, pi->port_id);
17653f345a5dSKip Macy 	t3_port_intr_disable(sc, pi->port_id);
17663f345a5dSKip Macy 	taskqueue_drain(sc->tq, &sc->slow_intr_task);
17673f345a5dSKip Macy 	taskqueue_drain(sc->tq, &sc->tick_task);
176877f07749SKip Macy 
1769bd1a9fbaSNavdeep Parhar 	callout_drain(&pi->link_check_ch);
1770bd1a9fbaSNavdeep Parhar 	taskqueue_drain(sc->tq, &pi->link_check_task);
1771bd1a9fbaSNavdeep Parhar 
17723f345a5dSKip Macy 	PORT_LOCK(pi);
1773954712e8SJustin Hibbits 	if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1774b6d90eb7SKip Macy 
177519905d6dSKip Macy 	/* disable pause frames */
17763f345a5dSKip Macy 	t3_set_reg_field(sc, A_XGM_TX_CFG + pi->mac.offset, F_TXPAUSEEN, 0);
1777bb38cd2fSKip Macy 
177819905d6dSKip Macy 	/* Reset RX FIFO HWM */
17793f345a5dSKip Macy 	t3_set_reg_field(sc, A_XGM_RXFIFO_CFG +  pi->mac.offset,
178019905d6dSKip Macy 			 V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM), 0);
178119905d6dSKip Macy 
1782a9c23ef0SNavdeep Parhar 	DELAY(100 * 1000);
178319905d6dSKip Macy 
178419905d6dSKip Macy 	/* Wait for TXFIFO empty */
17853f345a5dSKip Macy 	t3_wait_op_done(sc, A_XGM_TXFIFO_CFG + pi->mac.offset,
178619905d6dSKip Macy 			F_TXFIFO_EMPTY, 1, 20, 5);
178719905d6dSKip Macy 
1788a9c23ef0SNavdeep Parhar 	DELAY(100 * 1000);
1789a9c23ef0SNavdeep Parhar 	t3_mac_disable(&pi->mac, MAC_DIRECTION_RX);
179019905d6dSKip Macy 
179119905d6dSKip Macy 	pi->phy.ops->power_down(&pi->phy, 1);
1792bb38cd2fSKip Macy 
17933f345a5dSKip Macy 	PORT_UNLOCK(pi);
1794b6d90eb7SKip Macy 
17953f345a5dSKip Macy 	pi->link_config.link_ok = 0;
1796c01f2b83SNavdeep Parhar 	t3_os_link_changed(sc, pi->port_id, 0, 0, 0, 0, 0);
1797ef72318fSKip Macy 
17983f345a5dSKip Macy 	if (sc->open_device_map == 0)
17993f345a5dSKip Macy 		cxgb_down(pi->adapter);
18003f345a5dSKip Macy 
18013f345a5dSKip Macy 	return (0);
1802ef72318fSKip Macy }
1803ef72318fSKip Macy 
180425292debSKip Macy /*
180525292debSKip Macy  * Mark lro enabled or disabled in all qsets for this port
180625292debSKip Macy  */
180725292debSKip Macy static int
cxgb_set_lro(struct port_info * p,int enabled)180825292debSKip Macy cxgb_set_lro(struct port_info *p, int enabled)
180925292debSKip Macy {
181025292debSKip Macy 	int i;
181125292debSKip Macy 	struct adapter *adp = p->adapter;
181225292debSKip Macy 	struct sge_qset *q;
181325292debSKip Macy 
181425292debSKip Macy 	for (i = 0; i < p->nqsets; i++) {
181525292debSKip Macy 		q = &adp->sge.qs[p->first_qset + i];
181625292debSKip Macy 		q->lro.enabled = (enabled != 0);
181725292debSKip Macy 	}
181825292debSKip Macy 	return (0);
181925292debSKip Macy }
182025292debSKip Macy 
1821ef72318fSKip Macy static int
cxgb_ioctl(if_t ifp,unsigned long command,caddr_t data)1822954712e8SJustin Hibbits cxgb_ioctl(if_t ifp, unsigned long command, caddr_t data)
1823b6d90eb7SKip Macy {
1824954712e8SJustin Hibbits 	struct port_info *p = if_getsoftc(ifp);
1825b302b77cSNavdeep Parhar 	struct adapter *sc = p->adapter;
1826b6d90eb7SKip Macy 	struct ifreq *ifr = (struct ifreq *)data;
1827b302b77cSNavdeep Parhar 	int flags, error = 0, mtu;
1828b6d90eb7SKip Macy 	uint32_t mask;
1829b6d90eb7SKip Macy 
1830b6d90eb7SKip Macy 	switch (command) {
1831b6d90eb7SKip Macy 	case SIOCSIFMTU:
1832b302b77cSNavdeep Parhar 		ADAPTER_LOCK(sc);
1833b302b77cSNavdeep Parhar 		error = IS_DOOMED(p) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
1834b302b77cSNavdeep Parhar 		if (error) {
1835b302b77cSNavdeep Parhar fail:
1836b302b77cSNavdeep Parhar 			ADAPTER_UNLOCK(sc);
1837b302b77cSNavdeep Parhar 			return (error);
1838b302b77cSNavdeep Parhar 		}
1839b302b77cSNavdeep Parhar 
18403f345a5dSKip Macy 		mtu = ifr->ifr_mtu;
18413f345a5dSKip Macy 		if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) {
18423f345a5dSKip Macy 			error = EINVAL;
18433f345a5dSKip Macy 		} else {
1844954712e8SJustin Hibbits 			if_setmtu(ifp, mtu);
18458e10660fSKip Macy 			PORT_LOCK(p);
18463f345a5dSKip Macy 			cxgb_update_mac_settings(p);
18474f6a96aeSKip Macy 			PORT_UNLOCK(p);
18488e10660fSKip Macy 		}
1849b302b77cSNavdeep Parhar 		ADAPTER_UNLOCK(sc);
1850b6d90eb7SKip Macy 		break;
1851b6d90eb7SKip Macy 	case SIOCSIFFLAGS:
1852b302b77cSNavdeep Parhar 		ADAPTER_LOCK(sc);
1853b302b77cSNavdeep Parhar 		if (IS_DOOMED(p)) {
1854b302b77cSNavdeep Parhar 			error = ENXIO;
1855b302b77cSNavdeep Parhar 			goto fail;
1856b302b77cSNavdeep Parhar 		}
1857954712e8SJustin Hibbits 		if (if_getflags(ifp) & IFF_UP) {
1858954712e8SJustin Hibbits 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
1859b6d90eb7SKip Macy 				flags = p->if_flags;
1860954712e8SJustin Hibbits 				if (((if_getflags(ifp) ^ flags) & IFF_PROMISC) ||
1861954712e8SJustin Hibbits 				    ((if_getflags(ifp) ^ flags) & IFF_ALLMULTI)) {
1862b302b77cSNavdeep Parhar 					if (IS_BUSY(sc)) {
1863b302b77cSNavdeep Parhar 						error = EBUSY;
1864b302b77cSNavdeep Parhar 						goto fail;
1865b302b77cSNavdeep Parhar 					}
18663f345a5dSKip Macy 					PORT_LOCK(p);
18673f345a5dSKip Macy 					cxgb_update_mac_settings(p);
18683f345a5dSKip Macy 					PORT_UNLOCK(p);
18693f345a5dSKip Macy 				}
1870b302b77cSNavdeep Parhar 				ADAPTER_UNLOCK(sc);
1871b6d90eb7SKip Macy 			} else
1872b302b77cSNavdeep Parhar 				error = cxgb_init_locked(p);
1873954712e8SJustin Hibbits 			p->if_flags = if_getflags(ifp);
1874954712e8SJustin Hibbits 		} else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
1875b302b77cSNavdeep Parhar 			error = cxgb_uninit_locked(p);
18763c0e59deSNavdeep Parhar 		else
18773c0e59deSNavdeep Parhar 			ADAPTER_UNLOCK(sc);
1878bb38cd2fSKip Macy 
1879b302b77cSNavdeep Parhar 		ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1880b6d90eb7SKip Macy 		break;
18818e10660fSKip Macy 	case SIOCADDMULTI:
18828e10660fSKip Macy 	case SIOCDELMULTI:
1883b302b77cSNavdeep Parhar 		ADAPTER_LOCK(sc);
1884b302b77cSNavdeep Parhar 		error = IS_DOOMED(p) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
1885b302b77cSNavdeep Parhar 		if (error)
1886b302b77cSNavdeep Parhar 			goto fail;
1887b302b77cSNavdeep Parhar 
1888954712e8SJustin Hibbits 		if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
1889837f41b0SGeorge V. Neville-Neil 			PORT_LOCK(p);
18903f345a5dSKip Macy 			cxgb_update_mac_settings(p);
1891837f41b0SGeorge V. Neville-Neil 			PORT_UNLOCK(p);
18923f345a5dSKip Macy 		}
1893b302b77cSNavdeep Parhar 		ADAPTER_UNLOCK(sc);
18943f345a5dSKip Macy 
1895b6d90eb7SKip Macy 		break;
1896b6d90eb7SKip Macy 	case SIOCSIFCAP:
1897b302b77cSNavdeep Parhar 		ADAPTER_LOCK(sc);
1898b302b77cSNavdeep Parhar 		error = IS_DOOMED(p) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
1899b302b77cSNavdeep Parhar 		if (error)
1900b302b77cSNavdeep Parhar 			goto fail;
1901b302b77cSNavdeep Parhar 
1902954712e8SJustin Hibbits 		mask = ifr->ifr_reqcap ^ if_getcapenable(ifp);
1903b6d90eb7SKip Macy 		if (mask & IFCAP_TXCSUM) {
1904954712e8SJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TXCSUM);
1905954712e8SJustin Hibbits 			if_togglehwassist(ifp, CSUM_TCP | CSUM_UDP | CSUM_IP);
1906f9c6e164SNavdeep Parhar 
1907954712e8SJustin Hibbits 			if (IFCAP_TSO4 & if_getcapenable(ifp) &&
1908954712e8SJustin Hibbits 			    !(IFCAP_TXCSUM & if_getcapenable(ifp))) {
1909cbb9ccf7SRyan Moeller 				mask &= ~IFCAP_TSO4;
1910954712e8SJustin Hibbits 				if_setcapenablebit(ifp, 0, IFCAP_TSO4);
1911f9c6e164SNavdeep Parhar 				if_printf(ifp,
19120a704909SNavdeep Parhar 				    "tso4 disabled due to -txcsum.\n");
19130a704909SNavdeep Parhar 			}
19140a704909SNavdeep Parhar 		}
19150a704909SNavdeep Parhar 		if (mask & IFCAP_TXCSUM_IPV6) {
1916954712e8SJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TXCSUM_IPV6);
1917954712e8SJustin Hibbits 			if_togglehwassist(ifp, CSUM_UDP_IPV6 | CSUM_TCP_IPV6);
19180a704909SNavdeep Parhar 
1919954712e8SJustin Hibbits 			if (IFCAP_TSO6 & if_getcapenable(ifp) &&
1920954712e8SJustin Hibbits 			    !(IFCAP_TXCSUM_IPV6 & if_getcapenable(ifp))) {
1921cbb9ccf7SRyan Moeller 				mask &= ~IFCAP_TSO6;
1922954712e8SJustin Hibbits 				if_setcapenablebit(ifp, 0, IFCAP_TSO6);
19230a704909SNavdeep Parhar 				if_printf(ifp,
19240a704909SNavdeep Parhar 				    "tso6 disabled due to -txcsum6.\n");
1925f9c6e164SNavdeep Parhar 			}
1926f9c6e164SNavdeep Parhar 		}
1927f9c6e164SNavdeep Parhar 		if (mask & IFCAP_RXCSUM)
1928954712e8SJustin Hibbits 			if_togglecapenable(ifp, IFCAP_RXCSUM);
19290a704909SNavdeep Parhar 		if (mask & IFCAP_RXCSUM_IPV6)
1930954712e8SJustin Hibbits 			if_togglecapenable(ifp, IFCAP_RXCSUM_IPV6);
1931f9c6e164SNavdeep Parhar 
19320a704909SNavdeep Parhar 		/*
19330a704909SNavdeep Parhar 		 * Note that we leave CSUM_TSO alone (it is always set).  The
19340a704909SNavdeep Parhar 		 * kernel takes both IFCAP_TSOx and CSUM_TSO into account before
19350a704909SNavdeep Parhar 		 * sending a TSO request our way, so it's sufficient to toggle
19360a704909SNavdeep Parhar 		 * IFCAP_TSOx only.
19370a704909SNavdeep Parhar 		 */
19380a704909SNavdeep Parhar 		if (mask & IFCAP_TSO4) {
1939954712e8SJustin Hibbits 			if (!(IFCAP_TSO4 & if_getcapenable(ifp)) &&
1940954712e8SJustin Hibbits 			    !(IFCAP_TXCSUM & if_getcapenable(ifp))) {
19410a704909SNavdeep Parhar 				if_printf(ifp, "enable txcsum first.\n");
1942f9c6e164SNavdeep Parhar 				error = EAGAIN;
19430a704909SNavdeep Parhar 				goto fail;
1944f9c6e164SNavdeep Parhar 			}
1945954712e8SJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TSO4);
19460a704909SNavdeep Parhar 		}
19470a704909SNavdeep Parhar 		if (mask & IFCAP_TSO6) {
1948954712e8SJustin Hibbits 			if (!(IFCAP_TSO6 & if_getcapenable(ifp)) &&
1949954712e8SJustin Hibbits 			    !(IFCAP_TXCSUM_IPV6 & if_getcapenable(ifp))) {
19500a704909SNavdeep Parhar 				if_printf(ifp, "enable txcsum6 first.\n");
19510a704909SNavdeep Parhar 				error = EAGAIN;
19520a704909SNavdeep Parhar 				goto fail;
19530a704909SNavdeep Parhar 			}
1954954712e8SJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TSO6);
1955b6d90eb7SKip Macy 		}
195625292debSKip Macy 		if (mask & IFCAP_LRO) {
1957954712e8SJustin Hibbits 			if_togglecapenable(ifp, IFCAP_LRO);
195825292debSKip Macy 
195925292debSKip Macy 			/* Safe to do this even if cxgb_up not called yet */
1960954712e8SJustin Hibbits 			cxgb_set_lro(p, if_getcapenable(ifp) & IFCAP_LRO);
196125292debSKip Macy 		}
196209fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
196309fe6320SNavdeep Parhar 		if (mask & IFCAP_TOE4) {
1964954712e8SJustin Hibbits 			int enable = (if_getcapenable(ifp) ^ mask) & IFCAP_TOE4;
196509fe6320SNavdeep Parhar 
196609fe6320SNavdeep Parhar 			error = toe_capability(p, enable);
196709fe6320SNavdeep Parhar 			if (error == 0)
1968954712e8SJustin Hibbits 				if_togglecapenable(ifp, mask);
196909fe6320SNavdeep Parhar 		}
197009fe6320SNavdeep Parhar #endif
19714af83c8cSKip Macy 		if (mask & IFCAP_VLAN_HWTAGGING) {
1972954712e8SJustin Hibbits 			if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING);
1973954712e8SJustin Hibbits 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
19743f345a5dSKip Macy 				PORT_LOCK(p);
19753f345a5dSKip Macy 				cxgb_update_mac_settings(p);
19763f345a5dSKip Macy 				PORT_UNLOCK(p);
19773f345a5dSKip Macy 			}
19784af83c8cSKip Macy 		}
19794af83c8cSKip Macy 		if (mask & IFCAP_VLAN_MTU) {
1980954712e8SJustin Hibbits 			if_togglecapenable(ifp, IFCAP_VLAN_MTU);
1981954712e8SJustin Hibbits 			if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
19823f345a5dSKip Macy 				PORT_LOCK(p);
19833f345a5dSKip Macy 				cxgb_update_mac_settings(p);
19843f345a5dSKip Macy 				PORT_UNLOCK(p);
19853f345a5dSKip Macy 			}
19864af83c8cSKip Macy 		}
1987f9c6e164SNavdeep Parhar 		if (mask & IFCAP_VLAN_HWTSO)
1988954712e8SJustin Hibbits 			if_togglecapenable(ifp, IFCAP_VLAN_HWTSO);
1989b302b77cSNavdeep Parhar 		if (mask & IFCAP_VLAN_HWCSUM)
1990954712e8SJustin Hibbits 			if_togglecapenable(ifp, IFCAP_VLAN_HWCSUM);
19914af83c8cSKip Macy 
19924af83c8cSKip Macy #ifdef VLAN_CAPABILITIES
19934af83c8cSKip Macy 		VLAN_CAPABILITIES(ifp);
19944af83c8cSKip Macy #endif
1995b302b77cSNavdeep Parhar 		ADAPTER_UNLOCK(sc);
1996b302b77cSNavdeep Parhar 		break;
1997b302b77cSNavdeep Parhar 	case SIOCSIFMEDIA:
1998b302b77cSNavdeep Parhar 	case SIOCGIFMEDIA:
1999b302b77cSNavdeep Parhar 		error = ifmedia_ioctl(ifp, ifr, &p->media, command);
2000b6d90eb7SKip Macy 		break;
2001b6d90eb7SKip Macy 	default:
20023f345a5dSKip Macy 		error = ether_ioctl(ifp, command, data);
20033f345a5dSKip Macy 	}
20043f345a5dSKip Macy 
2005b6d90eb7SKip Macy 	return (error);
2006b6d90eb7SKip Macy }
2007b6d90eb7SKip Macy 
2008b6d90eb7SKip Macy static int
cxgb_media_change(if_t ifp)2009954712e8SJustin Hibbits cxgb_media_change(if_t ifp)
2010b6d90eb7SKip Macy {
20112975f787SNavdeep Parhar 	return (EOPNOTSUPP);
2012b6d90eb7SKip Macy }
2013b6d90eb7SKip Macy 
2014837f41b0SGeorge V. Neville-Neil /*
20152975f787SNavdeep Parhar  * Translates phy->modtype to the correct Ethernet media subtype.
2016837f41b0SGeorge V. Neville-Neil  */
2017837f41b0SGeorge V. Neville-Neil static int
cxgb_ifm_type(int mod)20182975f787SNavdeep Parhar cxgb_ifm_type(int mod)
2019837f41b0SGeorge V. Neville-Neil {
20202975f787SNavdeep Parhar 	switch (mod) {
2021837f41b0SGeorge V. Neville-Neil 	case phy_modtype_sr:
20222975f787SNavdeep Parhar 		return (IFM_10G_SR);
2023837f41b0SGeorge V. Neville-Neil 	case phy_modtype_lr:
20242975f787SNavdeep Parhar 		return (IFM_10G_LR);
2025837f41b0SGeorge V. Neville-Neil 	case phy_modtype_lrm:
20262975f787SNavdeep Parhar 		return (IFM_10G_LRM);
2027837f41b0SGeorge V. Neville-Neil 	case phy_modtype_twinax:
20282975f787SNavdeep Parhar 		return (IFM_10G_TWINAX);
2029837f41b0SGeorge V. Neville-Neil 	case phy_modtype_twinax_long:
20302975f787SNavdeep Parhar 		return (IFM_10G_TWINAX_LONG);
2031837f41b0SGeorge V. Neville-Neil 	case phy_modtype_none:
20322975f787SNavdeep Parhar 		return (IFM_NONE);
2033837f41b0SGeorge V. Neville-Neil 	case phy_modtype_unknown:
20342975f787SNavdeep Parhar 		return (IFM_UNKNOWN);
2035837f41b0SGeorge V. Neville-Neil 	}
2036837f41b0SGeorge V. Neville-Neil 
20372975f787SNavdeep Parhar 	KASSERT(0, ("%s: modtype %d unknown", __func__, mod));
20382975f787SNavdeep Parhar 	return (IFM_UNKNOWN);
20392975f787SNavdeep Parhar }
20402975f787SNavdeep Parhar 
20412975f787SNavdeep Parhar /*
20422975f787SNavdeep Parhar  * Rebuilds the ifmedia list for this port, and sets the current media.
20432975f787SNavdeep Parhar  */
20442975f787SNavdeep Parhar static void
cxgb_build_medialist(struct port_info * p)20452975f787SNavdeep Parhar cxgb_build_medialist(struct port_info *p)
20462975f787SNavdeep Parhar {
20472975f787SNavdeep Parhar 	struct cphy *phy = &p->phy;
20482975f787SNavdeep Parhar 	struct ifmedia *media = &p->media;
20492975f787SNavdeep Parhar 	int mod = phy->modtype;
20502975f787SNavdeep Parhar 	int m = IFM_ETHER | IFM_FDX;
20512975f787SNavdeep Parhar 
20522975f787SNavdeep Parhar 	PORT_LOCK(p);
20532975f787SNavdeep Parhar 
20542975f787SNavdeep Parhar 	ifmedia_removeall(media);
20552975f787SNavdeep Parhar 	if (phy->caps & SUPPORTED_TP && phy->caps & SUPPORTED_Autoneg) {
20562975f787SNavdeep Parhar 		/* Copper (RJ45) */
20572975f787SNavdeep Parhar 
20582975f787SNavdeep Parhar 		if (phy->caps & SUPPORTED_10000baseT_Full)
20592975f787SNavdeep Parhar 			ifmedia_add(media, m | IFM_10G_T, mod, NULL);
20602975f787SNavdeep Parhar 
20612975f787SNavdeep Parhar 		if (phy->caps & SUPPORTED_1000baseT_Full)
20622975f787SNavdeep Parhar 			ifmedia_add(media, m | IFM_1000_T, mod, NULL);
20632975f787SNavdeep Parhar 
20642975f787SNavdeep Parhar 		if (phy->caps & SUPPORTED_100baseT_Full)
20652975f787SNavdeep Parhar 			ifmedia_add(media, m | IFM_100_TX, mod, NULL);
20662975f787SNavdeep Parhar 
20672975f787SNavdeep Parhar 		if (phy->caps & SUPPORTED_10baseT_Full)
20682975f787SNavdeep Parhar 			ifmedia_add(media, m | IFM_10_T, mod, NULL);
20692975f787SNavdeep Parhar 
20702975f787SNavdeep Parhar 		ifmedia_add(media, IFM_ETHER | IFM_AUTO, mod, NULL);
20712975f787SNavdeep Parhar 		ifmedia_set(media, IFM_ETHER | IFM_AUTO);
20722975f787SNavdeep Parhar 
20732975f787SNavdeep Parhar 	} else if (phy->caps & SUPPORTED_TP) {
20742975f787SNavdeep Parhar 		/* Copper (CX4) */
20752975f787SNavdeep Parhar 
20762975f787SNavdeep Parhar 		KASSERT(phy->caps & SUPPORTED_10000baseT_Full,
20772975f787SNavdeep Parhar 			("%s: unexpected cap 0x%x", __func__, phy->caps));
20782975f787SNavdeep Parhar 
20792975f787SNavdeep Parhar 		ifmedia_add(media, m | IFM_10G_CX4, mod, NULL);
20802975f787SNavdeep Parhar 		ifmedia_set(media, m | IFM_10G_CX4);
20812975f787SNavdeep Parhar 
20822975f787SNavdeep Parhar 	} else if (phy->caps & SUPPORTED_FIBRE &&
20832975f787SNavdeep Parhar 		   phy->caps & SUPPORTED_10000baseT_Full) {
20842975f787SNavdeep Parhar 		/* 10G optical (but includes SFP+ twinax) */
20852975f787SNavdeep Parhar 
20862975f787SNavdeep Parhar 		m |= cxgb_ifm_type(mod);
20872975f787SNavdeep Parhar 		if (IFM_SUBTYPE(m) == IFM_NONE)
20882975f787SNavdeep Parhar 			m &= ~IFM_FDX;
20892975f787SNavdeep Parhar 
20902975f787SNavdeep Parhar 		ifmedia_add(media, m, mod, NULL);
20912975f787SNavdeep Parhar 		ifmedia_set(media, m);
20922975f787SNavdeep Parhar 
20932975f787SNavdeep Parhar 	} else if (phy->caps & SUPPORTED_FIBRE &&
20942975f787SNavdeep Parhar 		   phy->caps & SUPPORTED_1000baseT_Full) {
20952975f787SNavdeep Parhar 		/* 1G optical */
20962975f787SNavdeep Parhar 
20972975f787SNavdeep Parhar 		/* XXX: Lie and claim to be SX, could actually be any 1G-X */
20982975f787SNavdeep Parhar 		ifmedia_add(media, m | IFM_1000_SX, mod, NULL);
20992975f787SNavdeep Parhar 		ifmedia_set(media, m | IFM_1000_SX);
21002975f787SNavdeep Parhar 
21012975f787SNavdeep Parhar 	} else {
21022975f787SNavdeep Parhar 		KASSERT(0, ("%s: don't know how to handle 0x%x.", __func__,
21032975f787SNavdeep Parhar 			    phy->caps));
21042975f787SNavdeep Parhar 	}
21052975f787SNavdeep Parhar 
21062975f787SNavdeep Parhar 	PORT_UNLOCK(p);
2107837f41b0SGeorge V. Neville-Neil }
2108837f41b0SGeorge V. Neville-Neil 
2109b6d90eb7SKip Macy static void
cxgb_media_status(if_t ifp,struct ifmediareq * ifmr)2110954712e8SJustin Hibbits cxgb_media_status(if_t ifp, struct ifmediareq *ifmr)
2111b6d90eb7SKip Macy {
2112954712e8SJustin Hibbits 	struct port_info *p = if_getsoftc(ifp);
2113837f41b0SGeorge V. Neville-Neil 	struct ifmedia_entry *cur = p->media.ifm_cur;
21142975f787SNavdeep Parhar 	int speed = p->link_config.speed;
2115837f41b0SGeorge V. Neville-Neil 
2116837f41b0SGeorge V. Neville-Neil 	if (cur->ifm_data != p->phy.modtype) {
21172975f787SNavdeep Parhar 		cxgb_build_medialist(p);
21182975f787SNavdeep Parhar 		cur = p->media.ifm_cur;
2119837f41b0SGeorge V. Neville-Neil 	}
2120b6d90eb7SKip Macy 
2121b6d90eb7SKip Macy 	ifmr->ifm_status = IFM_AVALID;
2122b6d90eb7SKip Macy 	if (!p->link_config.link_ok)
2123b6d90eb7SKip Macy 		return;
2124b6d90eb7SKip Macy 
2125b6d90eb7SKip Macy 	ifmr->ifm_status |= IFM_ACTIVE;
2126b6d90eb7SKip Macy 
21272975f787SNavdeep Parhar 	/*
21282975f787SNavdeep Parhar 	 * active and current will differ iff current media is autoselect.  That
21292975f787SNavdeep Parhar 	 * can happen only for copper RJ45.
21302975f787SNavdeep Parhar 	 */
21312975f787SNavdeep Parhar 	if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO)
21322975f787SNavdeep Parhar 		return;
21332975f787SNavdeep Parhar 	KASSERT(p->phy.caps & SUPPORTED_TP && p->phy.caps & SUPPORTED_Autoneg,
21342975f787SNavdeep Parhar 		("%s: unexpected PHY caps 0x%x", __func__, p->phy.caps));
2135ef72318fSKip Macy 
21362975f787SNavdeep Parhar 	ifmr->ifm_active = IFM_ETHER | IFM_FDX;
21372975f787SNavdeep Parhar 	if (speed == SPEED_10000)
21382975f787SNavdeep Parhar 		ifmr->ifm_active |= IFM_10G_T;
21392975f787SNavdeep Parhar 	else if (speed == SPEED_1000)
21402975f787SNavdeep Parhar 		ifmr->ifm_active |= IFM_1000_T;
21412975f787SNavdeep Parhar 	else if (speed == SPEED_100)
21422975f787SNavdeep Parhar 		ifmr->ifm_active |= IFM_100_TX;
21432975f787SNavdeep Parhar 	else if (speed == SPEED_10)
21442975f787SNavdeep Parhar 		ifmr->ifm_active |= IFM_10_T;
2145b6d90eb7SKip Macy 	else
21462975f787SNavdeep Parhar 		KASSERT(0, ("%s: link up but speed unknown (%u)", __func__,
21472975f787SNavdeep Parhar 			    speed));
2148b6d90eb7SKip Macy }
2149b6d90eb7SKip Macy 
2150e26e6373SNavdeep Parhar static uint64_t
cxgb_get_counter(if_t ifp,ift_counter c)2151954712e8SJustin Hibbits cxgb_get_counter(if_t ifp, ift_counter c)
2152e26e6373SNavdeep Parhar {
2153954712e8SJustin Hibbits 	struct port_info *pi = if_getsoftc(ifp);
2154e26e6373SNavdeep Parhar 	struct adapter *sc = pi->adapter;
2155e26e6373SNavdeep Parhar 	struct cmac *mac = &pi->mac;
2156e26e6373SNavdeep Parhar 	struct mac_stats *mstats = &mac->stats;
2157e26e6373SNavdeep Parhar 
2158e26e6373SNavdeep Parhar 	cxgb_refresh_stats(pi);
2159e26e6373SNavdeep Parhar 
2160e26e6373SNavdeep Parhar 	switch (c) {
2161e26e6373SNavdeep Parhar 	case IFCOUNTER_IPACKETS:
2162e26e6373SNavdeep Parhar 		return (mstats->rx_frames);
2163e26e6373SNavdeep Parhar 
2164e26e6373SNavdeep Parhar 	case IFCOUNTER_IERRORS:
2165e26e6373SNavdeep Parhar 		return (mstats->rx_jabber + mstats->rx_data_errs +
2166e26e6373SNavdeep Parhar 		    mstats->rx_sequence_errs + mstats->rx_runt +
2167e26e6373SNavdeep Parhar 		    mstats->rx_too_long + mstats->rx_mac_internal_errs +
2168e26e6373SNavdeep Parhar 		    mstats->rx_short + mstats->rx_fcs_errs);
2169e26e6373SNavdeep Parhar 
2170e26e6373SNavdeep Parhar 	case IFCOUNTER_OPACKETS:
2171e26e6373SNavdeep Parhar 		return (mstats->tx_frames);
2172e26e6373SNavdeep Parhar 
2173e26e6373SNavdeep Parhar 	case IFCOUNTER_OERRORS:
2174e26e6373SNavdeep Parhar 		return (mstats->tx_excess_collisions + mstats->tx_underrun +
2175e26e6373SNavdeep Parhar 		    mstats->tx_len_errs + mstats->tx_mac_internal_errs +
2176e26e6373SNavdeep Parhar 		    mstats->tx_excess_deferral + mstats->tx_fcs_errs);
2177e26e6373SNavdeep Parhar 
2178e26e6373SNavdeep Parhar 	case IFCOUNTER_COLLISIONS:
2179e26e6373SNavdeep Parhar 		return (mstats->tx_total_collisions);
2180e26e6373SNavdeep Parhar 
2181e26e6373SNavdeep Parhar 	case IFCOUNTER_IBYTES:
2182e26e6373SNavdeep Parhar 		return (mstats->rx_octets);
2183e26e6373SNavdeep Parhar 
2184e26e6373SNavdeep Parhar 	case IFCOUNTER_OBYTES:
2185e26e6373SNavdeep Parhar 		return (mstats->tx_octets);
2186e26e6373SNavdeep Parhar 
2187e26e6373SNavdeep Parhar 	case IFCOUNTER_IMCASTS:
2188e26e6373SNavdeep Parhar 		return (mstats->rx_mcast_frames);
2189e26e6373SNavdeep Parhar 
2190e26e6373SNavdeep Parhar 	case IFCOUNTER_OMCASTS:
2191e26e6373SNavdeep Parhar 		return (mstats->tx_mcast_frames);
2192e26e6373SNavdeep Parhar 
2193e26e6373SNavdeep Parhar 	case IFCOUNTER_IQDROPS:
2194e26e6373SNavdeep Parhar 		return (mstats->rx_cong_drops);
2195e26e6373SNavdeep Parhar 
2196e26e6373SNavdeep Parhar 	case IFCOUNTER_OQDROPS: {
2197e26e6373SNavdeep Parhar 		int i;
2198e26e6373SNavdeep Parhar 		uint64_t drops;
2199e26e6373SNavdeep Parhar 
2200e26e6373SNavdeep Parhar 		drops = 0;
2201e26e6373SNavdeep Parhar 		if (sc->flags & FULL_INIT_DONE) {
2202e26e6373SNavdeep Parhar 			for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++)
2203e26e6373SNavdeep Parhar 				drops += sc->sge.qs[i].txq[TXQ_ETH].txq_mr->br_drops;
2204e26e6373SNavdeep Parhar 		}
2205e26e6373SNavdeep Parhar 
2206e26e6373SNavdeep Parhar 		return (drops);
2207e26e6373SNavdeep Parhar 
2208e26e6373SNavdeep Parhar 	}
2209e26e6373SNavdeep Parhar 
2210e26e6373SNavdeep Parhar 	default:
2211e26e6373SNavdeep Parhar 		return (if_get_counter_default(ifp, c));
2212e26e6373SNavdeep Parhar 	}
2213e26e6373SNavdeep Parhar }
2214e26e6373SNavdeep Parhar 
2215b6d90eb7SKip Macy static void
cxgb_async_intr(void * data)2216b6d90eb7SKip Macy cxgb_async_intr(void *data)
2217b6d90eb7SKip Macy {
2218693d746cSKip Macy 	adapter_t *sc = data;
2219693d746cSKip Macy 
22202c32b502SNavdeep Parhar 	t3_write_reg(sc, A_PL_INT_ENABLE0, 0);
22212c32b502SNavdeep Parhar 	(void) t3_read_reg(sc, A_PL_INT_ENABLE0);
2222bb38cd2fSKip Macy 	taskqueue_enqueue(sc->tq, &sc->slow_intr_task);
2223b6d90eb7SKip Macy }
2224b6d90eb7SKip Macy 
2225bd1a9fbaSNavdeep Parhar static void
link_check_callout(void * arg)2226bd1a9fbaSNavdeep Parhar link_check_callout(void *arg)
2227c01f2b83SNavdeep Parhar {
2228bd1a9fbaSNavdeep Parhar 	struct port_info *pi = arg;
2229bd1a9fbaSNavdeep Parhar 	struct adapter *sc = pi->adapter;
2230c01f2b83SNavdeep Parhar 
2231bd1a9fbaSNavdeep Parhar 	if (!isset(&sc->open_device_map, pi->port_id))
2232bd1a9fbaSNavdeep Parhar 		return;
2233c01f2b83SNavdeep Parhar 
2234bd1a9fbaSNavdeep Parhar 	taskqueue_enqueue(sc->tq, &pi->link_check_task);
2235c01f2b83SNavdeep Parhar }
2236c01f2b83SNavdeep Parhar 
2237b6d90eb7SKip Macy static void
check_link_status(void * arg,int pending)2238bd1a9fbaSNavdeep Parhar check_link_status(void *arg, int pending)
2239b6d90eb7SKip Macy {
2240bd1a9fbaSNavdeep Parhar 	struct port_info *pi = arg;
2241bd1a9fbaSNavdeep Parhar 	struct adapter *sc = pi->adapter;
2242b6d90eb7SKip Macy 
2243bd1a9fbaSNavdeep Parhar 	if (!isset(&sc->open_device_map, pi->port_id))
2244bd1a9fbaSNavdeep Parhar 		return;
2245b6d90eb7SKip Macy 
2246bd1a9fbaSNavdeep Parhar 	t3_link_changed(sc, pi->port_id);
22473f345a5dSKip Macy 
2248a5eb009bSNavdeep Parhar 	if (pi->link_fault || !(pi->phy.caps & SUPPORTED_LINK_IRQ) ||
2249a5eb009bSNavdeep Parhar 	    pi->link_config.link_ok == 0)
2250bd1a9fbaSNavdeep Parhar 		callout_reset(&pi->link_check_ch, hz, link_check_callout, pi);
2251b6d90eb7SKip Macy }
2252bd1a9fbaSNavdeep Parhar 
2253bd1a9fbaSNavdeep Parhar void
t3_os_link_intr(struct port_info * pi)2254bd1a9fbaSNavdeep Parhar t3_os_link_intr(struct port_info *pi)
2255bd1a9fbaSNavdeep Parhar {
2256bd1a9fbaSNavdeep Parhar 	/*
2257bd1a9fbaSNavdeep Parhar 	 * Schedule a link check in the near future.  If the link is flapping
2258bd1a9fbaSNavdeep Parhar 	 * rapidly we'll keep resetting the callout and delaying the check until
2259bd1a9fbaSNavdeep Parhar 	 * things stabilize a bit.
2260bd1a9fbaSNavdeep Parhar 	 */
2261bd1a9fbaSNavdeep Parhar 	callout_reset(&pi->link_check_ch, hz / 4, link_check_callout, pi);
2262b6d90eb7SKip Macy }
2263b6d90eb7SKip Macy 
2264577e9bbeSKip Macy static void
check_t3b2_mac(struct adapter * sc)22653f345a5dSKip Macy check_t3b2_mac(struct adapter *sc)
2266577e9bbeSKip Macy {
2267577e9bbeSKip Macy 	int i;
2268577e9bbeSKip Macy 
22693f345a5dSKip Macy 	if (sc->flags & CXGB_SHUTDOWN)
22708e10660fSKip Macy 		return;
22718e10660fSKip Macy 
22723f345a5dSKip Macy 	for_each_port(sc, i) {
22733f345a5dSKip Macy 		struct port_info *p = &sc->port[i];
2274577e9bbeSKip Macy 		int status;
22753f345a5dSKip Macy #ifdef INVARIANTS
2276954712e8SJustin Hibbits 		if_t ifp = p->ifp;
22773f345a5dSKip Macy #endif
2278577e9bbeSKip Macy 
2279c01f2b83SNavdeep Parhar 		if (!isset(&sc->open_device_map, p->port_id) || p->link_fault ||
2280c01f2b83SNavdeep Parhar 		    !p->link_config.link_ok)
2281577e9bbeSKip Macy 			continue;
2282577e9bbeSKip Macy 
2283954712e8SJustin Hibbits 		KASSERT(if_getdrvflags(ifp) & IFF_DRV_RUNNING,
22843f345a5dSKip Macy 			("%s: state mismatch (drv_flags %x, device_map %x)",
2285954712e8SJustin Hibbits 			 __func__, if_getdrvflags(ifp), sc->open_device_map));
22863f345a5dSKip Macy 
2287577e9bbeSKip Macy 		PORT_LOCK(p);
2288577e9bbeSKip Macy 		status = t3b2_mac_watchdog_task(&p->mac);
2289577e9bbeSKip Macy 		if (status == 1)
2290577e9bbeSKip Macy 			p->mac.stats.num_toggled++;
2291577e9bbeSKip Macy 		else if (status == 2) {
2292577e9bbeSKip Macy 			struct cmac *mac = &p->mac;
2293577e9bbeSKip Macy 
22943f345a5dSKip Macy 			cxgb_update_mac_settings(p);
2295577e9bbeSKip Macy 			t3_link_start(&p->phy, mac, &p->link_config);
2296577e9bbeSKip Macy 			t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
22973f345a5dSKip Macy 			t3_port_intr_enable(sc, p->port_id);
2298577e9bbeSKip Macy 			p->mac.stats.num_resets++;
2299577e9bbeSKip Macy 		}
2300577e9bbeSKip Macy 		PORT_UNLOCK(p);
2301577e9bbeSKip Macy 	}
2302577e9bbeSKip Macy }
2303577e9bbeSKip Macy 
2304577e9bbeSKip Macy static void
cxgb_tick(void * arg)2305577e9bbeSKip Macy cxgb_tick(void *arg)
2306577e9bbeSKip Macy {
2307577e9bbeSKip Macy 	adapter_t *sc = (adapter_t *)arg;
23088090c9f5SKip Macy 
23098e10660fSKip Macy 	if (sc->flags & CXGB_SHUTDOWN)
23108090c9f5SKip Macy 		return;
2311577e9bbeSKip Macy 
2312bb38cd2fSKip Macy 	taskqueue_enqueue(sc->tq, &sc->tick_task);
2313bd1a9fbaSNavdeep Parhar 	callout_reset(&sc->cxgb_tick_ch, hz, cxgb_tick, sc);
2314bb38cd2fSKip Macy }
2315bb38cd2fSKip Macy 
2316e26e6373SNavdeep Parhar void
cxgb_refresh_stats(struct port_info * pi)2317e26e6373SNavdeep Parhar cxgb_refresh_stats(struct port_info *pi)
2318e26e6373SNavdeep Parhar {
2319e26e6373SNavdeep Parhar 	struct timeval tv;
2320e26e6373SNavdeep Parhar 	const struct timeval interval = {0, 250000};    /* 250ms */
2321e26e6373SNavdeep Parhar 
2322e26e6373SNavdeep Parhar 	getmicrotime(&tv);
2323e26e6373SNavdeep Parhar 	timevalsub(&tv, &interval);
2324e26e6373SNavdeep Parhar 	if (timevalcmp(&tv, &pi->last_refreshed, <))
2325e26e6373SNavdeep Parhar 		return;
2326e26e6373SNavdeep Parhar 
2327e26e6373SNavdeep Parhar 	PORT_LOCK(pi);
2328e26e6373SNavdeep Parhar 	t3_mac_update_stats(&pi->mac);
2329e26e6373SNavdeep Parhar 	PORT_UNLOCK(pi);
2330e26e6373SNavdeep Parhar 	getmicrotime(&pi->last_refreshed);
2331e26e6373SNavdeep Parhar }
2332e26e6373SNavdeep Parhar 
2333bb38cd2fSKip Macy static void
cxgb_tick_handler(void * arg,int count)2334bb38cd2fSKip Macy cxgb_tick_handler(void *arg, int count)
2335bb38cd2fSKip Macy {
2336bb38cd2fSKip Macy 	adapter_t *sc = (adapter_t *)arg;
2337bb38cd2fSKip Macy 	const struct adapter_params *p = &sc->params;
2338706cb31fSKip Macy 	int i;
2339f2d8ff04SGeorge V. Neville-Neil 	uint32_t cause, reset;
2340bb38cd2fSKip Macy 
23410bbdea77SGeorge V. Neville-Neil 	if (sc->flags & CXGB_SHUTDOWN || !(sc->flags & FULL_INIT_DONE))
23428e10660fSKip Macy 		return;
23438e10660fSKip Macy 
2344f35c2d65SKip Macy 	if (p->rev == T3_REV_B2 && p->nports < 4 && sc->open_device_map)
2345f35c2d65SKip Macy 		check_t3b2_mac(sc);
2346f35c2d65SKip Macy 
2347489ca05bSNavdeep Parhar 	cause = t3_read_reg(sc, A_SG_INT_CAUSE) & (F_RSPQSTARVE | F_FLEMPTY);
2348489ca05bSNavdeep Parhar 	if (cause) {
2349f2d8ff04SGeorge V. Neville-Neil 		struct sge_qset *qs = &sc->sge.qs[0];
2350489ca05bSNavdeep Parhar 		uint32_t mask, v;
2351f2d8ff04SGeorge V. Neville-Neil 
2352489ca05bSNavdeep Parhar 		v = t3_read_reg(sc, A_SG_RSPQ_FL_STATUS) & ~0xff00;
2353f2d8ff04SGeorge V. Neville-Neil 
2354489ca05bSNavdeep Parhar 		mask = 1;
2355489ca05bSNavdeep Parhar 		for (i = 0; i < SGE_QSETS; i++) {
2356489ca05bSNavdeep Parhar 			if (v & mask)
2357489ca05bSNavdeep Parhar 				qs[i].rspq.starved++;
2358489ca05bSNavdeep Parhar 			mask <<= 1;
2359f2d8ff04SGeorge V. Neville-Neil 		}
2360489ca05bSNavdeep Parhar 
2361489ca05bSNavdeep Parhar 		mask <<= SGE_QSETS; /* skip RSPQXDISABLED */
2362489ca05bSNavdeep Parhar 
2363489ca05bSNavdeep Parhar 		for (i = 0; i < SGE_QSETS * 2; i++) {
2364489ca05bSNavdeep Parhar 			if (v & mask) {
2365489ca05bSNavdeep Parhar 				qs[i / 2].fl[i % 2].empty++;
2366f2d8ff04SGeorge V. Neville-Neil 			}
2367489ca05bSNavdeep Parhar 			mask <<= 1;
2368489ca05bSNavdeep Parhar 		}
2369489ca05bSNavdeep Parhar 
2370489ca05bSNavdeep Parhar 		/* clear */
2371489ca05bSNavdeep Parhar 		t3_write_reg(sc, A_SG_RSPQ_FL_STATUS, v);
2372489ca05bSNavdeep Parhar 		t3_write_reg(sc, A_SG_INT_CAUSE, cause);
2373489ca05bSNavdeep Parhar 	}
2374f2d8ff04SGeorge V. Neville-Neil 
2375ceac50ebSKip Macy 	for (i = 0; i < sc->params.nports; i++) {
2376ceac50ebSKip Macy 		struct port_info *pi = &sc->port[i];
2377f2d8ff04SGeorge V. Neville-Neil 		struct cmac *mac = &pi->mac;
23783f345a5dSKip Macy 
23793f345a5dSKip Macy 		if (!isset(&sc->open_device_map, pi->port_id))
23803f345a5dSKip Macy 			continue;
23813f345a5dSKip Macy 
2382e26e6373SNavdeep Parhar 		cxgb_refresh_stats(pi);
2383f2d8ff04SGeorge V. Neville-Neil 
2384f2d8ff04SGeorge V. Neville-Neil 		if (mac->multiport)
2385f2d8ff04SGeorge V. Neville-Neil 			continue;
2386f2d8ff04SGeorge V. Neville-Neil 
2387f2d8ff04SGeorge V. Neville-Neil 		/* Count rx fifo overflows, once per second */
2388f2d8ff04SGeorge V. Neville-Neil 		cause = t3_read_reg(sc, A_XGM_INT_CAUSE + mac->offset);
2389f2d8ff04SGeorge V. Neville-Neil 		reset = 0;
2390f2d8ff04SGeorge V. Neville-Neil 		if (cause & F_RXFIFO_OVERFLOW) {
2391f2d8ff04SGeorge V. Neville-Neil 			mac->stats.rx_fifo_ovfl++;
2392f2d8ff04SGeorge V. Neville-Neil 			reset |= F_RXFIFO_OVERFLOW;
2393f2d8ff04SGeorge V. Neville-Neil 		}
2394f2d8ff04SGeorge V. Neville-Neil 		t3_write_reg(sc, A_XGM_INT_CAUSE + mac->offset, reset);
2395ceac50ebSKip Macy 	}
2396577e9bbeSKip Macy }
2397577e9bbeSKip Macy 
23987ac2e6c3SKip Macy static void
touch_bars(device_t dev)23997ac2e6c3SKip Macy touch_bars(device_t dev)
24007ac2e6c3SKip Macy {
24017ac2e6c3SKip Macy 	/*
24027ac2e6c3SKip Macy 	 * Don't enable yet
24037ac2e6c3SKip Macy 	 */
24047ac2e6c3SKip Macy #if !defined(__LP64__) && 0
24057ac2e6c3SKip Macy 	u32 v;
24067ac2e6c3SKip Macy 
24077ac2e6c3SKip Macy 	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &v);
24087ac2e6c3SKip Macy 	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, v);
24097ac2e6c3SKip Macy 	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3, &v);
24107ac2e6c3SKip Macy 	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_3, v);
24117ac2e6c3SKip Macy 	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &v);
24127ac2e6c3SKip Macy 	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_5, v);
24137ac2e6c3SKip Macy #endif
24147ac2e6c3SKip Macy }
24157ac2e6c3SKip Macy 
2416ac3a6d9cSKip Macy static int
set_eeprom(struct port_info * pi,const uint8_t * data,int len,int offset)2417ac3a6d9cSKip Macy set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset)
2418ac3a6d9cSKip Macy {
2419ac3a6d9cSKip Macy 	uint8_t *buf;
2420ac3a6d9cSKip Macy 	int err = 0;
2421ac3a6d9cSKip Macy 	u32 aligned_offset, aligned_len, *p;
2422ac3a6d9cSKip Macy 	struct adapter *adapter = pi->adapter;
2423ac3a6d9cSKip Macy 
2424ac3a6d9cSKip Macy 
2425ac3a6d9cSKip Macy 	aligned_offset = offset & ~3;
2426ac3a6d9cSKip Macy 	aligned_len = (len + (offset & 3) + 3) & ~3;
2427ac3a6d9cSKip Macy 
2428ac3a6d9cSKip Macy 	if (aligned_offset != offset || aligned_len != len) {
2429ac3a6d9cSKip Macy 		buf = malloc(aligned_len, M_DEVBUF, M_WAITOK | M_ZERO);
2430ac3a6d9cSKip Macy 		err = t3_seeprom_read(adapter, aligned_offset, (u32 *)buf);
2431ac3a6d9cSKip Macy 		if (!err && aligned_len > 4)
2432ac3a6d9cSKip Macy 			err = t3_seeprom_read(adapter,
2433ac3a6d9cSKip Macy 					      aligned_offset + aligned_len - 4,
2434ac3a6d9cSKip Macy 					      (u32 *)&buf[aligned_len - 4]);
2435ac3a6d9cSKip Macy 		if (err)
2436ac3a6d9cSKip Macy 			goto out;
2437ac3a6d9cSKip Macy 		memcpy(buf + (offset & 3), data, len);
2438ac3a6d9cSKip Macy 	} else
2439ac3a6d9cSKip Macy 		buf = (uint8_t *)(uintptr_t)data;
2440ac3a6d9cSKip Macy 
2441ac3a6d9cSKip Macy 	err = t3_seeprom_wp(adapter, 0);
2442ac3a6d9cSKip Macy 	if (err)
2443ac3a6d9cSKip Macy 		goto out;
2444ac3a6d9cSKip Macy 
2445ac3a6d9cSKip Macy 	for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) {
2446ac3a6d9cSKip Macy 		err = t3_seeprom_write(adapter, aligned_offset, *p);
2447ac3a6d9cSKip Macy 		aligned_offset += 4;
2448ac3a6d9cSKip Macy 	}
2449ac3a6d9cSKip Macy 
2450ac3a6d9cSKip Macy 	if (!err)
2451ac3a6d9cSKip Macy 		err = t3_seeprom_wp(adapter, 1);
2452ac3a6d9cSKip Macy out:
2453ac3a6d9cSKip Macy 	if (buf != data)
2454ac3a6d9cSKip Macy 		free(buf, M_DEVBUF);
2455ac3a6d9cSKip Macy 	return err;
2456ac3a6d9cSKip Macy }
2457ac3a6d9cSKip Macy 
2458ac3a6d9cSKip Macy 
2459b6d90eb7SKip Macy static int
in_range(int val,int lo,int hi)2460b6d90eb7SKip Macy in_range(int val, int lo, int hi)
2461b6d90eb7SKip Macy {
2462b6d90eb7SKip Macy 	return val < 0 || (val <= hi && val >= lo);
2463b6d90eb7SKip Macy }
2464b6d90eb7SKip Macy 
2465b6d90eb7SKip Macy static int
cxgb_extension_open(struct cdev * dev,int flags,int fmp,struct thread * td)246600b4e54aSWarner Losh cxgb_extension_open(struct cdev *dev, int flags, int fmp, struct thread *td)
2467ef72318fSKip Macy {
2468ef72318fSKip Macy        return (0);
2469ef72318fSKip Macy }
2470ef72318fSKip Macy 
2471ef72318fSKip Macy static int
cxgb_extension_close(struct cdev * dev,int flags,int fmt,struct thread * td)247200b4e54aSWarner Losh cxgb_extension_close(struct cdev *dev, int flags, int fmt, struct thread *td)
2473ef72318fSKip Macy {
2474ef72318fSKip Macy        return (0);
2475ef72318fSKip Macy }
2476ef72318fSKip Macy 
2477ef72318fSKip Macy static int
cxgb_extension_ioctl(struct cdev * dev,unsigned long cmd,caddr_t data,int fflag,struct thread * td)2478b6d90eb7SKip Macy cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
2479b6d90eb7SKip Macy     int fflag, struct thread *td)
2480b6d90eb7SKip Macy {
2481b6d90eb7SKip Macy 	int mmd, error = 0;
2482b6d90eb7SKip Macy 	struct port_info *pi = dev->si_drv1;
2483b6d90eb7SKip Macy 	adapter_t *sc = pi->adapter;
2484b6d90eb7SKip Macy 
2485b6d90eb7SKip Macy #ifdef PRIV_SUPPORTED
2486b6d90eb7SKip Macy 	if (priv_check(td, PRIV_DRIVER)) {
2487b6d90eb7SKip Macy 		if (cxgb_debug)
2488b6d90eb7SKip Macy 			printf("user does not have access to privileged ioctls\n");
2489b6d90eb7SKip Macy 		return (EPERM);
2490b6d90eb7SKip Macy 	}
2491b6d90eb7SKip Macy #else
2492b6d90eb7SKip Macy 	if (suser(td)) {
2493b6d90eb7SKip Macy 		if (cxgb_debug)
2494b6d90eb7SKip Macy 			printf("user does not have access to privileged ioctls\n");
2495b6d90eb7SKip Macy 		return (EPERM);
2496b6d90eb7SKip Macy 	}
2497b6d90eb7SKip Macy #endif
2498b6d90eb7SKip Macy 
2499b6d90eb7SKip Macy 	switch (cmd) {
25001ffd6e58SKip Macy 	case CHELSIO_GET_MIIREG: {
2501b6d90eb7SKip Macy 		uint32_t val;
2502b6d90eb7SKip Macy 		struct cphy *phy = &pi->phy;
25031ffd6e58SKip Macy 		struct ch_mii_data *mid = (struct ch_mii_data *)data;
2504b6d90eb7SKip Macy 
2505b6d90eb7SKip Macy 		if (!phy->mdio_read)
2506b6d90eb7SKip Macy 			return (EOPNOTSUPP);
2507b6d90eb7SKip Macy 		if (is_10G(sc)) {
2508b6d90eb7SKip Macy 			mmd = mid->phy_id >> 8;
2509b6d90eb7SKip Macy 			if (!mmd)
2510b6d90eb7SKip Macy 				mmd = MDIO_DEV_PCS;
25110c1ff9c6SGeorge V. Neville-Neil 			else if (mmd > MDIO_DEV_VEND2)
2512ac3a6d9cSKip Macy 				return (EINVAL);
2513b6d90eb7SKip Macy 
2514b6d90eb7SKip Macy 			error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd,
2515b6d90eb7SKip Macy 					     mid->reg_num, &val);
2516b6d90eb7SKip Macy 		} else
2517b6d90eb7SKip Macy 		        error = phy->mdio_read(sc, mid->phy_id & 0x1f, 0,
2518b6d90eb7SKip Macy 					     mid->reg_num & 0x1f, &val);
2519b6d90eb7SKip Macy 		if (error == 0)
2520b6d90eb7SKip Macy 			mid->val_out = val;
2521b6d90eb7SKip Macy 		break;
2522b6d90eb7SKip Macy 	}
25231ffd6e58SKip Macy 	case CHELSIO_SET_MIIREG: {
2524b6d90eb7SKip Macy 		struct cphy *phy = &pi->phy;
25251ffd6e58SKip Macy 		struct ch_mii_data *mid = (struct ch_mii_data *)data;
2526b6d90eb7SKip Macy 
2527b6d90eb7SKip Macy 		if (!phy->mdio_write)
2528b6d90eb7SKip Macy 			return (EOPNOTSUPP);
2529b6d90eb7SKip Macy 		if (is_10G(sc)) {
2530b6d90eb7SKip Macy 			mmd = mid->phy_id >> 8;
2531b6d90eb7SKip Macy 			if (!mmd)
2532b6d90eb7SKip Macy 				mmd = MDIO_DEV_PCS;
25330c1ff9c6SGeorge V. Neville-Neil 			else if (mmd > MDIO_DEV_VEND2)
2534b6d90eb7SKip Macy 				return (EINVAL);
2535b6d90eb7SKip Macy 
2536b6d90eb7SKip Macy 			error = phy->mdio_write(sc, mid->phy_id & 0x1f,
2537b6d90eb7SKip Macy 					      mmd, mid->reg_num, mid->val_in);
2538b6d90eb7SKip Macy 		} else
2539b6d90eb7SKip Macy 			error = phy->mdio_write(sc, mid->phy_id & 0x1f, 0,
2540b6d90eb7SKip Macy 					      mid->reg_num & 0x1f,
2541b6d90eb7SKip Macy 					      mid->val_in);
2542b6d90eb7SKip Macy 		break;
2543b6d90eb7SKip Macy 	}
2544b6d90eb7SKip Macy 	case CHELSIO_SETREG: {
2545b6d90eb7SKip Macy 		struct ch_reg *edata = (struct ch_reg *)data;
2546b6d90eb7SKip Macy 		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2547b6d90eb7SKip Macy 			return (EFAULT);
2548b6d90eb7SKip Macy 		t3_write_reg(sc, edata->addr, edata->val);
2549b6d90eb7SKip Macy 		break;
2550b6d90eb7SKip Macy 	}
2551b6d90eb7SKip Macy 	case CHELSIO_GETREG: {
2552b6d90eb7SKip Macy 		struct ch_reg *edata = (struct ch_reg *)data;
2553b6d90eb7SKip Macy 		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2554b6d90eb7SKip Macy 			return (EFAULT);
2555b6d90eb7SKip Macy 		edata->val = t3_read_reg(sc, edata->addr);
2556b6d90eb7SKip Macy 		break;
2557b6d90eb7SKip Macy 	}
2558b6d90eb7SKip Macy 	case CHELSIO_GET_SGE_CONTEXT: {
2559b6d90eb7SKip Macy 		struct ch_cntxt *ecntxt = (struct ch_cntxt *)data;
25608e10660fSKip Macy 		mtx_lock_spin(&sc->sge.reg_lock);
2561b6d90eb7SKip Macy 		switch (ecntxt->cntxt_type) {
2562b6d90eb7SKip Macy 		case CNTXT_TYPE_EGRESS:
25631ffd6e58SKip Macy 			error = -t3_sge_read_ecntxt(sc, ecntxt->cntxt_id,
2564b6d90eb7SKip Macy 			    ecntxt->data);
2565b6d90eb7SKip Macy 			break;
2566b6d90eb7SKip Macy 		case CNTXT_TYPE_FL:
25671ffd6e58SKip Macy 			error = -t3_sge_read_fl(sc, ecntxt->cntxt_id,
2568b6d90eb7SKip Macy 			    ecntxt->data);
2569b6d90eb7SKip Macy 			break;
2570b6d90eb7SKip Macy 		case CNTXT_TYPE_RSP:
25711ffd6e58SKip Macy 			error = -t3_sge_read_rspq(sc, ecntxt->cntxt_id,
2572b6d90eb7SKip Macy 			    ecntxt->data);
2573b6d90eb7SKip Macy 			break;
2574b6d90eb7SKip Macy 		case CNTXT_TYPE_CQ:
25751ffd6e58SKip Macy 			error = -t3_sge_read_cq(sc, ecntxt->cntxt_id,
2576b6d90eb7SKip Macy 			    ecntxt->data);
2577b6d90eb7SKip Macy 			break;
2578b6d90eb7SKip Macy 		default:
2579b6d90eb7SKip Macy 			error = EINVAL;
2580b6d90eb7SKip Macy 			break;
2581b6d90eb7SKip Macy 		}
25828e10660fSKip Macy 		mtx_unlock_spin(&sc->sge.reg_lock);
2583b6d90eb7SKip Macy 		break;
2584b6d90eb7SKip Macy 	}
2585b6d90eb7SKip Macy 	case CHELSIO_GET_SGE_DESC: {
2586b6d90eb7SKip Macy 		struct ch_desc *edesc = (struct ch_desc *)data;
2587b6d90eb7SKip Macy 		int ret;
2588b6d90eb7SKip Macy 		if (edesc->queue_num >= SGE_QSETS * 6)
2589b6d90eb7SKip Macy 			return (EINVAL);
2590b6d90eb7SKip Macy 		ret = t3_get_desc(&sc->sge.qs[edesc->queue_num / 6],
2591b6d90eb7SKip Macy 		    edesc->queue_num % 6, edesc->idx, edesc->data);
2592b6d90eb7SKip Macy 		if (ret < 0)
2593b6d90eb7SKip Macy 			return (EINVAL);
2594b6d90eb7SKip Macy 		edesc->size = ret;
2595b6d90eb7SKip Macy 		break;
2596b6d90eb7SKip Macy 	}
2597b6d90eb7SKip Macy 	case CHELSIO_GET_QSET_PARAMS: {
2598b6d90eb7SKip Macy 		struct qset_params *q;
2599b6d90eb7SKip Macy 		struct ch_qset_params *t = (struct ch_qset_params *)data;
26001ffd6e58SKip Macy 		int q1 = pi->first_qset;
26011ffd6e58SKip Macy 		int nqsets = pi->nqsets;
26021ffd6e58SKip Macy 		int i;
2603b6d90eb7SKip Macy 
26041ffd6e58SKip Macy 		if (t->qset_idx >= nqsets)
26051ffd6e58SKip Macy 			return EINVAL;
2606b6d90eb7SKip Macy 
26071ffd6e58SKip Macy 		i = q1 + t->qset_idx;
26081ffd6e58SKip Macy 		q = &sc->params.sge.qset[i];
2609b6d90eb7SKip Macy 		t->rspq_size   = q->rspq_size;
2610b6d90eb7SKip Macy 		t->txq_size[0] = q->txq_size[0];
2611b6d90eb7SKip Macy 		t->txq_size[1] = q->txq_size[1];
2612b6d90eb7SKip Macy 		t->txq_size[2] = q->txq_size[2];
2613b6d90eb7SKip Macy 		t->fl_size[0]  = q->fl_size;
2614b6d90eb7SKip Macy 		t->fl_size[1]  = q->jumbo_size;
2615b6d90eb7SKip Macy 		t->polling     = q->polling;
26161ffd6e58SKip Macy 		t->lro         = q->lro;
26174af83c8cSKip Macy 		t->intr_lat    = q->coalesce_usecs;
2618b6d90eb7SKip Macy 		t->cong_thres  = q->cong_thres;
26191ffd6e58SKip Macy 		t->qnum        = i;
2620b6d90eb7SKip Macy 
26211d609d51SNavdeep Parhar 		if ((sc->flags & FULL_INIT_DONE) == 0)
26221d609d51SNavdeep Parhar 			t->vector = 0;
26231d609d51SNavdeep Parhar 		else if (sc->flags & USING_MSIX)
26241ffd6e58SKip Macy 			t->vector = rman_get_start(sc->msix_irq_res[i]);
26251ffd6e58SKip Macy 		else
26261ffd6e58SKip Macy 			t->vector = rman_get_start(sc->irq_res);
26271ffd6e58SKip Macy 
2628b6d90eb7SKip Macy 		break;
2629b6d90eb7SKip Macy 	}
2630b6d90eb7SKip Macy 	case CHELSIO_GET_QSET_NUM: {
2631b6d90eb7SKip Macy 		struct ch_reg *edata = (struct ch_reg *)data;
2632b6d90eb7SKip Macy 		edata->val = pi->nqsets;
2633b6d90eb7SKip Macy 		break;
2634b6d90eb7SKip Macy 	}
26351ffd6e58SKip Macy 	case CHELSIO_LOAD_FW: {
26361ffd6e58SKip Macy 		uint8_t *fw_data;
26371ffd6e58SKip Macy 		uint32_t vers;
26381ffd6e58SKip Macy 		struct ch_mem_range *t = (struct ch_mem_range *)data;
26391ffd6e58SKip Macy 
26401ffd6e58SKip Macy 		/*
26411ffd6e58SKip Macy 		 * You're allowed to load a firmware only before FULL_INIT_DONE
26421ffd6e58SKip Macy 		 *
26431ffd6e58SKip Macy 		 * FW_UPTODATE is also set so the rest of the initialization
26441ffd6e58SKip Macy 		 * will not overwrite what was loaded here.  This gives you the
26451ffd6e58SKip Macy 		 * flexibility to load any firmware (and maybe shoot yourself in
26461ffd6e58SKip Macy 		 * the foot).
26471ffd6e58SKip Macy 		 */
26481ffd6e58SKip Macy 
26491ffd6e58SKip Macy 		ADAPTER_LOCK(sc);
26501ffd6e58SKip Macy 		if (sc->open_device_map || sc->flags & FULL_INIT_DONE) {
26511ffd6e58SKip Macy 			ADAPTER_UNLOCK(sc);
26521ffd6e58SKip Macy 			return (EBUSY);
26531ffd6e58SKip Macy 		}
26541ffd6e58SKip Macy 
26551ffd6e58SKip Macy 		fw_data = malloc(t->len, M_DEVBUF, M_NOWAIT);
26561ffd6e58SKip Macy 		if (!fw_data)
26571ffd6e58SKip Macy 			error = ENOMEM;
26581ffd6e58SKip Macy 		else
26591ffd6e58SKip Macy 			error = copyin(t->buf, fw_data, t->len);
26601ffd6e58SKip Macy 
26611ffd6e58SKip Macy 		if (!error)
26621ffd6e58SKip Macy 			error = -t3_load_fw(sc, fw_data, t->len);
26631ffd6e58SKip Macy 
26641ffd6e58SKip Macy 		if (t3_get_fw_version(sc, &vers) == 0) {
26651ffd6e58SKip Macy 			snprintf(&sc->fw_version[0], sizeof(sc->fw_version),
26661ffd6e58SKip Macy 			    "%d.%d.%d", G_FW_VERSION_MAJOR(vers),
26671ffd6e58SKip Macy 			    G_FW_VERSION_MINOR(vers), G_FW_VERSION_MICRO(vers));
26681ffd6e58SKip Macy 		}
26691ffd6e58SKip Macy 
26701ffd6e58SKip Macy 		if (!error)
26711ffd6e58SKip Macy 			sc->flags |= FW_UPTODATE;
26721ffd6e58SKip Macy 
26731ffd6e58SKip Macy 		free(fw_data, M_DEVBUF);
26741ffd6e58SKip Macy 		ADAPTER_UNLOCK(sc);
2675b6d90eb7SKip Macy 		break;
26761ffd6e58SKip Macy 	}
26771ffd6e58SKip Macy 	case CHELSIO_LOAD_BOOT: {
26781ffd6e58SKip Macy 		uint8_t *boot_data;
26791ffd6e58SKip Macy 		struct ch_mem_range *t = (struct ch_mem_range *)data;
26801ffd6e58SKip Macy 
26811ffd6e58SKip Macy 		boot_data = malloc(t->len, M_DEVBUF, M_NOWAIT);
26821ffd6e58SKip Macy 		if (!boot_data)
26831ffd6e58SKip Macy 			return ENOMEM;
26841ffd6e58SKip Macy 
26851ffd6e58SKip Macy 		error = copyin(t->buf, boot_data, t->len);
26861ffd6e58SKip Macy 		if (!error)
26871ffd6e58SKip Macy 			error = -t3_load_boot(sc, boot_data, t->len);
26881ffd6e58SKip Macy 
26891ffd6e58SKip Macy 		free(boot_data, M_DEVBUF);
26901ffd6e58SKip Macy 		break;
26911ffd6e58SKip Macy 	}
26921ffd6e58SKip Macy 	case CHELSIO_GET_PM: {
26931ffd6e58SKip Macy 		struct ch_pm *m = (struct ch_pm *)data;
26941ffd6e58SKip Macy 		struct tp_params *p = &sc->params.tp;
26951ffd6e58SKip Macy 
26961ffd6e58SKip Macy 		if (!is_offload(sc))
26971ffd6e58SKip Macy 			return (EOPNOTSUPP);
26981ffd6e58SKip Macy 
26991ffd6e58SKip Macy 		m->tx_pg_sz = p->tx_pg_size;
27001ffd6e58SKip Macy 		m->tx_num_pg = p->tx_num_pgs;
27011ffd6e58SKip Macy 		m->rx_pg_sz  = p->rx_pg_size;
27021ffd6e58SKip Macy 		m->rx_num_pg = p->rx_num_pgs;
27031ffd6e58SKip Macy 		m->pm_total  = p->pmtx_size + p->chan_rx_size * p->nchan;
27041ffd6e58SKip Macy 
27051ffd6e58SKip Macy 		break;
27061ffd6e58SKip Macy 	}
27071ffd6e58SKip Macy 	case CHELSIO_SET_PM: {
27081ffd6e58SKip Macy 		struct ch_pm *m = (struct ch_pm *)data;
27091ffd6e58SKip Macy 		struct tp_params *p = &sc->params.tp;
27101ffd6e58SKip Macy 
27111ffd6e58SKip Macy 		if (!is_offload(sc))
27121ffd6e58SKip Macy 			return (EOPNOTSUPP);
27131ffd6e58SKip Macy 		if (sc->flags & FULL_INIT_DONE)
27141ffd6e58SKip Macy 			return (EBUSY);
27151ffd6e58SKip Macy 
27161ffd6e58SKip Macy 		if (!m->rx_pg_sz || (m->rx_pg_sz & (m->rx_pg_sz - 1)) ||
27171ffd6e58SKip Macy 		    !m->tx_pg_sz || (m->tx_pg_sz & (m->tx_pg_sz - 1)))
27181ffd6e58SKip Macy 			return (EINVAL);	/* not power of 2 */
27191ffd6e58SKip Macy 		if (!(m->rx_pg_sz & 0x14000))
27201ffd6e58SKip Macy 			return (EINVAL);	/* not 16KB or 64KB */
27211ffd6e58SKip Macy 		if (!(m->tx_pg_sz & 0x1554000))
27221ffd6e58SKip Macy 			return (EINVAL);
27231ffd6e58SKip Macy 		if (m->tx_num_pg == -1)
27241ffd6e58SKip Macy 			m->tx_num_pg = p->tx_num_pgs;
27251ffd6e58SKip Macy 		if (m->rx_num_pg == -1)
27261ffd6e58SKip Macy 			m->rx_num_pg = p->rx_num_pgs;
27271ffd6e58SKip Macy 		if (m->tx_num_pg % 24 || m->rx_num_pg % 24)
27281ffd6e58SKip Macy 			return (EINVAL);
27291ffd6e58SKip Macy 		if (m->rx_num_pg * m->rx_pg_sz > p->chan_rx_size ||
27301ffd6e58SKip Macy 		    m->tx_num_pg * m->tx_pg_sz > p->chan_tx_size)
27311ffd6e58SKip Macy 			return (EINVAL);
27321ffd6e58SKip Macy 
27331ffd6e58SKip Macy 		p->rx_pg_size = m->rx_pg_sz;
27341ffd6e58SKip Macy 		p->tx_pg_size = m->tx_pg_sz;
27351ffd6e58SKip Macy 		p->rx_num_pgs = m->rx_num_pg;
27361ffd6e58SKip Macy 		p->tx_num_pgs = m->tx_num_pg;
27371ffd6e58SKip Macy 		break;
27381ffd6e58SKip Macy 	}
2739d722cab4SKip Macy 	case CHELSIO_SETMTUTAB: {
2740d722cab4SKip Macy 		struct ch_mtus *m = (struct ch_mtus *)data;
2741d722cab4SKip Macy 		int i;
2742d722cab4SKip Macy 
2743d722cab4SKip Macy 		if (!is_offload(sc))
2744d722cab4SKip Macy 			return (EOPNOTSUPP);
2745d722cab4SKip Macy 		if (offload_running(sc))
2746d722cab4SKip Macy 			return (EBUSY);
2747d722cab4SKip Macy 		if (m->nmtus != NMTUS)
2748d722cab4SKip Macy 			return (EINVAL);
2749d722cab4SKip Macy 		if (m->mtus[0] < 81)         /* accommodate SACK */
2750d722cab4SKip Macy 			return (EINVAL);
2751d722cab4SKip Macy 
2752d722cab4SKip Macy 		/*
2753d722cab4SKip Macy 		 * MTUs must be in ascending order
2754d722cab4SKip Macy 		 */
2755d722cab4SKip Macy 		for (i = 1; i < NMTUS; ++i)
2756d722cab4SKip Macy 			if (m->mtus[i] < m->mtus[i - 1])
2757d722cab4SKip Macy 				return (EINVAL);
2758d722cab4SKip Macy 
27591ffd6e58SKip Macy 		memcpy(sc->params.mtus, m->mtus, sizeof(sc->params.mtus));
2760d722cab4SKip Macy 		break;
2761d722cab4SKip Macy 	}
2762d722cab4SKip Macy 	case CHELSIO_GETMTUTAB: {
2763d722cab4SKip Macy 		struct ch_mtus *m = (struct ch_mtus *)data;
2764d722cab4SKip Macy 
2765d722cab4SKip Macy 		if (!is_offload(sc))
2766d722cab4SKip Macy 			return (EOPNOTSUPP);
2767d722cab4SKip Macy 
2768d722cab4SKip Macy 		memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus));
2769d722cab4SKip Macy 		m->nmtus = NMTUS;
2770d722cab4SKip Macy 		break;
2771d722cab4SKip Macy 	}
2772b6d90eb7SKip Macy 	case CHELSIO_GET_MEM: {
2773b6d90eb7SKip Macy 		struct ch_mem_range *t = (struct ch_mem_range *)data;
2774b6d90eb7SKip Macy 		struct mc7 *mem;
2775b6d90eb7SKip Macy 		uint8_t *useraddr;
2776b6d90eb7SKip Macy 		u64 buf[32];
2777b6d90eb7SKip Macy 
27781ffd6e58SKip Macy 		/*
27796bccea7cSRebecca Cran 		 * Use these to avoid modifying len/addr in the return
27801ffd6e58SKip Macy 		 * struct
27811ffd6e58SKip Macy 		 */
27821ffd6e58SKip Macy 		uint32_t len = t->len, addr = t->addr;
27831ffd6e58SKip Macy 
2784b6d90eb7SKip Macy 		if (!is_offload(sc))
2785b6d90eb7SKip Macy 			return (EOPNOTSUPP);
2786b6d90eb7SKip Macy 		if (!(sc->flags & FULL_INIT_DONE))
2787b6d90eb7SKip Macy 			return (EIO);         /* need the memory controllers */
27881ffd6e58SKip Macy 		if ((addr & 0x7) || (len & 0x7))
2789b6d90eb7SKip Macy 			return (EINVAL);
2790b6d90eb7SKip Macy 		if (t->mem_id == MEM_CM)
2791b6d90eb7SKip Macy 			mem = &sc->cm;
2792b6d90eb7SKip Macy 		else if (t->mem_id == MEM_PMRX)
2793b6d90eb7SKip Macy 			mem = &sc->pmrx;
2794b6d90eb7SKip Macy 		else if (t->mem_id == MEM_PMTX)
2795b6d90eb7SKip Macy 			mem = &sc->pmtx;
2796b6d90eb7SKip Macy 		else
2797b6d90eb7SKip Macy 			return (EINVAL);
2798b6d90eb7SKip Macy 
2799b6d90eb7SKip Macy 		/*
2800b6d90eb7SKip Macy 		 * Version scheme:
2801b6d90eb7SKip Macy 		 * bits 0..9: chip version
2802b6d90eb7SKip Macy 		 * bits 10..15: chip revision
2803b6d90eb7SKip Macy 		 */
2804b6d90eb7SKip Macy 		t->version = 3 | (sc->params.rev << 10);
2805b6d90eb7SKip Macy 
2806b6d90eb7SKip Macy 		/*
2807b6d90eb7SKip Macy 		 * Read 256 bytes at a time as len can be large and we don't
2808b6d90eb7SKip Macy 		 * want to use huge intermediate buffers.
2809b6d90eb7SKip Macy 		 */
28108090c9f5SKip Macy 		useraddr = (uint8_t *)t->buf;
28111ffd6e58SKip Macy 		while (len) {
28121ffd6e58SKip Macy 			unsigned int chunk = min(len, sizeof(buf));
2813b6d90eb7SKip Macy 
28141ffd6e58SKip Macy 			error = t3_mc7_bd_read(mem, addr / 8, chunk / 8, buf);
2815b6d90eb7SKip Macy 			if (error)
2816b6d90eb7SKip Macy 				return (-error);
2817b6d90eb7SKip Macy 			if (copyout(buf, useraddr, chunk))
2818b6d90eb7SKip Macy 				return (EFAULT);
2819b6d90eb7SKip Macy 			useraddr += chunk;
28201ffd6e58SKip Macy 			addr += chunk;
28211ffd6e58SKip Macy 			len -= chunk;
2822b6d90eb7SKip Macy 		}
2823b6d90eb7SKip Macy 		break;
2824b6d90eb7SKip Macy 	}
2825d722cab4SKip Macy 	case CHELSIO_READ_TCAM_WORD: {
2826d722cab4SKip Macy 		struct ch_tcam_word *t = (struct ch_tcam_word *)data;
2827d722cab4SKip Macy 
2828d722cab4SKip Macy 		if (!is_offload(sc))
2829d722cab4SKip Macy 			return (EOPNOTSUPP);
2830ac3a6d9cSKip Macy 		if (!(sc->flags & FULL_INIT_DONE))
2831ac3a6d9cSKip Macy 			return (EIO);         /* need MC5 */
2832d722cab4SKip Macy 		return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf);
2833d722cab4SKip Macy 		break;
2834d722cab4SKip Macy 	}
2835b6d90eb7SKip Macy 	case CHELSIO_SET_TRACE_FILTER: {
2836b6d90eb7SKip Macy 		struct ch_trace *t = (struct ch_trace *)data;
2837b6d90eb7SKip Macy 		const struct trace_params *tp;
2838b6d90eb7SKip Macy 
2839b6d90eb7SKip Macy 		tp = (const struct trace_params *)&t->sip;
2840b6d90eb7SKip Macy 		if (t->config_tx)
2841b6d90eb7SKip Macy 			t3_config_trace_filter(sc, tp, 0, t->invert_match,
2842b6d90eb7SKip Macy 					       t->trace_tx);
2843b6d90eb7SKip Macy 		if (t->config_rx)
2844b6d90eb7SKip Macy 			t3_config_trace_filter(sc, tp, 1, t->invert_match,
2845b6d90eb7SKip Macy 					       t->trace_rx);
2846b6d90eb7SKip Macy 		break;
2847b6d90eb7SKip Macy 	}
2848b6d90eb7SKip Macy 	case CHELSIO_SET_PKTSCHED: {
2849b6d90eb7SKip Macy 		struct ch_pktsched_params *p = (struct ch_pktsched_params *)data;
2850b6d90eb7SKip Macy 		if (sc->open_device_map == 0)
2851b6d90eb7SKip Macy 			return (EAGAIN);
2852b6d90eb7SKip Macy 		send_pktsched_cmd(sc, p->sched, p->idx, p->min, p->max,
2853b6d90eb7SKip Macy 		    p->binding);
2854b6d90eb7SKip Macy 		break;
2855b6d90eb7SKip Macy 	}
2856b6d90eb7SKip Macy 	case CHELSIO_IFCONF_GETREGS: {
28571ffd6e58SKip Macy 		struct ch_ifconf_regs *regs = (struct ch_ifconf_regs *)data;
2858b6d90eb7SKip Macy 		int reglen = cxgb_get_regs_len();
28591ffd6e58SKip Macy 		uint8_t *buf = malloc(reglen, M_DEVBUF, M_NOWAIT);
2860b6d90eb7SKip Macy 		if (buf == NULL) {
2861b6d90eb7SKip Macy 			return (ENOMEM);
2862b6d90eb7SKip Macy 		}
28631ffd6e58SKip Macy 		if (regs->len > reglen)
28641ffd6e58SKip Macy 			regs->len = reglen;
28651ffd6e58SKip Macy 		else if (regs->len < reglen)
2866f2d8ff04SGeorge V. Neville-Neil 			error = ENOBUFS;
28671ffd6e58SKip Macy 
28681ffd6e58SKip Macy 		if (!error) {
2869b6d90eb7SKip Macy 			cxgb_get_regs(sc, regs, buf);
2870b6d90eb7SKip Macy 			error = copyout(buf, regs->data, reglen);
28711ffd6e58SKip Macy 		}
2872b6d90eb7SKip Macy 		free(buf, M_DEVBUF);
2873b6d90eb7SKip Macy 
2874b6d90eb7SKip Macy 		break;
2875b6d90eb7SKip Macy 	}
2876d722cab4SKip Macy 	case CHELSIO_SET_HW_SCHED: {
2877d722cab4SKip Macy 		struct ch_hw_sched *t = (struct ch_hw_sched *)data;
2878d722cab4SKip Macy 		unsigned int ticks_per_usec = core_ticks_per_usec(sc);
2879d722cab4SKip Macy 
2880d722cab4SKip Macy 		if ((sc->flags & FULL_INIT_DONE) == 0)
2881d722cab4SKip Macy 			return (EAGAIN);       /* need TP to be initialized */
2882d722cab4SKip Macy 		if (t->sched >= NTX_SCHED || !in_range(t->mode, 0, 1) ||
2883d722cab4SKip Macy 		    !in_range(t->channel, 0, 1) ||
2884d722cab4SKip Macy 		    !in_range(t->kbps, 0, 10000000) ||
2885d722cab4SKip Macy 		    !in_range(t->class_ipg, 0, 10000 * 65535 / ticks_per_usec) ||
2886d722cab4SKip Macy 		    !in_range(t->flow_ipg, 0,
2887d722cab4SKip Macy 			      dack_ticks_to_usec(sc, 0x7ff)))
2888d722cab4SKip Macy 			return (EINVAL);
2889d722cab4SKip Macy 
2890d722cab4SKip Macy 		if (t->kbps >= 0) {
2891d722cab4SKip Macy 			error = t3_config_sched(sc, t->kbps, t->sched);
2892d722cab4SKip Macy 			if (error < 0)
2893d722cab4SKip Macy 				return (-error);
2894d722cab4SKip Macy 		}
2895d722cab4SKip Macy 		if (t->class_ipg >= 0)
2896d722cab4SKip Macy 			t3_set_sched_ipg(sc, t->sched, t->class_ipg);
2897d722cab4SKip Macy 		if (t->flow_ipg >= 0) {
2898d722cab4SKip Macy 			t->flow_ipg *= 1000;     /* us -> ns */
2899d722cab4SKip Macy 			t3_set_pace_tbl(sc, &t->flow_ipg, t->sched, 1);
2900d722cab4SKip Macy 		}
2901d722cab4SKip Macy 		if (t->mode >= 0) {
2902d722cab4SKip Macy 			int bit = 1 << (S_TX_MOD_TIMER_MODE + t->sched);
2903d722cab4SKip Macy 
2904d722cab4SKip Macy 			t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2905d722cab4SKip Macy 					 bit, t->mode ? bit : 0);
2906d722cab4SKip Macy 		}
2907d722cab4SKip Macy 		if (t->channel >= 0)
2908d722cab4SKip Macy 			t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2909d722cab4SKip Macy 					 1 << t->sched, t->channel << t->sched);
2910d722cab4SKip Macy 		break;
2911d722cab4SKip Macy 	}
29121ffd6e58SKip Macy 	case CHELSIO_GET_EEPROM: {
29131ffd6e58SKip Macy 		int i;
29141ffd6e58SKip Macy 		struct ch_eeprom *e = (struct ch_eeprom *)data;
291576aca1d6SNavdeep Parhar 		uint8_t *buf;
29161ffd6e58SKip Macy 
291776aca1d6SNavdeep Parhar 		if (e->offset & 3 || e->offset >= EEPROMSIZE ||
291876aca1d6SNavdeep Parhar 		    e->len > EEPROMSIZE || e->offset + e->len > EEPROMSIZE) {
291976aca1d6SNavdeep Parhar 			return (EINVAL);
292076aca1d6SNavdeep Parhar 		}
292176aca1d6SNavdeep Parhar 
292276aca1d6SNavdeep Parhar 		buf = malloc(EEPROMSIZE, M_DEVBUF, M_NOWAIT);
29231ffd6e58SKip Macy 		if (buf == NULL) {
29241ffd6e58SKip Macy 			return (ENOMEM);
29251ffd6e58SKip Macy 		}
29261ffd6e58SKip Macy 		e->magic = EEPROM_MAGIC;
29271ffd6e58SKip Macy 		for (i = e->offset & ~3; !error && i < e->offset + e->len; i += 4)
29281ffd6e58SKip Macy 			error = -t3_seeprom_read(sc, i, (uint32_t *)&buf[i]);
29291ffd6e58SKip Macy 
29301ffd6e58SKip Macy 		if (!error)
29311ffd6e58SKip Macy 			error = copyout(buf + e->offset, e->data, e->len);
29321ffd6e58SKip Macy 
29331ffd6e58SKip Macy 		free(buf, M_DEVBUF);
29341ffd6e58SKip Macy 		break;
29351ffd6e58SKip Macy 	}
29361ffd6e58SKip Macy 	case CHELSIO_CLEAR_STATS: {
29371ffd6e58SKip Macy 		if (!(sc->flags & FULL_INIT_DONE))
29381ffd6e58SKip Macy 			return EAGAIN;
29391ffd6e58SKip Macy 
29401ffd6e58SKip Macy 		PORT_LOCK(pi);
29411ffd6e58SKip Macy 		t3_mac_update_stats(&pi->mac);
29421ffd6e58SKip Macy 		memset(&pi->mac.stats, 0, sizeof(pi->mac.stats));
29431ffd6e58SKip Macy 		PORT_UNLOCK(pi);
29441ffd6e58SKip Macy 		break;
29451ffd6e58SKip Macy 	}
2946f2d8ff04SGeorge V. Neville-Neil 	case CHELSIO_GET_UP_LA: {
2947f2d8ff04SGeorge V. Neville-Neil 		struct ch_up_la *la = (struct ch_up_la *)data;
2948f2d8ff04SGeorge V. Neville-Neil 		uint8_t *buf = malloc(LA_BUFSIZE, M_DEVBUF, M_NOWAIT);
2949f2d8ff04SGeorge V. Neville-Neil 		if (buf == NULL) {
2950f2d8ff04SGeorge V. Neville-Neil 			return (ENOMEM);
2951f2d8ff04SGeorge V. Neville-Neil 		}
2952f2d8ff04SGeorge V. Neville-Neil 		if (la->bufsize < LA_BUFSIZE)
2953f2d8ff04SGeorge V. Neville-Neil 			error = ENOBUFS;
2954f2d8ff04SGeorge V. Neville-Neil 
2955f2d8ff04SGeorge V. Neville-Neil 		if (!error)
2956f2d8ff04SGeorge V. Neville-Neil 			error = -t3_get_up_la(sc, &la->stopped, &la->idx,
2957f2d8ff04SGeorge V. Neville-Neil 					      &la->bufsize, buf);
2958f2d8ff04SGeorge V. Neville-Neil 		if (!error)
2959f2d8ff04SGeorge V. Neville-Neil 			error = copyout(buf, la->data, la->bufsize);
2960f2d8ff04SGeorge V. Neville-Neil 
2961f2d8ff04SGeorge V. Neville-Neil 		free(buf, M_DEVBUF);
2962f2d8ff04SGeorge V. Neville-Neil 		break;
2963f2d8ff04SGeorge V. Neville-Neil 	}
2964f2d8ff04SGeorge V. Neville-Neil 	case CHELSIO_GET_UP_IOQS: {
2965f2d8ff04SGeorge V. Neville-Neil 		struct ch_up_ioqs *ioqs = (struct ch_up_ioqs *)data;
2966f2d8ff04SGeorge V. Neville-Neil 		uint8_t *buf = malloc(IOQS_BUFSIZE, M_DEVBUF, M_NOWAIT);
2967f2d8ff04SGeorge V. Neville-Neil 		uint32_t *v;
2968f2d8ff04SGeorge V. Neville-Neil 
2969f2d8ff04SGeorge V. Neville-Neil 		if (buf == NULL) {
2970f2d8ff04SGeorge V. Neville-Neil 			return (ENOMEM);
2971f2d8ff04SGeorge V. Neville-Neil 		}
2972f2d8ff04SGeorge V. Neville-Neil 		if (ioqs->bufsize < IOQS_BUFSIZE)
2973f2d8ff04SGeorge V. Neville-Neil 			error = ENOBUFS;
2974f2d8ff04SGeorge V. Neville-Neil 
2975f2d8ff04SGeorge V. Neville-Neil 		if (!error)
2976f2d8ff04SGeorge V. Neville-Neil 			error = -t3_get_up_ioqs(sc, &ioqs->bufsize, buf);
2977f2d8ff04SGeorge V. Neville-Neil 
2978f2d8ff04SGeorge V. Neville-Neil 		if (!error) {
2979f2d8ff04SGeorge V. Neville-Neil 			v = (uint32_t *)buf;
2980f2d8ff04SGeorge V. Neville-Neil 
2981f2d8ff04SGeorge V. Neville-Neil 			ioqs->ioq_rx_enable = *v++;
2982f2d8ff04SGeorge V. Neville-Neil 			ioqs->ioq_tx_enable = *v++;
2983f2d8ff04SGeorge V. Neville-Neil 			ioqs->ioq_rx_status = *v++;
2984f2d8ff04SGeorge V. Neville-Neil 			ioqs->ioq_tx_status = *v++;
2985f2d8ff04SGeorge V. Neville-Neil 
2986f2d8ff04SGeorge V. Neville-Neil 			error = copyout(v, ioqs->data, ioqs->bufsize);
2987f2d8ff04SGeorge V. Neville-Neil 		}
2988f2d8ff04SGeorge V. Neville-Neil 
2989f2d8ff04SGeorge V. Neville-Neil 		free(buf, M_DEVBUF);
2990f2d8ff04SGeorge V. Neville-Neil 		break;
2991f2d8ff04SGeorge V. Neville-Neil 	}
2992d6da8362SNavdeep Parhar 	case CHELSIO_SET_FILTER: {
2993db702c59SEitan Adler 		struct ch_filter *f = (struct ch_filter *)data;
2994d6da8362SNavdeep Parhar 		struct filter_info *p;
2995d6da8362SNavdeep Parhar 		unsigned int nfilters = sc->params.mc5.nfilters;
2996d6da8362SNavdeep Parhar 
2997d6da8362SNavdeep Parhar 		if (!is_offload(sc))
2998d6da8362SNavdeep Parhar 			return (EOPNOTSUPP);	/* No TCAM */
2999d6da8362SNavdeep Parhar 		if (!(sc->flags & FULL_INIT_DONE))
3000d6da8362SNavdeep Parhar 			return (EAGAIN);	/* mc5 not setup yet */
3001d6da8362SNavdeep Parhar 		if (nfilters == 0)
3002d6da8362SNavdeep Parhar 			return (EBUSY);		/* TOE will use TCAM */
3003d6da8362SNavdeep Parhar 
3004d6da8362SNavdeep Parhar 		/* sanity checks */
3005d6da8362SNavdeep Parhar 		if (f->filter_id >= nfilters ||
3006d6da8362SNavdeep Parhar 		    (f->val.dip && f->mask.dip != 0xffffffff) ||
3007d6da8362SNavdeep Parhar 		    (f->val.sport && f->mask.sport != 0xffff) ||
3008d6da8362SNavdeep Parhar 		    (f->val.dport && f->mask.dport != 0xffff) ||
3009d6da8362SNavdeep Parhar 		    (f->val.vlan && f->mask.vlan != 0xfff) ||
3010d6da8362SNavdeep Parhar 		    (f->val.vlan_prio &&
3011d6da8362SNavdeep Parhar 			f->mask.vlan_prio != FILTER_NO_VLAN_PRI) ||
3012d6da8362SNavdeep Parhar 		    (f->mac_addr_idx != 0xffff && f->mac_addr_idx > 15) ||
3013d6da8362SNavdeep Parhar 		    f->qset >= SGE_QSETS ||
3014d6da8362SNavdeep Parhar 		    sc->rrss_map[f->qset] >= RSS_TABLE_SIZE)
3015d6da8362SNavdeep Parhar 			return (EINVAL);
3016d6da8362SNavdeep Parhar 
3017d6da8362SNavdeep Parhar 		/* Was allocated with M_WAITOK */
3018d6da8362SNavdeep Parhar 		KASSERT(sc->filters, ("filter table NULL\n"));
3019d6da8362SNavdeep Parhar 
3020d6da8362SNavdeep Parhar 		p = &sc->filters[f->filter_id];
3021d6da8362SNavdeep Parhar 		if (p->locked)
3022d6da8362SNavdeep Parhar 			return (EPERM);
3023d6da8362SNavdeep Parhar 
3024d6da8362SNavdeep Parhar 		bzero(p, sizeof(*p));
3025d6da8362SNavdeep Parhar 		p->sip = f->val.sip;
3026d6da8362SNavdeep Parhar 		p->sip_mask = f->mask.sip;
3027d6da8362SNavdeep Parhar 		p->dip = f->val.dip;
3028d6da8362SNavdeep Parhar 		p->sport = f->val.sport;
3029d6da8362SNavdeep Parhar 		p->dport = f->val.dport;
3030d6da8362SNavdeep Parhar 		p->vlan = f->mask.vlan ? f->val.vlan : 0xfff;
3031d6da8362SNavdeep Parhar 		p->vlan_prio = f->mask.vlan_prio ? (f->val.vlan_prio & 6) :
3032d6da8362SNavdeep Parhar 		    FILTER_NO_VLAN_PRI;
3033d6da8362SNavdeep Parhar 		p->mac_hit = f->mac_hit;
3034d6da8362SNavdeep Parhar 		p->mac_vld = f->mac_addr_idx != 0xffff;
3035d6da8362SNavdeep Parhar 		p->mac_idx = f->mac_addr_idx;
3036d6da8362SNavdeep Parhar 		p->pkt_type = f->proto;
3037d6da8362SNavdeep Parhar 		p->report_filter_id = f->want_filter_id;
3038d6da8362SNavdeep Parhar 		p->pass = f->pass;
3039d6da8362SNavdeep Parhar 		p->rss = f->rss;
3040d6da8362SNavdeep Parhar 		p->qset = f->qset;
3041d6da8362SNavdeep Parhar 
3042d6da8362SNavdeep Parhar 		error = set_filter(sc, f->filter_id, p);
3043d6da8362SNavdeep Parhar 		if (error == 0)
3044d6da8362SNavdeep Parhar 			p->valid = 1;
3045d6da8362SNavdeep Parhar 		break;
3046d6da8362SNavdeep Parhar 	}
3047d6da8362SNavdeep Parhar 	case CHELSIO_DEL_FILTER: {
3048d6da8362SNavdeep Parhar 		struct ch_filter *f = (struct ch_filter *)data;
3049d6da8362SNavdeep Parhar 		struct filter_info *p;
3050d6da8362SNavdeep Parhar 		unsigned int nfilters = sc->params.mc5.nfilters;
3051d6da8362SNavdeep Parhar 
3052d6da8362SNavdeep Parhar 		if (!is_offload(sc))
3053d6da8362SNavdeep Parhar 			return (EOPNOTSUPP);
3054d6da8362SNavdeep Parhar 		if (!(sc->flags & FULL_INIT_DONE))
3055d6da8362SNavdeep Parhar 			return (EAGAIN);
3056d6da8362SNavdeep Parhar 		if (nfilters == 0 || sc->filters == NULL)
3057d6da8362SNavdeep Parhar 			return (EINVAL);
3058d6da8362SNavdeep Parhar 		if (f->filter_id >= nfilters)
3059d6da8362SNavdeep Parhar 		       return (EINVAL);
3060d6da8362SNavdeep Parhar 
3061d6da8362SNavdeep Parhar 		p = &sc->filters[f->filter_id];
3062d6da8362SNavdeep Parhar 		if (p->locked)
3063d6da8362SNavdeep Parhar 			return (EPERM);
3064d6da8362SNavdeep Parhar 		if (!p->valid)
3065d6da8362SNavdeep Parhar 			return (EFAULT); /* Read "Bad address" as "Bad index" */
3066d6da8362SNavdeep Parhar 
3067d6da8362SNavdeep Parhar 		bzero(p, sizeof(*p));
3068d6da8362SNavdeep Parhar 		p->sip = p->sip_mask = 0xffffffff;
3069d6da8362SNavdeep Parhar 		p->vlan = 0xfff;
3070d6da8362SNavdeep Parhar 		p->vlan_prio = FILTER_NO_VLAN_PRI;
3071d6da8362SNavdeep Parhar 		p->pkt_type = 1;
3072d6da8362SNavdeep Parhar 		error = set_filter(sc, f->filter_id, p);
3073d6da8362SNavdeep Parhar 		break;
3074d6da8362SNavdeep Parhar 	}
3075d6da8362SNavdeep Parhar 	case CHELSIO_GET_FILTER: {
3076d6da8362SNavdeep Parhar 		struct ch_filter *f = (struct ch_filter *)data;
3077d6da8362SNavdeep Parhar 		struct filter_info *p;
3078d6da8362SNavdeep Parhar 		unsigned int i, nfilters = sc->params.mc5.nfilters;
3079d6da8362SNavdeep Parhar 
3080d6da8362SNavdeep Parhar 		if (!is_offload(sc))
3081d6da8362SNavdeep Parhar 			return (EOPNOTSUPP);
3082d6da8362SNavdeep Parhar 		if (!(sc->flags & FULL_INIT_DONE))
3083d6da8362SNavdeep Parhar 			return (EAGAIN);
3084d6da8362SNavdeep Parhar 		if (nfilters == 0 || sc->filters == NULL)
3085d6da8362SNavdeep Parhar 			return (EINVAL);
3086d6da8362SNavdeep Parhar 
3087d6da8362SNavdeep Parhar 		i = f->filter_id == 0xffffffff ? 0 : f->filter_id + 1;
3088d6da8362SNavdeep Parhar 		for (; i < nfilters; i++) {
3089d6da8362SNavdeep Parhar 			p = &sc->filters[i];
3090d6da8362SNavdeep Parhar 			if (!p->valid)
3091d6da8362SNavdeep Parhar 				continue;
3092d6da8362SNavdeep Parhar 
3093d6da8362SNavdeep Parhar 			bzero(f, sizeof(*f));
3094d6da8362SNavdeep Parhar 
3095d6da8362SNavdeep Parhar 			f->filter_id = i;
3096d6da8362SNavdeep Parhar 			f->val.sip = p->sip;
3097d6da8362SNavdeep Parhar 			f->mask.sip = p->sip_mask;
3098d6da8362SNavdeep Parhar 			f->val.dip = p->dip;
3099d6da8362SNavdeep Parhar 			f->mask.dip = p->dip ? 0xffffffff : 0;
3100d6da8362SNavdeep Parhar 			f->val.sport = p->sport;
3101d6da8362SNavdeep Parhar 			f->mask.sport = p->sport ? 0xffff : 0;
3102d6da8362SNavdeep Parhar 			f->val.dport = p->dport;
3103d6da8362SNavdeep Parhar 			f->mask.dport = p->dport ? 0xffff : 0;
3104d6da8362SNavdeep Parhar 			f->val.vlan = p->vlan == 0xfff ? 0 : p->vlan;
3105d6da8362SNavdeep Parhar 			f->mask.vlan = p->vlan == 0xfff ? 0 : 0xfff;
3106d6da8362SNavdeep Parhar 			f->val.vlan_prio = p->vlan_prio == FILTER_NO_VLAN_PRI ?
3107d6da8362SNavdeep Parhar 			    0 : p->vlan_prio;
3108d6da8362SNavdeep Parhar 			f->mask.vlan_prio = p->vlan_prio == FILTER_NO_VLAN_PRI ?
3109d6da8362SNavdeep Parhar 			    0 : FILTER_NO_VLAN_PRI;
3110d6da8362SNavdeep Parhar 			f->mac_hit = p->mac_hit;
3111d6da8362SNavdeep Parhar 			f->mac_addr_idx = p->mac_vld ? p->mac_idx : 0xffff;
3112d6da8362SNavdeep Parhar 			f->proto = p->pkt_type;
3113d6da8362SNavdeep Parhar 			f->want_filter_id = p->report_filter_id;
3114d6da8362SNavdeep Parhar 			f->pass = p->pass;
3115d6da8362SNavdeep Parhar 			f->rss = p->rss;
3116d6da8362SNavdeep Parhar 			f->qset = p->qset;
3117d6da8362SNavdeep Parhar 
3118d6da8362SNavdeep Parhar 			break;
3119d6da8362SNavdeep Parhar 		}
3120d6da8362SNavdeep Parhar 
3121d6da8362SNavdeep Parhar 		if (i == nfilters)
3122d6da8362SNavdeep Parhar 			f->filter_id = 0xffffffff;
3123d6da8362SNavdeep Parhar 		break;
3124d6da8362SNavdeep Parhar 	}
3125b6d90eb7SKip Macy 	default:
3126b6d90eb7SKip Macy 		return (EOPNOTSUPP);
3127b6d90eb7SKip Macy 		break;
3128b6d90eb7SKip Macy 	}
3129b6d90eb7SKip Macy 
3130b6d90eb7SKip Macy 	return (error);
3131b6d90eb7SKip Macy }
3132b6d90eb7SKip Macy 
3133b6d90eb7SKip Macy static __inline void
reg_block_dump(struct adapter * ap,uint8_t * buf,unsigned int start,unsigned int end)3134b6d90eb7SKip Macy reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
3135b6d90eb7SKip Macy     unsigned int end)
3136b6d90eb7SKip Macy {
31371ffd6e58SKip Macy 	uint32_t *p = (uint32_t *)(buf + start);
3138b6d90eb7SKip Macy 
3139b6d90eb7SKip Macy 	for ( ; start <= end; start += sizeof(uint32_t))
3140b6d90eb7SKip Macy 		*p++ = t3_read_reg(ap, start);
3141b6d90eb7SKip Macy }
3142b6d90eb7SKip Macy 
3143b6d90eb7SKip Macy #define T3_REGMAP_SIZE (3 * 1024)
3144b6d90eb7SKip Macy static int
cxgb_get_regs_len(void)3145b6d90eb7SKip Macy cxgb_get_regs_len(void)
3146b6d90eb7SKip Macy {
3147b6d90eb7SKip Macy 	return T3_REGMAP_SIZE;
3148b6d90eb7SKip Macy }
3149b6d90eb7SKip Macy 
3150b6d90eb7SKip Macy static void
cxgb_get_regs(adapter_t * sc,struct ch_ifconf_regs * regs,uint8_t * buf)31511ffd6e58SKip Macy cxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf)
3152b6d90eb7SKip Macy {
3153b6d90eb7SKip Macy 
3154b6d90eb7SKip Macy 	/*
3155b6d90eb7SKip Macy 	 * Version scheme:
3156b6d90eb7SKip Macy 	 * bits 0..9: chip version
3157b6d90eb7SKip Macy 	 * bits 10..15: chip revision
3158b6d90eb7SKip Macy 	 * bit 31: set for PCIe cards
3159b6d90eb7SKip Macy 	 */
3160b6d90eb7SKip Macy 	regs->version = 3 | (sc->params.rev << 10) | (is_pcie(sc) << 31);
3161b6d90eb7SKip Macy 
3162b6d90eb7SKip Macy 	/*
3163b6d90eb7SKip Macy 	 * We skip the MAC statistics registers because they are clear-on-read.
3164b6d90eb7SKip Macy 	 * Also reading multi-register stats would need to synchronize with the
3165b6d90eb7SKip Macy 	 * periodic mac stats accumulation.  Hard to justify the complexity.
3166b6d90eb7SKip Macy 	 */
31671ffd6e58SKip Macy 	memset(buf, 0, cxgb_get_regs_len());
3168b6d90eb7SKip Macy 	reg_block_dump(sc, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
3169b6d90eb7SKip Macy 	reg_block_dump(sc, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
3170b6d90eb7SKip Macy 	reg_block_dump(sc, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
3171b6d90eb7SKip Macy 	reg_block_dump(sc, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
3172b6d90eb7SKip Macy 	reg_block_dump(sc, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
3173b6d90eb7SKip Macy 	reg_block_dump(sc, buf, A_XGM_SERDES_STATUS0,
3174b6d90eb7SKip Macy 		       XGM_REG(A_XGM_SERDES_STAT3, 1));
3175b6d90eb7SKip Macy 	reg_block_dump(sc, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
3176b6d90eb7SKip Macy 		       XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
3177b6d90eb7SKip Macy }
3178404825a7SKip Macy 
3179d6da8362SNavdeep Parhar static int
alloc_filters(struct adapter * sc)3180d6da8362SNavdeep Parhar alloc_filters(struct adapter *sc)
3181d6da8362SNavdeep Parhar {
3182d6da8362SNavdeep Parhar 	struct filter_info *p;
3183d6da8362SNavdeep Parhar 	unsigned int nfilters = sc->params.mc5.nfilters;
3184d6da8362SNavdeep Parhar 
3185d6da8362SNavdeep Parhar 	if (nfilters == 0)
3186d6da8362SNavdeep Parhar 		return (0);
3187d6da8362SNavdeep Parhar 
3188d6da8362SNavdeep Parhar 	p = malloc(sizeof(*p) * nfilters, M_DEVBUF, M_WAITOK | M_ZERO);
3189d6da8362SNavdeep Parhar 	sc->filters = p;
3190d6da8362SNavdeep Parhar 
3191d6da8362SNavdeep Parhar 	p = &sc->filters[nfilters - 1];
3192d6da8362SNavdeep Parhar 	p->vlan = 0xfff;
3193d6da8362SNavdeep Parhar 	p->vlan_prio = FILTER_NO_VLAN_PRI;
3194d6da8362SNavdeep Parhar 	p->pass = p->rss = p->valid = p->locked = 1;
3195d6da8362SNavdeep Parhar 
3196d6da8362SNavdeep Parhar 	return (0);
3197d6da8362SNavdeep Parhar }
3198d6da8362SNavdeep Parhar 
3199d6da8362SNavdeep Parhar static int
setup_hw_filters(struct adapter * sc)3200d6da8362SNavdeep Parhar setup_hw_filters(struct adapter *sc)
3201d6da8362SNavdeep Parhar {
3202d6da8362SNavdeep Parhar 	int i, rc;
3203d6da8362SNavdeep Parhar 	unsigned int nfilters = sc->params.mc5.nfilters;
3204d6da8362SNavdeep Parhar 
3205d6da8362SNavdeep Parhar 	if (!sc->filters)
3206d6da8362SNavdeep Parhar 		return (0);
3207d6da8362SNavdeep Parhar 
3208d6da8362SNavdeep Parhar 	t3_enable_filters(sc);
3209d6da8362SNavdeep Parhar 
3210d6da8362SNavdeep Parhar 	for (i = rc = 0; i < nfilters && !rc; i++) {
3211d6da8362SNavdeep Parhar 		if (sc->filters[i].locked)
3212d6da8362SNavdeep Parhar 			rc = set_filter(sc, i, &sc->filters[i]);
3213d6da8362SNavdeep Parhar 	}
3214d6da8362SNavdeep Parhar 
3215d6da8362SNavdeep Parhar 	return (rc);
3216d6da8362SNavdeep Parhar }
3217d6da8362SNavdeep Parhar 
3218d6da8362SNavdeep Parhar static int
set_filter(struct adapter * sc,int id,const struct filter_info * f)3219d6da8362SNavdeep Parhar set_filter(struct adapter *sc, int id, const struct filter_info *f)
3220d6da8362SNavdeep Parhar {
3221d6da8362SNavdeep Parhar 	int len;
3222d6da8362SNavdeep Parhar 	struct mbuf *m;
3223d6da8362SNavdeep Parhar 	struct ulp_txpkt *txpkt;
3224d6da8362SNavdeep Parhar 	struct work_request_hdr *wr;
3225d6da8362SNavdeep Parhar 	struct cpl_pass_open_req *oreq;
3226d6da8362SNavdeep Parhar 	struct cpl_set_tcb_field *sreq;
3227d6da8362SNavdeep Parhar 
3228d6da8362SNavdeep Parhar 	len = sizeof(*wr) + sizeof(*oreq) + 2 * sizeof(*sreq);
3229d6da8362SNavdeep Parhar 	KASSERT(len <= MHLEN, ("filter request too big for an mbuf"));
3230d6da8362SNavdeep Parhar 
3231d6da8362SNavdeep Parhar 	id += t3_mc5_size(&sc->mc5) - sc->params.mc5.nroutes -
3232d6da8362SNavdeep Parhar 	      sc->params.mc5.nfilters;
3233d6da8362SNavdeep Parhar 
3234d6da8362SNavdeep Parhar 	m = m_gethdr(M_WAITOK, MT_DATA);
3235d6da8362SNavdeep Parhar 	m->m_len = m->m_pkthdr.len = len;
3236d6da8362SNavdeep Parhar 	bzero(mtod(m, char *), len);
3237d6da8362SNavdeep Parhar 
3238d6da8362SNavdeep Parhar 	wr = mtod(m, struct work_request_hdr *);
3239d6da8362SNavdeep Parhar 	wr->wrh_hi = htonl(V_WR_OP(FW_WROPCODE_BYPASS) | F_WR_ATOMIC);
3240d6da8362SNavdeep Parhar 
3241d6da8362SNavdeep Parhar 	oreq = (struct cpl_pass_open_req *)(wr + 1);
3242d6da8362SNavdeep Parhar 	txpkt = (struct ulp_txpkt *)oreq;
3243d6da8362SNavdeep Parhar 	txpkt->cmd_dest = htonl(V_ULPTX_CMD(ULP_TXPKT));
3244d6da8362SNavdeep Parhar 	txpkt->len = htonl(V_ULPTX_NFLITS(sizeof(*oreq) / 8));
3245d6da8362SNavdeep Parhar 	OPCODE_TID(oreq) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, id));
3246d6da8362SNavdeep Parhar 	oreq->local_port = htons(f->dport);
3247d6da8362SNavdeep Parhar 	oreq->peer_port = htons(f->sport);
3248d6da8362SNavdeep Parhar 	oreq->local_ip = htonl(f->dip);
3249d6da8362SNavdeep Parhar 	oreq->peer_ip = htonl(f->sip);
3250d6da8362SNavdeep Parhar 	oreq->peer_netmask = htonl(f->sip_mask);
3251d6da8362SNavdeep Parhar 	oreq->opt0h = 0;
3252d6da8362SNavdeep Parhar 	oreq->opt0l = htonl(F_NO_OFFLOAD);
3253d6da8362SNavdeep Parhar 	oreq->opt1 = htonl(V_MAC_MATCH_VALID(f->mac_vld) |
3254d6da8362SNavdeep Parhar 			 V_CONN_POLICY(CPL_CONN_POLICY_FILTER) |
3255d6da8362SNavdeep Parhar 			 V_VLAN_PRI(f->vlan_prio >> 1) |
3256d6da8362SNavdeep Parhar 			 V_VLAN_PRI_VALID(f->vlan_prio != FILTER_NO_VLAN_PRI) |
3257d6da8362SNavdeep Parhar 			 V_PKT_TYPE(f->pkt_type) | V_OPT1_VLAN(f->vlan) |
3258d6da8362SNavdeep Parhar 			 V_MAC_MATCH(f->mac_idx | (f->mac_hit << 4)));
3259d6da8362SNavdeep Parhar 
3260d6da8362SNavdeep Parhar 	sreq = (struct cpl_set_tcb_field *)(oreq + 1);
3261d6da8362SNavdeep Parhar 	set_tcb_field_ulp(sreq, id, 1, 0x1800808000ULL,
3262d6da8362SNavdeep Parhar 			  (f->report_filter_id << 15) | (1 << 23) |
3263d6da8362SNavdeep Parhar 			  ((u64)f->pass << 35) | ((u64)!f->rss << 36));
3264d6da8362SNavdeep Parhar 	set_tcb_field_ulp(sreq + 1, id, 0, 0xffffffff, (2 << 19) | 1);
3265d6da8362SNavdeep Parhar 	t3_mgmt_tx(sc, m);
3266d6da8362SNavdeep Parhar 
3267d6da8362SNavdeep Parhar 	if (f->pass && !f->rss) {
3268d6da8362SNavdeep Parhar 		len = sizeof(*sreq);
3269d6da8362SNavdeep Parhar 		m = m_gethdr(M_WAITOK, MT_DATA);
3270d6da8362SNavdeep Parhar 		m->m_len = m->m_pkthdr.len = len;
3271d6da8362SNavdeep Parhar 		bzero(mtod(m, char *), len);
3272d6da8362SNavdeep Parhar 		sreq = mtod(m, struct cpl_set_tcb_field *);
3273d6da8362SNavdeep Parhar 		sreq->wr.wrh_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
3274d6da8362SNavdeep Parhar 		mk_set_tcb_field(sreq, id, 25, 0x3f80000,
3275d6da8362SNavdeep Parhar 				 (u64)sc->rrss_map[f->qset] << 19);
3276d6da8362SNavdeep Parhar 		t3_mgmt_tx(sc, m);
3277d6da8362SNavdeep Parhar 	}
3278d6da8362SNavdeep Parhar 	return 0;
3279d6da8362SNavdeep Parhar }
3280d6da8362SNavdeep Parhar 
3281d6da8362SNavdeep Parhar static inline void
mk_set_tcb_field(struct cpl_set_tcb_field * req,unsigned int tid,unsigned int word,u64 mask,u64 val)3282d6da8362SNavdeep Parhar mk_set_tcb_field(struct cpl_set_tcb_field *req, unsigned int tid,
3283d6da8362SNavdeep Parhar     unsigned int word, u64 mask, u64 val)
3284d6da8362SNavdeep Parhar {
3285d6da8362SNavdeep Parhar 	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
3286d6da8362SNavdeep Parhar 	req->reply = V_NO_REPLY(1);
3287d6da8362SNavdeep Parhar 	req->cpu_idx = 0;
3288d6da8362SNavdeep Parhar 	req->word = htons(word);
3289d6da8362SNavdeep Parhar 	req->mask = htobe64(mask);
3290d6da8362SNavdeep Parhar 	req->val = htobe64(val);
3291d6da8362SNavdeep Parhar }
3292d6da8362SNavdeep Parhar 
3293d6da8362SNavdeep Parhar static inline void
set_tcb_field_ulp(struct cpl_set_tcb_field * req,unsigned int tid,unsigned int word,u64 mask,u64 val)3294d6da8362SNavdeep Parhar set_tcb_field_ulp(struct cpl_set_tcb_field *req, unsigned int tid,
3295d6da8362SNavdeep Parhar     unsigned int word, u64 mask, u64 val)
3296d6da8362SNavdeep Parhar {
3297d6da8362SNavdeep Parhar 	struct ulp_txpkt *txpkt = (struct ulp_txpkt *)req;
3298d6da8362SNavdeep Parhar 
3299d6da8362SNavdeep Parhar 	txpkt->cmd_dest = htonl(V_ULPTX_CMD(ULP_TXPKT));
3300d6da8362SNavdeep Parhar 	txpkt->len = htonl(V_ULPTX_NFLITS(sizeof(*req) / 8));
3301d6da8362SNavdeep Parhar 	mk_set_tcb_field(req, tid, word, mask, val);
3302d6da8362SNavdeep Parhar }
330309fe6320SNavdeep Parhar 
330409fe6320SNavdeep Parhar void
t3_iterate(void (* func)(struct adapter *,void *),void * arg)330509fe6320SNavdeep Parhar t3_iterate(void (*func)(struct adapter *, void *), void *arg)
330609fe6320SNavdeep Parhar {
330709fe6320SNavdeep Parhar 	struct adapter *sc;
330809fe6320SNavdeep Parhar 
330909fe6320SNavdeep Parhar 	mtx_lock(&t3_list_lock);
331009fe6320SNavdeep Parhar 	SLIST_FOREACH(sc, &t3_list, link) {
331109fe6320SNavdeep Parhar 		/*
331209fe6320SNavdeep Parhar 		 * func should not make any assumptions about what state sc is
331309fe6320SNavdeep Parhar 		 * in - the only guarantee is that sc->sc_lock is a valid lock.
331409fe6320SNavdeep Parhar 		 */
331509fe6320SNavdeep Parhar 		func(sc, arg);
331609fe6320SNavdeep Parhar 	}
331709fe6320SNavdeep Parhar 	mtx_unlock(&t3_list_lock);
331809fe6320SNavdeep Parhar }
331909fe6320SNavdeep Parhar 
332009fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
332109fe6320SNavdeep Parhar static int
toe_capability(struct port_info * pi,int enable)332209fe6320SNavdeep Parhar toe_capability(struct port_info *pi, int enable)
332309fe6320SNavdeep Parhar {
332409fe6320SNavdeep Parhar 	int rc;
332509fe6320SNavdeep Parhar 	struct adapter *sc = pi->adapter;
332609fe6320SNavdeep Parhar 
332709fe6320SNavdeep Parhar 	ADAPTER_LOCK_ASSERT_OWNED(sc);
332809fe6320SNavdeep Parhar 
332909fe6320SNavdeep Parhar 	if (!is_offload(sc))
333009fe6320SNavdeep Parhar 		return (ENODEV);
333109fe6320SNavdeep Parhar 
333209fe6320SNavdeep Parhar 	if (enable) {
333309fe6320SNavdeep Parhar 		if (!(sc->flags & FULL_INIT_DONE)) {
333409fe6320SNavdeep Parhar 			log(LOG_WARNING,
333509fe6320SNavdeep Parhar 			    "You must enable a cxgb interface first\n");
333609fe6320SNavdeep Parhar 			return (EAGAIN);
333709fe6320SNavdeep Parhar 		}
333809fe6320SNavdeep Parhar 
333909fe6320SNavdeep Parhar 		if (isset(&sc->offload_map, pi->port_id))
334009fe6320SNavdeep Parhar 			return (0);
334109fe6320SNavdeep Parhar 
334209fe6320SNavdeep Parhar 		if (!(sc->flags & TOM_INIT_DONE)) {
334309fe6320SNavdeep Parhar 			rc = t3_activate_uld(sc, ULD_TOM);
334409fe6320SNavdeep Parhar 			if (rc == EAGAIN) {
334509fe6320SNavdeep Parhar 				log(LOG_WARNING,
334609fe6320SNavdeep Parhar 				    "You must kldload t3_tom.ko before trying "
334709fe6320SNavdeep Parhar 				    "to enable TOE on a cxgb interface.\n");
334809fe6320SNavdeep Parhar 			}
334909fe6320SNavdeep Parhar 			if (rc != 0)
335009fe6320SNavdeep Parhar 				return (rc);
335109fe6320SNavdeep Parhar 			KASSERT(sc->tom_softc != NULL,
335209fe6320SNavdeep Parhar 			    ("%s: TOM activated but softc NULL", __func__));
335309fe6320SNavdeep Parhar 			KASSERT(sc->flags & TOM_INIT_DONE,
335409fe6320SNavdeep Parhar 			    ("%s: TOM activated but flag not set", __func__));
335509fe6320SNavdeep Parhar 		}
335609fe6320SNavdeep Parhar 
335709fe6320SNavdeep Parhar 		setbit(&sc->offload_map, pi->port_id);
335809fe6320SNavdeep Parhar 
335909fe6320SNavdeep Parhar 		/*
336009fe6320SNavdeep Parhar 		 * XXX: Temporary code to allow iWARP to be enabled when TOE is
336109fe6320SNavdeep Parhar 		 * enabled on any port.  Need to figure out how to enable,
336209fe6320SNavdeep Parhar 		 * disable, load, and unload iWARP cleanly.
336309fe6320SNavdeep Parhar 		 */
336409fe6320SNavdeep Parhar 		if (!isset(&sc->offload_map, MAX_NPORTS) &&
336509fe6320SNavdeep Parhar 		    t3_activate_uld(sc, ULD_IWARP) == 0)
336609fe6320SNavdeep Parhar 			setbit(&sc->offload_map, MAX_NPORTS);
336709fe6320SNavdeep Parhar 	} else {
336809fe6320SNavdeep Parhar 		if (!isset(&sc->offload_map, pi->port_id))
336909fe6320SNavdeep Parhar 			return (0);
337009fe6320SNavdeep Parhar 
337109fe6320SNavdeep Parhar 		KASSERT(sc->flags & TOM_INIT_DONE,
337209fe6320SNavdeep Parhar 		    ("%s: TOM never initialized?", __func__));
337309fe6320SNavdeep Parhar 		clrbit(&sc->offload_map, pi->port_id);
337409fe6320SNavdeep Parhar 	}
337509fe6320SNavdeep Parhar 
337609fe6320SNavdeep Parhar 	return (0);
337709fe6320SNavdeep Parhar }
337809fe6320SNavdeep Parhar 
337909fe6320SNavdeep Parhar /*
338009fe6320SNavdeep Parhar  * Add an upper layer driver to the global list.
338109fe6320SNavdeep Parhar  */
338209fe6320SNavdeep Parhar int
t3_register_uld(struct uld_info * ui)338309fe6320SNavdeep Parhar t3_register_uld(struct uld_info *ui)
338409fe6320SNavdeep Parhar {
338509fe6320SNavdeep Parhar 	int rc = 0;
338609fe6320SNavdeep Parhar 	struct uld_info *u;
338709fe6320SNavdeep Parhar 
338809fe6320SNavdeep Parhar 	mtx_lock(&t3_uld_list_lock);
338909fe6320SNavdeep Parhar 	SLIST_FOREACH(u, &t3_uld_list, link) {
339009fe6320SNavdeep Parhar 	    if (u->uld_id == ui->uld_id) {
339109fe6320SNavdeep Parhar 		    rc = EEXIST;
339209fe6320SNavdeep Parhar 		    goto done;
339309fe6320SNavdeep Parhar 	    }
339409fe6320SNavdeep Parhar 	}
339509fe6320SNavdeep Parhar 
339609fe6320SNavdeep Parhar 	SLIST_INSERT_HEAD(&t3_uld_list, ui, link);
339709fe6320SNavdeep Parhar 	ui->refcount = 0;
339809fe6320SNavdeep Parhar done:
339909fe6320SNavdeep Parhar 	mtx_unlock(&t3_uld_list_lock);
340009fe6320SNavdeep Parhar 	return (rc);
340109fe6320SNavdeep Parhar }
340209fe6320SNavdeep Parhar 
340309fe6320SNavdeep Parhar int
t3_unregister_uld(struct uld_info * ui)340409fe6320SNavdeep Parhar t3_unregister_uld(struct uld_info *ui)
340509fe6320SNavdeep Parhar {
340609fe6320SNavdeep Parhar 	int rc = EINVAL;
340709fe6320SNavdeep Parhar 	struct uld_info *u;
340809fe6320SNavdeep Parhar 
340909fe6320SNavdeep Parhar 	mtx_lock(&t3_uld_list_lock);
341009fe6320SNavdeep Parhar 
341109fe6320SNavdeep Parhar 	SLIST_FOREACH(u, &t3_uld_list, link) {
341209fe6320SNavdeep Parhar 	    if (u == ui) {
341309fe6320SNavdeep Parhar 		    if (ui->refcount > 0) {
341409fe6320SNavdeep Parhar 			    rc = EBUSY;
341509fe6320SNavdeep Parhar 			    goto done;
341609fe6320SNavdeep Parhar 		    }
341709fe6320SNavdeep Parhar 
341809fe6320SNavdeep Parhar 		    SLIST_REMOVE(&t3_uld_list, ui, uld_info, link);
341909fe6320SNavdeep Parhar 		    rc = 0;
342009fe6320SNavdeep Parhar 		    goto done;
342109fe6320SNavdeep Parhar 	    }
342209fe6320SNavdeep Parhar 	}
342309fe6320SNavdeep Parhar done:
342409fe6320SNavdeep Parhar 	mtx_unlock(&t3_uld_list_lock);
342509fe6320SNavdeep Parhar 	return (rc);
342609fe6320SNavdeep Parhar }
342709fe6320SNavdeep Parhar 
342809fe6320SNavdeep Parhar int
t3_activate_uld(struct adapter * sc,int id)342909fe6320SNavdeep Parhar t3_activate_uld(struct adapter *sc, int id)
343009fe6320SNavdeep Parhar {
343109fe6320SNavdeep Parhar 	int rc = EAGAIN;
343209fe6320SNavdeep Parhar 	struct uld_info *ui;
343309fe6320SNavdeep Parhar 
343409fe6320SNavdeep Parhar 	mtx_lock(&t3_uld_list_lock);
343509fe6320SNavdeep Parhar 
343609fe6320SNavdeep Parhar 	SLIST_FOREACH(ui, &t3_uld_list, link) {
343709fe6320SNavdeep Parhar 		if (ui->uld_id == id) {
343809fe6320SNavdeep Parhar 			rc = ui->activate(sc);
343909fe6320SNavdeep Parhar 			if (rc == 0)
344009fe6320SNavdeep Parhar 				ui->refcount++;
344109fe6320SNavdeep Parhar 			goto done;
344209fe6320SNavdeep Parhar 		}
344309fe6320SNavdeep Parhar 	}
344409fe6320SNavdeep Parhar done:
344509fe6320SNavdeep Parhar 	mtx_unlock(&t3_uld_list_lock);
344609fe6320SNavdeep Parhar 
344709fe6320SNavdeep Parhar 	return (rc);
344809fe6320SNavdeep Parhar }
344909fe6320SNavdeep Parhar 
345009fe6320SNavdeep Parhar int
t3_deactivate_uld(struct adapter * sc,int id)345109fe6320SNavdeep Parhar t3_deactivate_uld(struct adapter *sc, int id)
345209fe6320SNavdeep Parhar {
345309fe6320SNavdeep Parhar 	int rc = EINVAL;
345409fe6320SNavdeep Parhar 	struct uld_info *ui;
345509fe6320SNavdeep Parhar 
345609fe6320SNavdeep Parhar 	mtx_lock(&t3_uld_list_lock);
345709fe6320SNavdeep Parhar 
345809fe6320SNavdeep Parhar 	SLIST_FOREACH(ui, &t3_uld_list, link) {
345909fe6320SNavdeep Parhar 		if (ui->uld_id == id) {
346009fe6320SNavdeep Parhar 			rc = ui->deactivate(sc);
346109fe6320SNavdeep Parhar 			if (rc == 0)
346209fe6320SNavdeep Parhar 				ui->refcount--;
346309fe6320SNavdeep Parhar 			goto done;
346409fe6320SNavdeep Parhar 		}
346509fe6320SNavdeep Parhar 	}
346609fe6320SNavdeep Parhar done:
346709fe6320SNavdeep Parhar 	mtx_unlock(&t3_uld_list_lock);
346809fe6320SNavdeep Parhar 
346909fe6320SNavdeep Parhar 	return (rc);
347009fe6320SNavdeep Parhar }
347109fe6320SNavdeep Parhar 
347209fe6320SNavdeep Parhar static int
cpl_not_handled(struct sge_qset * qs __unused,struct rsp_desc * r __unused,struct mbuf * m)347309fe6320SNavdeep Parhar cpl_not_handled(struct sge_qset *qs __unused, struct rsp_desc *r __unused,
347409fe6320SNavdeep Parhar     struct mbuf *m)
347509fe6320SNavdeep Parhar {
347609fe6320SNavdeep Parhar 	m_freem(m);
347709fe6320SNavdeep Parhar 	return (EDOOFUS);
347809fe6320SNavdeep Parhar }
347909fe6320SNavdeep Parhar 
348009fe6320SNavdeep Parhar int
t3_register_cpl_handler(struct adapter * sc,int opcode,cpl_handler_t h)348109fe6320SNavdeep Parhar t3_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h)
348209fe6320SNavdeep Parhar {
348309fe6320SNavdeep Parhar 	uintptr_t *loc, new;
348409fe6320SNavdeep Parhar 
348509fe6320SNavdeep Parhar 	if (opcode >= NUM_CPL_HANDLERS)
348609fe6320SNavdeep Parhar 		return (EINVAL);
348709fe6320SNavdeep Parhar 
348809fe6320SNavdeep Parhar 	new = h ? (uintptr_t)h : (uintptr_t)cpl_not_handled;
348909fe6320SNavdeep Parhar 	loc = (uintptr_t *) &sc->cpl_handler[opcode];
349009fe6320SNavdeep Parhar 	atomic_store_rel_ptr(loc, new);
349109fe6320SNavdeep Parhar 
349209fe6320SNavdeep Parhar 	return (0);
349309fe6320SNavdeep Parhar }
349409fe6320SNavdeep Parhar #endif
349509fe6320SNavdeep Parhar 
349609fe6320SNavdeep Parhar static int
cxgbc_mod_event(module_t mod,int cmd,void * arg)349709fe6320SNavdeep Parhar cxgbc_mod_event(module_t mod, int cmd, void *arg)
349809fe6320SNavdeep Parhar {
349909fe6320SNavdeep Parhar 	int rc = 0;
350009fe6320SNavdeep Parhar 
350109fe6320SNavdeep Parhar 	switch (cmd) {
350209fe6320SNavdeep Parhar 	case MOD_LOAD:
350309fe6320SNavdeep Parhar 		mtx_init(&t3_list_lock, "T3 adapters", 0, MTX_DEF);
350409fe6320SNavdeep Parhar 		SLIST_INIT(&t3_list);
350509fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
350609fe6320SNavdeep Parhar 		mtx_init(&t3_uld_list_lock, "T3 ULDs", 0, MTX_DEF);
350709fe6320SNavdeep Parhar 		SLIST_INIT(&t3_uld_list);
350809fe6320SNavdeep Parhar #endif
350909fe6320SNavdeep Parhar 		break;
351009fe6320SNavdeep Parhar 
351109fe6320SNavdeep Parhar 	case MOD_UNLOAD:
351209fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
351309fe6320SNavdeep Parhar 		mtx_lock(&t3_uld_list_lock);
351409fe6320SNavdeep Parhar 		if (!SLIST_EMPTY(&t3_uld_list)) {
351509fe6320SNavdeep Parhar 			rc = EBUSY;
351609fe6320SNavdeep Parhar 			mtx_unlock(&t3_uld_list_lock);
351709fe6320SNavdeep Parhar 			break;
351809fe6320SNavdeep Parhar 		}
351909fe6320SNavdeep Parhar 		mtx_unlock(&t3_uld_list_lock);
352009fe6320SNavdeep Parhar 		mtx_destroy(&t3_uld_list_lock);
352109fe6320SNavdeep Parhar #endif
352209fe6320SNavdeep Parhar 		mtx_lock(&t3_list_lock);
352309fe6320SNavdeep Parhar 		if (!SLIST_EMPTY(&t3_list)) {
352409fe6320SNavdeep Parhar 			rc = EBUSY;
352509fe6320SNavdeep Parhar 			mtx_unlock(&t3_list_lock);
352609fe6320SNavdeep Parhar 			break;
352709fe6320SNavdeep Parhar 		}
352809fe6320SNavdeep Parhar 		mtx_unlock(&t3_list_lock);
352909fe6320SNavdeep Parhar 		mtx_destroy(&t3_list_lock);
353009fe6320SNavdeep Parhar 		break;
353109fe6320SNavdeep Parhar 	}
353209fe6320SNavdeep Parhar 
353309fe6320SNavdeep Parhar 	return (rc);
353409fe6320SNavdeep Parhar }
3535eb07d67eSMark Johnston 
35367790c8c1SConrad Meyer #ifdef DEBUGNET
3537eb07d67eSMark Johnston static void
cxgb_debugnet_init(if_t ifp,int * nrxr,int * ncl,int * clsize)3538954712e8SJustin Hibbits cxgb_debugnet_init(if_t ifp, int *nrxr, int *ncl, int *clsize)
3539eb07d67eSMark Johnston {
3540eb07d67eSMark Johnston 	struct port_info *pi;
3541eb07d67eSMark Johnston 	adapter_t *adap;
3542eb07d67eSMark Johnston 
3543eb07d67eSMark Johnston 	pi = if_getsoftc(ifp);
3544eb07d67eSMark Johnston 	adap = pi->adapter;
3545eb07d67eSMark Johnston 	ADAPTER_LOCK(adap);
35463948ad29SConrad Meyer 	*nrxr = adap->nqsets;
3547eb07d67eSMark Johnston 	*ncl = adap->sge.qs[0].fl[1].size;
3548eb07d67eSMark Johnston 	*clsize = adap->sge.qs[0].fl[1].buf_size;
3549eb07d67eSMark Johnston 	ADAPTER_UNLOCK(adap);
3550eb07d67eSMark Johnston }
3551eb07d67eSMark Johnston 
3552eb07d67eSMark Johnston static void
cxgb_debugnet_event(if_t ifp,enum debugnet_ev event)3553954712e8SJustin Hibbits cxgb_debugnet_event(if_t ifp, enum debugnet_ev event)
3554eb07d67eSMark Johnston {
3555eb07d67eSMark Johnston 	struct port_info *pi;
3556eb07d67eSMark Johnston 	struct sge_qset *qs;
3557eb07d67eSMark Johnston 	int i;
3558eb07d67eSMark Johnston 
3559eb07d67eSMark Johnston 	pi = if_getsoftc(ifp);
35607790c8c1SConrad Meyer 	if (event == DEBUGNET_START)
35613948ad29SConrad Meyer 		for (i = 0; i < pi->adapter->nqsets; i++) {
3562eb07d67eSMark Johnston 			qs = &pi->adapter->sge.qs[i];
3563eb07d67eSMark Johnston 
35647790c8c1SConrad Meyer 			/* Need to reinit after debugnet_mbuf_start(). */
3565eb07d67eSMark Johnston 			qs->fl[0].zone = zone_pack;
3566eb07d67eSMark Johnston 			qs->fl[1].zone = zone_clust;
3567eb07d67eSMark Johnston 			qs->lro.enabled = 0;
3568eb07d67eSMark Johnston 		}
3569eb07d67eSMark Johnston }
3570eb07d67eSMark Johnston 
3571eb07d67eSMark Johnston static int
cxgb_debugnet_transmit(if_t ifp,struct mbuf * m)3572954712e8SJustin Hibbits cxgb_debugnet_transmit(if_t ifp, struct mbuf *m)
3573eb07d67eSMark Johnston {
3574eb07d67eSMark Johnston 	struct port_info *pi;
3575eb07d67eSMark Johnston 	struct sge_qset *qs;
3576eb07d67eSMark Johnston 
3577eb07d67eSMark Johnston 	pi = if_getsoftc(ifp);
3578eb07d67eSMark Johnston 	if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
3579eb07d67eSMark Johnston 	    IFF_DRV_RUNNING)
3580eb07d67eSMark Johnston 		return (ENOENT);
3581eb07d67eSMark Johnston 
3582eb07d67eSMark Johnston 	qs = &pi->adapter->sge.qs[pi->first_qset];
35837790c8c1SConrad Meyer 	return (cxgb_debugnet_encap(qs, &m));
3584eb07d67eSMark Johnston }
3585eb07d67eSMark Johnston 
3586eb07d67eSMark Johnston static int
cxgb_debugnet_poll(if_t ifp,int count)3587954712e8SJustin Hibbits cxgb_debugnet_poll(if_t ifp, int count)
3588eb07d67eSMark Johnston {
3589eb07d67eSMark Johnston 	struct port_info *pi;
3590eb07d67eSMark Johnston 	adapter_t *adap;
3591eb07d67eSMark Johnston 	int i;
3592eb07d67eSMark Johnston 
3593eb07d67eSMark Johnston 	pi = if_getsoftc(ifp);
3594eb07d67eSMark Johnston 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
3595eb07d67eSMark Johnston 		return (ENOENT);
3596eb07d67eSMark Johnston 
3597eb07d67eSMark Johnston 	adap = pi->adapter;
35983948ad29SConrad Meyer 	for (i = 0; i < adap->nqsets; i++)
35997790c8c1SConrad Meyer 		(void)cxgb_debugnet_poll_rx(adap, &adap->sge.qs[i]);
36007790c8c1SConrad Meyer 	(void)cxgb_debugnet_poll_tx(&adap->sge.qs[pi->first_qset]);
3601eb07d67eSMark Johnston 	return (0);
3602eb07d67eSMark Johnston }
36037790c8c1SConrad Meyer #endif /* DEBUGNET */
3604