xref: /freebsd/sys/dev/cxgb/cxgb_main.c (revision f2d8ff04feec8f1a44edde6789c800ad07a22648)
1b6d90eb7SKip Macy /**************************************************************************
2b6d90eb7SKip Macy 
3f2d8ff04SGeorge V. Neville-Neil Copyright (c) 2007-2009, Chelsio Inc.
4b6d90eb7SKip Macy All rights reserved.
5b6d90eb7SKip Macy 
6b6d90eb7SKip Macy Redistribution and use in source and binary forms, with or without
7b6d90eb7SKip Macy modification, are permitted provided that the following conditions are met:
8b6d90eb7SKip Macy 
9b6d90eb7SKip Macy  1. Redistributions of source code must retain the above copyright notice,
10b6d90eb7SKip Macy     this list of conditions and the following disclaimer.
11b6d90eb7SKip Macy 
12d722cab4SKip Macy  2. Neither the name of the Chelsio Corporation nor the names of its
13b6d90eb7SKip Macy     contributors may be used to endorse or promote products derived from
14b6d90eb7SKip Macy     this software without specific prior written permission.
15b6d90eb7SKip Macy 
16b6d90eb7SKip Macy THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17b6d90eb7SKip Macy AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18b6d90eb7SKip Macy IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19b6d90eb7SKip Macy ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20b6d90eb7SKip Macy LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21b6d90eb7SKip Macy CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22b6d90eb7SKip Macy SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23b6d90eb7SKip Macy INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24b6d90eb7SKip Macy CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25b6d90eb7SKip Macy ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26b6d90eb7SKip Macy POSSIBILITY OF SUCH DAMAGE.
27b6d90eb7SKip Macy 
28b6d90eb7SKip Macy ***************************************************************************/
29b6d90eb7SKip Macy 
30b6d90eb7SKip Macy #include <sys/cdefs.h>
31b6d90eb7SKip Macy __FBSDID("$FreeBSD$");
32b6d90eb7SKip Macy 
33b6d90eb7SKip Macy #include <sys/param.h>
34b6d90eb7SKip Macy #include <sys/systm.h>
35b6d90eb7SKip Macy #include <sys/kernel.h>
36b6d90eb7SKip Macy #include <sys/bus.h>
37b6d90eb7SKip Macy #include <sys/module.h>
38b6d90eb7SKip Macy #include <sys/pciio.h>
39b6d90eb7SKip Macy #include <sys/conf.h>
40b6d90eb7SKip Macy #include <machine/bus.h>
41b6d90eb7SKip Macy #include <machine/resource.h>
42b6d90eb7SKip Macy #include <sys/bus_dma.h>
438e10660fSKip Macy #include <sys/ktr.h>
44b6d90eb7SKip Macy #include <sys/rman.h>
45b6d90eb7SKip Macy #include <sys/ioccom.h>
46b6d90eb7SKip Macy #include <sys/mbuf.h>
47b6d90eb7SKip Macy #include <sys/linker.h>
48b6d90eb7SKip Macy #include <sys/firmware.h>
49b6d90eb7SKip Macy #include <sys/socket.h>
50b6d90eb7SKip Macy #include <sys/sockio.h>
51b6d90eb7SKip Macy #include <sys/smp.h>
52b6d90eb7SKip Macy #include <sys/sysctl.h>
538090c9f5SKip Macy #include <sys/syslog.h>
54b6d90eb7SKip Macy #include <sys/queue.h>
55b6d90eb7SKip Macy #include <sys/taskqueue.h>
568090c9f5SKip Macy #include <sys/proc.h>
57b6d90eb7SKip Macy 
58b6d90eb7SKip Macy #include <net/bpf.h>
59b6d90eb7SKip Macy #include <net/ethernet.h>
60b6d90eb7SKip Macy #include <net/if.h>
61b6d90eb7SKip Macy #include <net/if_arp.h>
62b6d90eb7SKip Macy #include <net/if_dl.h>
63b6d90eb7SKip Macy #include <net/if_media.h>
64b6d90eb7SKip Macy #include <net/if_types.h>
654af83c8cSKip Macy #include <net/if_vlan_var.h>
66b6d90eb7SKip Macy 
67b6d90eb7SKip Macy #include <netinet/in_systm.h>
68b6d90eb7SKip Macy #include <netinet/in.h>
69b6d90eb7SKip Macy #include <netinet/if_ether.h>
70b6d90eb7SKip Macy #include <netinet/ip.h>
71b6d90eb7SKip Macy #include <netinet/ip.h>
72b6d90eb7SKip Macy #include <netinet/tcp.h>
73b6d90eb7SKip Macy #include <netinet/udp.h>
74b6d90eb7SKip Macy 
75b6d90eb7SKip Macy #include <dev/pci/pcireg.h>
76b6d90eb7SKip Macy #include <dev/pci/pcivar.h>
77b6d90eb7SKip Macy #include <dev/pci/pci_private.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 
85b6d90eb7SKip Macy static int cxgb_setup_msix(adapter_t *, int);
86ef72318fSKip Macy static void cxgb_teardown_msix(adapter_t *);
87b6d90eb7SKip Macy static void cxgb_init(void *);
88b6d90eb7SKip Macy static void cxgb_init_locked(struct port_info *);
8977f07749SKip Macy static void cxgb_stop_locked(struct port_info *);
90b6d90eb7SKip Macy static void cxgb_set_rxmode(struct port_info *);
91b6d90eb7SKip Macy static int cxgb_ioctl(struct ifnet *, unsigned long, caddr_t);
92b6d90eb7SKip Macy static int cxgb_media_change(struct ifnet *);
93837f41b0SGeorge V. Neville-Neil static int cxgb_ifm_type(int);
94b6d90eb7SKip Macy static void cxgb_media_status(struct ifnet *, struct ifmediareq *);
95b6d90eb7SKip Macy static int setup_sge_qsets(adapter_t *);
96b6d90eb7SKip Macy static void cxgb_async_intr(void *);
97b6d90eb7SKip Macy static void cxgb_ext_intr_handler(void *, int);
98bb38cd2fSKip Macy static void cxgb_tick_handler(void *, int);
99bb38cd2fSKip Macy static void cxgb_down_locked(struct adapter *sc);
100b6d90eb7SKip Macy static void cxgb_tick(void *);
101b6d90eb7SKip Macy static void setup_rss(adapter_t *sc);
102b6d90eb7SKip Macy 
103b6d90eb7SKip Macy /* Attachment glue for the PCI controller end of the device.  Each port of
104b6d90eb7SKip Macy  * the device is attached separately, as defined later.
105b6d90eb7SKip Macy  */
106b6d90eb7SKip Macy static int cxgb_controller_probe(device_t);
107b6d90eb7SKip Macy static int cxgb_controller_attach(device_t);
108b6d90eb7SKip Macy static int cxgb_controller_detach(device_t);
109b6d90eb7SKip Macy static void cxgb_free(struct adapter *);
110b6d90eb7SKip Macy static __inline void reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
111b6d90eb7SKip Macy     unsigned int end);
1121ffd6e58SKip Macy static void cxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf);
113b6d90eb7SKip Macy static int cxgb_get_regs_len(void);
114d722cab4SKip Macy static int offload_open(struct port_info *pi);
1157ac2e6c3SKip Macy static void touch_bars(device_t dev);
1163e96c7e7SKip Macy static int offload_close(struct t3cdev *tdev);
1178e10660fSKip Macy static void cxgb_link_start(struct port_info *p);
118f2d8ff04SGeorge V. Neville-Neil static void cxgb_link_fault(void *arg, int ncount);
119b6d90eb7SKip Macy 
120b6d90eb7SKip Macy static device_method_t cxgb_controller_methods[] = {
121b6d90eb7SKip Macy 	DEVMETHOD(device_probe,		cxgb_controller_probe),
122b6d90eb7SKip Macy 	DEVMETHOD(device_attach,	cxgb_controller_attach),
123b6d90eb7SKip Macy 	DEVMETHOD(device_detach,	cxgb_controller_detach),
124b6d90eb7SKip Macy 
125b6d90eb7SKip Macy 	/* bus interface */
126b6d90eb7SKip Macy 	DEVMETHOD(bus_print_child,	bus_generic_print_child),
127b6d90eb7SKip Macy 	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
128b6d90eb7SKip Macy 
129b6d90eb7SKip Macy 	{ 0, 0 }
130b6d90eb7SKip Macy };
131b6d90eb7SKip Macy 
132b6d90eb7SKip Macy static driver_t cxgb_controller_driver = {
133b6d90eb7SKip Macy 	"cxgbc",
134b6d90eb7SKip Macy 	cxgb_controller_methods,
135b6d90eb7SKip Macy 	sizeof(struct adapter)
136b6d90eb7SKip Macy };
137b6d90eb7SKip Macy 
138b6d90eb7SKip Macy static devclass_t	cxgb_controller_devclass;
139b6d90eb7SKip Macy DRIVER_MODULE(cxgbc, pci, cxgb_controller_driver, cxgb_controller_devclass, 0, 0);
140b6d90eb7SKip Macy 
141b6d90eb7SKip Macy /*
142b6d90eb7SKip Macy  * Attachment glue for the ports.  Attachment is done directly to the
143b6d90eb7SKip Macy  * controller device.
144b6d90eb7SKip Macy  */
145b6d90eb7SKip Macy static int cxgb_port_probe(device_t);
146b6d90eb7SKip Macy static int cxgb_port_attach(device_t);
147b6d90eb7SKip Macy static int cxgb_port_detach(device_t);
148b6d90eb7SKip Macy 
149b6d90eb7SKip Macy static device_method_t cxgb_port_methods[] = {
150b6d90eb7SKip Macy 	DEVMETHOD(device_probe,		cxgb_port_probe),
151b6d90eb7SKip Macy 	DEVMETHOD(device_attach,	cxgb_port_attach),
152b6d90eb7SKip Macy 	DEVMETHOD(device_detach,	cxgb_port_detach),
153b6d90eb7SKip Macy 	{ 0, 0 }
154b6d90eb7SKip Macy };
155b6d90eb7SKip Macy 
156b6d90eb7SKip Macy static driver_t cxgb_port_driver = {
157b6d90eb7SKip Macy 	"cxgb",
158b6d90eb7SKip Macy 	cxgb_port_methods,
159b6d90eb7SKip Macy 	0
160b6d90eb7SKip Macy };
161b6d90eb7SKip Macy 
162b6d90eb7SKip Macy static d_ioctl_t cxgb_extension_ioctl;
163ef72318fSKip Macy static d_open_t cxgb_extension_open;
164ef72318fSKip Macy static d_close_t cxgb_extension_close;
165ef72318fSKip Macy 
166ef72318fSKip Macy static struct cdevsw cxgb_cdevsw = {
167ef72318fSKip Macy        .d_version =    D_VERSION,
168ef72318fSKip Macy        .d_flags =      0,
169ef72318fSKip Macy        .d_open =       cxgb_extension_open,
170ef72318fSKip Macy        .d_close =      cxgb_extension_close,
171ef72318fSKip Macy        .d_ioctl =      cxgb_extension_ioctl,
172ef72318fSKip Macy        .d_name =       "cxgb",
173ef72318fSKip Macy };
174b6d90eb7SKip Macy 
175b6d90eb7SKip Macy static devclass_t	cxgb_port_devclass;
176b6d90eb7SKip Macy DRIVER_MODULE(cxgb, cxgbc, cxgb_port_driver, cxgb_port_devclass, 0, 0);
177b6d90eb7SKip Macy 
178b6d90eb7SKip Macy #define SGE_MSIX_COUNT (SGE_QSETS + 1)
179b6d90eb7SKip Macy 
180b6d90eb7SKip Macy /*
181b6d90eb7SKip Macy  * The driver uses the best interrupt scheme available on a platform in the
182b6d90eb7SKip Macy  * order MSI-X, MSI, legacy pin interrupts.  This parameter determines which
183b6d90eb7SKip Macy  * of these schemes the driver may consider as follows:
184b6d90eb7SKip Macy  *
185b6d90eb7SKip Macy  * msi = 2: choose from among all three options
186b6d90eb7SKip Macy  * msi = 1 : only consider MSI and pin interrupts
187b6d90eb7SKip Macy  * msi = 0: force pin interrupts
188b6d90eb7SKip Macy  */
189693d746cSKip Macy static int msi_allowed = 2;
190cebf6b9fSKip Macy 
191b6d90eb7SKip Macy TUNABLE_INT("hw.cxgb.msi_allowed", &msi_allowed);
192b6d90eb7SKip Macy SYSCTL_NODE(_hw, OID_AUTO, cxgb, CTLFLAG_RD, 0, "CXGB driver parameters");
193b6d90eb7SKip Macy SYSCTL_UINT(_hw_cxgb, OID_AUTO, msi_allowed, CTLFLAG_RDTUN, &msi_allowed, 0,
194b6d90eb7SKip Macy     "MSI-X, MSI, INTx selector");
195d722cab4SKip Macy 
19664c43db5SKip Macy /*
197d722cab4SKip Macy  * The driver enables offload as a default.
198d722cab4SKip Macy  * To disable it, use ofld_disable = 1.
199d722cab4SKip Macy  */
200d722cab4SKip Macy static int ofld_disable = 0;
201d722cab4SKip Macy TUNABLE_INT("hw.cxgb.ofld_disable", &ofld_disable);
202d722cab4SKip Macy SYSCTL_UINT(_hw_cxgb, OID_AUTO, ofld_disable, CTLFLAG_RDTUN, &ofld_disable, 0,
203d722cab4SKip Macy     "disable ULP offload");
204d722cab4SKip Macy 
205d722cab4SKip Macy /*
206d722cab4SKip Macy  * The driver uses an auto-queue algorithm by default.
207a02573bcSKip Macy  * To disable it and force a single queue-set per port, use multiq = 0
20864c43db5SKip Macy  */
209a02573bcSKip Macy static int multiq = 1;
210a02573bcSKip Macy TUNABLE_INT("hw.cxgb.multiq", &multiq);
211a02573bcSKip Macy SYSCTL_UINT(_hw_cxgb, OID_AUTO, multiq, CTLFLAG_RDTUN, &multiq, 0,
212a02573bcSKip Macy     "use min(ncpus/ports, 8) queue-sets per port");
213f001b63dSKip Macy 
214404825a7SKip Macy /*
215a02573bcSKip Macy  * By default the driver will not update the firmware unless
216a02573bcSKip Macy  * it was compiled against a newer version
217a02573bcSKip Macy  *
218404825a7SKip Macy  */
219404825a7SKip Macy static int force_fw_update = 0;
220404825a7SKip Macy TUNABLE_INT("hw.cxgb.force_fw_update", &force_fw_update);
221404825a7SKip Macy SYSCTL_UINT(_hw_cxgb, OID_AUTO, force_fw_update, CTLFLAG_RDTUN, &force_fw_update, 0,
222404825a7SKip Macy     "update firmware even if up to date");
223f001b63dSKip Macy 
224af9b081cSKip Macy int cxgb_use_16k_clusters = 1;
225f001b63dSKip Macy TUNABLE_INT("hw.cxgb.use_16k_clusters", &cxgb_use_16k_clusters);
226f001b63dSKip Macy SYSCTL_UINT(_hw_cxgb, OID_AUTO, use_16k_clusters, CTLFLAG_RDTUN,
227f001b63dSKip Macy     &cxgb_use_16k_clusters, 0, "use 16kB clusters for the jumbo queue ");
228f001b63dSKip Macy 
229b6d90eb7SKip Macy enum {
230b6d90eb7SKip Macy 	MAX_TXQ_ENTRIES      = 16384,
231b6d90eb7SKip Macy 	MAX_CTRL_TXQ_ENTRIES = 1024,
232b6d90eb7SKip Macy 	MAX_RSPQ_ENTRIES     = 16384,
233b6d90eb7SKip Macy 	MAX_RX_BUFFERS       = 16384,
234b6d90eb7SKip Macy 	MAX_RX_JUMBO_BUFFERS = 16384,
235b6d90eb7SKip Macy 	MIN_TXQ_ENTRIES      = 4,
236b6d90eb7SKip Macy 	MIN_CTRL_TXQ_ENTRIES = 4,
237b6d90eb7SKip Macy 	MIN_RSPQ_ENTRIES     = 32,
2385c5df3daSKip Macy 	MIN_FL_ENTRIES       = 32,
2395c5df3daSKip Macy 	MIN_FL_JUMBO_ENTRIES = 32
240b6d90eb7SKip Macy };
241b6d90eb7SKip Macy 
242ac3a6d9cSKip Macy struct filter_info {
243ac3a6d9cSKip Macy 	u32 sip;
244ac3a6d9cSKip Macy 	u32 sip_mask;
245ac3a6d9cSKip Macy 	u32 dip;
246ac3a6d9cSKip Macy 	u16 sport;
247ac3a6d9cSKip Macy 	u16 dport;
248ac3a6d9cSKip Macy 	u32 vlan:12;
249ac3a6d9cSKip Macy 	u32 vlan_prio:3;
250ac3a6d9cSKip Macy 	u32 mac_hit:1;
251ac3a6d9cSKip Macy 	u32 mac_idx:4;
252ac3a6d9cSKip Macy 	u32 mac_vld:1;
253ac3a6d9cSKip Macy 	u32 pkt_type:2;
254ac3a6d9cSKip Macy 	u32 report_filter_id:1;
255ac3a6d9cSKip Macy 	u32 pass:1;
256ac3a6d9cSKip Macy 	u32 rss:1;
257ac3a6d9cSKip Macy 	u32 qset:3;
258ac3a6d9cSKip Macy 	u32 locked:1;
259ac3a6d9cSKip Macy 	u32 valid:1;
260ac3a6d9cSKip Macy };
261ac3a6d9cSKip Macy 
262ac3a6d9cSKip Macy enum { FILTER_NO_VLAN_PRI = 7 };
263ac3a6d9cSKip Macy 
2641ffd6e58SKip Macy #define EEPROM_MAGIC 0x38E2F10C
2651ffd6e58SKip Macy 
266b6d90eb7SKip Macy #define PORT_MASK ((1 << MAX_NPORTS) - 1)
267b6d90eb7SKip Macy 
268b6d90eb7SKip Macy /* Table for probing the cards.  The desc field isn't actually used */
269b6d90eb7SKip Macy struct cxgb_ident {
270b6d90eb7SKip Macy 	uint16_t	vendor;
271b6d90eb7SKip Macy 	uint16_t	device;
272b6d90eb7SKip Macy 	int		index;
273b6d90eb7SKip Macy 	char		*desc;
274b6d90eb7SKip Macy } cxgb_identifiers[] = {
275b6d90eb7SKip Macy 	{PCI_VENDOR_ID_CHELSIO, 0x0020, 0, "PE9000"},
276b6d90eb7SKip Macy 	{PCI_VENDOR_ID_CHELSIO, 0x0021, 1, "T302E"},
277b6d90eb7SKip Macy 	{PCI_VENDOR_ID_CHELSIO, 0x0022, 2, "T310E"},
278b6d90eb7SKip Macy 	{PCI_VENDOR_ID_CHELSIO, 0x0023, 3, "T320X"},
279b6d90eb7SKip Macy 	{PCI_VENDOR_ID_CHELSIO, 0x0024, 1, "T302X"},
280b6d90eb7SKip Macy 	{PCI_VENDOR_ID_CHELSIO, 0x0025, 3, "T320E"},
281b6d90eb7SKip Macy 	{PCI_VENDOR_ID_CHELSIO, 0x0026, 2, "T310X"},
282b6d90eb7SKip Macy 	{PCI_VENDOR_ID_CHELSIO, 0x0030, 2, "T3B10"},
283b6d90eb7SKip Macy 	{PCI_VENDOR_ID_CHELSIO, 0x0031, 3, "T3B20"},
284b6d90eb7SKip Macy 	{PCI_VENDOR_ID_CHELSIO, 0x0032, 1, "T3B02"},
285ef72318fSKip Macy 	{PCI_VENDOR_ID_CHELSIO, 0x0033, 4, "T3B04"},
2867f15419bSGeorge V. Neville-Neil 	{PCI_VENDOR_ID_CHELSIO, 0x0035, 6, "N310E"},
287b6d90eb7SKip Macy 	{0, 0, 0, NULL}
288b6d90eb7SKip Macy };
289b6d90eb7SKip Macy 
290ac3a6d9cSKip Macy static int set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset);
291ac3a6d9cSKip Macy 
2928e10660fSKip Macy 
2938090c9f5SKip Macy static __inline char
294ac3a6d9cSKip Macy t3rev2char(struct adapter *adapter)
295ac3a6d9cSKip Macy {
296ac3a6d9cSKip Macy 	char rev = 'z';
297ac3a6d9cSKip Macy 
298ac3a6d9cSKip Macy 	switch(adapter->params.rev) {
299ac3a6d9cSKip Macy 	case T3_REV_A:
300ac3a6d9cSKip Macy 		rev = 'a';
301ac3a6d9cSKip Macy 		break;
302ac3a6d9cSKip Macy 	case T3_REV_B:
303ac3a6d9cSKip Macy 	case T3_REV_B2:
304ac3a6d9cSKip Macy 		rev = 'b';
305ac3a6d9cSKip Macy 		break;
306ac3a6d9cSKip Macy 	case T3_REV_C:
307ac3a6d9cSKip Macy 		rev = 'c';
308ac3a6d9cSKip Macy 		break;
309ac3a6d9cSKip Macy 	}
310ac3a6d9cSKip Macy 	return rev;
311ac3a6d9cSKip Macy }
312ac3a6d9cSKip Macy 
313b6d90eb7SKip Macy static struct cxgb_ident *
314b6d90eb7SKip Macy cxgb_get_ident(device_t dev)
315b6d90eb7SKip Macy {
316b6d90eb7SKip Macy 	struct cxgb_ident *id;
317b6d90eb7SKip Macy 
318b6d90eb7SKip Macy 	for (id = cxgb_identifiers; id->desc != NULL; id++) {
319b6d90eb7SKip Macy 		if ((id->vendor == pci_get_vendor(dev)) &&
320b6d90eb7SKip Macy 		    (id->device == pci_get_device(dev))) {
321b6d90eb7SKip Macy 			return (id);
322b6d90eb7SKip Macy 		}
323b6d90eb7SKip Macy 	}
324b6d90eb7SKip Macy 	return (NULL);
325b6d90eb7SKip Macy }
326b6d90eb7SKip Macy 
327b6d90eb7SKip Macy static const struct adapter_info *
328b6d90eb7SKip Macy cxgb_get_adapter_info(device_t dev)
329b6d90eb7SKip Macy {
330b6d90eb7SKip Macy 	struct cxgb_ident *id;
331b6d90eb7SKip Macy 	const struct adapter_info *ai;
332b6d90eb7SKip Macy 
333b6d90eb7SKip Macy 	id = cxgb_get_ident(dev);
334b6d90eb7SKip Macy 	if (id == NULL)
335b6d90eb7SKip Macy 		return (NULL);
336b6d90eb7SKip Macy 
337b6d90eb7SKip Macy 	ai = t3_get_adapter_info(id->index);
338b6d90eb7SKip Macy 
339b6d90eb7SKip Macy 	return (ai);
340b6d90eb7SKip Macy }
341b6d90eb7SKip Macy 
342b6d90eb7SKip Macy static int
343b6d90eb7SKip Macy cxgb_controller_probe(device_t dev)
344b6d90eb7SKip Macy {
345b6d90eb7SKip Macy 	const struct adapter_info *ai;
346b6d90eb7SKip Macy 	char *ports, buf[80];
347ef72318fSKip Macy 	int nports;
3486eb15755SKip Macy 	struct adapter *sc = device_get_softc(dev);
349b6d90eb7SKip Macy 
350b6d90eb7SKip Macy 	ai = cxgb_get_adapter_info(dev);
351b6d90eb7SKip Macy 	if (ai == NULL)
352b6d90eb7SKip Macy 		return (ENXIO);
353b6d90eb7SKip Macy 
354ef72318fSKip Macy 	nports = ai->nports0 + ai->nports1;
355ef72318fSKip Macy 	if (nports == 1)
356b6d90eb7SKip Macy 		ports = "port";
357b6d90eb7SKip Macy 	else
358b6d90eb7SKip Macy 		ports = "ports";
359b6d90eb7SKip Macy 
3606eb15755SKip Macy 	snprintf(buf, sizeof(buf), "%s %sNIC, rev: %d nports: %d %s",
3616eb15755SKip Macy 	    ai->desc, is_offload(sc) ? "R" : "",
3626eb15755SKip Macy 	    sc->params.rev, nports, ports);
363b6d90eb7SKip Macy 	device_set_desc_copy(dev, buf);
364b6d90eb7SKip Macy 	return (BUS_PROBE_DEFAULT);
365b6d90eb7SKip Macy }
366b6d90eb7SKip Macy 
367404825a7SKip Macy #define FW_FNAME "cxgb_t3fw"
368f2d8ff04SGeorge V. Neville-Neil #define TPEEPROM_NAME "t3%c_tp_eeprom"
369f2d8ff04SGeorge V. Neville-Neil #define TPSRAM_NAME "t3%c_protocol_sram"
370ac3a6d9cSKip Macy 
371b6d90eb7SKip Macy static int
372d722cab4SKip Macy upgrade_fw(adapter_t *sc)
373b6d90eb7SKip Macy {
374b6d90eb7SKip Macy #ifdef FIRMWARE_LATEST
375b6d90eb7SKip Macy 	const struct firmware *fw;
376b6d90eb7SKip Macy #else
377b6d90eb7SKip Macy 	struct firmware *fw;
378b6d90eb7SKip Macy #endif
379b6d90eb7SKip Macy 	int status;
380b6d90eb7SKip Macy 
381404825a7SKip Macy 	if ((fw = firmware_get(FW_FNAME)) == NULL)  {
382404825a7SKip Macy 		device_printf(sc->dev, "Could not find firmware image %s\n", FW_FNAME);
383d722cab4SKip Macy 		return (ENOENT);
384ac3a6d9cSKip Macy 	} else
385404825a7SKip Macy 		device_printf(sc->dev, "updating firmware on card\n");
386b6d90eb7SKip Macy 	status = t3_load_fw(sc, (const uint8_t *)fw->data, fw->datasize);
387b6d90eb7SKip Macy 
388ac3a6d9cSKip Macy 	device_printf(sc->dev, "firmware update returned %s %d\n", (status == 0) ? "success" : "fail", status);
389ac3a6d9cSKip Macy 
390b6d90eb7SKip Macy 	firmware_put(fw, FIRMWARE_UNLOAD);
391b6d90eb7SKip Macy 
392b6d90eb7SKip Macy 	return (status);
393b6d90eb7SKip Macy }
394b6d90eb7SKip Macy 
395b6d90eb7SKip Macy static int
396b6d90eb7SKip Macy cxgb_controller_attach(device_t dev)
397b6d90eb7SKip Macy {
398b6d90eb7SKip Macy 	device_t child;
399b6d90eb7SKip Macy 	const struct adapter_info *ai;
400b6d90eb7SKip Macy 	struct adapter *sc;
4012de1fa86SKip Macy 	int i, error = 0;
402b6d90eb7SKip Macy 	uint32_t vers;
403693d746cSKip Macy 	int port_qsets = 1;
4047aff6d8eSKip Macy #ifdef MSI_SUPPORTED
4052de1fa86SKip Macy 	int msi_needed, reg;
4067aff6d8eSKip Macy #endif
4075197f3abSGeorge V. Neville-Neil 	char buf[80];
4085197f3abSGeorge V. Neville-Neil 
409b6d90eb7SKip Macy 	sc = device_get_softc(dev);
410b6d90eb7SKip Macy 	sc->dev = dev;
411d722cab4SKip Macy 	sc->msi_count = 0;
4122de1fa86SKip Macy 	ai = cxgb_get_adapter_info(dev);
413b6d90eb7SKip Macy 
4142de1fa86SKip Macy 	/*
4152de1fa86SKip Macy 	 * XXX not really related but a recent addition
4162de1fa86SKip Macy 	 */
4172de1fa86SKip Macy #ifdef MSI_SUPPORTED
418fc01c613SKip Macy 	/* find the PCIe link width and set max read request to 4KB*/
419fc01c613SKip Macy 	if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
420fc01c613SKip Macy 		uint16_t lnk, pectl;
421fc01c613SKip Macy 		lnk = pci_read_config(dev, reg + 0x12, 2);
422fc01c613SKip Macy 		sc->link_width = (lnk >> 4) & 0x3f;
423fc01c613SKip Macy 
424fc01c613SKip Macy 		pectl = pci_read_config(dev, reg + 0x8, 2);
425fc01c613SKip Macy 		pectl = (pectl & ~0x7000) | (5 << 12);
426fc01c613SKip Macy 		pci_write_config(dev, reg + 0x8, pectl, 2);
427fc01c613SKip Macy 	}
428ac3a6d9cSKip Macy 
429ac3a6d9cSKip Macy 	if (sc->link_width != 0 && sc->link_width <= 4 &&
430ac3a6d9cSKip Macy 	    (ai->nports0 + ai->nports1) <= 2) {
431fc01c613SKip Macy 		device_printf(sc->dev,
432ac6b4cf1SKip Macy 		    "PCIe x%d Link, expect reduced performance\n",
433fc01c613SKip Macy 		    sc->link_width);
434fc01c613SKip Macy 	}
4352de1fa86SKip Macy #endif
4367ac2e6c3SKip Macy 	touch_bars(dev);
437b6d90eb7SKip Macy 	pci_enable_busmaster(dev);
438b6d90eb7SKip Macy 	/*
439b6d90eb7SKip Macy 	 * Allocate the registers and make them available to the driver.
440b6d90eb7SKip Macy 	 * The registers that we care about for NIC mode are in BAR 0
441b6d90eb7SKip Macy 	 */
442b6d90eb7SKip Macy 	sc->regs_rid = PCIR_BAR(0);
443b6d90eb7SKip Macy 	if ((sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
444b6d90eb7SKip Macy 	    &sc->regs_rid, RF_ACTIVE)) == NULL) {
4458e10660fSKip Macy 		device_printf(dev, "Cannot allocate BAR region 0\n");
446b6d90eb7SKip Macy 		return (ENXIO);
447b6d90eb7SKip Macy 	}
4488e10660fSKip Macy 	sc->udbs_rid = PCIR_BAR(2);
4497f15419bSGeorge V. Neville-Neil 	sc->udbs_res = NULL;
4507f15419bSGeorge V. Neville-Neil 	if (is_offload(sc) &&
4517f15419bSGeorge V. Neville-Neil 	    ((sc->udbs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
4527f15419bSGeorge V. Neville-Neil 		   &sc->udbs_rid, RF_ACTIVE)) == NULL)) {
4538e10660fSKip Macy 		device_printf(dev, "Cannot allocate BAR region 1\n");
4548e10660fSKip Macy 		error = ENXIO;
4558e10660fSKip Macy 		goto out;
4568e10660fSKip Macy 	}
457b6d90eb7SKip Macy 
458bb38cd2fSKip Macy 	snprintf(sc->lockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb controller lock %d",
459bb38cd2fSKip Macy 	    device_get_unit(dev));
460bb38cd2fSKip Macy 	ADAPTER_LOCK_INIT(sc, sc->lockbuf);
461bb38cd2fSKip Macy 
462bb38cd2fSKip Macy 	snprintf(sc->reglockbuf, ADAPTER_LOCK_NAME_LEN, "SGE reg lock %d",
463bb38cd2fSKip Macy 	    device_get_unit(dev));
464bb38cd2fSKip Macy 	snprintf(sc->mdiolockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb mdio lock %d",
465bb38cd2fSKip Macy 	    device_get_unit(dev));
466bb38cd2fSKip Macy 	snprintf(sc->elmerlockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb elmer lock %d",
467bb38cd2fSKip Macy 	    device_get_unit(dev));
468bb38cd2fSKip Macy 
4698e10660fSKip Macy 	MTX_INIT(&sc->sge.reg_lock, sc->reglockbuf, NULL, MTX_SPIN);
470bb38cd2fSKip Macy 	MTX_INIT(&sc->mdio_lock, sc->mdiolockbuf, NULL, MTX_DEF);
471bb38cd2fSKip Macy 	MTX_INIT(&sc->elmer_lock, sc->elmerlockbuf, NULL, MTX_DEF);
472b6d90eb7SKip Macy 
473b6d90eb7SKip Macy 	sc->bt = rman_get_bustag(sc->regs_res);
474b6d90eb7SKip Macy 	sc->bh = rman_get_bushandle(sc->regs_res);
475b6d90eb7SKip Macy 	sc->mmio_len = rman_get_size(sc->regs_res);
476b6d90eb7SKip Macy 
47724cdd067SKip Macy 	if (t3_prep_adapter(sc, ai, 1) < 0) {
478ef72318fSKip Macy 		printf("prep adapter failed\n");
47924cdd067SKip Macy 		error = ENODEV;
48024cdd067SKip Macy 		goto out;
48124cdd067SKip Macy 	}
482b6d90eb7SKip Macy         /* Allocate the BAR for doing MSI-X.  If it succeeds, try to allocate
483b6d90eb7SKip Macy 	 * enough messages for the queue sets.  If that fails, try falling
484b6d90eb7SKip Macy 	 * back to MSI.  If that fails, then try falling back to the legacy
485b6d90eb7SKip Macy 	 * interrupt pin model.
486b6d90eb7SKip Macy 	 */
487b6d90eb7SKip Macy #ifdef MSI_SUPPORTED
488693d746cSKip Macy 
489b6d90eb7SKip Macy 	sc->msix_regs_rid = 0x20;
490b6d90eb7SKip Macy 	if ((msi_allowed >= 2) &&
491b6d90eb7SKip Macy 	    (sc->msix_regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
492b6d90eb7SKip Macy 	    &sc->msix_regs_rid, RF_ACTIVE)) != NULL) {
493b6d90eb7SKip Macy 
494d722cab4SKip Macy 		msi_needed = sc->msi_count = SGE_MSIX_COUNT;
495693d746cSKip Macy 
496d722cab4SKip Macy 		if (((error = pci_alloc_msix(dev, &sc->msi_count)) != 0) ||
497d722cab4SKip Macy 		    (sc->msi_count != msi_needed)) {
498d722cab4SKip Macy 			device_printf(dev, "msix allocation failed - msi_count = %d"
499d722cab4SKip Macy 			    " msi_needed=%d will try msi err=%d\n", sc->msi_count,
500d722cab4SKip Macy 			    msi_needed, error);
501d722cab4SKip Macy 			sc->msi_count = 0;
502b6d90eb7SKip Macy 			pci_release_msi(dev);
503b6d90eb7SKip Macy 			bus_release_resource(dev, SYS_RES_MEMORY,
504b6d90eb7SKip Macy 			    sc->msix_regs_rid, sc->msix_regs_res);
505b6d90eb7SKip Macy 			sc->msix_regs_res = NULL;
506b6d90eb7SKip Macy 		} else {
507b6d90eb7SKip Macy 			sc->flags |= USING_MSIX;
508f0a542f8SKip Macy 			sc->cxgb_intr = t3_intr_msix;
509b6d90eb7SKip Macy 		}
510b6d90eb7SKip Macy 	}
511b6d90eb7SKip Macy 
512d722cab4SKip Macy 	if ((msi_allowed >= 1) && (sc->msi_count == 0)) {
513d722cab4SKip Macy 		sc->msi_count = 1;
514d722cab4SKip Macy 		if (pci_alloc_msi(dev, &sc->msi_count)) {
515693d746cSKip Macy 			device_printf(dev, "alloc msi failed - will try INTx\n");
516d722cab4SKip Macy 			sc->msi_count = 0;
517b6d90eb7SKip Macy 			pci_release_msi(dev);
518b6d90eb7SKip Macy 		} else {
519b6d90eb7SKip Macy 			sc->flags |= USING_MSI;
520b6d90eb7SKip Macy 			sc->irq_rid = 1;
521f0a542f8SKip Macy 			sc->cxgb_intr = t3_intr_msi;
522b6d90eb7SKip Macy 		}
523b6d90eb7SKip Macy 	}
524b6d90eb7SKip Macy #endif
525d722cab4SKip Macy 	if (sc->msi_count == 0) {
526693d746cSKip Macy 		device_printf(dev, "using line interrupts\n");
527b6d90eb7SKip Macy 		sc->irq_rid = 0;
528f0a542f8SKip Macy 		sc->cxgb_intr = t3b_intr;
529b6d90eb7SKip Macy 	}
530b6d90eb7SKip Macy 
531a02573bcSKip Macy 	if ((sc->flags & USING_MSIX) && multiq)
532f705d735SKip Macy 		port_qsets = min((SGE_QSETS/(sc)->params.nports), mp_ncpus);
533b6d90eb7SKip Macy 
534b6d90eb7SKip Macy 	/* Create a private taskqueue thread for handling driver events */
535b6d90eb7SKip Macy #ifdef TASKQUEUE_CURRENT
536b6d90eb7SKip Macy 	sc->tq = taskqueue_create("cxgb_taskq", M_NOWAIT,
537b6d90eb7SKip Macy 	    taskqueue_thread_enqueue, &sc->tq);
538b6d90eb7SKip Macy #else
539b6d90eb7SKip Macy 	sc->tq = taskqueue_create_fast("cxgb_taskq", M_NOWAIT,
540b6d90eb7SKip Macy 	    taskqueue_thread_enqueue, &sc->tq);
541b6d90eb7SKip Macy #endif
542b6d90eb7SKip Macy 	if (sc->tq == NULL) {
543b6d90eb7SKip Macy 		device_printf(dev, "failed to allocate controller task queue\n");
544b6d90eb7SKip Macy 		goto out;
545b6d90eb7SKip Macy 	}
546b6d90eb7SKip Macy 
547b6d90eb7SKip Macy 	taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq",
548b6d90eb7SKip Macy 	    device_get_nameunit(dev));
549b6d90eb7SKip Macy 	TASK_INIT(&sc->ext_intr_task, 0, cxgb_ext_intr_handler, sc);
550bb38cd2fSKip Macy 	TASK_INIT(&sc->tick_task, 0, cxgb_tick_handler, sc);
551b6d90eb7SKip Macy 
552b6d90eb7SKip Macy 
553b6d90eb7SKip Macy 	/* Create a periodic callout for checking adapter status */
554bb38cd2fSKip Macy 	callout_init(&sc->cxgb_tick_ch, TRUE);
555b6d90eb7SKip Macy 
556f2d8ff04SGeorge V. Neville-Neil 	if (t3_check_fw_version(sc) < 0 || force_fw_update) {
557b6d90eb7SKip Macy 		/*
558b6d90eb7SKip Macy 		 * Warn user that a firmware update will be attempted in init.
559b6d90eb7SKip Macy 		 */
560d722cab4SKip Macy 		device_printf(dev, "firmware needs to be updated to version %d.%d.%d\n",
561d722cab4SKip Macy 		    FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
562b6d90eb7SKip Macy 		sc->flags &= ~FW_UPTODATE;
563b6d90eb7SKip Macy 	} else {
564b6d90eb7SKip Macy 		sc->flags |= FW_UPTODATE;
565b6d90eb7SKip Macy 	}
566b6d90eb7SKip Macy 
567f2d8ff04SGeorge V. Neville-Neil 	if (t3_check_tpsram_version(sc) < 0) {
568ac3a6d9cSKip Macy 		/*
569ac3a6d9cSKip Macy 		 * Warn user that a firmware update will be attempted in init.
570ac3a6d9cSKip Macy 		 */
571ac3a6d9cSKip Macy 		device_printf(dev, "SRAM needs to be updated to version %c-%d.%d.%d\n",
572ac3a6d9cSKip Macy 		    t3rev2char(sc), TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
573ac3a6d9cSKip Macy 		sc->flags &= ~TPS_UPTODATE;
574ac3a6d9cSKip Macy 	} else {
575ac3a6d9cSKip Macy 		sc->flags |= TPS_UPTODATE;
576ac3a6d9cSKip Macy 	}
577ac3a6d9cSKip Macy 
578b6d90eb7SKip Macy 	/*
579b6d90eb7SKip Macy 	 * Create a child device for each MAC.  The ethernet attachment
580b6d90eb7SKip Macy 	 * will be done in these children.
581b6d90eb7SKip Macy 	 */
582693d746cSKip Macy 	for (i = 0; i < (sc)->params.nports; i++) {
5837ac2e6c3SKip Macy 		struct port_info *pi;
5847ac2e6c3SKip Macy 
585b6d90eb7SKip Macy 		if ((child = device_add_child(dev, "cxgb", -1)) == NULL) {
586b6d90eb7SKip Macy 			device_printf(dev, "failed to add child port\n");
587b6d90eb7SKip Macy 			error = EINVAL;
588b6d90eb7SKip Macy 			goto out;
589b6d90eb7SKip Macy 		}
5907ac2e6c3SKip Macy 		pi = &sc->port[i];
5917ac2e6c3SKip Macy 		pi->adapter = sc;
5927ac2e6c3SKip Macy 		pi->nqsets = port_qsets;
5937ac2e6c3SKip Macy 		pi->first_qset = i*port_qsets;
5947ac2e6c3SKip Macy 		pi->port_id = i;
5957ac2e6c3SKip Macy 		pi->tx_chan = i >= ai->nports0;
5967ac2e6c3SKip Macy 		pi->txpkt_intf = pi->tx_chan ? 2 * (i - ai->nports0) + 1 : 2 * i;
5977ac2e6c3SKip Macy 		sc->rxpkt_map[pi->txpkt_intf] = i;
5988090c9f5SKip Macy 		sc->port[i].tx_chan = i >= ai->nports0;
599ac3a6d9cSKip Macy 		sc->portdev[i] = child;
6007ac2e6c3SKip Macy 		device_set_softc(child, pi);
601b6d90eb7SKip Macy 	}
602b6d90eb7SKip Macy 	if ((error = bus_generic_attach(dev)) != 0)
603b6d90eb7SKip Macy 		goto out;
604b6d90eb7SKip Macy 
605b6d90eb7SKip Macy 	/* initialize sge private state */
606ef72318fSKip Macy 	t3_sge_init_adapter(sc);
607b6d90eb7SKip Macy 
608b6d90eb7SKip Macy 	t3_led_ready(sc);
609b6d90eb7SKip Macy 
610d722cab4SKip Macy 	cxgb_offload_init();
611d722cab4SKip Macy 	if (is_offload(sc)) {
612d722cab4SKip Macy 		setbit(&sc->registered_device_map, OFFLOAD_DEVMAP_BIT);
613d722cab4SKip Macy 		cxgb_adapter_ofld(sc);
614d722cab4SKip Macy         }
615b6d90eb7SKip Macy 	error = t3_get_fw_version(sc, &vers);
616b6d90eb7SKip Macy 	if (error)
617b6d90eb7SKip Macy 		goto out;
618b6d90eb7SKip Macy 
619d722cab4SKip Macy 	snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d.%d",
620d722cab4SKip Macy 	    G_FW_VERSION_MAJOR(vers), G_FW_VERSION_MINOR(vers),
621d722cab4SKip Macy 	    G_FW_VERSION_MICRO(vers));
622b6d90eb7SKip Macy 
6235197f3abSGeorge V. Neville-Neil 	snprintf(buf, sizeof(buf), "%s\t E/C: %s S/N: %s",
6245197f3abSGeorge V. Neville-Neil 		 ai->desc,
6255197f3abSGeorge V. Neville-Neil 		 sc->params.vpd.ec, sc->params.vpd.sn);
6265197f3abSGeorge V. Neville-Neil 	device_set_desc_copy(dev, buf);
6275197f3abSGeorge V. Neville-Neil 
6288e10660fSKip Macy 	device_printf(sc->dev, "Firmware Version %s\n", &sc->fw_version[0]);
629706cb31fSKip Macy 	callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc);
6308090c9f5SKip Macy 	t3_add_attach_sysctls(sc);
631b6d90eb7SKip Macy out:
632b6d90eb7SKip Macy 	if (error)
633b6d90eb7SKip Macy 		cxgb_free(sc);
634b6d90eb7SKip Macy 
635b6d90eb7SKip Macy 	return (error);
636b6d90eb7SKip Macy }
637b6d90eb7SKip Macy 
638b6d90eb7SKip Macy static int
639b6d90eb7SKip Macy cxgb_controller_detach(device_t dev)
640b6d90eb7SKip Macy {
641b6d90eb7SKip Macy 	struct adapter *sc;
642b6d90eb7SKip Macy 
643b6d90eb7SKip Macy 	sc = device_get_softc(dev);
644b6d90eb7SKip Macy 
645b6d90eb7SKip Macy 	cxgb_free(sc);
646b6d90eb7SKip Macy 
647b6d90eb7SKip Macy 	return (0);
648b6d90eb7SKip Macy }
649b6d90eb7SKip Macy 
650b6d90eb7SKip Macy static void
651b6d90eb7SKip Macy cxgb_free(struct adapter *sc)
652b6d90eb7SKip Macy {
653b6d90eb7SKip Macy 	int i;
654b6d90eb7SKip Macy 
6558e10660fSKip Macy 	ADAPTER_LOCK(sc);
6568e10660fSKip Macy 	sc->flags |= CXGB_SHUTDOWN;
6578e10660fSKip Macy 	ADAPTER_UNLOCK(sc);
6588090c9f5SKip Macy 	cxgb_pcpu_shutdown_threads(sc);
659bb38cd2fSKip Macy 	ADAPTER_LOCK(sc);
6608e10660fSKip Macy 
661bb38cd2fSKip Macy /*
662bb38cd2fSKip Macy  * drops the lock
663bb38cd2fSKip Macy  */
664bb38cd2fSKip Macy 	cxgb_down_locked(sc);
665d722cab4SKip Macy 
666d722cab4SKip Macy #ifdef MSI_SUPPORTED
667d722cab4SKip Macy 	if (sc->flags & (USING_MSI | USING_MSIX)) {
668d722cab4SKip Macy 		device_printf(sc->dev, "releasing msi message(s)\n");
669d722cab4SKip Macy 		pci_release_msi(sc->dev);
670d722cab4SKip Macy 	} else {
671d722cab4SKip Macy 		device_printf(sc->dev, "no msi message to release\n");
672d722cab4SKip Macy 	}
673d722cab4SKip Macy #endif
674d722cab4SKip Macy 	if (sc->msix_regs_res != NULL) {
675d722cab4SKip Macy 		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid,
676d722cab4SKip Macy 		    sc->msix_regs_res);
677d722cab4SKip Macy 	}
678d722cab4SKip Macy 
6797ac2e6c3SKip Macy 	t3_sge_deinit_sw(sc);
6807ac2e6c3SKip Macy 	/*
6817ac2e6c3SKip Macy 	 * Wait for last callout
6827ac2e6c3SKip Macy 	 */
683b6d90eb7SKip Macy 
6848090c9f5SKip Macy 	DELAY(hz*100);
685bb38cd2fSKip Macy 
686693d746cSKip Macy 	for (i = 0; i < (sc)->params.nports; ++i) {
687693d746cSKip Macy 		if (sc->portdev[i] != NULL)
688693d746cSKip Macy 			device_delete_child(sc->dev, sc->portdev[i]);
689693d746cSKip Macy 	}
690b6d90eb7SKip Macy 
691b6d90eb7SKip Macy 	bus_generic_detach(sc->dev);
6928e10660fSKip Macy 	if (sc->tq != NULL) {
6937ac2e6c3SKip Macy 		taskqueue_free(sc->tq);
6948e10660fSKip Macy 		sc->tq = NULL;
6958e10660fSKip Macy 	}
6968e10660fSKip Macy 
697d722cab4SKip Macy 	if (is_offload(sc)) {
698d722cab4SKip Macy 		cxgb_adapter_unofld(sc);
699d722cab4SKip Macy 		if (isset(&sc->open_device_map,	OFFLOAD_DEVMAP_BIT))
700d722cab4SKip Macy 			offload_close(&sc->tdev);
7018090c9f5SKip Macy 		else
7028090c9f5SKip Macy 			printf("cxgb_free: DEVMAP_BIT not set\n");
7038090c9f5SKip Macy 	} else
7048090c9f5SKip Macy 		printf("not offloading set\n");
70546b0a854SKip Macy #ifdef notyet
7068e10660fSKip Macy 	if (sc->flags & CXGB_OFLD_INIT)
7078e10660fSKip Macy 		cxgb_offload_deactivate(sc);
70846b0a854SKip Macy #endif
709ac3a6d9cSKip Macy 	free(sc->filters, M_DEVBUF);
710b6d90eb7SKip Macy 	t3_sge_free(sc);
711b6d90eb7SKip Macy 
712bb38cd2fSKip Macy 	cxgb_offload_exit();
713bb38cd2fSKip Macy 
7148e10660fSKip Macy 	if (sc->udbs_res != NULL)
7158e10660fSKip Macy 		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->udbs_rid,
7168e10660fSKip Macy 		    sc->udbs_res);
7178e10660fSKip Macy 
718b6d90eb7SKip Macy 	if (sc->regs_res != NULL)
719b6d90eb7SKip Macy 		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->regs_rid,
720b6d90eb7SKip Macy 		    sc->regs_res);
721b6d90eb7SKip Macy 
722bb38cd2fSKip Macy 	MTX_DESTROY(&sc->mdio_lock);
723bb38cd2fSKip Macy 	MTX_DESTROY(&sc->sge.reg_lock);
724bb38cd2fSKip Macy 	MTX_DESTROY(&sc->elmer_lock);
725bb38cd2fSKip Macy 	ADAPTER_LOCK_DEINIT(sc);
726b6d90eb7SKip Macy }
727b6d90eb7SKip Macy 
728b6d90eb7SKip Macy /**
729b6d90eb7SKip Macy  *	setup_sge_qsets - configure SGE Tx/Rx/response queues
730b6d90eb7SKip Macy  *	@sc: the controller softc
731b6d90eb7SKip Macy  *
732b6d90eb7SKip Macy  *	Determines how many sets of SGE queues to use and initializes them.
733b6d90eb7SKip Macy  *	We support multiple queue sets per port if we have MSI-X, otherwise
734b6d90eb7SKip Macy  *	just one queue set per port.
735b6d90eb7SKip Macy  */
736b6d90eb7SKip Macy static int
737b6d90eb7SKip Macy setup_sge_qsets(adapter_t *sc)
738b6d90eb7SKip Macy {
7395c5df3daSKip Macy 	int i, j, err, irq_idx = 0, qset_idx = 0;
740d722cab4SKip Macy 	u_int ntxq = SGE_TXQ_PER_SET;
741b6d90eb7SKip Macy 
742b6d90eb7SKip Macy 	if ((err = t3_sge_alloc(sc)) != 0) {
743693d746cSKip Macy 		device_printf(sc->dev, "t3_sge_alloc returned %d\n", err);
744b6d90eb7SKip Macy 		return (err);
745b6d90eb7SKip Macy 	}
746b6d90eb7SKip Macy 
747b6d90eb7SKip Macy 	if (sc->params.rev > 0 && !(sc->flags & USING_MSI))
748b6d90eb7SKip Macy 		irq_idx = -1;
749b6d90eb7SKip Macy 
7505c5df3daSKip Macy 	for (i = 0; i < (sc)->params.nports; i++) {
751b6d90eb7SKip Macy 		struct port_info *pi = &sc->port[i];
752b6d90eb7SKip Macy 
7537ac2e6c3SKip Macy 		for (j = 0; j < pi->nqsets; j++, qset_idx++) {
754693d746cSKip Macy 			err = t3_sge_alloc_qset(sc, qset_idx, (sc)->params.nports,
755b6d90eb7SKip Macy 			    (sc->flags & USING_MSIX) ? qset_idx + 1 : irq_idx,
756b6d90eb7SKip Macy 			    &sc->params.sge.qset[qset_idx], ntxq, pi);
757b6d90eb7SKip Macy 			if (err) {
758b6d90eb7SKip Macy 				t3_free_sge_resources(sc);
7597ac2e6c3SKip Macy 				device_printf(sc->dev, "t3_sge_alloc_qset failed with %d\n",
7607ac2e6c3SKip Macy 				    err);
761b6d90eb7SKip Macy 				return (err);
762b6d90eb7SKip Macy 			}
763b6d90eb7SKip Macy 		}
764b6d90eb7SKip Macy 	}
765b6d90eb7SKip Macy 
766b6d90eb7SKip Macy 	return (0);
767b6d90eb7SKip Macy }
768b6d90eb7SKip Macy 
769ef72318fSKip Macy static void
770ef72318fSKip Macy cxgb_teardown_msix(adapter_t *sc)
771ef72318fSKip Macy {
772ef72318fSKip Macy 	int i, nqsets;
773ef72318fSKip Macy 
774ef72318fSKip Macy 	for (nqsets = i = 0; i < (sc)->params.nports; i++)
775ef72318fSKip Macy 		nqsets += sc->port[i].nqsets;
776ef72318fSKip Macy 
777ef72318fSKip Macy 	for (i = 0; i < nqsets; i++) {
778ef72318fSKip Macy 		if (sc->msix_intr_tag[i] != NULL) {
779ef72318fSKip Macy 			bus_teardown_intr(sc->dev, sc->msix_irq_res[i],
780ef72318fSKip Macy 			    sc->msix_intr_tag[i]);
781ef72318fSKip Macy 			sc->msix_intr_tag[i] = NULL;
782ef72318fSKip Macy 		}
783ef72318fSKip Macy 		if (sc->msix_irq_res[i] != NULL) {
784ef72318fSKip Macy 			bus_release_resource(sc->dev, SYS_RES_IRQ,
785ef72318fSKip Macy 			    sc->msix_irq_rid[i], sc->msix_irq_res[i]);
786ef72318fSKip Macy 			sc->msix_irq_res[i] = NULL;
787ef72318fSKip Macy 		}
788ef72318fSKip Macy 	}
789ef72318fSKip Macy }
790ef72318fSKip Macy 
791b6d90eb7SKip Macy static int
792b6d90eb7SKip Macy cxgb_setup_msix(adapter_t *sc, int msix_count)
793b6d90eb7SKip Macy {
794b6d90eb7SKip Macy 	int i, j, k, nqsets, rid;
795b6d90eb7SKip Macy 
796b6d90eb7SKip Macy 	/* The first message indicates link changes and error conditions */
797b6d90eb7SKip Macy 	sc->irq_rid = 1;
798b6d90eb7SKip Macy 	if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
799b6d90eb7SKip Macy 	   &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
800b6d90eb7SKip Macy 		device_printf(sc->dev, "Cannot allocate msix interrupt\n");
801b6d90eb7SKip Macy 		return (EINVAL);
802b6d90eb7SKip Macy 	}
803693d746cSKip Macy 
804b6d90eb7SKip Macy 	if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET,
805b6d90eb7SKip Macy #ifdef INTR_FILTERS
806b6d90eb7SKip Macy 		NULL,
807b6d90eb7SKip Macy #endif
808b6d90eb7SKip Macy 		cxgb_async_intr, sc, &sc->intr_tag)) {
809b6d90eb7SKip Macy 		device_printf(sc->dev, "Cannot set up interrupt\n");
810b6d90eb7SKip Macy 		return (EINVAL);
811b6d90eb7SKip Macy 	}
812ef72318fSKip Macy 	for (i = k = 0; i < (sc)->params.nports; i++) {
813b6d90eb7SKip Macy 		nqsets = sc->port[i].nqsets;
814ef72318fSKip Macy 		for (j = 0; j < nqsets; j++, k++) {
815b6d90eb7SKip Macy 			struct sge_qset *qs = &sc->sge.qs[k];
816b6d90eb7SKip Macy 
817b6d90eb7SKip Macy 			rid = k + 2;
818b6d90eb7SKip Macy 			if (cxgb_debug)
819b6d90eb7SKip Macy 				printf("rid=%d ", rid);
820b6d90eb7SKip Macy 			if ((sc->msix_irq_res[k] = bus_alloc_resource_any(
821b6d90eb7SKip Macy 			    sc->dev, SYS_RES_IRQ, &rid,
822b6d90eb7SKip Macy 			    RF_SHAREABLE | RF_ACTIVE)) == NULL) {
823b6d90eb7SKip Macy 				device_printf(sc->dev, "Cannot allocate "
824b6d90eb7SKip Macy 				    "interrupt for message %d\n", rid);
825b6d90eb7SKip Macy 				return (EINVAL);
826b6d90eb7SKip Macy 			}
827b6d90eb7SKip Macy 			sc->msix_irq_rid[k] = rid;
828ef72318fSKip Macy 			if (bus_setup_intr(sc->dev, sc->msix_irq_res[k],
829b6d90eb7SKip Macy 				INTR_MPSAFE|INTR_TYPE_NET,
830b6d90eb7SKip Macy #ifdef INTR_FILTERS
831b6d90eb7SKip Macy 				NULL,
832b6d90eb7SKip Macy #endif
833b6d90eb7SKip Macy 				t3_intr_msix, qs, &sc->msix_intr_tag[k])) {
834b6d90eb7SKip Macy 				device_printf(sc->dev, "Cannot set up "
835b6d90eb7SKip Macy 				    "interrupt for message %d\n", rid);
836b6d90eb7SKip Macy 				return (EINVAL);
837a02573bcSKip Macy 
838b6d90eb7SKip Macy 			}
839a02573bcSKip Macy #if 0
8408090c9f5SKip Macy #ifdef IFNET_MULTIQUEUE
841a02573bcSKip Macy 			if (multiq) {
8428090c9f5SKip Macy 				int vector = rman_get_start(sc->msix_irq_res[k]);
8438090c9f5SKip Macy 				if (bootverbose)
8448090c9f5SKip Macy 					device_printf(sc->dev, "binding vector=%d to cpu=%d\n", vector, k % mp_ncpus);
8458090c9f5SKip Macy 				intr_bind(vector, k % mp_ncpus);
8468090c9f5SKip Macy 			}
8478090c9f5SKip Macy #endif
848a02573bcSKip Macy #endif
849b6d90eb7SKip Macy 		}
850b6d90eb7SKip Macy 	}
851693d746cSKip Macy 
852b6d90eb7SKip Macy 	return (0);
853b6d90eb7SKip Macy }
854b6d90eb7SKip Macy 
855b6d90eb7SKip Macy static int
856b6d90eb7SKip Macy cxgb_port_probe(device_t dev)
857b6d90eb7SKip Macy {
858b6d90eb7SKip Macy 	struct port_info *p;
859b6d90eb7SKip Macy 	char buf[80];
8608e10660fSKip Macy 	const char *desc;
861b6d90eb7SKip Macy 
862b6d90eb7SKip Macy 	p = device_get_softc(dev);
8638e10660fSKip Macy 	desc = p->phy.desc;
8648e10660fSKip Macy 	snprintf(buf, sizeof(buf), "Port %d %s", p->port_id, desc);
865b6d90eb7SKip Macy 	device_set_desc_copy(dev, buf);
866b6d90eb7SKip Macy 	return (0);
867b6d90eb7SKip Macy }
868b6d90eb7SKip Macy 
869b6d90eb7SKip Macy 
870b6d90eb7SKip Macy static int
871b6d90eb7SKip Macy cxgb_makedev(struct port_info *pi)
872b6d90eb7SKip Macy {
873b6d90eb7SKip Macy 
874ef72318fSKip Macy 	pi->port_cdev = make_dev(&cxgb_cdevsw, pi->ifp->if_dunit,
875ef72318fSKip Macy 	    UID_ROOT, GID_WHEEL, 0600, if_name(pi->ifp));
876b6d90eb7SKip Macy 
877b6d90eb7SKip Macy 	if (pi->port_cdev == NULL)
878b6d90eb7SKip Macy 		return (ENOMEM);
879b6d90eb7SKip Macy 
880b6d90eb7SKip Macy 	pi->port_cdev->si_drv1 = (void *)pi;
881b6d90eb7SKip Macy 
882b6d90eb7SKip Macy 	return (0);
883b6d90eb7SKip Macy }
884b6d90eb7SKip Macy 
885e97121daSKip Macy #ifndef LRO_SUPPORTED
886e97121daSKip Macy #ifdef IFCAP_LRO
887e97121daSKip Macy #undef IFCAP_LRO
888e97121daSKip Macy #endif
889e97121daSKip Macy #define IFCAP_LRO 0x0
890e97121daSKip Macy #endif
891b6d90eb7SKip Macy 
892b6d90eb7SKip Macy #ifdef TSO_SUPPORTED
89325292debSKip Macy #define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO)
894b6d90eb7SKip Macy /* Don't enable TSO6 yet */
89525292debSKip Macy #define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO4 | IFCAP_JUMBO_MTU | IFCAP_LRO)
896b6d90eb7SKip Macy #else
897b6d90eb7SKip Macy #define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU)
898b6d90eb7SKip Macy /* Don't enable TSO6 yet */
899b6d90eb7SKip Macy #define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM |  IFCAP_JUMBO_MTU)
900b6d90eb7SKip Macy #define IFCAP_TSO4 0x0
9017aff6d8eSKip Macy #define IFCAP_TSO6 0x0
902b6d90eb7SKip Macy #define CSUM_TSO   0x0
903b6d90eb7SKip Macy #endif
904b6d90eb7SKip Macy 
905b6d90eb7SKip Macy 
906b6d90eb7SKip Macy static int
907b6d90eb7SKip Macy cxgb_port_attach(device_t dev)
908b6d90eb7SKip Macy {
909b6d90eb7SKip Macy 	struct port_info *p;
910b6d90eb7SKip Macy 	struct ifnet *ifp;
911ef72318fSKip Macy 	int err, media_flags;
9128e10660fSKip Macy 	struct adapter *sc;
9138e10660fSKip Macy 
914b6d90eb7SKip Macy 
915b6d90eb7SKip Macy 	p = device_get_softc(dev);
9168e10660fSKip Macy 	sc = p->adapter;
917bb38cd2fSKip Macy 	snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d",
9186b68e276SKip Macy 	    device_get_unit(device_get_parent(dev)), p->port_id);
919bb38cd2fSKip Macy 	PORT_LOCK_INIT(p, p->lockbuf);
920b6d90eb7SKip Macy 
921b6d90eb7SKip Macy 	/* Allocate an ifnet object and set it up */
922b6d90eb7SKip Macy 	ifp = p->ifp = if_alloc(IFT_ETHER);
923b6d90eb7SKip Macy 	if (ifp == NULL) {
924b6d90eb7SKip Macy 		device_printf(dev, "Cannot allocate ifnet\n");
925b6d90eb7SKip Macy 		return (ENOMEM);
926b6d90eb7SKip Macy 	}
927b6d90eb7SKip Macy 
928b6d90eb7SKip Macy 	/*
929b6d90eb7SKip Macy 	 * Note that there is currently no watchdog timer.
930b6d90eb7SKip Macy 	 */
931b6d90eb7SKip Macy 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
932b6d90eb7SKip Macy 	ifp->if_init = cxgb_init;
933b6d90eb7SKip Macy 	ifp->if_softc = p;
934b6d90eb7SKip Macy 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
935b6d90eb7SKip Macy 	ifp->if_ioctl = cxgb_ioctl;
936b6d90eb7SKip Macy 	ifp->if_start = cxgb_start;
9378090c9f5SKip Macy 
938a02573bcSKip Macy 
939b6d90eb7SKip Macy 	ifp->if_timer = 0;	/* Disable ifnet watchdog */
940b6d90eb7SKip Macy 	ifp->if_watchdog = NULL;
941b6d90eb7SKip Macy 
942a02573bcSKip Macy 	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
943b6d90eb7SKip Macy 	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
944b6d90eb7SKip Macy 	IFQ_SET_READY(&ifp->if_snd);
945b6d90eb7SKip Macy 
946b6d90eb7SKip Macy 	ifp->if_hwassist = ifp->if_capabilities = ifp->if_capenable = 0;
947b6d90eb7SKip Macy 	ifp->if_capabilities |= CXGB_CAP;
948b6d90eb7SKip Macy 	ifp->if_capenable |= CXGB_CAP_ENABLE;
949b6d90eb7SKip Macy 	ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO);
950ac3a6d9cSKip Macy 	/*
951ac3a6d9cSKip Macy 	 * disable TSO on 4-port - it isn't supported by the firmware yet
952ac3a6d9cSKip Macy 	 */
953ac3a6d9cSKip Macy 	if (p->adapter->params.nports > 2) {
954ac3a6d9cSKip Macy 		ifp->if_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6);
955ac3a6d9cSKip Macy 		ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TSO6);
956ac3a6d9cSKip Macy 		ifp->if_hwassist &= ~CSUM_TSO;
957ac3a6d9cSKip Macy 	}
958b6d90eb7SKip Macy 
959b6d90eb7SKip Macy 	ether_ifattach(ifp, p->hw_addr);
9605eba27feSKip Macy #ifdef IFNET_MULTIQUEUE
961a02573bcSKip Macy 	ifp->if_transmit = cxgb_pcpu_transmit;
9625eba27feSKip Macy #endif
963ac3a6d9cSKip Macy 	/*
964ac3a6d9cSKip Macy 	 * Only default to jumbo frames on 10GigE
965ac3a6d9cSKip Macy 	 */
966ac3a6d9cSKip Macy 	if (p->adapter->params.nports <= 2)
9674af83c8cSKip Macy 		ifp->if_mtu = ETHERMTU_JUMBO;
968b6d90eb7SKip Macy 	if ((err = cxgb_makedev(p)) != 0) {
969b6d90eb7SKip Macy 		printf("makedev failed %d\n", err);
970b6d90eb7SKip Macy 		return (err);
971b6d90eb7SKip Macy 	}
972b6d90eb7SKip Macy 	ifmedia_init(&p->media, IFM_IMASK, cxgb_media_change,
973b6d90eb7SKip Macy 	    cxgb_media_status);
974b6d90eb7SKip Macy 
9758e10660fSKip Macy 	if (!strcmp(p->phy.desc,	"10GBASE-CX4")) {
976ef72318fSKip Macy 		media_flags = IFM_ETHER | IFM_10G_CX4 | IFM_FDX;
9778e10660fSKip Macy 	} else if (!strcmp(p->phy.desc, "10GBASE-SR")) {
978ef72318fSKip Macy 		media_flags = IFM_ETHER | IFM_10G_SR | IFM_FDX;
97919905d6dSKip Macy 	} else if (!strcmp(p->phy.desc, "10GBASE-R")) {
980837f41b0SGeorge V. Neville-Neil 		media_flags = cxgb_ifm_type(p->phy.modtype);
9818e10660fSKip Macy 	} else if (!strcmp(p->phy.desc, "10/100/1000BASE-T")) {
982ef72318fSKip Macy 		ifmedia_add(&p->media, IFM_ETHER | IFM_10_T, 0, NULL);
983ef72318fSKip Macy 		ifmedia_add(&p->media, IFM_ETHER | IFM_10_T | IFM_FDX,
984ef72318fSKip Macy 			    0, NULL);
985ef72318fSKip Macy 		ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX,
986ef72318fSKip Macy 			    0, NULL);
987ef72318fSKip Macy 		ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX | IFM_FDX,
988ef72318fSKip Macy 			    0, NULL);
989ef72318fSKip Macy 		ifmedia_add(&p->media, IFM_ETHER | IFM_1000_T | IFM_FDX,
990ef72318fSKip Macy 			    0, NULL);
991ef72318fSKip Macy 		media_flags = 0;
99241509ecdSKip Macy 	} else if (!strcmp(p->phy.desc, "1000BASE-X")) {
99341509ecdSKip Macy 		/*
99441509ecdSKip Macy 		 * XXX: This is not very accurate.  Fix when common code
99541509ecdSKip Macy 		 * returns more specific value - eg 1000BASE-SX, LX, etc.
996837f41b0SGeorge V. Neville-Neil 		 *
997837f41b0SGeorge V. Neville-Neil 		 * XXX: In the meantime, don't lie. Consider setting IFM_AUTO
998837f41b0SGeorge V. Neville-Neil 		 * instead of SX.
99941509ecdSKip Macy 		 */
100041509ecdSKip Macy 		media_flags = IFM_ETHER | IFM_1000_SX | IFM_FDX;
1001ef72318fSKip Macy 	} else {
10028e10660fSKip Macy 	        printf("unsupported media type %s\n", p->phy.desc);
1003b6d90eb7SKip Macy 		return (ENXIO);
1004b6d90eb7SKip Macy 	}
1005ef72318fSKip Macy 	if (media_flags) {
1006837f41b0SGeorge V. Neville-Neil 		/*
1007837f41b0SGeorge V. Neville-Neil 		 * Note the modtype on which we based our flags.  If modtype
1008837f41b0SGeorge V. Neville-Neil 		 * changes, we'll redo the ifmedia for this ifp.  modtype may
1009837f41b0SGeorge V. Neville-Neil 		 * change when transceivers are plugged in/out, and in other
1010837f41b0SGeorge V. Neville-Neil 		 * situations.
1011837f41b0SGeorge V. Neville-Neil 		 */
1012837f41b0SGeorge V. Neville-Neil 		ifmedia_add(&p->media, media_flags, p->phy.modtype, NULL);
1013b6d90eb7SKip Macy 		ifmedia_set(&p->media, media_flags);
1014ef72318fSKip Macy 	} else {
1015ef72318fSKip Macy 		ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL);
1016ef72318fSKip Macy 		ifmedia_set(&p->media, IFM_ETHER | IFM_AUTO);
1017ef72318fSKip Macy 	}
1018ef72318fSKip Macy 
101919905d6dSKip Macy 	/* Get the latest mac address, User can use a LAA */
102019905d6dSKip Macy 	bcopy(IF_LLADDR(p->ifp), p->hw_addr, ETHER_ADDR_LEN);
1021ef72318fSKip Macy 	t3_sge_init_port(p);
1022f2d8ff04SGeorge V. Neville-Neil 
1023f2d8ff04SGeorge V. Neville-Neil 	TASK_INIT(&p->link_fault_task, 0, cxgb_link_fault, p);
1024f2d8ff04SGeorge V. Neville-Neil 
1025ef027c52SKip Macy #if defined(LINK_ATTACH)
10268e10660fSKip Macy 	cxgb_link_start(p);
10278e10660fSKip Macy 	t3_link_changed(sc, p->port_id);
1028ef027c52SKip Macy #endif
1029b6d90eb7SKip Macy 	return (0);
1030b6d90eb7SKip Macy }
1031b6d90eb7SKip Macy 
1032b6d90eb7SKip Macy static int
1033b6d90eb7SKip Macy cxgb_port_detach(device_t dev)
1034b6d90eb7SKip Macy {
1035b6d90eb7SKip Macy 	struct port_info *p;
1036b6d90eb7SKip Macy 
1037b6d90eb7SKip Macy 	p = device_get_softc(dev);
1038d722cab4SKip Macy 
1039d722cab4SKip Macy 	PORT_LOCK(p);
1040ef72318fSKip Macy 	if (p->ifp->if_drv_flags & IFF_DRV_RUNNING)
1041d722cab4SKip Macy 		cxgb_stop_locked(p);
1042d722cab4SKip Macy 	PORT_UNLOCK(p);
1043d722cab4SKip Macy 
1044b6d90eb7SKip Macy 	ether_ifdetach(p->ifp);
10458090c9f5SKip Macy 	printf("waiting for callout to stop ...");
10468090c9f5SKip Macy 	DELAY(1000000);
10478090c9f5SKip Macy 	printf("done\n");
10487ac2e6c3SKip Macy 	/*
10497ac2e6c3SKip Macy 	 * the lock may be acquired in ifdetach
10507ac2e6c3SKip Macy 	 */
10517ac2e6c3SKip Macy 	PORT_LOCK_DEINIT(p);
1052b6d90eb7SKip Macy 	if_free(p->ifp);
1053b6d90eb7SKip Macy 
1054ef72318fSKip Macy 	if (p->port_cdev != NULL)
1055b6d90eb7SKip Macy 		destroy_dev(p->port_cdev);
1056b6d90eb7SKip Macy 
1057b6d90eb7SKip Macy 	return (0);
1058b6d90eb7SKip Macy }
1059b6d90eb7SKip Macy 
1060b6d90eb7SKip Macy void
1061b6d90eb7SKip Macy t3_fatal_err(struct adapter *sc)
1062b6d90eb7SKip Macy {
1063b6d90eb7SKip Macy 	u_int fw_status[4];
1064b6d90eb7SKip Macy 
10655c5df3daSKip Macy 	if (sc->flags & FULL_INIT_DONE) {
10665c5df3daSKip Macy 		t3_sge_stop(sc);
10675c5df3daSKip Macy 		t3_write_reg(sc, A_XGM_TX_CTRL, 0);
10685c5df3daSKip Macy 		t3_write_reg(sc, A_XGM_RX_CTRL, 0);
10695c5df3daSKip Macy 		t3_write_reg(sc, XGM_REG(A_XGM_TX_CTRL, 1), 0);
10705c5df3daSKip Macy 		t3_write_reg(sc, XGM_REG(A_XGM_RX_CTRL, 1), 0);
10715c5df3daSKip Macy 		t3_intr_disable(sc);
10725c5df3daSKip Macy 	}
1073b6d90eb7SKip Macy 	device_printf(sc->dev,"encountered fatal error, operation suspended\n");
1074b6d90eb7SKip Macy 	if (!t3_cim_ctl_blk_read(sc, 0xa0, 4, fw_status))
1075b6d90eb7SKip Macy 		device_printf(sc->dev, "FW_ status: 0x%x, 0x%x, 0x%x, 0x%x\n",
1076b6d90eb7SKip Macy 		    fw_status[0], fw_status[1], fw_status[2], fw_status[3]);
1077b6d90eb7SKip Macy }
1078b6d90eb7SKip Macy 
1079b6d90eb7SKip Macy int
1080b6d90eb7SKip Macy t3_os_find_pci_capability(adapter_t *sc, int cap)
1081b6d90eb7SKip Macy {
1082b6d90eb7SKip Macy 	device_t dev;
1083b6d90eb7SKip Macy 	struct pci_devinfo *dinfo;
1084b6d90eb7SKip Macy 	pcicfgregs *cfg;
1085b6d90eb7SKip Macy 	uint32_t status;
1086b6d90eb7SKip Macy 	uint8_t ptr;
1087b6d90eb7SKip Macy 
1088b6d90eb7SKip Macy 	dev = sc->dev;
1089b6d90eb7SKip Macy 	dinfo = device_get_ivars(dev);
1090b6d90eb7SKip Macy 	cfg = &dinfo->cfg;
1091b6d90eb7SKip Macy 
1092b6d90eb7SKip Macy 	status = pci_read_config(dev, PCIR_STATUS, 2);
1093b6d90eb7SKip Macy 	if (!(status & PCIM_STATUS_CAPPRESENT))
1094b6d90eb7SKip Macy 		return (0);
1095b6d90eb7SKip Macy 
1096b6d90eb7SKip Macy 	switch (cfg->hdrtype & PCIM_HDRTYPE) {
1097b6d90eb7SKip Macy 	case 0:
1098b6d90eb7SKip Macy 	case 1:
1099b6d90eb7SKip Macy 		ptr = PCIR_CAP_PTR;
1100b6d90eb7SKip Macy 		break;
1101b6d90eb7SKip Macy 	case 2:
1102b6d90eb7SKip Macy 		ptr = PCIR_CAP_PTR_2;
1103b6d90eb7SKip Macy 		break;
1104b6d90eb7SKip Macy 	default:
1105b6d90eb7SKip Macy 		return (0);
1106b6d90eb7SKip Macy 		break;
1107b6d90eb7SKip Macy 	}
1108b6d90eb7SKip Macy 	ptr = pci_read_config(dev, ptr, 1);
1109b6d90eb7SKip Macy 
1110b6d90eb7SKip Macy 	while (ptr != 0) {
1111b6d90eb7SKip Macy 		if (pci_read_config(dev, ptr + PCICAP_ID, 1) == cap)
1112b6d90eb7SKip Macy 			return (ptr);
1113b6d90eb7SKip Macy 		ptr = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1);
1114b6d90eb7SKip Macy 	}
1115b6d90eb7SKip Macy 
1116b6d90eb7SKip Macy 	return (0);
1117b6d90eb7SKip Macy }
1118b6d90eb7SKip Macy 
1119b6d90eb7SKip Macy int
1120b6d90eb7SKip Macy t3_os_pci_save_state(struct adapter *sc)
1121b6d90eb7SKip Macy {
1122b6d90eb7SKip Macy 	device_t dev;
1123b6d90eb7SKip Macy 	struct pci_devinfo *dinfo;
1124b6d90eb7SKip Macy 
1125b6d90eb7SKip Macy 	dev = sc->dev;
1126b6d90eb7SKip Macy 	dinfo = device_get_ivars(dev);
1127b6d90eb7SKip Macy 
1128b6d90eb7SKip Macy 	pci_cfg_save(dev, dinfo, 0);
1129b6d90eb7SKip Macy 	return (0);
1130b6d90eb7SKip Macy }
1131b6d90eb7SKip Macy 
1132b6d90eb7SKip Macy int
1133b6d90eb7SKip Macy t3_os_pci_restore_state(struct adapter *sc)
1134b6d90eb7SKip Macy {
1135b6d90eb7SKip Macy 	device_t dev;
1136b6d90eb7SKip Macy 	struct pci_devinfo *dinfo;
1137b6d90eb7SKip Macy 
1138b6d90eb7SKip Macy 	dev = sc->dev;
1139b6d90eb7SKip Macy 	dinfo = device_get_ivars(dev);
1140b6d90eb7SKip Macy 
1141b6d90eb7SKip Macy 	pci_cfg_restore(dev, dinfo);
1142b6d90eb7SKip Macy 	return (0);
1143b6d90eb7SKip Macy }
1144b6d90eb7SKip Macy 
1145f2d8ff04SGeorge V. Neville-Neil void t3_os_link_fault(struct adapter *adap, int port_id, int state)
1146f2d8ff04SGeorge V. Neville-Neil {
1147f2d8ff04SGeorge V. Neville-Neil 	struct port_info *pi = &adap->port[port_id];
1148f2d8ff04SGeorge V. Neville-Neil 
1149f2d8ff04SGeorge V. Neville-Neil 	if (!state) {
1150f2d8ff04SGeorge V. Neville-Neil 		if_link_state_change(pi->ifp, LINK_STATE_DOWN);
1151f2d8ff04SGeorge V. Neville-Neil 		return;
1152f2d8ff04SGeorge V. Neville-Neil 	}
1153f2d8ff04SGeorge V. Neville-Neil 
1154f2d8ff04SGeorge V. Neville-Neil 	if (adap->params.nports <= 2) {
1155f2d8ff04SGeorge V. Neville-Neil 		struct cmac *mac = &pi->mac;
1156f2d8ff04SGeorge V. Neville-Neil 
1157f2d8ff04SGeorge V. Neville-Neil 		/* Clear local faults */
1158f2d8ff04SGeorge V. Neville-Neil 		t3_xgm_intr_disable(adap, port_id);
1159f2d8ff04SGeorge V. Neville-Neil 		t3_read_reg(adap, A_XGM_INT_STATUS + pi->mac.offset);
1160f2d8ff04SGeorge V. Neville-Neil 		t3_write_reg(adap, A_XGM_INT_CAUSE + pi->mac.offset, F_XGM_INT);
1161f2d8ff04SGeorge V. Neville-Neil 
1162f2d8ff04SGeorge V. Neville-Neil 		t3_set_reg_field(adap, A_XGM_INT_ENABLE + pi->mac.offset,
1163f2d8ff04SGeorge V. Neville-Neil 				 F_XGM_INT, F_XGM_INT);
1164f2d8ff04SGeorge V. Neville-Neil 		t3_xgm_intr_enable(adap, pi->port_id);
1165f2d8ff04SGeorge V. Neville-Neil 		t3_mac_enable(mac, MAC_DIRECTION_TX);
1166f2d8ff04SGeorge V. Neville-Neil 	}
1167f2d8ff04SGeorge V. Neville-Neil 
1168f2d8ff04SGeorge V. Neville-Neil 	if_link_state_change(pi->ifp, LINK_STATE_UP);
1169f2d8ff04SGeorge V. Neville-Neil }
1170f2d8ff04SGeorge V. Neville-Neil 
1171b6d90eb7SKip Macy /**
1172b6d90eb7SKip Macy  *	t3_os_link_changed - handle link status changes
1173b6d90eb7SKip Macy  *	@adapter: the adapter associated with the link change
1174b6d90eb7SKip Macy  *	@port_id: the port index whose limk status has changed
117519905d6dSKip Macy  *	@link_status: the new status of the link
1176b6d90eb7SKip Macy  *	@speed: the new speed setting
1177b6d90eb7SKip Macy  *	@duplex: the new duplex setting
1178b6d90eb7SKip Macy  *	@fc: the new flow-control setting
1179b6d90eb7SKip Macy  *
1180b6d90eb7SKip Macy  *	This is the OS-dependent handler for link status changes.  The OS
1181b6d90eb7SKip Macy  *	neutral handler takes care of most of the processing for these events,
1182b6d90eb7SKip Macy  *	then calls this handler for any OS-specific processing.
1183b6d90eb7SKip Macy  */
1184b6d90eb7SKip Macy void
1185b6d90eb7SKip Macy t3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed,
1186b6d90eb7SKip Macy      int duplex, int fc)
1187b6d90eb7SKip Macy {
1188b6d90eb7SKip Macy 	struct port_info *pi = &adapter->port[port_id];
1189d722cab4SKip Macy 	struct cmac *mac = &adapter->port[port_id].mac;
1190b6d90eb7SKip Macy 
1191d722cab4SKip Macy 	if (link_status) {
119219905d6dSKip Macy 		DELAY(10);
119319905d6dSKip Macy 		t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
119419905d6dSKip Macy 		/* Clear errors created by MAC enable */
1195f2d8ff04SGeorge V. Neville-Neil 		t3_set_reg_field(adapter, A_XGM_STAT_CTRL + pi->mac.offset,
119619905d6dSKip Macy 				 F_CLRSTATS, 1);
119719905d6dSKip Macy 
1198f2d8ff04SGeorge V. Neville-Neil 		if (adapter->params.nports <= 2) {
1199f2d8ff04SGeorge V. Neville-Neil 			/* Clear local faults */
1200f2d8ff04SGeorge V. Neville-Neil 			t3_xgm_intr_disable(adapter, pi->port_id);
1201f2d8ff04SGeorge V. Neville-Neil 			t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
1202f2d8ff04SGeorge V. Neville-Neil 			t3_write_reg(adapter, A_XGM_INT_CAUSE + pi->mac.offset,
1203f2d8ff04SGeorge V. Neville-Neil 				     F_XGM_INT);
1204f2d8ff04SGeorge V. Neville-Neil 
1205f2d8ff04SGeorge V. Neville-Neil 			t3_set_reg_field(adapter,
1206f2d8ff04SGeorge V. Neville-Neil 					 A_XGM_INT_ENABLE + pi->mac.offset,
1207f2d8ff04SGeorge V. Neville-Neil 					 F_XGM_INT, F_XGM_INT);
1208f2d8ff04SGeorge V. Neville-Neil 			t3_xgm_intr_enable(adapter, pi->port_id);
1209f2d8ff04SGeorge V. Neville-Neil 		}
1210f2d8ff04SGeorge V. Neville-Neil 
1211f2d8ff04SGeorge V. Neville-Neil 		if_link_state_change(pi->ifp, LINK_STATE_UP);
1212d722cab4SKip Macy 	} else {
1213f2d8ff04SGeorge V. Neville-Neil 		t3_xgm_intr_disable(adapter, pi->port_id);
1214f2d8ff04SGeorge V. Neville-Neil 		t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
1215f2d8ff04SGeorge V. Neville-Neil 		if (adapter->params.nports <= 2) {
1216f2d8ff04SGeorge V. Neville-Neil 			t3_set_reg_field(adapter,
1217f2d8ff04SGeorge V. Neville-Neil 					 A_XGM_INT_ENABLE + pi->mac.offset,
1218f2d8ff04SGeorge V. Neville-Neil 					 F_XGM_INT, 0);
1219f2d8ff04SGeorge V. Neville-Neil 		}
1220f2d8ff04SGeorge V. Neville-Neil 
1221f2d8ff04SGeorge V. Neville-Neil 		/* PR 5666. We shouldn't power down 1G phys */
1222f2d8ff04SGeorge V. Neville-Neil 		if (is_10G(adapter))
1223d722cab4SKip Macy 			pi->phy.ops->power_down(&pi->phy, 1);
1224f2d8ff04SGeorge V. Neville-Neil 
1225f2d8ff04SGeorge V. Neville-Neil 		t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
1226d722cab4SKip Macy 		t3_mac_disable(mac, MAC_DIRECTION_RX);
1227d722cab4SKip Macy 		t3_link_start(&pi->phy, mac, &pi->link_config);
1228f2d8ff04SGeorge V. Neville-Neil 
12298e10660fSKip Macy 		if_link_state_change(pi->ifp, LINK_STATE_DOWN);
1230d722cab4SKip Macy 	}
1231b6d90eb7SKip Macy }
1232b6d90eb7SKip Macy 
12339b4de886SKip Macy /**
12349b4de886SKip Macy  *	t3_os_phymod_changed - handle PHY module changes
12359b4de886SKip Macy  *	@phy: the PHY reporting the module change
12369b4de886SKip Macy  *	@mod_type: new module type
12379b4de886SKip Macy  *
12389b4de886SKip Macy  *	This is the OS-dependent handler for PHY module changes.  It is
12399b4de886SKip Macy  *	invoked when a PHY module is removed or inserted for any OS-specific
12409b4de886SKip Macy  *	processing.
12419b4de886SKip Macy  */
12429b4de886SKip Macy void t3_os_phymod_changed(struct adapter *adap, int port_id)
12439b4de886SKip Macy {
12449b4de886SKip Macy 	static const char *mod_str[] = {
12459b4de886SKip Macy 		NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown"
12469b4de886SKip Macy 	};
12479b4de886SKip Macy 
12489b4de886SKip Macy 	struct port_info *pi = &adap->port[port_id];
12499b4de886SKip Macy 
12509b4de886SKip Macy 	if (pi->phy.modtype == phy_modtype_none)
12519b4de886SKip Macy 		device_printf(adap->dev, "PHY module unplugged\n");
12529b4de886SKip Macy 	else {
12539b4de886SKip Macy 		KASSERT(pi->phy.modtype < ARRAY_SIZE(mod_str),
12549b4de886SKip Macy 		    ("invalid PHY module type %d", pi->phy.modtype));
12559b4de886SKip Macy 		device_printf(adap->dev, "%s PHY module inserted\n",
12569b4de886SKip Macy 		    mod_str[pi->phy.modtype]);
12579b4de886SKip Macy 	}
12589b4de886SKip Macy }
12599b4de886SKip Macy 
1260b6d90eb7SKip Macy /*
1261b6d90eb7SKip Macy  * Interrupt-context handler for external (PHY) interrupts.
1262b6d90eb7SKip Macy  */
1263b6d90eb7SKip Macy void
1264b6d90eb7SKip Macy t3_os_ext_intr_handler(adapter_t *sc)
1265b6d90eb7SKip Macy {
1266b6d90eb7SKip Macy 	if (cxgb_debug)
1267b6d90eb7SKip Macy 		printf("t3_os_ext_intr_handler\n");
1268b6d90eb7SKip Macy 	/*
1269b6d90eb7SKip Macy 	 * Schedule a task to handle external interrupts as they may be slow
1270b6d90eb7SKip Macy 	 * and we use a mutex to protect MDIO registers.  We disable PHY
1271b6d90eb7SKip Macy 	 * interrupts in the meantime and let the task reenable them when
1272b6d90eb7SKip Macy 	 * it's done.
1273b6d90eb7SKip Macy 	 */
1274d722cab4SKip Macy 	ADAPTER_LOCK(sc);
1275b6d90eb7SKip Macy 	if (sc->slow_intr_mask) {
1276b6d90eb7SKip Macy 		sc->slow_intr_mask &= ~F_T3DBG;
1277b6d90eb7SKip Macy 		t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
1278b6d90eb7SKip Macy 		taskqueue_enqueue(sc->tq, &sc->ext_intr_task);
1279b6d90eb7SKip Macy 	}
1280d722cab4SKip Macy 	ADAPTER_UNLOCK(sc);
1281b6d90eb7SKip Macy }
1282b6d90eb7SKip Macy 
1283f2d8ff04SGeorge V. Neville-Neil static void
1284f2d8ff04SGeorge V. Neville-Neil cxgb_link_fault(void *arg, int ncount)
1285f2d8ff04SGeorge V. Neville-Neil {
1286f2d8ff04SGeorge V. Neville-Neil 	struct port_info *pi = arg;
1287f2d8ff04SGeorge V. Neville-Neil 
1288f2d8ff04SGeorge V. Neville-Neil 	t3_link_fault(pi->adapter, pi->port_id);
1289f2d8ff04SGeorge V. Neville-Neil }
1290f2d8ff04SGeorge V. Neville-Neil 
1291f2d8ff04SGeorge V. Neville-Neil void t3_os_link_fault_handler(struct adapter *sc, int port_id)
1292f2d8ff04SGeorge V. Neville-Neil {
1293f2d8ff04SGeorge V. Neville-Neil 	struct port_info *pi = &sc->port[port_id];
1294f2d8ff04SGeorge V. Neville-Neil 
1295f2d8ff04SGeorge V. Neville-Neil 	ADAPTER_LOCK(sc);
1296f2d8ff04SGeorge V. Neville-Neil 	pi->link_fault = 1;
1297f2d8ff04SGeorge V. Neville-Neil 	taskqueue_enqueue(sc->tq, &pi->link_fault_task);
1298f2d8ff04SGeorge V. Neville-Neil 	ADAPTER_UNLOCK(sc);
1299f2d8ff04SGeorge V. Neville-Neil }
1300f2d8ff04SGeorge V. Neville-Neil 
1301b6d90eb7SKip Macy void
1302b6d90eb7SKip Macy t3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[])
1303b6d90eb7SKip Macy {
1304b6d90eb7SKip Macy 
1305b6d90eb7SKip Macy 	/*
1306b6d90eb7SKip Macy 	 * The ifnet might not be allocated before this gets called,
1307b6d90eb7SKip Macy 	 * as this is called early on in attach by t3_prep_adapter
1308b6d90eb7SKip Macy 	 * save the address off in the port structure
1309b6d90eb7SKip Macy 	 */
1310b6d90eb7SKip Macy 	if (cxgb_debug)
1311b6d90eb7SKip Macy 		printf("set_hw_addr on idx %d addr %6D\n", port_idx, hw_addr, ":");
1312b6d90eb7SKip Macy 	bcopy(hw_addr, adapter->port[port_idx].hw_addr, ETHER_ADDR_LEN);
1313b6d90eb7SKip Macy }
1314b6d90eb7SKip Macy 
1315b6d90eb7SKip Macy /**
1316b6d90eb7SKip Macy  *	link_start - enable a port
1317b6d90eb7SKip Macy  *	@p: the port to enable
1318b6d90eb7SKip Macy  *
1319b6d90eb7SKip Macy  *	Performs the MAC and PHY actions needed to enable a port.
1320b6d90eb7SKip Macy  */
1321b6d90eb7SKip Macy static void
1322b6d90eb7SKip Macy cxgb_link_start(struct port_info *p)
1323b6d90eb7SKip Macy {
1324b6d90eb7SKip Macy 	struct ifnet *ifp;
1325b6d90eb7SKip Macy 	struct t3_rx_mode rm;
1326b6d90eb7SKip Macy 	struct cmac *mac = &p->mac;
13274af83c8cSKip Macy 	int mtu, hwtagging;
1328b6d90eb7SKip Macy 
1329b6d90eb7SKip Macy 	ifp = p->ifp;
1330b6d90eb7SKip Macy 
13314af83c8cSKip Macy 	bcopy(IF_LLADDR(ifp), p->hw_addr, ETHER_ADDR_LEN);
13324af83c8cSKip Macy 
13334af83c8cSKip Macy 	mtu = ifp->if_mtu;
13344af83c8cSKip Macy 	if (ifp->if_capenable & IFCAP_VLAN_MTU)
13354af83c8cSKip Macy 		mtu += ETHER_VLAN_ENCAP_LEN;
13364af83c8cSKip Macy 
13374af83c8cSKip Macy 	hwtagging = (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0;
13384af83c8cSKip Macy 
1339b6d90eb7SKip Macy 	t3_init_rx_mode(&rm, p);
13407ac2e6c3SKip Macy 	if (!mac->multiport)
1341b6d90eb7SKip Macy 		t3_mac_reset(mac);
13424af83c8cSKip Macy 	t3_mac_set_mtu(mac, mtu);
13434af83c8cSKip Macy 	t3_set_vlan_accel(p->adapter, 1 << p->tx_chan, hwtagging);
1344b6d90eb7SKip Macy 	t3_mac_set_address(mac, 0, p->hw_addr);
1345b6d90eb7SKip Macy 	t3_mac_set_rx_mode(mac, &rm);
1346b6d90eb7SKip Macy 	t3_link_start(&p->phy, mac, &p->link_config);
1347b6d90eb7SKip Macy 	t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
1348b6d90eb7SKip Macy }
1349b6d90eb7SKip Macy 
13508e10660fSKip Macy 
13518e10660fSKip Macy static int
13528e10660fSKip Macy await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
13538e10660fSKip Macy 			      unsigned long n)
13548e10660fSKip Macy {
13558e10660fSKip Macy 	int attempts = 5;
13568e10660fSKip Macy 
13578e10660fSKip Macy 	while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
13588e10660fSKip Macy 		if (!--attempts)
13598e10660fSKip Macy 			return (ETIMEDOUT);
13608e10660fSKip Macy 		t3_os_sleep(10);
13618e10660fSKip Macy 	}
13628e10660fSKip Macy 	return 0;
13638e10660fSKip Macy }
13648e10660fSKip Macy 
13658e10660fSKip Macy static int
13668e10660fSKip Macy init_tp_parity(struct adapter *adap)
13678e10660fSKip Macy {
13688e10660fSKip Macy 	int i;
13698e10660fSKip Macy 	struct mbuf *m;
13708e10660fSKip Macy 	struct cpl_set_tcb_field *greq;
13718e10660fSKip Macy 	unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts;
13728e10660fSKip Macy 
13738e10660fSKip Macy 	t3_tp_set_offload_mode(adap, 1);
13748e10660fSKip Macy 
13758e10660fSKip Macy 	for (i = 0; i < 16; i++) {
13768e10660fSKip Macy 		struct cpl_smt_write_req *req;
13778e10660fSKip Macy 
13788e10660fSKip Macy 		m = m_gethdr(M_WAITOK, MT_DATA);
13798e10660fSKip Macy 		req = mtod(m, struct cpl_smt_write_req *);
13808e10660fSKip Macy 		m->m_len = m->m_pkthdr.len = sizeof(*req);
13818e10660fSKip Macy 		memset(req, 0, sizeof(*req));
13828e10660fSKip Macy 		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
13838e10660fSKip Macy 		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
13848e10660fSKip Macy 		req->iff = i;
13858e10660fSKip Macy 		t3_mgmt_tx(adap, m);
13868e10660fSKip Macy 	}
13878e10660fSKip Macy 
13888e10660fSKip Macy 	for (i = 0; i < 2048; i++) {
13898e10660fSKip Macy 		struct cpl_l2t_write_req *req;
13908e10660fSKip Macy 
13918e10660fSKip Macy 		m = m_gethdr(M_WAITOK, MT_DATA);
13928e10660fSKip Macy 		req = mtod(m, struct cpl_l2t_write_req *);
13938e10660fSKip Macy 		m->m_len = m->m_pkthdr.len = sizeof(*req);
13948e10660fSKip Macy 		memset(req, 0, sizeof(*req));
13958e10660fSKip Macy 		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
13968e10660fSKip Macy 		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
13978e10660fSKip Macy 		req->params = htonl(V_L2T_W_IDX(i));
13988e10660fSKip Macy 		t3_mgmt_tx(adap, m);
13998e10660fSKip Macy 	}
14008e10660fSKip Macy 
14018e10660fSKip Macy 	for (i = 0; i < 2048; i++) {
14028e10660fSKip Macy 		struct cpl_rte_write_req *req;
14038e10660fSKip Macy 
14048e10660fSKip Macy 		m = m_gethdr(M_WAITOK, MT_DATA);
14058e10660fSKip Macy 		req = mtod(m, struct cpl_rte_write_req *);
14068e10660fSKip Macy 		m->m_len = m->m_pkthdr.len = sizeof(*req);
14078e10660fSKip Macy 		memset(req, 0, sizeof(*req));
14088e10660fSKip Macy 		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
14098e10660fSKip Macy 		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
14108e10660fSKip Macy 		req->l2t_idx = htonl(V_L2T_W_IDX(i));
14118e10660fSKip Macy 		t3_mgmt_tx(adap, m);
14128e10660fSKip Macy 	}
14138e10660fSKip Macy 
14148e10660fSKip Macy 	m = m_gethdr(M_WAITOK, MT_DATA);
14158e10660fSKip Macy 	greq = mtod(m, struct cpl_set_tcb_field *);
14168e10660fSKip Macy 	m->m_len = m->m_pkthdr.len = sizeof(*greq);
14178e10660fSKip Macy 	memset(greq, 0, sizeof(*greq));
14188e10660fSKip Macy 	greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
14198e10660fSKip Macy 	OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0));
14208e10660fSKip Macy 	greq->mask = htobe64(1);
14218e10660fSKip Macy 	t3_mgmt_tx(adap, m);
14228e10660fSKip Macy 
14238e10660fSKip Macy 	i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
14248e10660fSKip Macy 	t3_tp_set_offload_mode(adap, 0);
14258e10660fSKip Macy 	return (i);
14268e10660fSKip Macy }
14278e10660fSKip Macy 
1428b6d90eb7SKip Macy /**
1429b6d90eb7SKip Macy  *	setup_rss - configure Receive Side Steering (per-queue connection demux)
1430b6d90eb7SKip Macy  *	@adap: the adapter
1431b6d90eb7SKip Macy  *
1432b6d90eb7SKip Macy  *	Sets up RSS to distribute packets to multiple receive queues.  We
1433b6d90eb7SKip Macy  *	configure the RSS CPU lookup table to distribute to the number of HW
1434b6d90eb7SKip Macy  *	receive queues, and the response queue lookup table to narrow that
1435b6d90eb7SKip Macy  *	down to the response queues actually configured for each port.
1436b6d90eb7SKip Macy  *	We always configure the RSS mapping for two ports since the mapping
1437b6d90eb7SKip Macy  *	table has plenty of entries.
1438b6d90eb7SKip Macy  */
1439b6d90eb7SKip Macy static void
1440b6d90eb7SKip Macy setup_rss(adapter_t *adap)
1441b6d90eb7SKip Macy {
1442b6d90eb7SKip Macy 	int i;
1443ac3a6d9cSKip Macy 	u_int nq[2];
1444b6d90eb7SKip Macy 	uint8_t cpus[SGE_QSETS + 1];
1445b6d90eb7SKip Macy 	uint16_t rspq_map[RSS_TABLE_SIZE];
14465c5df3daSKip Macy 
1447b6d90eb7SKip Macy 	for (i = 0; i < SGE_QSETS; ++i)
1448b6d90eb7SKip Macy 		cpus[i] = i;
1449b6d90eb7SKip Macy 	cpus[SGE_QSETS] = 0xff;
1450b6d90eb7SKip Macy 
14517ac2e6c3SKip Macy 	nq[0] = nq[1] = 0;
14527ac2e6c3SKip Macy 	for_each_port(adap, i) {
14537ac2e6c3SKip Macy 		const struct port_info *pi = adap2pinfo(adap, i);
14547ac2e6c3SKip Macy 
14557ac2e6c3SKip Macy 		nq[pi->tx_chan] += pi->nqsets;
14567ac2e6c3SKip Macy 	}
1457b6d90eb7SKip Macy 	for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
14588e10660fSKip Macy 		rspq_map[i] = nq[0] ? i % nq[0] : 0;
14598e10660fSKip Macy 		rspq_map[i + RSS_TABLE_SIZE / 2] = nq[1] ? i % nq[1] + nq[0] : 0;
1460b6d90eb7SKip Macy 	}
1461ac3a6d9cSKip Macy 	/* Calculate the reverse RSS map table */
1462ac3a6d9cSKip Macy 	for (i = 0; i < RSS_TABLE_SIZE; ++i)
1463ac3a6d9cSKip Macy 		if (adap->rrss_map[rspq_map[i]] == 0xff)
1464ac3a6d9cSKip Macy 			adap->rrss_map[rspq_map[i]] = i;
1465b6d90eb7SKip Macy 
1466b6d90eb7SKip Macy 	t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
1467ac3a6d9cSKip Macy 		      F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | F_OFDMAPEN |
14688e10660fSKip Macy 	              F_RRCPLMAPEN | V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ,
14698e10660fSKip Macy 	              cpus, rspq_map);
1470ac3a6d9cSKip Macy 
1471b6d90eb7SKip Macy }
1472b6d90eb7SKip Macy 
1473d722cab4SKip Macy /*
1474d722cab4SKip Macy  * Sends an mbuf to an offload queue driver
1475d722cab4SKip Macy  * after dealing with any active network taps.
1476d722cab4SKip Macy  */
1477d722cab4SKip Macy static inline int
14783e96c7e7SKip Macy offload_tx(struct t3cdev *tdev, struct mbuf *m)
1479d722cab4SKip Macy {
1480d722cab4SKip Macy 	int ret;
1481d722cab4SKip Macy 
1482d722cab4SKip Macy 	ret = t3_offload_tx(tdev, m);
1483ef72318fSKip Macy 	return (ret);
1484d722cab4SKip Macy }
1485d722cab4SKip Macy 
1486d722cab4SKip Macy static int
1487d722cab4SKip Macy write_smt_entry(struct adapter *adapter, int idx)
1488d722cab4SKip Macy {
1489d722cab4SKip Macy 	struct port_info *pi = &adapter->port[idx];
1490d722cab4SKip Macy 	struct cpl_smt_write_req *req;
1491d722cab4SKip Macy 	struct mbuf *m;
1492d722cab4SKip Macy 
1493d722cab4SKip Macy 	if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
1494d722cab4SKip Macy 		return (ENOMEM);
1495d722cab4SKip Macy 
1496d722cab4SKip Macy 	req = mtod(m, struct cpl_smt_write_req *);
14978090c9f5SKip Macy 	m->m_pkthdr.len = m->m_len = sizeof(struct cpl_smt_write_req);
14988090c9f5SKip Macy 
1499d722cab4SKip Macy 	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1500d722cab4SKip Macy 	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
1501d722cab4SKip Macy 	req->mtu_idx = NMTUS - 1;  /* should be 0 but there's a T3 bug */
1502d722cab4SKip Macy 	req->iff = idx;
1503d722cab4SKip Macy 	memset(req->src_mac1, 0, sizeof(req->src_mac1));
1504d722cab4SKip Macy 	memcpy(req->src_mac0, pi->hw_addr, ETHER_ADDR_LEN);
1505d722cab4SKip Macy 
1506d722cab4SKip Macy 	m_set_priority(m, 1);
1507d722cab4SKip Macy 
1508d722cab4SKip Macy 	offload_tx(&adapter->tdev, m);
1509d722cab4SKip Macy 
1510d722cab4SKip Macy 	return (0);
1511d722cab4SKip Macy }
1512d722cab4SKip Macy 
1513d722cab4SKip Macy static int
1514d722cab4SKip Macy init_smt(struct adapter *adapter)
1515d722cab4SKip Macy {
1516d722cab4SKip Macy 	int i;
1517d722cab4SKip Macy 
1518d722cab4SKip Macy 	for_each_port(adapter, i)
1519d722cab4SKip Macy 		write_smt_entry(adapter, i);
1520d722cab4SKip Macy 	return 0;
1521d722cab4SKip Macy }
1522d722cab4SKip Macy 
1523d722cab4SKip Macy static void
1524d722cab4SKip Macy init_port_mtus(adapter_t *adapter)
1525d722cab4SKip Macy {
1526d722cab4SKip Macy 	unsigned int mtus = adapter->port[0].ifp->if_mtu;
1527d722cab4SKip Macy 
1528d722cab4SKip Macy 	if (adapter->port[1].ifp)
1529d722cab4SKip Macy 		mtus |= adapter->port[1].ifp->if_mtu << 16;
1530d722cab4SKip Macy 	t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
1531d722cab4SKip Macy }
1532d722cab4SKip Macy 
1533b6d90eb7SKip Macy static void
1534b6d90eb7SKip Macy send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
1535b6d90eb7SKip Macy 			      int hi, int port)
1536b6d90eb7SKip Macy {
1537b6d90eb7SKip Macy 	struct mbuf *m;
1538b6d90eb7SKip Macy 	struct mngt_pktsched_wr *req;
1539b6d90eb7SKip Macy 
1540ac3a6d9cSKip Macy 	m = m_gethdr(M_DONTWAIT, MT_DATA);
154120fe52b8SKip Macy 	if (m) {
1542d722cab4SKip Macy 		req = mtod(m, struct mngt_pktsched_wr *);
1543b6d90eb7SKip Macy 		req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
1544b6d90eb7SKip Macy 		req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
1545b6d90eb7SKip Macy 		req->sched = sched;
1546b6d90eb7SKip Macy 		req->idx = qidx;
1547b6d90eb7SKip Macy 		req->min = lo;
1548b6d90eb7SKip Macy 		req->max = hi;
1549b6d90eb7SKip Macy 		req->binding = port;
1550b6d90eb7SKip Macy 		m->m_len = m->m_pkthdr.len = sizeof(*req);
1551b6d90eb7SKip Macy 		t3_mgmt_tx(adap, m);
1552b6d90eb7SKip Macy 	}
155320fe52b8SKip Macy }
1554b6d90eb7SKip Macy 
1555b6d90eb7SKip Macy static void
1556b6d90eb7SKip Macy bind_qsets(adapter_t *sc)
1557b6d90eb7SKip Macy {
1558b6d90eb7SKip Macy 	int i, j;
1559b6d90eb7SKip Macy 
15608090c9f5SKip Macy 	cxgb_pcpu_startup_threads(sc);
1561b6d90eb7SKip Macy 	for (i = 0; i < (sc)->params.nports; ++i) {
1562b6d90eb7SKip Macy 		const struct port_info *pi = adap2pinfo(sc, i);
1563b6d90eb7SKip Macy 
15645c5df3daSKip Macy 		for (j = 0; j < pi->nqsets; ++j) {
1565b6d90eb7SKip Macy 			send_pktsched_cmd(sc, 1, pi->first_qset + j, -1,
15665c5df3daSKip Macy 					  -1, pi->tx_chan);
15675c5df3daSKip Macy 
15685c5df3daSKip Macy 		}
1569b6d90eb7SKip Macy 	}
1570b6d90eb7SKip Macy }
1571b6d90eb7SKip Macy 
1572ac3a6d9cSKip Macy static void
1573ac3a6d9cSKip Macy update_tpeeprom(struct adapter *adap)
1574ac3a6d9cSKip Macy {
15752de1fa86SKip Macy #ifdef FIRMWARE_LATEST
1576ac3a6d9cSKip Macy 	const struct firmware *tpeeprom;
15772de1fa86SKip Macy #else
15782de1fa86SKip Macy 	struct firmware *tpeeprom;
15792de1fa86SKip Macy #endif
15802de1fa86SKip Macy 
1581ac3a6d9cSKip Macy 	uint32_t version;
1582ac3a6d9cSKip Macy 	unsigned int major, minor;
1583ac3a6d9cSKip Macy 	int ret, len;
1584f2d8ff04SGeorge V. Neville-Neil 	char rev, name[32];
1585ac3a6d9cSKip Macy 
1586ac3a6d9cSKip Macy 	t3_seeprom_read(adap, TP_SRAM_OFFSET, &version);
1587ac3a6d9cSKip Macy 
1588ac3a6d9cSKip Macy 	major = G_TP_VERSION_MAJOR(version);
1589ac3a6d9cSKip Macy 	minor = G_TP_VERSION_MINOR(version);
1590ac3a6d9cSKip Macy 	if (major == TP_VERSION_MAJOR  && minor == TP_VERSION_MINOR)
1591ac3a6d9cSKip Macy 		return;
1592ac3a6d9cSKip Macy 
1593ac3a6d9cSKip Macy 	rev = t3rev2char(adap);
1594f2d8ff04SGeorge V. Neville-Neil 	snprintf(name, sizeof(name), TPEEPROM_NAME, rev);
1595ac3a6d9cSKip Macy 
1596f2d8ff04SGeorge V. Neville-Neil 	tpeeprom = firmware_get(name);
1597ac3a6d9cSKip Macy 	if (tpeeprom == NULL) {
1598ac3a6d9cSKip Macy 		device_printf(adap->dev, "could not load TP EEPROM: unable to load %s\n",
159964a37133SKip Macy 		    TPEEPROM_NAME);
1600ac3a6d9cSKip Macy 		return;
1601ac3a6d9cSKip Macy 	}
1602ac3a6d9cSKip Macy 
1603ac3a6d9cSKip Macy 	len = tpeeprom->datasize - 4;
1604ac3a6d9cSKip Macy 
1605ac3a6d9cSKip Macy 	ret = t3_check_tpsram(adap, tpeeprom->data, tpeeprom->datasize);
1606ac3a6d9cSKip Macy 	if (ret)
1607ac3a6d9cSKip Macy 		goto release_tpeeprom;
1608ac3a6d9cSKip Macy 
1609ac3a6d9cSKip Macy 	if (len != TP_SRAM_LEN) {
161064a37133SKip Macy 		device_printf(adap->dev, "%s length is wrong len=%d expected=%d\n", TPEEPROM_NAME, len, TP_SRAM_LEN);
1611ac3a6d9cSKip Macy 		return;
1612ac3a6d9cSKip Macy 	}
1613ac3a6d9cSKip Macy 
1614ac3a6d9cSKip Macy 	ret = set_eeprom(&adap->port[0], tpeeprom->data, tpeeprom->datasize,
1615ac3a6d9cSKip Macy 	    TP_SRAM_OFFSET);
1616ac3a6d9cSKip Macy 
1617ac3a6d9cSKip Macy 	if (!ret) {
1618ac3a6d9cSKip Macy 		device_printf(adap->dev,
1619ac3a6d9cSKip Macy 			"Protocol SRAM image updated in EEPROM to %d.%d.%d\n",
1620ac3a6d9cSKip Macy 			 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1621ac3a6d9cSKip Macy 	} else
1622ac3a6d9cSKip Macy 		device_printf(adap->dev, "Protocol SRAM image update in EEPROM failed\n");
1623ac3a6d9cSKip Macy 
1624ac3a6d9cSKip Macy release_tpeeprom:
1625ac3a6d9cSKip Macy 	firmware_put(tpeeprom, FIRMWARE_UNLOAD);
1626ac3a6d9cSKip Macy 
1627ac3a6d9cSKip Macy 	return;
1628ac3a6d9cSKip Macy }
1629ac3a6d9cSKip Macy 
1630ac3a6d9cSKip Macy static int
1631ac3a6d9cSKip Macy update_tpsram(struct adapter *adap)
1632ac3a6d9cSKip Macy {
16332de1fa86SKip Macy #ifdef FIRMWARE_LATEST
1634ac3a6d9cSKip Macy 	const struct firmware *tpsram;
16352de1fa86SKip Macy #else
16362de1fa86SKip Macy 	struct firmware *tpsram;
16372de1fa86SKip Macy #endif
1638ac3a6d9cSKip Macy 	int ret;
1639f2d8ff04SGeorge V. Neville-Neil 	char rev, name[32];
1640ac3a6d9cSKip Macy 
1641ac3a6d9cSKip Macy 	rev = t3rev2char(adap);
1642f2d8ff04SGeorge V. Neville-Neil 	snprintf(name, sizeof(name), TPSRAM_NAME, rev);
1643ac3a6d9cSKip Macy 
1644ac3a6d9cSKip Macy 	update_tpeeprom(adap);
1645ac3a6d9cSKip Macy 
1646f2d8ff04SGeorge V. Neville-Neil 	tpsram = firmware_get(name);
1647ac3a6d9cSKip Macy 	if (tpsram == NULL){
164864a37133SKip Macy 		device_printf(adap->dev, "could not load TP SRAM\n");
1649ac3a6d9cSKip Macy 		return (EINVAL);
1650ac3a6d9cSKip Macy 	} else
165164a37133SKip Macy 		device_printf(adap->dev, "updating TP SRAM\n");
1652ac3a6d9cSKip Macy 
1653ac3a6d9cSKip Macy 	ret = t3_check_tpsram(adap, tpsram->data, tpsram->datasize);
1654ac3a6d9cSKip Macy 	if (ret)
1655ac3a6d9cSKip Macy 		goto release_tpsram;
1656ac3a6d9cSKip Macy 
1657ac3a6d9cSKip Macy 	ret = t3_set_proto_sram(adap, tpsram->data);
1658ac3a6d9cSKip Macy 	if (ret)
1659ac3a6d9cSKip Macy 		device_printf(adap->dev, "loading protocol SRAM failed\n");
1660ac3a6d9cSKip Macy 
1661ac3a6d9cSKip Macy release_tpsram:
1662ac3a6d9cSKip Macy 	firmware_put(tpsram, FIRMWARE_UNLOAD);
1663ac3a6d9cSKip Macy 
1664ac3a6d9cSKip Macy 	return ret;
1665ac3a6d9cSKip Macy }
1666ac3a6d9cSKip Macy 
1667d722cab4SKip Macy /**
1668d722cab4SKip Macy  *	cxgb_up - enable the adapter
1669d722cab4SKip Macy  *	@adap: adapter being enabled
1670d722cab4SKip Macy  *
1671d722cab4SKip Macy  *	Called when the first port is enabled, this function performs the
1672d722cab4SKip Macy  *	actions necessary to make an adapter operational, such as completing
1673d722cab4SKip Macy  *	the initialization of HW modules, and enabling interrupts.
1674d722cab4SKip Macy  */
1675d722cab4SKip Macy static int
1676d722cab4SKip Macy cxgb_up(struct adapter *sc)
1677d722cab4SKip Macy {
1678d722cab4SKip Macy 	int err = 0;
1679d722cab4SKip Macy 
1680d722cab4SKip Macy 	if ((sc->flags & FULL_INIT_DONE) == 0) {
1681d722cab4SKip Macy 
1682d722cab4SKip Macy 		if ((sc->flags & FW_UPTODATE) == 0)
1683ac3a6d9cSKip Macy 			if ((err = upgrade_fw(sc)))
1684d722cab4SKip Macy 				goto out;
1685ac3a6d9cSKip Macy 		if ((sc->flags & TPS_UPTODATE) == 0)
1686ac3a6d9cSKip Macy 			if ((err = update_tpsram(sc)))
1687ac3a6d9cSKip Macy 				goto out;
1688d722cab4SKip Macy 		err = t3_init_hw(sc, 0);
1689d722cab4SKip Macy 		if (err)
1690d722cab4SKip Macy 			goto out;
1691d722cab4SKip Macy 
16928e10660fSKip Macy 		t3_set_reg_field(sc, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT);
1693d722cab4SKip Macy 		t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
1694d722cab4SKip Macy 
1695d722cab4SKip Macy 		err = setup_sge_qsets(sc);
1696d722cab4SKip Macy 		if (err)
1697d722cab4SKip Macy 			goto out;
1698d722cab4SKip Macy 
1699d722cab4SKip Macy 		setup_rss(sc);
17008090c9f5SKip Macy 		t3_add_configured_sysctls(sc);
1701d722cab4SKip Macy 		sc->flags |= FULL_INIT_DONE;
1702d722cab4SKip Macy 	}
1703d722cab4SKip Macy 
1704d722cab4SKip Macy 	t3_intr_clear(sc);
1705d722cab4SKip Macy 
1706d722cab4SKip Macy 	/* If it's MSI or INTx, allocate a single interrupt for everything */
1707d722cab4SKip Macy 	if ((sc->flags & USING_MSIX) == 0) {
1708d722cab4SKip Macy 		if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
1709d722cab4SKip Macy 		   &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
17107ac2e6c3SKip Macy 			device_printf(sc->dev, "Cannot allocate interrupt rid=%d\n",
17117ac2e6c3SKip Macy 			    sc->irq_rid);
1712d722cab4SKip Macy 			err = EINVAL;
1713d722cab4SKip Macy 			goto out;
1714d722cab4SKip Macy 		}
1715d722cab4SKip Macy 		device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res);
1716d722cab4SKip Macy 
1717d722cab4SKip Macy 		if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET,
1718d722cab4SKip Macy #ifdef INTR_FILTERS
1719d722cab4SKip Macy 			NULL,
1720d722cab4SKip Macy #endif
1721d722cab4SKip Macy 			sc->cxgb_intr, sc, &sc->intr_tag)) {
1722d722cab4SKip Macy 			device_printf(sc->dev, "Cannot set up interrupt\n");
1723d722cab4SKip Macy 			err = EINVAL;
1724d722cab4SKip Macy 			goto irq_err;
1725d722cab4SKip Macy 		}
1726d722cab4SKip Macy 	} else {
1727d722cab4SKip Macy 		cxgb_setup_msix(sc, sc->msi_count);
1728d722cab4SKip Macy 	}
1729d722cab4SKip Macy 
1730d722cab4SKip Macy 	t3_sge_start(sc);
1731d722cab4SKip Macy 	t3_intr_enable(sc);
1732d722cab4SKip Macy 
17338e10660fSKip Macy 	if (sc->params.rev >= T3_REV_C && !(sc->flags & TP_PARITY_INIT) &&
17348e10660fSKip Macy 	    is_offload(sc) && init_tp_parity(sc) == 0)
17358e10660fSKip Macy 		sc->flags |= TP_PARITY_INIT;
17368e10660fSKip Macy 
17378e10660fSKip Macy 	if (sc->flags & TP_PARITY_INIT) {
17388e10660fSKip Macy 		t3_write_reg(sc, A_TP_INT_CAUSE,
17398e10660fSKip Macy 				F_CMCACHEPERR | F_ARPLUTPERR);
17408e10660fSKip Macy 		t3_write_reg(sc, A_TP_INT_ENABLE, 0x7fbfffff);
17418e10660fSKip Macy 	}
17428e10660fSKip Macy 
17438e10660fSKip Macy 
17445c5df3daSKip Macy 	if (!(sc->flags & QUEUES_BOUND)) {
1745d722cab4SKip Macy 		bind_qsets(sc);
1746d722cab4SKip Macy 		sc->flags |= QUEUES_BOUND;
1747ac3a6d9cSKip Macy 	}
1748d722cab4SKip Macy out:
1749d722cab4SKip Macy 	return (err);
1750d722cab4SKip Macy irq_err:
1751d722cab4SKip Macy 	CH_ERR(sc, "request_irq failed, err %d\n", err);
1752d722cab4SKip Macy 	goto out;
1753d722cab4SKip Macy }
1754d722cab4SKip Macy 
1755d722cab4SKip Macy 
1756d722cab4SKip Macy /*
1757d722cab4SKip Macy  * Release resources when all the ports and offloading have been stopped.
1758d722cab4SKip Macy  */
1759d722cab4SKip Macy static void
1760bb38cd2fSKip Macy cxgb_down_locked(struct adapter *sc)
1761d722cab4SKip Macy {
1762d722cab4SKip Macy 
1763d722cab4SKip Macy 	t3_sge_stop(sc);
1764d722cab4SKip Macy 	t3_intr_disable(sc);
1765d722cab4SKip Macy 
1766d722cab4SKip Macy 	if (sc->intr_tag != NULL) {
1767d722cab4SKip Macy 		bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag);
1768d722cab4SKip Macy 		sc->intr_tag = NULL;
1769d722cab4SKip Macy 	}
1770d722cab4SKip Macy 	if (sc->irq_res != NULL) {
1771d722cab4SKip Macy 		device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n",
1772d722cab4SKip Macy 		    sc->irq_rid, sc->irq_res);
1773d722cab4SKip Macy 		bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
1774d722cab4SKip Macy 		    sc->irq_res);
1775d722cab4SKip Macy 		sc->irq_res = NULL;
1776d722cab4SKip Macy 	}
1777d722cab4SKip Macy 
1778ef72318fSKip Macy 	if (sc->flags & USING_MSIX)
1779ef72318fSKip Macy 		cxgb_teardown_msix(sc);
1780ef72318fSKip Macy 
17818090c9f5SKip Macy 	callout_stop(&sc->cxgb_tick_ch);
17828090c9f5SKip Macy 	callout_stop(&sc->sge_timer_ch);
1783bb38cd2fSKip Macy 	callout_drain(&sc->cxgb_tick_ch);
1784d722cab4SKip Macy 	callout_drain(&sc->sge_timer_ch);
1785bb38cd2fSKip Macy 
17867ac2e6c3SKip Macy 	if (sc->tq != NULL) {
17878e10660fSKip Macy 		printf("draining slow intr\n");
17888e10660fSKip Macy 
1789d722cab4SKip Macy 		taskqueue_drain(sc->tq, &sc->slow_intr_task);
17908e10660fSKip Macy 			printf("draining ext intr\n");
17918e10660fSKip Macy 		taskqueue_drain(sc->tq, &sc->ext_intr_task);
17928e10660fSKip Macy 		printf("draining tick task\n");
17938e10660fSKip Macy 		taskqueue_drain(sc->tq, &sc->tick_task);
17947ac2e6c3SKip Macy 	}
17958e10660fSKip Macy 	ADAPTER_UNLOCK(sc);
1796d722cab4SKip Macy }
1797d722cab4SKip Macy 
1798d722cab4SKip Macy static int
1799d722cab4SKip Macy offload_open(struct port_info *pi)
1800d722cab4SKip Macy {
1801d722cab4SKip Macy 	struct adapter *adapter = pi->adapter;
18028090c9f5SKip Macy 	struct t3cdev *tdev = &adapter->tdev;
1803af9b081cSKip Macy 
1804d722cab4SKip Macy 	int adap_up = adapter->open_device_map & PORT_MASK;
1805d722cab4SKip Macy 	int err = 0;
1806d722cab4SKip Macy 
1807d722cab4SKip Macy 	if (atomic_cmpset_int(&adapter->open_device_map,
18088090c9f5SKip Macy 		(adapter->open_device_map & ~(1<<OFFLOAD_DEVMAP_BIT)),
18098090c9f5SKip Macy 		(adapter->open_device_map | (1<<OFFLOAD_DEVMAP_BIT))) == 0)
1810d722cab4SKip Macy 		return (0);
1811d722cab4SKip Macy 
18128090c9f5SKip Macy 	if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT))
1813af9b081cSKip Macy 		printf("offload_open: DEVMAP_BIT did not get set 0x%x\n",
1814af9b081cSKip Macy 		    adapter->open_device_map);
1815d722cab4SKip Macy 	ADAPTER_LOCK(pi->adapter);
1816d722cab4SKip Macy 	if (!adap_up)
1817d722cab4SKip Macy 		err = cxgb_up(adapter);
1818d722cab4SKip Macy 	ADAPTER_UNLOCK(pi->adapter);
1819ac3a6d9cSKip Macy 	if (err)
1820d722cab4SKip Macy 		return (err);
1821d722cab4SKip Macy 
1822d722cab4SKip Macy 	t3_tp_set_offload_mode(adapter, 1);
18238090c9f5SKip Macy 	tdev->lldev = pi->ifp;
1824d722cab4SKip Macy 
1825d722cab4SKip Macy 	init_port_mtus(adapter);
1826d722cab4SKip Macy 	t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
1827d722cab4SKip Macy 		     adapter->params.b_wnd,
1828d722cab4SKip Macy 		     adapter->params.rev == 0 ?
1829d722cab4SKip Macy 		       adapter->port[0].ifp->if_mtu : 0xffff);
1830d722cab4SKip Macy 	init_smt(adapter);
1831ed0fb18dSKip Macy 	/* Call back all registered clients */
1832ed0fb18dSKip Macy 	cxgb_add_clients(tdev);
1833ed0fb18dSKip Macy 
1834d722cab4SKip Macy 	/* restore them in case the offload module has changed them */
1835d722cab4SKip Macy 	if (err) {
1836d722cab4SKip Macy 		t3_tp_set_offload_mode(adapter, 0);
1837d722cab4SKip Macy 		clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT);
1838d722cab4SKip Macy 		cxgb_set_dummy_ops(tdev);
1839d722cab4SKip Macy 	}
1840d722cab4SKip Macy 	return (err);
1841d722cab4SKip Macy }
18428090c9f5SKip Macy 
1843d722cab4SKip Macy static int
18448090c9f5SKip Macy offload_close(struct t3cdev *tdev)
1845d722cab4SKip Macy {
1846d722cab4SKip Macy 	struct adapter *adapter = tdev2adap(tdev);
1847d722cab4SKip Macy 
18488e10660fSKip Macy 	if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT))
1849ef72318fSKip Macy 		return (0);
1850d722cab4SKip Macy 
1851ed0fb18dSKip Macy 	/* Call back all registered clients */
1852ed0fb18dSKip Macy 	cxgb_remove_clients(tdev);
1853ed0fb18dSKip Macy 
1854d722cab4SKip Macy 	tdev->lldev = NULL;
1855d722cab4SKip Macy 	cxgb_set_dummy_ops(tdev);
1856d722cab4SKip Macy 	t3_tp_set_offload_mode(adapter, 0);
1857d722cab4SKip Macy 	clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT);
1858d722cab4SKip Macy 
18598090c9f5SKip Macy 	ADAPTER_LOCK(adapter);
1860d722cab4SKip Macy 	if (!adapter->open_device_map)
18618090c9f5SKip Macy 		cxgb_down_locked(adapter);
18628090c9f5SKip Macy 	else
18638090c9f5SKip Macy 		ADAPTER_UNLOCK(adapter);
1864ef72318fSKip Macy 	return (0);
1865d722cab4SKip Macy }
18668090c9f5SKip Macy 
1867d722cab4SKip Macy 
1868b6d90eb7SKip Macy static void
1869b6d90eb7SKip Macy cxgb_init(void *arg)
1870b6d90eb7SKip Macy {
1871b6d90eb7SKip Macy 	struct port_info *p = arg;
1872b6d90eb7SKip Macy 
1873b6d90eb7SKip Macy 	PORT_LOCK(p);
1874b6d90eb7SKip Macy 	cxgb_init_locked(p);
1875b6d90eb7SKip Macy 	PORT_UNLOCK(p);
1876b6d90eb7SKip Macy }
1877b6d90eb7SKip Macy 
1878b6d90eb7SKip Macy static void
1879b6d90eb7SKip Macy cxgb_init_locked(struct port_info *p)
1880b6d90eb7SKip Macy {
1881b6d90eb7SKip Macy 	struct ifnet *ifp;
1882b6d90eb7SKip Macy 	adapter_t *sc = p->adapter;
1883d722cab4SKip Macy 	int err;
1884b6d90eb7SKip Macy 
1885bb38cd2fSKip Macy 	PORT_LOCK_ASSERT_OWNED(p);
1886b6d90eb7SKip Macy 	ifp = p->ifp;
1887d722cab4SKip Macy 
1888d722cab4SKip Macy 	ADAPTER_LOCK(p->adapter);
1889ac3a6d9cSKip Macy 	if ((sc->open_device_map == 0) && (err = cxgb_up(sc))) {
1890d722cab4SKip Macy 		ADAPTER_UNLOCK(p->adapter);
1891d722cab4SKip Macy 		cxgb_stop_locked(p);
1892b6d90eb7SKip Macy 		return;
1893b6d90eb7SKip Macy 	}
1894bb38cd2fSKip Macy 	if (p->adapter->open_device_map == 0) {
1895b6d90eb7SKip Macy 		t3_intr_clear(sc);
1896bb38cd2fSKip Macy 	}
18976b68e276SKip Macy 	setbit(&p->adapter->open_device_map, p->port_id);
1898b6d90eb7SKip Macy 	ADAPTER_UNLOCK(p->adapter);
1899ef72318fSKip Macy 
1900d722cab4SKip Macy 	if (is_offload(sc) && !ofld_disable) {
1901d722cab4SKip Macy 		err = offload_open(p);
1902d722cab4SKip Macy 		if (err)
1903d722cab4SKip Macy 			log(LOG_WARNING,
1904d722cab4SKip Macy 			    "Could not initialize offload capabilities\n");
1905d722cab4SKip Macy 	}
1906ef027c52SKip Macy #if !defined(LINK_ATTACH)
1907ef027c52SKip Macy 	cxgb_link_start(p);
1908ef027c52SKip Macy 	t3_link_changed(sc, p->port_id);
1909ef027c52SKip Macy #endif
1910837f41b0SGeorge V. Neville-Neil 	ifp->if_baudrate = IF_Mbps(p->link_config.speed);
1911ef72318fSKip Macy 
19125c5df3daSKip Macy 	device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id);
19136b68e276SKip Macy 	t3_port_intr_enable(sc, p->port_id);
1914693d746cSKip Macy 
19159330dbc3SKip Macy 	t3_sge_reset_adapter(sc);
1916b6d90eb7SKip Macy 
1917b6d90eb7SKip Macy 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1918b6d90eb7SKip Macy 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1919b6d90eb7SKip Macy }
1920b6d90eb7SKip Macy 
1921b6d90eb7SKip Macy static void
1922b6d90eb7SKip Macy cxgb_set_rxmode(struct port_info *p)
1923b6d90eb7SKip Macy {
1924b6d90eb7SKip Macy 	struct t3_rx_mode rm;
1925b6d90eb7SKip Macy 	struct cmac *mac = &p->mac;
1926b6d90eb7SKip Macy 
1927b6d90eb7SKip Macy 	t3_init_rx_mode(&rm, p);
19288e10660fSKip Macy 	mtx_lock(&p->adapter->mdio_lock);
1929b6d90eb7SKip Macy 	t3_mac_set_rx_mode(mac, &rm);
19308e10660fSKip Macy 	mtx_unlock(&p->adapter->mdio_lock);
1931b6d90eb7SKip Macy }
1932b6d90eb7SKip Macy 
1933b6d90eb7SKip Macy static void
193419905d6dSKip Macy cxgb_stop_locked(struct port_info *pi)
1935b6d90eb7SKip Macy {
1936b6d90eb7SKip Macy 	struct ifnet *ifp;
1937b6d90eb7SKip Macy 
193819905d6dSKip Macy 	PORT_LOCK_ASSERT_OWNED(pi);
193919905d6dSKip Macy 	ADAPTER_LOCK_ASSERT_NOTOWNED(pi->adapter);
194077f07749SKip Macy 
194119905d6dSKip Macy 	ifp = pi->ifp;
194219905d6dSKip Macy 	t3_port_intr_disable(pi->adapter, pi->port_id);
1943d722cab4SKip Macy 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1944b6d90eb7SKip Macy 
194519905d6dSKip Macy 	/* disable pause frames */
194619905d6dSKip Macy 	t3_set_reg_field(pi->adapter, A_XGM_TX_CFG + pi->mac.offset,
194719905d6dSKip Macy 			 F_TXPAUSEEN, 0);
1948bb38cd2fSKip Macy 
194919905d6dSKip Macy 	/* Reset RX FIFO HWM */
195019905d6dSKip Macy         t3_set_reg_field(pi->adapter, A_XGM_RXFIFO_CFG +  pi->mac.offset,
195119905d6dSKip Macy 			 V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM), 0);
195219905d6dSKip Macy 
195319905d6dSKip Macy 
195419905d6dSKip Macy 	ADAPTER_LOCK(pi->adapter);
195519905d6dSKip Macy 	clrbit(&pi->adapter->open_device_map, pi->port_id);
195619905d6dSKip Macy 
195719905d6dSKip Macy 	if (pi->adapter->open_device_map == 0) {
195819905d6dSKip Macy 		cxgb_down_locked(pi->adapter);
1959bb38cd2fSKip Macy 	} else
196019905d6dSKip Macy 		ADAPTER_UNLOCK(pi->adapter);
196119905d6dSKip Macy 
1962ef027c52SKip Macy #if !defined(LINK_ATTACH)
196319905d6dSKip Macy 	DELAY(100);
196419905d6dSKip Macy 
196519905d6dSKip Macy 	/* Wait for TXFIFO empty */
196619905d6dSKip Macy 	t3_wait_op_done(pi->adapter, A_XGM_TXFIFO_CFG + pi->mac.offset,
196719905d6dSKip Macy 			F_TXFIFO_EMPTY, 1, 20, 5);
196819905d6dSKip Macy 
196919905d6dSKip Macy 	DELAY(100);
197019905d6dSKip Macy 	t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
197119905d6dSKip Macy 
197219905d6dSKip Macy 	pi->phy.ops->power_down(&pi->phy, 1);
1973ef027c52SKip Macy #endif
1974bb38cd2fSKip Macy 
1975b6d90eb7SKip Macy }
1976b6d90eb7SKip Macy 
1977b6d90eb7SKip Macy static int
1978ef72318fSKip Macy cxgb_set_mtu(struct port_info *p, int mtu)
1979ef72318fSKip Macy {
1980ef72318fSKip Macy 	struct ifnet *ifp = p->ifp;
1981ef72318fSKip Macy 	int error = 0;
1982ef72318fSKip Macy 
19834af83c8cSKip Macy 	if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO))
1984ef72318fSKip Macy 		error = EINVAL;
1985ef72318fSKip Macy 	else if (ifp->if_mtu != mtu) {
1986ef72318fSKip Macy 		PORT_LOCK(p);
1987ef72318fSKip Macy 		ifp->if_mtu = mtu;
1988ef72318fSKip Macy 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1989ef72318fSKip Macy 			cxgb_stop_locked(p);
1990ef72318fSKip Macy 			cxgb_init_locked(p);
1991ef72318fSKip Macy 		}
1992ef72318fSKip Macy 		PORT_UNLOCK(p);
1993ef72318fSKip Macy 	}
1994ef72318fSKip Macy 	return (error);
1995ef72318fSKip Macy }
1996ef72318fSKip Macy 
1997e97121daSKip Macy #ifdef LRO_SUPPORTED
199825292debSKip Macy /*
199925292debSKip Macy  * Mark lro enabled or disabled in all qsets for this port
200025292debSKip Macy  */
200125292debSKip Macy static int
200225292debSKip Macy cxgb_set_lro(struct port_info *p, int enabled)
200325292debSKip Macy {
200425292debSKip Macy 	int i;
200525292debSKip Macy 	struct adapter *adp = p->adapter;
200625292debSKip Macy 	struct sge_qset *q;
200725292debSKip Macy 
200825292debSKip Macy 	PORT_LOCK_ASSERT_OWNED(p);
200925292debSKip Macy 	for (i = 0; i < p->nqsets; i++) {
201025292debSKip Macy 		q = &adp->sge.qs[p->first_qset + i];
201125292debSKip Macy 		q->lro.enabled = (enabled != 0);
201225292debSKip Macy 	}
201325292debSKip Macy 	return (0);
201425292debSKip Macy }
2015e97121daSKip Macy #endif
201625292debSKip Macy 
2017ef72318fSKip Macy static int
2018b6d90eb7SKip Macy cxgb_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data)
2019b6d90eb7SKip Macy {
2020b6d90eb7SKip Macy 	struct port_info *p = ifp->if_softc;
202134627f93SBjoern A. Zeeb #ifdef INET
2022b6d90eb7SKip Macy 	struct ifaddr *ifa = (struct ifaddr *)data;
202334627f93SBjoern A. Zeeb #endif
2024b6d90eb7SKip Macy 	struct ifreq *ifr = (struct ifreq *)data;
20254af83c8cSKip Macy 	int flags, error = 0, reinit = 0;
2026b6d90eb7SKip Macy 	uint32_t mask;
2027b6d90eb7SKip Macy 
202851580731SKip Macy 	/*
202951580731SKip Macy 	 * XXX need to check that we aren't in the middle of an unload
203051580731SKip Macy 	 */
2031b6d90eb7SKip Macy 	switch (command) {
2032b6d90eb7SKip Macy 	case SIOCSIFMTU:
2033ef72318fSKip Macy 		error = cxgb_set_mtu(p, ifr->ifr_mtu);
2034b6d90eb7SKip Macy 		break;
2035b6d90eb7SKip Macy 	case SIOCSIFADDR:
203634627f93SBjoern A. Zeeb #ifdef INET
2037b6d90eb7SKip Macy 		if (ifa->ifa_addr->sa_family == AF_INET) {
2038b6d90eb7SKip Macy 			ifp->if_flags |= IFF_UP;
20398e10660fSKip Macy 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
20408e10660fSKip Macy 				PORT_LOCK(p);
2041ef72318fSKip Macy 				cxgb_init_locked(p);
20424f6a96aeSKip Macy 				PORT_UNLOCK(p);
20438e10660fSKip Macy 			}
20448e10660fSKip Macy 			arp_ifinit(ifp, ifa);
2045b6d90eb7SKip Macy 		} else
204634627f93SBjoern A. Zeeb #endif
2047b6d90eb7SKip Macy 			error = ether_ioctl(ifp, command, data);
2048b6d90eb7SKip Macy 		break;
2049b6d90eb7SKip Macy 	case SIOCSIFFLAGS:
2050693d746cSKip Macy 		PORT_LOCK(p);
2051ef72318fSKip Macy 		if (ifp->if_flags & IFF_UP) {
2052b6d90eb7SKip Macy 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2053b6d90eb7SKip Macy 				flags = p->if_flags;
2054b6d90eb7SKip Macy 				if (((ifp->if_flags ^ flags) & IFF_PROMISC) ||
2055b6d90eb7SKip Macy 				    ((ifp->if_flags ^ flags) & IFF_ALLMULTI))
2056b6d90eb7SKip Macy 					cxgb_set_rxmode(p);
2057b6d90eb7SKip Macy 			} else
2058b6d90eb7SKip Macy 				cxgb_init_locked(p);
2059b6d90eb7SKip Macy 			p->if_flags = ifp->if_flags;
2060bb38cd2fSKip Macy 		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2061693d746cSKip Macy 			cxgb_stop_locked(p);
2062bb38cd2fSKip Macy 
2063ef72318fSKip Macy 		PORT_UNLOCK(p);
2064b6d90eb7SKip Macy 		break;
20658e10660fSKip Macy 	case SIOCADDMULTI:
20668e10660fSKip Macy 	case SIOCDELMULTI:
20678e10660fSKip Macy 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
20688e10660fSKip Macy 			cxgb_set_rxmode(p);
20698e10660fSKip Macy 		}
20708e10660fSKip Macy 		break;
2071b6d90eb7SKip Macy 	case SIOCSIFMEDIA:
2072b6d90eb7SKip Macy 	case SIOCGIFMEDIA:
2073837f41b0SGeorge V. Neville-Neil 		PORT_LOCK(p);
2074b6d90eb7SKip Macy 		error = ifmedia_ioctl(ifp, ifr, &p->media, command);
2075837f41b0SGeorge V. Neville-Neil 		PORT_UNLOCK(p);
2076b6d90eb7SKip Macy 		break;
2077b6d90eb7SKip Macy 	case SIOCSIFCAP:
2078b6d90eb7SKip Macy 		PORT_LOCK(p);
2079b6d90eb7SKip Macy 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
2080b6d90eb7SKip Macy 		if (mask & IFCAP_TXCSUM) {
2081b6d90eb7SKip Macy 			if (IFCAP_TXCSUM & ifp->if_capenable) {
2082b6d90eb7SKip Macy 				ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4);
2083b6d90eb7SKip Macy 				ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP
20844af83c8cSKip Macy 				    | CSUM_IP | CSUM_TSO);
2085b6d90eb7SKip Macy 			} else {
2086b6d90eb7SKip Macy 				ifp->if_capenable |= IFCAP_TXCSUM;
20874af83c8cSKip Macy 				ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP
20884af83c8cSKip Macy 				    | CSUM_IP);
2089b6d90eb7SKip Macy 			}
2090b6d90eb7SKip Macy 		}
20914af83c8cSKip Macy 		if (mask & IFCAP_RXCSUM) {
20924af83c8cSKip Macy 			ifp->if_capenable ^= IFCAP_RXCSUM;
2093b6d90eb7SKip Macy 		}
2094b6d90eb7SKip Macy 		if (mask & IFCAP_TSO4) {
2095b6d90eb7SKip Macy 			if (IFCAP_TSO4 & ifp->if_capenable) {
2096b6d90eb7SKip Macy 				ifp->if_capenable &= ~IFCAP_TSO4;
2097b6d90eb7SKip Macy 				ifp->if_hwassist &= ~CSUM_TSO;
2098b6d90eb7SKip Macy 			} else if (IFCAP_TXCSUM & ifp->if_capenable) {
2099b6d90eb7SKip Macy 				ifp->if_capenable |= IFCAP_TSO4;
2100b6d90eb7SKip Macy 				ifp->if_hwassist |= CSUM_TSO;
2101b6d90eb7SKip Macy 			} else {
2102b6d90eb7SKip Macy 				if (cxgb_debug)
2103b6d90eb7SKip Macy 					printf("cxgb requires tx checksum offload"
2104b6d90eb7SKip Macy 					    " be enabled to use TSO\n");
2105b6d90eb7SKip Macy 				error = EINVAL;
2106b6d90eb7SKip Macy 			}
2107b6d90eb7SKip Macy 		}
2108e97121daSKip Macy #ifdef LRO_SUPPORTED
210925292debSKip Macy 		if (mask & IFCAP_LRO) {
211025292debSKip Macy 			ifp->if_capenable ^= IFCAP_LRO;
211125292debSKip Macy 
211225292debSKip Macy 			/* Safe to do this even if cxgb_up not called yet */
211325292debSKip Macy 			cxgb_set_lro(p, ifp->if_capenable & IFCAP_LRO);
211425292debSKip Macy 		}
2115e97121daSKip Macy #endif
21164af83c8cSKip Macy 		if (mask & IFCAP_VLAN_HWTAGGING) {
21174af83c8cSKip Macy 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
21184af83c8cSKip Macy 			reinit = ifp->if_drv_flags & IFF_DRV_RUNNING;
21194af83c8cSKip Macy 		}
21204af83c8cSKip Macy 		if (mask & IFCAP_VLAN_MTU) {
21214af83c8cSKip Macy 			ifp->if_capenable ^= IFCAP_VLAN_MTU;
21224af83c8cSKip Macy 			reinit = ifp->if_drv_flags & IFF_DRV_RUNNING;
21234af83c8cSKip Macy 		}
21244af83c8cSKip Macy 		if (mask & IFCAP_VLAN_HWCSUM) {
21254af83c8cSKip Macy 			ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
21264af83c8cSKip Macy 		}
21274af83c8cSKip Macy 		if (reinit) {
21284af83c8cSKip Macy 			cxgb_stop_locked(p);
21294af83c8cSKip Macy 			cxgb_init_locked(p);
21304af83c8cSKip Macy 		}
2131b6d90eb7SKip Macy 		PORT_UNLOCK(p);
21324af83c8cSKip Macy 
21334af83c8cSKip Macy #ifdef VLAN_CAPABILITIES
21344af83c8cSKip Macy 		VLAN_CAPABILITIES(ifp);
21354af83c8cSKip Macy #endif
2136b6d90eb7SKip Macy 		break;
2137b6d90eb7SKip Macy 	default:
2138b6d90eb7SKip Macy 		error = ether_ioctl(ifp, command, data);
2139b6d90eb7SKip Macy 		break;
2140b6d90eb7SKip Macy 	}
2141b6d90eb7SKip Macy 	return (error);
2142b6d90eb7SKip Macy }
2143b6d90eb7SKip Macy 
2144b6d90eb7SKip Macy static int
2145b6d90eb7SKip Macy cxgb_media_change(struct ifnet *ifp)
2146b6d90eb7SKip Macy {
2147b6d90eb7SKip Macy 	if_printf(ifp, "media change not supported\n");
2148b6d90eb7SKip Macy 	return (ENXIO);
2149b6d90eb7SKip Macy }
2150b6d90eb7SKip Macy 
2151837f41b0SGeorge V. Neville-Neil /*
2152837f41b0SGeorge V. Neville-Neil  * Translates from phy->modtype to IFM_TYPE.
2153837f41b0SGeorge V. Neville-Neil  */
2154837f41b0SGeorge V. Neville-Neil static int
2155837f41b0SGeorge V. Neville-Neil cxgb_ifm_type(int phymod)
2156837f41b0SGeorge V. Neville-Neil {
2157837f41b0SGeorge V. Neville-Neil 	int rc = IFM_ETHER | IFM_FDX;
2158837f41b0SGeorge V. Neville-Neil 
2159837f41b0SGeorge V. Neville-Neil 	switch (phymod) {
2160837f41b0SGeorge V. Neville-Neil 	case phy_modtype_sr:
2161837f41b0SGeorge V. Neville-Neil 		rc |= IFM_10G_SR;
2162837f41b0SGeorge V. Neville-Neil 		break;
2163837f41b0SGeorge V. Neville-Neil 	case phy_modtype_lr:
2164837f41b0SGeorge V. Neville-Neil 		rc |= IFM_10G_LR;
2165837f41b0SGeorge V. Neville-Neil 		break;
2166837f41b0SGeorge V. Neville-Neil 	case phy_modtype_lrm:
2167837f41b0SGeorge V. Neville-Neil #ifdef IFM_10G_LRM
2168837f41b0SGeorge V. Neville-Neil 		rc |= IFM_10G_LRM;
2169837f41b0SGeorge V. Neville-Neil #endif
2170837f41b0SGeorge V. Neville-Neil 		break;
2171837f41b0SGeorge V. Neville-Neil 	case phy_modtype_twinax:
2172837f41b0SGeorge V. Neville-Neil #ifdef IFM_10G_TWINAX
2173837f41b0SGeorge V. Neville-Neil 		rc |= IFM_10G_TWINAX;
2174837f41b0SGeorge V. Neville-Neil #endif
2175837f41b0SGeorge V. Neville-Neil 		break;
2176837f41b0SGeorge V. Neville-Neil 	case phy_modtype_twinax_long:
2177837f41b0SGeorge V. Neville-Neil #ifdef IFM_10G_TWINAX_LONG
2178837f41b0SGeorge V. Neville-Neil 		rc |= IFM_10G_TWINAX_LONG;
2179837f41b0SGeorge V. Neville-Neil #endif
2180837f41b0SGeorge V. Neville-Neil 		break;
2181837f41b0SGeorge V. Neville-Neil 	case phy_modtype_none:
2182837f41b0SGeorge V. Neville-Neil 		rc = IFM_ETHER | IFM_NONE;
2183837f41b0SGeorge V. Neville-Neil 		break;
2184837f41b0SGeorge V. Neville-Neil 	case phy_modtype_unknown:
2185837f41b0SGeorge V. Neville-Neil 		break;
2186837f41b0SGeorge V. Neville-Neil 	}
2187837f41b0SGeorge V. Neville-Neil 
2188837f41b0SGeorge V. Neville-Neil 	return (rc);
2189837f41b0SGeorge V. Neville-Neil }
2190837f41b0SGeorge V. Neville-Neil 
2191b6d90eb7SKip Macy static void
2192b6d90eb7SKip Macy cxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
2193b6d90eb7SKip Macy {
2194b6d90eb7SKip Macy 	struct port_info *p = ifp->if_softc;
2195837f41b0SGeorge V. Neville-Neil 	struct ifmedia_entry *cur = p->media.ifm_cur;
2196837f41b0SGeorge V. Neville-Neil 	int m;
2197837f41b0SGeorge V. Neville-Neil 
2198837f41b0SGeorge V. Neville-Neil 	if (cur->ifm_data != p->phy.modtype) {
2199837f41b0SGeorge V. Neville-Neil 		/* p->media about to be rebuilt, must hold lock */
2200837f41b0SGeorge V. Neville-Neil 		PORT_LOCK_ASSERT_OWNED(p);
2201837f41b0SGeorge V. Neville-Neil 
2202837f41b0SGeorge V. Neville-Neil 		m = cxgb_ifm_type(p->phy.modtype);
2203837f41b0SGeorge V. Neville-Neil 		ifmedia_removeall(&p->media);
2204837f41b0SGeorge V. Neville-Neil 		ifmedia_add(&p->media, m, p->phy.modtype, NULL);
2205837f41b0SGeorge V. Neville-Neil 		ifmedia_set(&p->media, m);
2206837f41b0SGeorge V. Neville-Neil 		cur = p->media.ifm_cur; /* ifmedia_set modified ifm_cur */
2207837f41b0SGeorge V. Neville-Neil 		ifmr->ifm_current = m;
2208837f41b0SGeorge V. Neville-Neil 	}
2209b6d90eb7SKip Macy 
2210b6d90eb7SKip Macy 	ifmr->ifm_status = IFM_AVALID;
2211b6d90eb7SKip Macy 	ifmr->ifm_active = IFM_ETHER;
2212b6d90eb7SKip Macy 
2213b6d90eb7SKip Macy 	if (!p->link_config.link_ok)
2214b6d90eb7SKip Macy 		return;
2215b6d90eb7SKip Macy 
2216b6d90eb7SKip Macy 	ifmr->ifm_status |= IFM_ACTIVE;
2217b6d90eb7SKip Macy 
2218ef72318fSKip Macy 	switch (p->link_config.speed) {
2219ef72318fSKip Macy 	case 10:
2220ef72318fSKip Macy 		ifmr->ifm_active |= IFM_10_T;
2221ef72318fSKip Macy 		break;
2222ef72318fSKip Macy 	case 100:
2223ef72318fSKip Macy 		ifmr->ifm_active |= IFM_100_TX;
2224ef72318fSKip Macy 			break;
2225ef72318fSKip Macy 	case 1000:
2226ef72318fSKip Macy 		ifmr->ifm_active |= IFM_1000_T;
2227ef72318fSKip Macy 		break;
2228837f41b0SGeorge V. Neville-Neil 	case 10000:
2229837f41b0SGeorge V. Neville-Neil 		ifmr->ifm_active |= IFM_SUBTYPE(cur->ifm_media);
2230837f41b0SGeorge V. Neville-Neil 		break;
2231ef72318fSKip Macy 	}
2232ef72318fSKip Macy 
2233b6d90eb7SKip Macy 	if (p->link_config.duplex)
2234b6d90eb7SKip Macy 		ifmr->ifm_active |= IFM_FDX;
2235b6d90eb7SKip Macy 	else
2236b6d90eb7SKip Macy 		ifmr->ifm_active |= IFM_HDX;
2237b6d90eb7SKip Macy }
2238b6d90eb7SKip Macy 
2239b6d90eb7SKip Macy static void
2240b6d90eb7SKip Macy cxgb_async_intr(void *data)
2241b6d90eb7SKip Macy {
2242693d746cSKip Macy 	adapter_t *sc = data;
2243693d746cSKip Macy 
2244b6d90eb7SKip Macy 	if (cxgb_debug)
2245693d746cSKip Macy 		device_printf(sc->dev, "cxgb_async_intr\n");
2246bb38cd2fSKip Macy 	/*
2247bb38cd2fSKip Macy 	 * May need to sleep - defer to taskqueue
2248bb38cd2fSKip Macy 	 */
2249bb38cd2fSKip Macy 	taskqueue_enqueue(sc->tq, &sc->slow_intr_task);
2250b6d90eb7SKip Macy }
2251b6d90eb7SKip Macy 
2252b6d90eb7SKip Macy static void
2253b6d90eb7SKip Macy cxgb_ext_intr_handler(void *arg, int count)
2254b6d90eb7SKip Macy {
2255b6d90eb7SKip Macy 	adapter_t *sc = (adapter_t *)arg;
2256b6d90eb7SKip Macy 
2257b6d90eb7SKip Macy 	if (cxgb_debug)
2258b6d90eb7SKip Macy 		printf("cxgb_ext_intr_handler\n");
2259b6d90eb7SKip Macy 
2260b6d90eb7SKip Macy 	t3_phy_intr_handler(sc);
2261b6d90eb7SKip Macy 
2262b6d90eb7SKip Macy 	/* Now reenable external interrupts */
2263d722cab4SKip Macy 	ADAPTER_LOCK(sc);
2264b6d90eb7SKip Macy 	if (sc->slow_intr_mask) {
2265b6d90eb7SKip Macy 		sc->slow_intr_mask |= F_T3DBG;
2266b6d90eb7SKip Macy 		t3_write_reg(sc, A_PL_INT_CAUSE0, F_T3DBG);
2267b6d90eb7SKip Macy 		t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
2268b6d90eb7SKip Macy 	}
2269d722cab4SKip Macy 	ADAPTER_UNLOCK(sc);
2270b6d90eb7SKip Macy }
2271b6d90eb7SKip Macy 
2272b6d90eb7SKip Macy static void
2273b6d90eb7SKip Macy check_link_status(adapter_t *sc)
2274b6d90eb7SKip Macy {
2275b6d90eb7SKip Macy 	int i;
2276b6d90eb7SKip Macy 
2277b6d90eb7SKip Macy 	for (i = 0; i < (sc)->params.nports; ++i) {
2278b6d90eb7SKip Macy 		struct port_info *p = &sc->port[i];
2279b6d90eb7SKip Macy 
22808e10660fSKip Macy 		if (!(p->phy.caps & SUPPORTED_IRQ))
2281b6d90eb7SKip Macy 			t3_link_changed(sc, i);
2282837f41b0SGeorge V. Neville-Neil 		p->ifp->if_baudrate = IF_Mbps(p->link_config.speed);
2283b6d90eb7SKip Macy 	}
2284b6d90eb7SKip Macy }
2285b6d90eb7SKip Macy 
2286577e9bbeSKip Macy static void
2287577e9bbeSKip Macy check_t3b2_mac(struct adapter *adapter)
2288577e9bbeSKip Macy {
2289577e9bbeSKip Macy 	int i;
2290577e9bbeSKip Macy 
22918e10660fSKip Macy 	if(adapter->flags & CXGB_SHUTDOWN)
22928e10660fSKip Macy 		return;
22938e10660fSKip Macy 
2294577e9bbeSKip Macy 	for_each_port(adapter, i) {
2295577e9bbeSKip Macy 		struct port_info *p = &adapter->port[i];
2296577e9bbeSKip Macy 		struct ifnet *ifp = p->ifp;
2297577e9bbeSKip Macy 		int status;
2298577e9bbeSKip Macy 
22998e10660fSKip Macy 		if(adapter->flags & CXGB_SHUTDOWN)
23008e10660fSKip Macy 			return;
23018e10660fSKip Macy 
2302577e9bbeSKip Macy 		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
2303577e9bbeSKip Macy 			continue;
2304577e9bbeSKip Macy 
2305577e9bbeSKip Macy 		status = 0;
2306577e9bbeSKip Macy 		PORT_LOCK(p);
2307577e9bbeSKip Macy 		if ((ifp->if_drv_flags & IFF_DRV_RUNNING))
2308577e9bbeSKip Macy 			status = t3b2_mac_watchdog_task(&p->mac);
2309577e9bbeSKip Macy 		if (status == 1)
2310577e9bbeSKip Macy 			p->mac.stats.num_toggled++;
2311577e9bbeSKip Macy 		else if (status == 2) {
2312577e9bbeSKip Macy 			struct cmac *mac = &p->mac;
23134af83c8cSKip Macy 			int mtu = ifp->if_mtu;
2314577e9bbeSKip Macy 
23154af83c8cSKip Macy 			if (ifp->if_capenable & IFCAP_VLAN_MTU)
23164af83c8cSKip Macy 				mtu += ETHER_VLAN_ENCAP_LEN;
23174af83c8cSKip Macy 			t3_mac_set_mtu(mac, mtu);
2318577e9bbeSKip Macy 			t3_mac_set_address(mac, 0, p->hw_addr);
2319577e9bbeSKip Macy 			cxgb_set_rxmode(p);
2320577e9bbeSKip Macy 			t3_link_start(&p->phy, mac, &p->link_config);
2321577e9bbeSKip Macy 			t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
23226b68e276SKip Macy 			t3_port_intr_enable(adapter, p->port_id);
2323577e9bbeSKip Macy 			p->mac.stats.num_resets++;
2324577e9bbeSKip Macy 		}
2325577e9bbeSKip Macy 		PORT_UNLOCK(p);
2326577e9bbeSKip Macy 	}
2327577e9bbeSKip Macy }
2328577e9bbeSKip Macy 
2329577e9bbeSKip Macy static void
2330577e9bbeSKip Macy cxgb_tick(void *arg)
2331577e9bbeSKip Macy {
2332577e9bbeSKip Macy 	adapter_t *sc = (adapter_t *)arg;
23338090c9f5SKip Macy 
23348e10660fSKip Macy 	if(sc->flags & CXGB_SHUTDOWN)
23358090c9f5SKip Macy 		return;
2336577e9bbeSKip Macy 
2337bb38cd2fSKip Macy 	taskqueue_enqueue(sc->tq, &sc->tick_task);
2338706cb31fSKip Macy 	callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc);
2339bb38cd2fSKip Macy }
2340bb38cd2fSKip Macy 
2341bb38cd2fSKip Macy static void
2342bb38cd2fSKip Macy cxgb_tick_handler(void *arg, int count)
2343bb38cd2fSKip Macy {
2344bb38cd2fSKip Macy 	adapter_t *sc = (adapter_t *)arg;
2345bb38cd2fSKip Macy 	const struct adapter_params *p = &sc->params;
2346706cb31fSKip Macy 	int i;
2347f2d8ff04SGeorge V. Neville-Neil 	uint32_t cause, reset;
2348bb38cd2fSKip Macy 
23498e10660fSKip Macy 	if(sc->flags & CXGB_SHUTDOWN)
23508e10660fSKip Macy 		return;
23518e10660fSKip Macy 
2352bb38cd2fSKip Macy 	ADAPTER_LOCK(sc);
2353bb38cd2fSKip Macy 	if (p->linkpoll_period)
2354bb38cd2fSKip Macy 		check_link_status(sc);
2355577e9bbeSKip Macy 
2356f35c2d65SKip Macy 	sc->check_task_cnt++;
2357f35c2d65SKip Macy 
2358f35c2d65SKip Macy 	/*
2359f35c2d65SKip Macy 	 * adapter lock can currently only be acquired after the
2360f35c2d65SKip Macy 	 * port lock
2361f35c2d65SKip Macy 	 */
2362f35c2d65SKip Macy 	ADAPTER_UNLOCK(sc);
2363f35c2d65SKip Macy 
2364f35c2d65SKip Macy 	if (p->rev == T3_REV_B2 && p->nports < 4 && sc->open_device_map)
2365f35c2d65SKip Macy 		check_t3b2_mac(sc);
2366f35c2d65SKip Macy 
2367f2d8ff04SGeorge V. Neville-Neil 	cause = t3_read_reg(sc, A_SG_INT_CAUSE);
2368f2d8ff04SGeorge V. Neville-Neil 	reset = 0;
2369f2d8ff04SGeorge V. Neville-Neil 	if (cause & F_FLEMPTY) {
2370f2d8ff04SGeorge V. Neville-Neil 		struct sge_qset *qs = &sc->sge.qs[0];
2371f2d8ff04SGeorge V. Neville-Neil 
2372f2d8ff04SGeorge V. Neville-Neil 		i = 0;
2373f2d8ff04SGeorge V. Neville-Neil 		reset |= F_FLEMPTY;
2374f2d8ff04SGeorge V. Neville-Neil 
2375f2d8ff04SGeorge V. Neville-Neil 		cause = (t3_read_reg(sc, A_SG_RSPQ_FL_STATUS) >>
2376f2d8ff04SGeorge V. Neville-Neil 			 S_FL0EMPTY) & 0xffff;
2377f2d8ff04SGeorge V. Neville-Neil 		while (cause) {
2378f2d8ff04SGeorge V. Neville-Neil 			qs->fl[i].empty += (cause & 1);
2379f2d8ff04SGeorge V. Neville-Neil 			if (i)
2380f2d8ff04SGeorge V. Neville-Neil 				qs++;
2381f2d8ff04SGeorge V. Neville-Neil 			i ^= 1;
2382f2d8ff04SGeorge V. Neville-Neil 			cause >>= 1;
2383f2d8ff04SGeorge V. Neville-Neil 		}
2384f2d8ff04SGeorge V. Neville-Neil 	}
2385f2d8ff04SGeorge V. Neville-Neil 	t3_write_reg(sc, A_SG_INT_CAUSE, reset);
2386f2d8ff04SGeorge V. Neville-Neil 
2387ceac50ebSKip Macy 	for (i = 0; i < sc->params.nports; i++) {
2388ceac50ebSKip Macy 		struct port_info *pi = &sc->port[i];
2389ceac50ebSKip Macy 		struct ifnet *ifp = pi->ifp;
2390f2d8ff04SGeorge V. Neville-Neil 		struct cmac *mac = &pi->mac;
2391f2d8ff04SGeorge V. Neville-Neil 		struct mac_stats *mstats = &mac->stats;
2392f35c2d65SKip Macy 		PORT_LOCK(pi);
2393f2d8ff04SGeorge V. Neville-Neil 		t3_mac_update_stats(mac);
2394f35c2d65SKip Macy 		PORT_UNLOCK(pi);
2395f35c2d65SKip Macy 
2396f2d8ff04SGeorge V. Neville-Neil 		if (pi->link_fault)
2397f2d8ff04SGeorge V. Neville-Neil 			taskqueue_enqueue(sc->tq, &pi->link_fault_task);
2398ceac50ebSKip Macy 
2399ceac50ebSKip Macy 		ifp->if_opackets =
2400ceac50ebSKip Macy 		    mstats->tx_frames_64 +
2401ceac50ebSKip Macy 		    mstats->tx_frames_65_127 +
2402ceac50ebSKip Macy 		    mstats->tx_frames_128_255 +
2403ceac50ebSKip Macy 		    mstats->tx_frames_256_511 +
2404ceac50ebSKip Macy 		    mstats->tx_frames_512_1023 +
2405ceac50ebSKip Macy 		    mstats->tx_frames_1024_1518 +
2406ceac50ebSKip Macy 		    mstats->tx_frames_1519_max;
2407ceac50ebSKip Macy 
2408ceac50ebSKip Macy 		ifp->if_ipackets =
2409ceac50ebSKip Macy 		    mstats->rx_frames_64 +
2410ceac50ebSKip Macy 		    mstats->rx_frames_65_127 +
2411ceac50ebSKip Macy 		    mstats->rx_frames_128_255 +
2412ceac50ebSKip Macy 		    mstats->rx_frames_256_511 +
2413ceac50ebSKip Macy 		    mstats->rx_frames_512_1023 +
2414ceac50ebSKip Macy 		    mstats->rx_frames_1024_1518 +
2415ceac50ebSKip Macy 		    mstats->rx_frames_1519_max;
2416ceac50ebSKip Macy 
2417ceac50ebSKip Macy 		ifp->if_obytes = mstats->tx_octets;
2418ceac50ebSKip Macy 		ifp->if_ibytes = mstats->rx_octets;
2419ceac50ebSKip Macy 		ifp->if_omcasts = mstats->tx_mcast_frames;
2420ceac50ebSKip Macy 		ifp->if_imcasts = mstats->rx_mcast_frames;
2421ceac50ebSKip Macy 
2422ceac50ebSKip Macy 		ifp->if_collisions =
2423ceac50ebSKip Macy 		    mstats->tx_total_collisions;
2424ceac50ebSKip Macy 
2425ceac50ebSKip Macy 		ifp->if_iqdrops = mstats->rx_cong_drops;
2426ceac50ebSKip Macy 
2427ceac50ebSKip Macy 		ifp->if_oerrors =
2428ceac50ebSKip Macy 		    mstats->tx_excess_collisions +
2429ceac50ebSKip Macy 		    mstats->tx_underrun +
2430ceac50ebSKip Macy 		    mstats->tx_len_errs +
2431ceac50ebSKip Macy 		    mstats->tx_mac_internal_errs +
2432ceac50ebSKip Macy 		    mstats->tx_excess_deferral +
2433ceac50ebSKip Macy 		    mstats->tx_fcs_errs;
2434ceac50ebSKip Macy 		ifp->if_ierrors =
2435ceac50ebSKip Macy 		    mstats->rx_jabber +
2436ceac50ebSKip Macy 		    mstats->rx_data_errs +
2437ceac50ebSKip Macy 		    mstats->rx_sequence_errs +
2438ceac50ebSKip Macy 		    mstats->rx_runt +
2439ceac50ebSKip Macy 		    mstats->rx_too_long +
2440ceac50ebSKip Macy 		    mstats->rx_mac_internal_errs +
2441ceac50ebSKip Macy 		    mstats->rx_short +
2442ceac50ebSKip Macy 		    mstats->rx_fcs_errs;
2443f2d8ff04SGeorge V. Neville-Neil 
2444f2d8ff04SGeorge V. Neville-Neil 		if (mac->multiport)
2445f2d8ff04SGeorge V. Neville-Neil 			continue;
2446f2d8ff04SGeorge V. Neville-Neil 
2447f2d8ff04SGeorge V. Neville-Neil 		/* Count rx fifo overflows, once per second */
2448f2d8ff04SGeorge V. Neville-Neil 		cause = t3_read_reg(sc, A_XGM_INT_CAUSE + mac->offset);
2449f2d8ff04SGeorge V. Neville-Neil 		reset = 0;
2450f2d8ff04SGeorge V. Neville-Neil 		if (cause & F_RXFIFO_OVERFLOW) {
2451f2d8ff04SGeorge V. Neville-Neil 			mac->stats.rx_fifo_ovfl++;
2452f2d8ff04SGeorge V. Neville-Neil 			reset |= F_RXFIFO_OVERFLOW;
2453f2d8ff04SGeorge V. Neville-Neil 		}
2454f2d8ff04SGeorge V. Neville-Neil 		t3_write_reg(sc, A_XGM_INT_CAUSE + mac->offset, reset);
2455ceac50ebSKip Macy 	}
2456577e9bbeSKip Macy }
2457577e9bbeSKip Macy 
24587ac2e6c3SKip Macy static void
24597ac2e6c3SKip Macy touch_bars(device_t dev)
24607ac2e6c3SKip Macy {
24617ac2e6c3SKip Macy 	/*
24627ac2e6c3SKip Macy 	 * Don't enable yet
24637ac2e6c3SKip Macy 	 */
24647ac2e6c3SKip Macy #if !defined(__LP64__) && 0
24657ac2e6c3SKip Macy 	u32 v;
24667ac2e6c3SKip Macy 
24677ac2e6c3SKip Macy 	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &v);
24687ac2e6c3SKip Macy 	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, v);
24697ac2e6c3SKip Macy 	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3, &v);
24707ac2e6c3SKip Macy 	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_3, v);
24717ac2e6c3SKip Macy 	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &v);
24727ac2e6c3SKip Macy 	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_5, v);
24737ac2e6c3SKip Macy #endif
24747ac2e6c3SKip Macy }
24757ac2e6c3SKip Macy 
2476ac3a6d9cSKip Macy static int
2477ac3a6d9cSKip Macy set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset)
2478ac3a6d9cSKip Macy {
2479ac3a6d9cSKip Macy 	uint8_t *buf;
2480ac3a6d9cSKip Macy 	int err = 0;
2481ac3a6d9cSKip Macy 	u32 aligned_offset, aligned_len, *p;
2482ac3a6d9cSKip Macy 	struct adapter *adapter = pi->adapter;
2483ac3a6d9cSKip Macy 
2484ac3a6d9cSKip Macy 
2485ac3a6d9cSKip Macy 	aligned_offset = offset & ~3;
2486ac3a6d9cSKip Macy 	aligned_len = (len + (offset & 3) + 3) & ~3;
2487ac3a6d9cSKip Macy 
2488ac3a6d9cSKip Macy 	if (aligned_offset != offset || aligned_len != len) {
2489ac3a6d9cSKip Macy 		buf = malloc(aligned_len, M_DEVBUF, M_WAITOK|M_ZERO);
2490ac3a6d9cSKip Macy 		if (!buf)
2491ac3a6d9cSKip Macy 			return (ENOMEM);
2492ac3a6d9cSKip Macy 		err = t3_seeprom_read(adapter, aligned_offset, (u32 *)buf);
2493ac3a6d9cSKip Macy 		if (!err && aligned_len > 4)
2494ac3a6d9cSKip Macy 			err = t3_seeprom_read(adapter,
2495ac3a6d9cSKip Macy 					      aligned_offset + aligned_len - 4,
2496ac3a6d9cSKip Macy 					      (u32 *)&buf[aligned_len - 4]);
2497ac3a6d9cSKip Macy 		if (err)
2498ac3a6d9cSKip Macy 			goto out;
2499ac3a6d9cSKip Macy 		memcpy(buf + (offset & 3), data, len);
2500ac3a6d9cSKip Macy 	} else
2501ac3a6d9cSKip Macy 		buf = (uint8_t *)(uintptr_t)data;
2502ac3a6d9cSKip Macy 
2503ac3a6d9cSKip Macy 	err = t3_seeprom_wp(adapter, 0);
2504ac3a6d9cSKip Macy 	if (err)
2505ac3a6d9cSKip Macy 		goto out;
2506ac3a6d9cSKip Macy 
2507ac3a6d9cSKip Macy 	for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) {
2508ac3a6d9cSKip Macy 		err = t3_seeprom_write(adapter, aligned_offset, *p);
2509ac3a6d9cSKip Macy 		aligned_offset += 4;
2510ac3a6d9cSKip Macy 	}
2511ac3a6d9cSKip Macy 
2512ac3a6d9cSKip Macy 	if (!err)
2513ac3a6d9cSKip Macy 		err = t3_seeprom_wp(adapter, 1);
2514ac3a6d9cSKip Macy out:
2515ac3a6d9cSKip Macy 	if (buf != data)
2516ac3a6d9cSKip Macy 		free(buf, M_DEVBUF);
2517ac3a6d9cSKip Macy 	return err;
2518ac3a6d9cSKip Macy }
2519ac3a6d9cSKip Macy 
2520ac3a6d9cSKip Macy 
2521b6d90eb7SKip Macy static int
2522b6d90eb7SKip Macy in_range(int val, int lo, int hi)
2523b6d90eb7SKip Macy {
2524b6d90eb7SKip Macy 	return val < 0 || (val <= hi && val >= lo);
2525b6d90eb7SKip Macy }
2526b6d90eb7SKip Macy 
2527b6d90eb7SKip Macy static int
2528ef72318fSKip Macy cxgb_extension_open(struct cdev *dev, int flags, int fmp, d_thread_t *td)
2529ef72318fSKip Macy {
2530ef72318fSKip Macy        return (0);
2531ef72318fSKip Macy }
2532ef72318fSKip Macy 
2533ef72318fSKip Macy static int
2534ef72318fSKip Macy cxgb_extension_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
2535ef72318fSKip Macy {
2536ef72318fSKip Macy        return (0);
2537ef72318fSKip Macy }
2538ef72318fSKip Macy 
2539ef72318fSKip Macy static int
2540b6d90eb7SKip Macy cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
2541b6d90eb7SKip Macy     int fflag, struct thread *td)
2542b6d90eb7SKip Macy {
2543b6d90eb7SKip Macy 	int mmd, error = 0;
2544b6d90eb7SKip Macy 	struct port_info *pi = dev->si_drv1;
2545b6d90eb7SKip Macy 	adapter_t *sc = pi->adapter;
2546b6d90eb7SKip Macy 
2547b6d90eb7SKip Macy #ifdef PRIV_SUPPORTED
2548b6d90eb7SKip Macy 	if (priv_check(td, PRIV_DRIVER)) {
2549b6d90eb7SKip Macy 		if (cxgb_debug)
2550b6d90eb7SKip Macy 			printf("user does not have access to privileged ioctls\n");
2551b6d90eb7SKip Macy 		return (EPERM);
2552b6d90eb7SKip Macy 	}
2553b6d90eb7SKip Macy #else
2554b6d90eb7SKip Macy 	if (suser(td)) {
2555b6d90eb7SKip Macy 		if (cxgb_debug)
2556b6d90eb7SKip Macy 			printf("user does not have access to privileged ioctls\n");
2557b6d90eb7SKip Macy 		return (EPERM);
2558b6d90eb7SKip Macy 	}
2559b6d90eb7SKip Macy #endif
2560b6d90eb7SKip Macy 
2561b6d90eb7SKip Macy 	switch (cmd) {
25621ffd6e58SKip Macy 	case CHELSIO_GET_MIIREG: {
2563b6d90eb7SKip Macy 		uint32_t val;
2564b6d90eb7SKip Macy 		struct cphy *phy = &pi->phy;
25651ffd6e58SKip Macy 		struct ch_mii_data *mid = (struct ch_mii_data *)data;
2566b6d90eb7SKip Macy 
2567b6d90eb7SKip Macy 		if (!phy->mdio_read)
2568b6d90eb7SKip Macy 			return (EOPNOTSUPP);
2569b6d90eb7SKip Macy 		if (is_10G(sc)) {
2570b6d90eb7SKip Macy 			mmd = mid->phy_id >> 8;
2571b6d90eb7SKip Macy 			if (!mmd)
2572b6d90eb7SKip Macy 				mmd = MDIO_DEV_PCS;
2573b6d90eb7SKip Macy 			else if (mmd > MDIO_DEV_XGXS)
2574ac3a6d9cSKip Macy 				return (EINVAL);
2575b6d90eb7SKip Macy 
2576b6d90eb7SKip Macy 			error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd,
2577b6d90eb7SKip Macy 					     mid->reg_num, &val);
2578b6d90eb7SKip Macy 		} else
2579b6d90eb7SKip Macy 		        error = phy->mdio_read(sc, mid->phy_id & 0x1f, 0,
2580b6d90eb7SKip Macy 					     mid->reg_num & 0x1f, &val);
2581b6d90eb7SKip Macy 		if (error == 0)
2582b6d90eb7SKip Macy 			mid->val_out = val;
2583b6d90eb7SKip Macy 		break;
2584b6d90eb7SKip Macy 	}
25851ffd6e58SKip Macy 	case CHELSIO_SET_MIIREG: {
2586b6d90eb7SKip Macy 		struct cphy *phy = &pi->phy;
25871ffd6e58SKip Macy 		struct ch_mii_data *mid = (struct ch_mii_data *)data;
2588b6d90eb7SKip Macy 
2589b6d90eb7SKip Macy 		if (!phy->mdio_write)
2590b6d90eb7SKip Macy 			return (EOPNOTSUPP);
2591b6d90eb7SKip Macy 		if (is_10G(sc)) {
2592b6d90eb7SKip Macy 			mmd = mid->phy_id >> 8;
2593b6d90eb7SKip Macy 			if (!mmd)
2594b6d90eb7SKip Macy 				mmd = MDIO_DEV_PCS;
2595b6d90eb7SKip Macy 			else if (mmd > MDIO_DEV_XGXS)
2596b6d90eb7SKip Macy 				return (EINVAL);
2597b6d90eb7SKip Macy 
2598b6d90eb7SKip Macy 			error = phy->mdio_write(sc, mid->phy_id & 0x1f,
2599b6d90eb7SKip Macy 					      mmd, mid->reg_num, mid->val_in);
2600b6d90eb7SKip Macy 		} else
2601b6d90eb7SKip Macy 			error = phy->mdio_write(sc, mid->phy_id & 0x1f, 0,
2602b6d90eb7SKip Macy 					      mid->reg_num & 0x1f,
2603b6d90eb7SKip Macy 					      mid->val_in);
2604b6d90eb7SKip Macy 		break;
2605b6d90eb7SKip Macy 	}
2606b6d90eb7SKip Macy 	case CHELSIO_SETREG: {
2607b6d90eb7SKip Macy 		struct ch_reg *edata = (struct ch_reg *)data;
2608b6d90eb7SKip Macy 		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2609b6d90eb7SKip Macy 			return (EFAULT);
2610b6d90eb7SKip Macy 		t3_write_reg(sc, edata->addr, edata->val);
2611b6d90eb7SKip Macy 		break;
2612b6d90eb7SKip Macy 	}
2613b6d90eb7SKip Macy 	case CHELSIO_GETREG: {
2614b6d90eb7SKip Macy 		struct ch_reg *edata = (struct ch_reg *)data;
2615b6d90eb7SKip Macy 		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2616b6d90eb7SKip Macy 			return (EFAULT);
2617b6d90eb7SKip Macy 		edata->val = t3_read_reg(sc, edata->addr);
2618b6d90eb7SKip Macy 		break;
2619b6d90eb7SKip Macy 	}
2620b6d90eb7SKip Macy 	case CHELSIO_GET_SGE_CONTEXT: {
2621b6d90eb7SKip Macy 		struct ch_cntxt *ecntxt = (struct ch_cntxt *)data;
26228e10660fSKip Macy 		mtx_lock_spin(&sc->sge.reg_lock);
2623b6d90eb7SKip Macy 		switch (ecntxt->cntxt_type) {
2624b6d90eb7SKip Macy 		case CNTXT_TYPE_EGRESS:
26251ffd6e58SKip Macy 			error = -t3_sge_read_ecntxt(sc, ecntxt->cntxt_id,
2626b6d90eb7SKip Macy 			    ecntxt->data);
2627b6d90eb7SKip Macy 			break;
2628b6d90eb7SKip Macy 		case CNTXT_TYPE_FL:
26291ffd6e58SKip Macy 			error = -t3_sge_read_fl(sc, ecntxt->cntxt_id,
2630b6d90eb7SKip Macy 			    ecntxt->data);
2631b6d90eb7SKip Macy 			break;
2632b6d90eb7SKip Macy 		case CNTXT_TYPE_RSP:
26331ffd6e58SKip Macy 			error = -t3_sge_read_rspq(sc, ecntxt->cntxt_id,
2634b6d90eb7SKip Macy 			    ecntxt->data);
2635b6d90eb7SKip Macy 			break;
2636b6d90eb7SKip Macy 		case CNTXT_TYPE_CQ:
26371ffd6e58SKip Macy 			error = -t3_sge_read_cq(sc, ecntxt->cntxt_id,
2638b6d90eb7SKip Macy 			    ecntxt->data);
2639b6d90eb7SKip Macy 			break;
2640b6d90eb7SKip Macy 		default:
2641b6d90eb7SKip Macy 			error = EINVAL;
2642b6d90eb7SKip Macy 			break;
2643b6d90eb7SKip Macy 		}
26448e10660fSKip Macy 		mtx_unlock_spin(&sc->sge.reg_lock);
2645b6d90eb7SKip Macy 		break;
2646b6d90eb7SKip Macy 	}
2647b6d90eb7SKip Macy 	case CHELSIO_GET_SGE_DESC: {
2648b6d90eb7SKip Macy 		struct ch_desc *edesc = (struct ch_desc *)data;
2649b6d90eb7SKip Macy 		int ret;
2650b6d90eb7SKip Macy 		if (edesc->queue_num >= SGE_QSETS * 6)
2651b6d90eb7SKip Macy 			return (EINVAL);
2652b6d90eb7SKip Macy 		ret = t3_get_desc(&sc->sge.qs[edesc->queue_num / 6],
2653b6d90eb7SKip Macy 		    edesc->queue_num % 6, edesc->idx, edesc->data);
2654b6d90eb7SKip Macy 		if (ret < 0)
2655b6d90eb7SKip Macy 			return (EINVAL);
2656b6d90eb7SKip Macy 		edesc->size = ret;
2657b6d90eb7SKip Macy 		break;
2658b6d90eb7SKip Macy 	}
2659b6d90eb7SKip Macy 	case CHELSIO_GET_QSET_PARAMS: {
2660b6d90eb7SKip Macy 		struct qset_params *q;
2661b6d90eb7SKip Macy 		struct ch_qset_params *t = (struct ch_qset_params *)data;
26621ffd6e58SKip Macy 		int q1 = pi->first_qset;
26631ffd6e58SKip Macy 		int nqsets = pi->nqsets;
26641ffd6e58SKip Macy 		int i;
2665b6d90eb7SKip Macy 
26661ffd6e58SKip Macy 		if (t->qset_idx >= nqsets)
26671ffd6e58SKip Macy 			return EINVAL;
2668b6d90eb7SKip Macy 
26691ffd6e58SKip Macy 		i = q1 + t->qset_idx;
26701ffd6e58SKip Macy 		q = &sc->params.sge.qset[i];
2671b6d90eb7SKip Macy 		t->rspq_size   = q->rspq_size;
2672b6d90eb7SKip Macy 		t->txq_size[0] = q->txq_size[0];
2673b6d90eb7SKip Macy 		t->txq_size[1] = q->txq_size[1];
2674b6d90eb7SKip Macy 		t->txq_size[2] = q->txq_size[2];
2675b6d90eb7SKip Macy 		t->fl_size[0]  = q->fl_size;
2676b6d90eb7SKip Macy 		t->fl_size[1]  = q->jumbo_size;
2677b6d90eb7SKip Macy 		t->polling     = q->polling;
26781ffd6e58SKip Macy 		t->lro         = q->lro;
26794af83c8cSKip Macy 		t->intr_lat    = q->coalesce_usecs;
2680b6d90eb7SKip Macy 		t->cong_thres  = q->cong_thres;
26811ffd6e58SKip Macy 		t->qnum        = i;
2682b6d90eb7SKip Macy 
26831ffd6e58SKip Macy 		if (sc->flags & USING_MSIX)
26841ffd6e58SKip Macy 			t->vector = rman_get_start(sc->msix_irq_res[i]);
26851ffd6e58SKip Macy 		else
26861ffd6e58SKip Macy 			t->vector = rman_get_start(sc->irq_res);
26871ffd6e58SKip Macy 
2688b6d90eb7SKip Macy 		break;
2689b6d90eb7SKip Macy 	}
2690b6d90eb7SKip Macy 	case CHELSIO_GET_QSET_NUM: {
2691b6d90eb7SKip Macy 		struct ch_reg *edata = (struct ch_reg *)data;
2692b6d90eb7SKip Macy 		edata->val = pi->nqsets;
2693b6d90eb7SKip Macy 		break;
2694b6d90eb7SKip Macy 	}
26951ffd6e58SKip Macy 	case CHELSIO_LOAD_FW: {
26961ffd6e58SKip Macy 		uint8_t *fw_data;
26971ffd6e58SKip Macy 		uint32_t vers;
26981ffd6e58SKip Macy 		struct ch_mem_range *t = (struct ch_mem_range *)data;
26991ffd6e58SKip Macy 
27001ffd6e58SKip Macy 		/*
27011ffd6e58SKip Macy 		 * You're allowed to load a firmware only before FULL_INIT_DONE
27021ffd6e58SKip Macy 		 *
27031ffd6e58SKip Macy 		 * FW_UPTODATE is also set so the rest of the initialization
27041ffd6e58SKip Macy 		 * will not overwrite what was loaded here.  This gives you the
27051ffd6e58SKip Macy 		 * flexibility to load any firmware (and maybe shoot yourself in
27061ffd6e58SKip Macy 		 * the foot).
27071ffd6e58SKip Macy 		 */
27081ffd6e58SKip Macy 
27091ffd6e58SKip Macy 		ADAPTER_LOCK(sc);
27101ffd6e58SKip Macy 		if (sc->open_device_map || sc->flags & FULL_INIT_DONE) {
27111ffd6e58SKip Macy 			ADAPTER_UNLOCK(sc);
27121ffd6e58SKip Macy 			return (EBUSY);
27131ffd6e58SKip Macy 		}
27141ffd6e58SKip Macy 
27151ffd6e58SKip Macy 		fw_data = malloc(t->len, M_DEVBUF, M_NOWAIT);
27161ffd6e58SKip Macy 		if (!fw_data)
27171ffd6e58SKip Macy 			error = ENOMEM;
27181ffd6e58SKip Macy 		else
27191ffd6e58SKip Macy 			error = copyin(t->buf, fw_data, t->len);
27201ffd6e58SKip Macy 
27211ffd6e58SKip Macy 		if (!error)
27221ffd6e58SKip Macy 			error = -t3_load_fw(sc, fw_data, t->len);
27231ffd6e58SKip Macy 
27241ffd6e58SKip Macy 		if (t3_get_fw_version(sc, &vers) == 0) {
27251ffd6e58SKip Macy 			snprintf(&sc->fw_version[0], sizeof(sc->fw_version),
27261ffd6e58SKip Macy 			    "%d.%d.%d", G_FW_VERSION_MAJOR(vers),
27271ffd6e58SKip Macy 			    G_FW_VERSION_MINOR(vers), G_FW_VERSION_MICRO(vers));
27281ffd6e58SKip Macy 		}
27291ffd6e58SKip Macy 
27301ffd6e58SKip Macy 		if (!error)
27311ffd6e58SKip Macy 			sc->flags |= FW_UPTODATE;
27321ffd6e58SKip Macy 
27331ffd6e58SKip Macy 		free(fw_data, M_DEVBUF);
27341ffd6e58SKip Macy 		ADAPTER_UNLOCK(sc);
2735b6d90eb7SKip Macy 		break;
27361ffd6e58SKip Macy 	}
27371ffd6e58SKip Macy 	case CHELSIO_LOAD_BOOT: {
27381ffd6e58SKip Macy 		uint8_t *boot_data;
27391ffd6e58SKip Macy 		struct ch_mem_range *t = (struct ch_mem_range *)data;
27401ffd6e58SKip Macy 
27411ffd6e58SKip Macy 		boot_data = malloc(t->len, M_DEVBUF, M_NOWAIT);
27421ffd6e58SKip Macy 		if (!boot_data)
27431ffd6e58SKip Macy 			return ENOMEM;
27441ffd6e58SKip Macy 
27451ffd6e58SKip Macy 		error = copyin(t->buf, boot_data, t->len);
27461ffd6e58SKip Macy 		if (!error)
27471ffd6e58SKip Macy 			error = -t3_load_boot(sc, boot_data, t->len);
27481ffd6e58SKip Macy 
27491ffd6e58SKip Macy 		free(boot_data, M_DEVBUF);
27501ffd6e58SKip Macy 		break;
27511ffd6e58SKip Macy 	}
27521ffd6e58SKip Macy 	case CHELSIO_GET_PM: {
27531ffd6e58SKip Macy 		struct ch_pm *m = (struct ch_pm *)data;
27541ffd6e58SKip Macy 		struct tp_params *p = &sc->params.tp;
27551ffd6e58SKip Macy 
27561ffd6e58SKip Macy 		if (!is_offload(sc))
27571ffd6e58SKip Macy 			return (EOPNOTSUPP);
27581ffd6e58SKip Macy 
27591ffd6e58SKip Macy 		m->tx_pg_sz = p->tx_pg_size;
27601ffd6e58SKip Macy 		m->tx_num_pg = p->tx_num_pgs;
27611ffd6e58SKip Macy 		m->rx_pg_sz  = p->rx_pg_size;
27621ffd6e58SKip Macy 		m->rx_num_pg = p->rx_num_pgs;
27631ffd6e58SKip Macy 		m->pm_total  = p->pmtx_size + p->chan_rx_size * p->nchan;
27641ffd6e58SKip Macy 
27651ffd6e58SKip Macy 		break;
27661ffd6e58SKip Macy 	}
27671ffd6e58SKip Macy 	case CHELSIO_SET_PM: {
27681ffd6e58SKip Macy 		struct ch_pm *m = (struct ch_pm *)data;
27691ffd6e58SKip Macy 		struct tp_params *p = &sc->params.tp;
27701ffd6e58SKip Macy 
27711ffd6e58SKip Macy 		if (!is_offload(sc))
27721ffd6e58SKip Macy 			return (EOPNOTSUPP);
27731ffd6e58SKip Macy 		if (sc->flags & FULL_INIT_DONE)
27741ffd6e58SKip Macy 			return (EBUSY);
27751ffd6e58SKip Macy 
27761ffd6e58SKip Macy 		if (!m->rx_pg_sz || (m->rx_pg_sz & (m->rx_pg_sz - 1)) ||
27771ffd6e58SKip Macy 		    !m->tx_pg_sz || (m->tx_pg_sz & (m->tx_pg_sz - 1)))
27781ffd6e58SKip Macy 			return (EINVAL);	/* not power of 2 */
27791ffd6e58SKip Macy 		if (!(m->rx_pg_sz & 0x14000))
27801ffd6e58SKip Macy 			return (EINVAL);	/* not 16KB or 64KB */
27811ffd6e58SKip Macy 		if (!(m->tx_pg_sz & 0x1554000))
27821ffd6e58SKip Macy 			return (EINVAL);
27831ffd6e58SKip Macy 		if (m->tx_num_pg == -1)
27841ffd6e58SKip Macy 			m->tx_num_pg = p->tx_num_pgs;
27851ffd6e58SKip Macy 		if (m->rx_num_pg == -1)
27861ffd6e58SKip Macy 			m->rx_num_pg = p->rx_num_pgs;
27871ffd6e58SKip Macy 		if (m->tx_num_pg % 24 || m->rx_num_pg % 24)
27881ffd6e58SKip Macy 			return (EINVAL);
27891ffd6e58SKip Macy 		if (m->rx_num_pg * m->rx_pg_sz > p->chan_rx_size ||
27901ffd6e58SKip Macy 		    m->tx_num_pg * m->tx_pg_sz > p->chan_tx_size)
27911ffd6e58SKip Macy 			return (EINVAL);
27921ffd6e58SKip Macy 
27931ffd6e58SKip Macy 		p->rx_pg_size = m->rx_pg_sz;
27941ffd6e58SKip Macy 		p->tx_pg_size = m->tx_pg_sz;
27951ffd6e58SKip Macy 		p->rx_num_pgs = m->rx_num_pg;
27961ffd6e58SKip Macy 		p->tx_num_pgs = m->tx_num_pg;
27971ffd6e58SKip Macy 		break;
27981ffd6e58SKip Macy 	}
2799d722cab4SKip Macy 	case CHELSIO_SETMTUTAB: {
2800d722cab4SKip Macy 		struct ch_mtus *m = (struct ch_mtus *)data;
2801d722cab4SKip Macy 		int i;
2802d722cab4SKip Macy 
2803d722cab4SKip Macy 		if (!is_offload(sc))
2804d722cab4SKip Macy 			return (EOPNOTSUPP);
2805d722cab4SKip Macy 		if (offload_running(sc))
2806d722cab4SKip Macy 			return (EBUSY);
2807d722cab4SKip Macy 		if (m->nmtus != NMTUS)
2808d722cab4SKip Macy 			return (EINVAL);
2809d722cab4SKip Macy 		if (m->mtus[0] < 81)         /* accommodate SACK */
2810d722cab4SKip Macy 			return (EINVAL);
2811d722cab4SKip Macy 
2812d722cab4SKip Macy 		/*
2813d722cab4SKip Macy 		 * MTUs must be in ascending order
2814d722cab4SKip Macy 		 */
2815d722cab4SKip Macy 		for (i = 1; i < NMTUS; ++i)
2816d722cab4SKip Macy 			if (m->mtus[i] < m->mtus[i - 1])
2817d722cab4SKip Macy 				return (EINVAL);
2818d722cab4SKip Macy 
28191ffd6e58SKip Macy 		memcpy(sc->params.mtus, m->mtus, sizeof(sc->params.mtus));
2820d722cab4SKip Macy 		break;
2821d722cab4SKip Macy 	}
2822d722cab4SKip Macy 	case CHELSIO_GETMTUTAB: {
2823d722cab4SKip Macy 		struct ch_mtus *m = (struct ch_mtus *)data;
2824d722cab4SKip Macy 
2825d722cab4SKip Macy 		if (!is_offload(sc))
2826d722cab4SKip Macy 			return (EOPNOTSUPP);
2827d722cab4SKip Macy 
2828d722cab4SKip Macy 		memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus));
2829d722cab4SKip Macy 		m->nmtus = NMTUS;
2830d722cab4SKip Macy 		break;
2831d722cab4SKip Macy 	}
2832b6d90eb7SKip Macy 	case CHELSIO_GET_MEM: {
2833b6d90eb7SKip Macy 		struct ch_mem_range *t = (struct ch_mem_range *)data;
2834b6d90eb7SKip Macy 		struct mc7 *mem;
2835b6d90eb7SKip Macy 		uint8_t *useraddr;
2836b6d90eb7SKip Macy 		u64 buf[32];
2837b6d90eb7SKip Macy 
28381ffd6e58SKip Macy 		/*
28391ffd6e58SKip Macy 		 * Use these to avoid modifying len/addr in the the return
28401ffd6e58SKip Macy 		 * struct
28411ffd6e58SKip Macy 		 */
28421ffd6e58SKip Macy 		uint32_t len = t->len, addr = t->addr;
28431ffd6e58SKip Macy 
2844b6d90eb7SKip Macy 		if (!is_offload(sc))
2845b6d90eb7SKip Macy 			return (EOPNOTSUPP);
2846b6d90eb7SKip Macy 		if (!(sc->flags & FULL_INIT_DONE))
2847b6d90eb7SKip Macy 			return (EIO);         /* need the memory controllers */
28481ffd6e58SKip Macy 		if ((addr & 0x7) || (len & 0x7))
2849b6d90eb7SKip Macy 			return (EINVAL);
2850b6d90eb7SKip Macy 		if (t->mem_id == MEM_CM)
2851b6d90eb7SKip Macy 			mem = &sc->cm;
2852b6d90eb7SKip Macy 		else if (t->mem_id == MEM_PMRX)
2853b6d90eb7SKip Macy 			mem = &sc->pmrx;
2854b6d90eb7SKip Macy 		else if (t->mem_id == MEM_PMTX)
2855b6d90eb7SKip Macy 			mem = &sc->pmtx;
2856b6d90eb7SKip Macy 		else
2857b6d90eb7SKip Macy 			return (EINVAL);
2858b6d90eb7SKip Macy 
2859b6d90eb7SKip Macy 		/*
2860b6d90eb7SKip Macy 		 * Version scheme:
2861b6d90eb7SKip Macy 		 * bits 0..9: chip version
2862b6d90eb7SKip Macy 		 * bits 10..15: chip revision
2863b6d90eb7SKip Macy 		 */
2864b6d90eb7SKip Macy 		t->version = 3 | (sc->params.rev << 10);
2865b6d90eb7SKip Macy 
2866b6d90eb7SKip Macy 		/*
2867b6d90eb7SKip Macy 		 * Read 256 bytes at a time as len can be large and we don't
2868b6d90eb7SKip Macy 		 * want to use huge intermediate buffers.
2869b6d90eb7SKip Macy 		 */
28708090c9f5SKip Macy 		useraddr = (uint8_t *)t->buf;
28711ffd6e58SKip Macy 		while (len) {
28721ffd6e58SKip Macy 			unsigned int chunk = min(len, sizeof(buf));
2873b6d90eb7SKip Macy 
28741ffd6e58SKip Macy 			error = t3_mc7_bd_read(mem, addr / 8, chunk / 8, buf);
2875b6d90eb7SKip Macy 			if (error)
2876b6d90eb7SKip Macy 				return (-error);
2877b6d90eb7SKip Macy 			if (copyout(buf, useraddr, chunk))
2878b6d90eb7SKip Macy 				return (EFAULT);
2879b6d90eb7SKip Macy 			useraddr += chunk;
28801ffd6e58SKip Macy 			addr += chunk;
28811ffd6e58SKip Macy 			len -= chunk;
2882b6d90eb7SKip Macy 		}
2883b6d90eb7SKip Macy 		break;
2884b6d90eb7SKip Macy 	}
2885d722cab4SKip Macy 	case CHELSIO_READ_TCAM_WORD: {
2886d722cab4SKip Macy 		struct ch_tcam_word *t = (struct ch_tcam_word *)data;
2887d722cab4SKip Macy 
2888d722cab4SKip Macy 		if (!is_offload(sc))
2889d722cab4SKip Macy 			return (EOPNOTSUPP);
2890ac3a6d9cSKip Macy 		if (!(sc->flags & FULL_INIT_DONE))
2891ac3a6d9cSKip Macy 			return (EIO);         /* need MC5 */
2892d722cab4SKip Macy 		return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf);
2893d722cab4SKip Macy 		break;
2894d722cab4SKip Macy 	}
2895b6d90eb7SKip Macy 	case CHELSIO_SET_TRACE_FILTER: {
2896b6d90eb7SKip Macy 		struct ch_trace *t = (struct ch_trace *)data;
2897b6d90eb7SKip Macy 		const struct trace_params *tp;
2898b6d90eb7SKip Macy 
2899b6d90eb7SKip Macy 		tp = (const struct trace_params *)&t->sip;
2900b6d90eb7SKip Macy 		if (t->config_tx)
2901b6d90eb7SKip Macy 			t3_config_trace_filter(sc, tp, 0, t->invert_match,
2902b6d90eb7SKip Macy 					       t->trace_tx);
2903b6d90eb7SKip Macy 		if (t->config_rx)
2904b6d90eb7SKip Macy 			t3_config_trace_filter(sc, tp, 1, t->invert_match,
2905b6d90eb7SKip Macy 					       t->trace_rx);
2906b6d90eb7SKip Macy 		break;
2907b6d90eb7SKip Macy 	}
2908b6d90eb7SKip Macy 	case CHELSIO_SET_PKTSCHED: {
2909b6d90eb7SKip Macy 		struct ch_pktsched_params *p = (struct ch_pktsched_params *)data;
2910b6d90eb7SKip Macy 		if (sc->open_device_map == 0)
2911b6d90eb7SKip Macy 			return (EAGAIN);
2912b6d90eb7SKip Macy 		send_pktsched_cmd(sc, p->sched, p->idx, p->min, p->max,
2913b6d90eb7SKip Macy 		    p->binding);
2914b6d90eb7SKip Macy 		break;
2915b6d90eb7SKip Macy 	}
2916b6d90eb7SKip Macy 	case CHELSIO_IFCONF_GETREGS: {
29171ffd6e58SKip Macy 		struct ch_ifconf_regs *regs = (struct ch_ifconf_regs *)data;
2918b6d90eb7SKip Macy 		int reglen = cxgb_get_regs_len();
29191ffd6e58SKip Macy 		uint8_t *buf = malloc(reglen, M_DEVBUF, M_NOWAIT);
2920b6d90eb7SKip Macy 		if (buf == NULL) {
2921b6d90eb7SKip Macy 			return (ENOMEM);
2922b6d90eb7SKip Macy 		}
29231ffd6e58SKip Macy 		if (regs->len > reglen)
29241ffd6e58SKip Macy 			regs->len = reglen;
29251ffd6e58SKip Macy 		else if (regs->len < reglen)
2926f2d8ff04SGeorge V. Neville-Neil 			error = ENOBUFS;
29271ffd6e58SKip Macy 
29281ffd6e58SKip Macy 		if (!error) {
2929b6d90eb7SKip Macy 			cxgb_get_regs(sc, regs, buf);
2930b6d90eb7SKip Macy 			error = copyout(buf, regs->data, reglen);
29311ffd6e58SKip Macy 		}
2932b6d90eb7SKip Macy 		free(buf, M_DEVBUF);
2933b6d90eb7SKip Macy 
2934b6d90eb7SKip Macy 		break;
2935b6d90eb7SKip Macy 	}
2936d722cab4SKip Macy 	case CHELSIO_SET_HW_SCHED: {
2937d722cab4SKip Macy 		struct ch_hw_sched *t = (struct ch_hw_sched *)data;
2938d722cab4SKip Macy 		unsigned int ticks_per_usec = core_ticks_per_usec(sc);
2939d722cab4SKip Macy 
2940d722cab4SKip Macy 		if ((sc->flags & FULL_INIT_DONE) == 0)
2941d722cab4SKip Macy 			return (EAGAIN);       /* need TP to be initialized */
2942d722cab4SKip Macy 		if (t->sched >= NTX_SCHED || !in_range(t->mode, 0, 1) ||
2943d722cab4SKip Macy 		    !in_range(t->channel, 0, 1) ||
2944d722cab4SKip Macy 		    !in_range(t->kbps, 0, 10000000) ||
2945d722cab4SKip Macy 		    !in_range(t->class_ipg, 0, 10000 * 65535 / ticks_per_usec) ||
2946d722cab4SKip Macy 		    !in_range(t->flow_ipg, 0,
2947d722cab4SKip Macy 			      dack_ticks_to_usec(sc, 0x7ff)))
2948d722cab4SKip Macy 			return (EINVAL);
2949d722cab4SKip Macy 
2950d722cab4SKip Macy 		if (t->kbps >= 0) {
2951d722cab4SKip Macy 			error = t3_config_sched(sc, t->kbps, t->sched);
2952d722cab4SKip Macy 			if (error < 0)
2953d722cab4SKip Macy 				return (-error);
2954d722cab4SKip Macy 		}
2955d722cab4SKip Macy 		if (t->class_ipg >= 0)
2956d722cab4SKip Macy 			t3_set_sched_ipg(sc, t->sched, t->class_ipg);
2957d722cab4SKip Macy 		if (t->flow_ipg >= 0) {
2958d722cab4SKip Macy 			t->flow_ipg *= 1000;     /* us -> ns */
2959d722cab4SKip Macy 			t3_set_pace_tbl(sc, &t->flow_ipg, t->sched, 1);
2960d722cab4SKip Macy 		}
2961d722cab4SKip Macy 		if (t->mode >= 0) {
2962d722cab4SKip Macy 			int bit = 1 << (S_TX_MOD_TIMER_MODE + t->sched);
2963d722cab4SKip Macy 
2964d722cab4SKip Macy 			t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2965d722cab4SKip Macy 					 bit, t->mode ? bit : 0);
2966d722cab4SKip Macy 		}
2967d722cab4SKip Macy 		if (t->channel >= 0)
2968d722cab4SKip Macy 			t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2969d722cab4SKip Macy 					 1 << t->sched, t->channel << t->sched);
2970d722cab4SKip Macy 		break;
2971d722cab4SKip Macy 	}
29721ffd6e58SKip Macy 	case CHELSIO_GET_EEPROM: {
29731ffd6e58SKip Macy 		int i;
29741ffd6e58SKip Macy 		struct ch_eeprom *e = (struct ch_eeprom *)data;
29751ffd6e58SKip Macy 		uint8_t *buf = malloc(EEPROMSIZE, M_DEVBUF, M_NOWAIT);
29761ffd6e58SKip Macy 
29771ffd6e58SKip Macy 		if (buf == NULL) {
29781ffd6e58SKip Macy 			return (ENOMEM);
29791ffd6e58SKip Macy 		}
29801ffd6e58SKip Macy 		e->magic = EEPROM_MAGIC;
29811ffd6e58SKip Macy 		for (i = e->offset & ~3; !error && i < e->offset + e->len; i += 4)
29821ffd6e58SKip Macy 			error = -t3_seeprom_read(sc, i, (uint32_t *)&buf[i]);
29831ffd6e58SKip Macy 
29841ffd6e58SKip Macy 		if (!error)
29851ffd6e58SKip Macy 			error = copyout(buf + e->offset, e->data, e->len);
29861ffd6e58SKip Macy 
29871ffd6e58SKip Macy 		free(buf, M_DEVBUF);
29881ffd6e58SKip Macy 		break;
29891ffd6e58SKip Macy 	}
29901ffd6e58SKip Macy 	case CHELSIO_CLEAR_STATS: {
29911ffd6e58SKip Macy 		if (!(sc->flags & FULL_INIT_DONE))
29921ffd6e58SKip Macy 			return EAGAIN;
29931ffd6e58SKip Macy 
29941ffd6e58SKip Macy 		PORT_LOCK(pi);
29951ffd6e58SKip Macy 		t3_mac_update_stats(&pi->mac);
29961ffd6e58SKip Macy 		memset(&pi->mac.stats, 0, sizeof(pi->mac.stats));
29971ffd6e58SKip Macy 		PORT_UNLOCK(pi);
29981ffd6e58SKip Macy 		break;
29991ffd6e58SKip Macy 	}
3000f2d8ff04SGeorge V. Neville-Neil 	case CHELSIO_GET_UP_LA: {
3001f2d8ff04SGeorge V. Neville-Neil 		struct ch_up_la *la = (struct ch_up_la *)data;
3002f2d8ff04SGeorge V. Neville-Neil 		uint8_t *buf = malloc(LA_BUFSIZE, M_DEVBUF, M_NOWAIT);
3003f2d8ff04SGeorge V. Neville-Neil 		if (buf == NULL) {
3004f2d8ff04SGeorge V. Neville-Neil 			return (ENOMEM);
3005f2d8ff04SGeorge V. Neville-Neil 		}
3006f2d8ff04SGeorge V. Neville-Neil 		if (la->bufsize < LA_BUFSIZE)
3007f2d8ff04SGeorge V. Neville-Neil 			error = ENOBUFS;
3008f2d8ff04SGeorge V. Neville-Neil 
3009f2d8ff04SGeorge V. Neville-Neil 		if (!error)
3010f2d8ff04SGeorge V. Neville-Neil 			error = -t3_get_up_la(sc, &la->stopped, &la->idx,
3011f2d8ff04SGeorge V. Neville-Neil 					      &la->bufsize, buf);
3012f2d8ff04SGeorge V. Neville-Neil 		if (!error)
3013f2d8ff04SGeorge V. Neville-Neil 			error = copyout(buf, la->data, la->bufsize);
3014f2d8ff04SGeorge V. Neville-Neil 
3015f2d8ff04SGeorge V. Neville-Neil 		free(buf, M_DEVBUF);
3016f2d8ff04SGeorge V. Neville-Neil 		break;
3017f2d8ff04SGeorge V. Neville-Neil 	}
3018f2d8ff04SGeorge V. Neville-Neil 	case CHELSIO_GET_UP_IOQS: {
3019f2d8ff04SGeorge V. Neville-Neil 		struct ch_up_ioqs *ioqs = (struct ch_up_ioqs *)data;
3020f2d8ff04SGeorge V. Neville-Neil 		uint8_t *buf = malloc(IOQS_BUFSIZE, M_DEVBUF, M_NOWAIT);
3021f2d8ff04SGeorge V. Neville-Neil 		uint32_t *v;
3022f2d8ff04SGeorge V. Neville-Neil 
3023f2d8ff04SGeorge V. Neville-Neil 		if (buf == NULL) {
3024f2d8ff04SGeorge V. Neville-Neil 			return (ENOMEM);
3025f2d8ff04SGeorge V. Neville-Neil 		}
3026f2d8ff04SGeorge V. Neville-Neil 		if (ioqs->bufsize < IOQS_BUFSIZE)
3027f2d8ff04SGeorge V. Neville-Neil 			error = ENOBUFS;
3028f2d8ff04SGeorge V. Neville-Neil 
3029f2d8ff04SGeorge V. Neville-Neil 		if (!error)
3030f2d8ff04SGeorge V. Neville-Neil 			error = -t3_get_up_ioqs(sc, &ioqs->bufsize, buf);
3031f2d8ff04SGeorge V. Neville-Neil 
3032f2d8ff04SGeorge V. Neville-Neil 		if (!error) {
3033f2d8ff04SGeorge V. Neville-Neil 			v = (uint32_t *)buf;
3034f2d8ff04SGeorge V. Neville-Neil 
3035f2d8ff04SGeorge V. Neville-Neil 			ioqs->bufsize -= 4 * sizeof(uint32_t);
3036f2d8ff04SGeorge V. Neville-Neil 			ioqs->ioq_rx_enable = *v++;
3037f2d8ff04SGeorge V. Neville-Neil 			ioqs->ioq_tx_enable = *v++;
3038f2d8ff04SGeorge V. Neville-Neil 			ioqs->ioq_rx_status = *v++;
3039f2d8ff04SGeorge V. Neville-Neil 			ioqs->ioq_tx_status = *v++;
3040f2d8ff04SGeorge V. Neville-Neil 
3041f2d8ff04SGeorge V. Neville-Neil 			error = copyout(v, ioqs->data, ioqs->bufsize);
3042f2d8ff04SGeorge V. Neville-Neil 		}
3043f2d8ff04SGeorge V. Neville-Neil 
3044f2d8ff04SGeorge V. Neville-Neil 		free(buf, M_DEVBUF);
3045f2d8ff04SGeorge V. Neville-Neil 		break;
3046f2d8ff04SGeorge V. Neville-Neil 	}
3047b6d90eb7SKip Macy 	default:
3048b6d90eb7SKip Macy 		return (EOPNOTSUPP);
3049b6d90eb7SKip Macy 		break;
3050b6d90eb7SKip Macy 	}
3051b6d90eb7SKip Macy 
3052b6d90eb7SKip Macy 	return (error);
3053b6d90eb7SKip Macy }
3054b6d90eb7SKip Macy 
3055b6d90eb7SKip Macy static __inline void
3056b6d90eb7SKip Macy reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
3057b6d90eb7SKip Macy     unsigned int end)
3058b6d90eb7SKip Macy {
30591ffd6e58SKip Macy 	uint32_t *p = (uint32_t *)(buf + start);
3060b6d90eb7SKip Macy 
3061b6d90eb7SKip Macy 	for ( ; start <= end; start += sizeof(uint32_t))
3062b6d90eb7SKip Macy 		*p++ = t3_read_reg(ap, start);
3063b6d90eb7SKip Macy }
3064b6d90eb7SKip Macy 
3065b6d90eb7SKip Macy #define T3_REGMAP_SIZE (3 * 1024)
3066b6d90eb7SKip Macy static int
3067b6d90eb7SKip Macy cxgb_get_regs_len(void)
3068b6d90eb7SKip Macy {
3069b6d90eb7SKip Macy 	return T3_REGMAP_SIZE;
3070b6d90eb7SKip Macy }
3071b6d90eb7SKip Macy 
3072b6d90eb7SKip Macy static void
30731ffd6e58SKip Macy cxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf)
3074b6d90eb7SKip Macy {
3075b6d90eb7SKip Macy 
3076b6d90eb7SKip Macy 	/*
3077b6d90eb7SKip Macy 	 * Version scheme:
3078b6d90eb7SKip Macy 	 * bits 0..9: chip version
3079b6d90eb7SKip Macy 	 * bits 10..15: chip revision
3080b6d90eb7SKip Macy 	 * bit 31: set for PCIe cards
3081b6d90eb7SKip Macy 	 */
3082b6d90eb7SKip Macy 	regs->version = 3 | (sc->params.rev << 10) | (is_pcie(sc) << 31);
3083b6d90eb7SKip Macy 
3084b6d90eb7SKip Macy 	/*
3085b6d90eb7SKip Macy 	 * We skip the MAC statistics registers because they are clear-on-read.
3086b6d90eb7SKip Macy 	 * Also reading multi-register stats would need to synchronize with the
3087b6d90eb7SKip Macy 	 * periodic mac stats accumulation.  Hard to justify the complexity.
3088b6d90eb7SKip Macy 	 */
30891ffd6e58SKip Macy 	memset(buf, 0, cxgb_get_regs_len());
3090b6d90eb7SKip Macy 	reg_block_dump(sc, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
3091b6d90eb7SKip Macy 	reg_block_dump(sc, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
3092b6d90eb7SKip Macy 	reg_block_dump(sc, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
3093b6d90eb7SKip Macy 	reg_block_dump(sc, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
3094b6d90eb7SKip Macy 	reg_block_dump(sc, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
3095b6d90eb7SKip Macy 	reg_block_dump(sc, buf, A_XGM_SERDES_STATUS0,
3096b6d90eb7SKip Macy 		       XGM_REG(A_XGM_SERDES_STAT3, 1));
3097b6d90eb7SKip Macy 	reg_block_dump(sc, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
3098b6d90eb7SKip Macy 		       XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
3099b6d90eb7SKip Macy }
3100404825a7SKip Macy 
3101404825a7SKip Macy 
3102404825a7SKip Macy MODULE_DEPEND(if_cxgb, cxgb_t3fw, 1, 1, 1);
3103