xref: /freebsd/sys/dev/cxgb/cxgb_main.c (revision c2009a4c90853a08129783a36b5d8d5dd8fcdfed)
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);
1180bbdea77SGeorge V. Neville-Neil int t3_detect_link_fault(adapter_t *adapter, int port_id);
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"
3680c1ff9c6SGeorge V. Neville-Neil #define TPEEPROM_NAME "cxgb_t3%c_tp_eeprom"
3690c1ff9c6SGeorge V. Neville-Neil #define TPSRAM_NAME "cxgb_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 
3953cf138bbSGeorge V. Neville-Neil /*
3963cf138bbSGeorge V. Neville-Neil  * The cxgb_controller_attach function is responsible for the initial
3973cf138bbSGeorge V. Neville-Neil  * bringup of the device.  Its responsibilities include:
3983cf138bbSGeorge V. Neville-Neil  *
3993cf138bbSGeorge V. Neville-Neil  *  1. Determine if the device supports MSI or MSI-X.
4003cf138bbSGeorge V. Neville-Neil  *  2. Allocate bus resources so that we can access the Base Address Register
4013cf138bbSGeorge V. Neville-Neil  *  3. Create and initialize mutexes for the controller and its control
4023cf138bbSGeorge V. Neville-Neil  *     logic such as SGE and MDIO.
4033cf138bbSGeorge V. Neville-Neil  *  4. Call hardware specific setup routine for the adapter as a whole.
4043cf138bbSGeorge V. Neville-Neil  *  5. Allocate the BAR for doing MSI-X.
4053cf138bbSGeorge V. Neville-Neil  *  6. Setup the line interrupt iff MSI-X is not supported.
4063cf138bbSGeorge V. Neville-Neil  *  7. Create the driver's taskq.
407c2009a4cSGeorge V. Neville-Neil  *  8. Start one task queue service thread.
408c2009a4cSGeorge V. Neville-Neil  *  9. Check if the firmware and SRAM are up-to-date.  They will be
409c2009a4cSGeorge V. Neville-Neil  *     auto-updated later (before FULL_INIT_DONE), if required.
4103cf138bbSGeorge V. Neville-Neil  * 10. Create a child device for each MAC (port)
4113cf138bbSGeorge V. Neville-Neil  * 11. Initialize T3 private state.
4123cf138bbSGeorge V. Neville-Neil  * 12. Trigger the LED
4133cf138bbSGeorge V. Neville-Neil  * 13. Setup offload iff supported.
4143cf138bbSGeorge V. Neville-Neil  * 14. Reset/restart the tick callout.
4153cf138bbSGeorge V. Neville-Neil  * 15. Attach sysctls
4163cf138bbSGeorge V. Neville-Neil  *
4173cf138bbSGeorge V. Neville-Neil  * NOTE: Any modification or deviation from this list MUST be reflected in
4183cf138bbSGeorge V. Neville-Neil  * the above comment.  Failure to do so will result in problems on various
4193cf138bbSGeorge V. Neville-Neil  * error conditions including link flapping.
4203cf138bbSGeorge V. Neville-Neil  */
421b6d90eb7SKip Macy static int
422b6d90eb7SKip Macy cxgb_controller_attach(device_t dev)
423b6d90eb7SKip Macy {
424b6d90eb7SKip Macy 	device_t child;
425b6d90eb7SKip Macy 	const struct adapter_info *ai;
426b6d90eb7SKip Macy 	struct adapter *sc;
4272de1fa86SKip Macy 	int i, error = 0;
428b6d90eb7SKip Macy 	uint32_t vers;
429693d746cSKip Macy 	int port_qsets = 1;
4307aff6d8eSKip Macy #ifdef MSI_SUPPORTED
4312de1fa86SKip Macy 	int msi_needed, reg;
4327aff6d8eSKip Macy #endif
4335197f3abSGeorge V. Neville-Neil 	char buf[80];
4345197f3abSGeorge V. Neville-Neil 
435b6d90eb7SKip Macy 	sc = device_get_softc(dev);
436b6d90eb7SKip Macy 	sc->dev = dev;
437d722cab4SKip Macy 	sc->msi_count = 0;
4382de1fa86SKip Macy 	ai = cxgb_get_adapter_info(dev);
439b6d90eb7SKip Macy 
4402de1fa86SKip Macy 	/*
4412de1fa86SKip Macy 	 * XXX not really related but a recent addition
4422de1fa86SKip Macy 	 */
4432de1fa86SKip Macy #ifdef MSI_SUPPORTED
444fc01c613SKip Macy 	/* find the PCIe link width and set max read request to 4KB*/
445fc01c613SKip Macy 	if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
446fc01c613SKip Macy 		uint16_t lnk, pectl;
447fc01c613SKip Macy 		lnk = pci_read_config(dev, reg + 0x12, 2);
448fc01c613SKip Macy 		sc->link_width = (lnk >> 4) & 0x3f;
449fc01c613SKip Macy 
450fc01c613SKip Macy 		pectl = pci_read_config(dev, reg + 0x8, 2);
451fc01c613SKip Macy 		pectl = (pectl & ~0x7000) | (5 << 12);
452fc01c613SKip Macy 		pci_write_config(dev, reg + 0x8, pectl, 2);
453fc01c613SKip Macy 	}
454ac3a6d9cSKip Macy 
455ac3a6d9cSKip Macy 	if (sc->link_width != 0 && sc->link_width <= 4 &&
456ac3a6d9cSKip Macy 	    (ai->nports0 + ai->nports1) <= 2) {
457fc01c613SKip Macy 		device_printf(sc->dev,
458ac6b4cf1SKip Macy 		    "PCIe x%d Link, expect reduced performance\n",
459fc01c613SKip Macy 		    sc->link_width);
460fc01c613SKip Macy 	}
4612de1fa86SKip Macy #endif
4627ac2e6c3SKip Macy 	touch_bars(dev);
463b6d90eb7SKip Macy 	pci_enable_busmaster(dev);
464b6d90eb7SKip Macy 	/*
465b6d90eb7SKip Macy 	 * Allocate the registers and make them available to the driver.
466b6d90eb7SKip Macy 	 * The registers that we care about for NIC mode are in BAR 0
467b6d90eb7SKip Macy 	 */
468b6d90eb7SKip Macy 	sc->regs_rid = PCIR_BAR(0);
469b6d90eb7SKip Macy 	if ((sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
470b6d90eb7SKip Macy 	    &sc->regs_rid, RF_ACTIVE)) == NULL) {
4718e10660fSKip Macy 		device_printf(dev, "Cannot allocate BAR region 0\n");
472b6d90eb7SKip Macy 		return (ENXIO);
473b6d90eb7SKip Macy 	}
4748e10660fSKip Macy 	sc->udbs_rid = PCIR_BAR(2);
4757f15419bSGeorge V. Neville-Neil 	sc->udbs_res = NULL;
4767f15419bSGeorge V. Neville-Neil 	if (is_offload(sc) &&
4777f15419bSGeorge V. Neville-Neil 	    ((sc->udbs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
4787f15419bSGeorge V. Neville-Neil 		   &sc->udbs_rid, RF_ACTIVE)) == NULL)) {
4798e10660fSKip Macy 		device_printf(dev, "Cannot allocate BAR region 1\n");
4808e10660fSKip Macy 		error = ENXIO;
4818e10660fSKip Macy 		goto out;
4828e10660fSKip Macy 	}
483b6d90eb7SKip Macy 
484bb38cd2fSKip Macy 	snprintf(sc->lockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb controller lock %d",
485bb38cd2fSKip Macy 	    device_get_unit(dev));
486bb38cd2fSKip Macy 	ADAPTER_LOCK_INIT(sc, sc->lockbuf);
487bb38cd2fSKip Macy 
488bb38cd2fSKip Macy 	snprintf(sc->reglockbuf, ADAPTER_LOCK_NAME_LEN, "SGE reg lock %d",
489bb38cd2fSKip Macy 	    device_get_unit(dev));
490bb38cd2fSKip Macy 	snprintf(sc->mdiolockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb mdio lock %d",
491bb38cd2fSKip Macy 	    device_get_unit(dev));
492bb38cd2fSKip Macy 	snprintf(sc->elmerlockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb elmer lock %d",
493bb38cd2fSKip Macy 	    device_get_unit(dev));
494bb38cd2fSKip Macy 
4958e10660fSKip Macy 	MTX_INIT(&sc->sge.reg_lock, sc->reglockbuf, NULL, MTX_SPIN);
496bb38cd2fSKip Macy 	MTX_INIT(&sc->mdio_lock, sc->mdiolockbuf, NULL, MTX_DEF);
497bb38cd2fSKip Macy 	MTX_INIT(&sc->elmer_lock, sc->elmerlockbuf, NULL, MTX_DEF);
498b6d90eb7SKip Macy 
499b6d90eb7SKip Macy 	sc->bt = rman_get_bustag(sc->regs_res);
500b6d90eb7SKip Macy 	sc->bh = rman_get_bushandle(sc->regs_res);
501b6d90eb7SKip Macy 	sc->mmio_len = rman_get_size(sc->regs_res);
502b6d90eb7SKip Macy 
50324cdd067SKip Macy 	if (t3_prep_adapter(sc, ai, 1) < 0) {
504ef72318fSKip Macy 		printf("prep adapter failed\n");
50524cdd067SKip Macy 		error = ENODEV;
50624cdd067SKip Macy 		goto out;
50724cdd067SKip Macy 	}
508b6d90eb7SKip Macy         /* Allocate the BAR for doing MSI-X.  If it succeeds, try to allocate
509b6d90eb7SKip Macy 	 * enough messages for the queue sets.  If that fails, try falling
510b6d90eb7SKip Macy 	 * back to MSI.  If that fails, then try falling back to the legacy
511b6d90eb7SKip Macy 	 * interrupt pin model.
512b6d90eb7SKip Macy 	 */
513b6d90eb7SKip Macy #ifdef MSI_SUPPORTED
514693d746cSKip Macy 
515b6d90eb7SKip Macy 	sc->msix_regs_rid = 0x20;
516b6d90eb7SKip Macy 	if ((msi_allowed >= 2) &&
517b6d90eb7SKip Macy 	    (sc->msix_regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
518b6d90eb7SKip Macy 	    &sc->msix_regs_rid, RF_ACTIVE)) != NULL) {
519b6d90eb7SKip Macy 
520d722cab4SKip Macy 		msi_needed = sc->msi_count = SGE_MSIX_COUNT;
521693d746cSKip Macy 
522d722cab4SKip Macy 		if (((error = pci_alloc_msix(dev, &sc->msi_count)) != 0) ||
523d722cab4SKip Macy 		    (sc->msi_count != msi_needed)) {
524d722cab4SKip Macy 			device_printf(dev, "msix allocation failed - msi_count = %d"
525d722cab4SKip Macy 			    " msi_needed=%d will try msi err=%d\n", sc->msi_count,
526d722cab4SKip Macy 			    msi_needed, error);
527d722cab4SKip Macy 			sc->msi_count = 0;
528b6d90eb7SKip Macy 			pci_release_msi(dev);
529b6d90eb7SKip Macy 			bus_release_resource(dev, SYS_RES_MEMORY,
530b6d90eb7SKip Macy 			    sc->msix_regs_rid, sc->msix_regs_res);
531b6d90eb7SKip Macy 			sc->msix_regs_res = NULL;
532b6d90eb7SKip Macy 		} else {
533b6d90eb7SKip Macy 			sc->flags |= USING_MSIX;
534f0a542f8SKip Macy 			sc->cxgb_intr = t3_intr_msix;
535b6d90eb7SKip Macy 		}
536b6d90eb7SKip Macy 	}
537b6d90eb7SKip Macy 
538d722cab4SKip Macy 	if ((msi_allowed >= 1) && (sc->msi_count == 0)) {
539d722cab4SKip Macy 		sc->msi_count = 1;
540d722cab4SKip Macy 		if (pci_alloc_msi(dev, &sc->msi_count)) {
541693d746cSKip Macy 			device_printf(dev, "alloc msi failed - will try INTx\n");
542d722cab4SKip Macy 			sc->msi_count = 0;
543b6d90eb7SKip Macy 			pci_release_msi(dev);
544b6d90eb7SKip Macy 		} else {
545b6d90eb7SKip Macy 			sc->flags |= USING_MSI;
546b6d90eb7SKip Macy 			sc->irq_rid = 1;
547f0a542f8SKip Macy 			sc->cxgb_intr = t3_intr_msi;
548b6d90eb7SKip Macy 		}
549b6d90eb7SKip Macy 	}
550b6d90eb7SKip Macy #endif
551d722cab4SKip Macy 	if (sc->msi_count == 0) {
552693d746cSKip Macy 		device_printf(dev, "using line interrupts\n");
553b6d90eb7SKip Macy 		sc->irq_rid = 0;
554f0a542f8SKip Macy 		sc->cxgb_intr = t3b_intr;
555b6d90eb7SKip Macy 	}
556b6d90eb7SKip Macy 
557a02573bcSKip Macy 	if ((sc->flags & USING_MSIX) && multiq)
558f705d735SKip Macy 		port_qsets = min((SGE_QSETS/(sc)->params.nports), mp_ncpus);
559b6d90eb7SKip Macy 
560b6d90eb7SKip Macy 	/* Create a private taskqueue thread for handling driver events */
561b6d90eb7SKip Macy #ifdef TASKQUEUE_CURRENT
562b6d90eb7SKip Macy 	sc->tq = taskqueue_create("cxgb_taskq", M_NOWAIT,
563b6d90eb7SKip Macy 	    taskqueue_thread_enqueue, &sc->tq);
564b6d90eb7SKip Macy #else
565b6d90eb7SKip Macy 	sc->tq = taskqueue_create_fast("cxgb_taskq", M_NOWAIT,
566b6d90eb7SKip Macy 	    taskqueue_thread_enqueue, &sc->tq);
567b6d90eb7SKip Macy #endif
568b6d90eb7SKip Macy 	if (sc->tq == NULL) {
569b6d90eb7SKip Macy 		device_printf(dev, "failed to allocate controller task queue\n");
570b6d90eb7SKip Macy 		goto out;
571b6d90eb7SKip Macy 	}
572b6d90eb7SKip Macy 
573b6d90eb7SKip Macy 	taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq",
574b6d90eb7SKip Macy 	    device_get_nameunit(dev));
575b6d90eb7SKip Macy 	TASK_INIT(&sc->ext_intr_task, 0, cxgb_ext_intr_handler, sc);
576bb38cd2fSKip Macy 	TASK_INIT(&sc->tick_task, 0, cxgb_tick_handler, sc);
577b6d90eb7SKip Macy 
578b6d90eb7SKip Macy 
579b6d90eb7SKip Macy 	/* Create a periodic callout for checking adapter status */
580bb38cd2fSKip Macy 	callout_init(&sc->cxgb_tick_ch, TRUE);
581b6d90eb7SKip Macy 
582f2d8ff04SGeorge V. Neville-Neil 	if (t3_check_fw_version(sc) < 0 || force_fw_update) {
583b6d90eb7SKip Macy 		/*
584b6d90eb7SKip Macy 		 * Warn user that a firmware update will be attempted in init.
585b6d90eb7SKip Macy 		 */
586d722cab4SKip Macy 		device_printf(dev, "firmware needs to be updated to version %d.%d.%d\n",
587d722cab4SKip Macy 		    FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
588b6d90eb7SKip Macy 		sc->flags &= ~FW_UPTODATE;
589b6d90eb7SKip Macy 	} else {
590b6d90eb7SKip Macy 		sc->flags |= FW_UPTODATE;
591b6d90eb7SKip Macy 	}
592b6d90eb7SKip Macy 
593f2d8ff04SGeorge V. Neville-Neil 	if (t3_check_tpsram_version(sc) < 0) {
594ac3a6d9cSKip Macy 		/*
595ac3a6d9cSKip Macy 		 * Warn user that a firmware update will be attempted in init.
596ac3a6d9cSKip Macy 		 */
597ac3a6d9cSKip Macy 		device_printf(dev, "SRAM needs to be updated to version %c-%d.%d.%d\n",
598ac3a6d9cSKip Macy 		    t3rev2char(sc), TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
599ac3a6d9cSKip Macy 		sc->flags &= ~TPS_UPTODATE;
600ac3a6d9cSKip Macy 	} else {
601ac3a6d9cSKip Macy 		sc->flags |= TPS_UPTODATE;
602ac3a6d9cSKip Macy 	}
603ac3a6d9cSKip Macy 
604b6d90eb7SKip Macy 	/*
605b6d90eb7SKip Macy 	 * Create a child device for each MAC.  The ethernet attachment
606b6d90eb7SKip Macy 	 * will be done in these children.
607b6d90eb7SKip Macy 	 */
608693d746cSKip Macy 	for (i = 0; i < (sc)->params.nports; i++) {
6097ac2e6c3SKip Macy 		struct port_info *pi;
6107ac2e6c3SKip Macy 
611b6d90eb7SKip Macy 		if ((child = device_add_child(dev, "cxgb", -1)) == NULL) {
612b6d90eb7SKip Macy 			device_printf(dev, "failed to add child port\n");
613b6d90eb7SKip Macy 			error = EINVAL;
614b6d90eb7SKip Macy 			goto out;
615b6d90eb7SKip Macy 		}
6167ac2e6c3SKip Macy 		pi = &sc->port[i];
6177ac2e6c3SKip Macy 		pi->adapter = sc;
6187ac2e6c3SKip Macy 		pi->nqsets = port_qsets;
6197ac2e6c3SKip Macy 		pi->first_qset = i*port_qsets;
6207ac2e6c3SKip Macy 		pi->port_id = i;
6217ac2e6c3SKip Macy 		pi->tx_chan = i >= ai->nports0;
6227ac2e6c3SKip Macy 		pi->txpkt_intf = pi->tx_chan ? 2 * (i - ai->nports0) + 1 : 2 * i;
6237ac2e6c3SKip Macy 		sc->rxpkt_map[pi->txpkt_intf] = i;
6248090c9f5SKip Macy 		sc->port[i].tx_chan = i >= ai->nports0;
625ac3a6d9cSKip Macy 		sc->portdev[i] = child;
6267ac2e6c3SKip Macy 		device_set_softc(child, pi);
627b6d90eb7SKip Macy 	}
628b6d90eb7SKip Macy 	if ((error = bus_generic_attach(dev)) != 0)
629b6d90eb7SKip Macy 		goto out;
630b6d90eb7SKip Macy 
631b6d90eb7SKip Macy 	/* initialize sge private state */
632ef72318fSKip Macy 	t3_sge_init_adapter(sc);
633b6d90eb7SKip Macy 
634b6d90eb7SKip Macy 	t3_led_ready(sc);
635b6d90eb7SKip Macy 
636d722cab4SKip Macy 	cxgb_offload_init();
637d722cab4SKip Macy 	if (is_offload(sc)) {
638d722cab4SKip Macy 		setbit(&sc->registered_device_map, OFFLOAD_DEVMAP_BIT);
639d722cab4SKip Macy 		cxgb_adapter_ofld(sc);
640d722cab4SKip Macy         }
641b6d90eb7SKip Macy 	error = t3_get_fw_version(sc, &vers);
642b6d90eb7SKip Macy 	if (error)
643b6d90eb7SKip Macy 		goto out;
644b6d90eb7SKip Macy 
645d722cab4SKip Macy 	snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d.%d",
646d722cab4SKip Macy 	    G_FW_VERSION_MAJOR(vers), G_FW_VERSION_MINOR(vers),
647d722cab4SKip Macy 	    G_FW_VERSION_MICRO(vers));
648b6d90eb7SKip Macy 
6495197f3abSGeorge V. Neville-Neil 	snprintf(buf, sizeof(buf), "%s\t E/C: %s S/N: %s",
6505197f3abSGeorge V. Neville-Neil 		 ai->desc,
6515197f3abSGeorge V. Neville-Neil 		 sc->params.vpd.ec, sc->params.vpd.sn);
6525197f3abSGeorge V. Neville-Neil 	device_set_desc_copy(dev, buf);
6535197f3abSGeorge V. Neville-Neil 
6540bbdea77SGeorge V. Neville-Neil 	snprintf(&sc->port_types[0], sizeof(sc->port_types), "%x%x%x%x",
6550bbdea77SGeorge V. Neville-Neil 		 sc->params.vpd.port_type[0], sc->params.vpd.port_type[1],
6560bbdea77SGeorge V. Neville-Neil 		 sc->params.vpd.port_type[2], sc->params.vpd.port_type[3]);
6570bbdea77SGeorge V. Neville-Neil 
6588e10660fSKip Macy 	device_printf(sc->dev, "Firmware Version %s\n", &sc->fw_version[0]);
659706cb31fSKip Macy 	callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc);
6608090c9f5SKip Macy 	t3_add_attach_sysctls(sc);
661b6d90eb7SKip Macy out:
662b6d90eb7SKip Macy 	if (error)
663b6d90eb7SKip Macy 		cxgb_free(sc);
664b6d90eb7SKip Macy 
665b6d90eb7SKip Macy 	return (error);
666b6d90eb7SKip Macy }
667b6d90eb7SKip Macy 
6683cf138bbSGeorge V. Neville-Neil /*
669c2009a4cSGeorge V. Neville-Neil  * The cxgb_controller_detach routine is called with the device is
6703cf138bbSGeorge V. Neville-Neil  * unloaded from the system.
6713cf138bbSGeorge V. Neville-Neil  */
6723cf138bbSGeorge V. Neville-Neil 
673b6d90eb7SKip Macy static int
674b6d90eb7SKip Macy cxgb_controller_detach(device_t dev)
675b6d90eb7SKip Macy {
676b6d90eb7SKip Macy 	struct adapter *sc;
677b6d90eb7SKip Macy 
678b6d90eb7SKip Macy 	sc = device_get_softc(dev);
679b6d90eb7SKip Macy 
680b6d90eb7SKip Macy 	cxgb_free(sc);
681b6d90eb7SKip Macy 
682b6d90eb7SKip Macy 	return (0);
683b6d90eb7SKip Macy }
684b6d90eb7SKip Macy 
6853cf138bbSGeorge V. Neville-Neil /*
6863cf138bbSGeorge V. Neville-Neil  * The cxgb_free() is called by the cxgb_controller_detach() routine
6873cf138bbSGeorge V. Neville-Neil  * to tear down the structures that were built up in
6883cf138bbSGeorge V. Neville-Neil  * cxgb_controller_attach(), and should be the final piece of work
689c2009a4cSGeorge V. Neville-Neil  * done when fully unloading the driver.
6903cf138bbSGeorge V. Neville-Neil  *
6913cf138bbSGeorge V. Neville-Neil  *
6923cf138bbSGeorge V. Neville-Neil  *  1. Shutting down the threads started by the cxgb_controller_attach()
6933cf138bbSGeorge V. Neville-Neil  *     routine.
6943cf138bbSGeorge V. Neville-Neil  *  2. Stopping the lower level device and all callouts (cxgb_down_locked()).
6953cf138bbSGeorge V. Neville-Neil  *  3. Detaching all of the port devices created during the
6963cf138bbSGeorge V. Neville-Neil  *     cxgb_controller_attach() routine.
6973cf138bbSGeorge V. Neville-Neil  *  4. Removing the device children created via cxgb_controller_attach().
6983cf138bbSGeorge V. Neville-Neil  *  5. Releaseing PCI resources associated with the device.
6993cf138bbSGeorge V. Neville-Neil  *  6. Turning off the offload support, iff it was turned on.
7003cf138bbSGeorge V. Neville-Neil  *  7. Destroying the mutexes created in cxgb_controller_attach().
7013cf138bbSGeorge V. Neville-Neil  *
7023cf138bbSGeorge V. Neville-Neil  */
703b6d90eb7SKip Macy static void
704b6d90eb7SKip Macy cxgb_free(struct adapter *sc)
705b6d90eb7SKip Macy {
706b6d90eb7SKip Macy 	int i;
707b6d90eb7SKip Macy 
7088e10660fSKip Macy 	ADAPTER_LOCK(sc);
7098e10660fSKip Macy 	sc->flags |= CXGB_SHUTDOWN;
7108e10660fSKip Macy 	ADAPTER_UNLOCK(sc);
7118e10660fSKip Macy 
7123cf138bbSGeorge V. Neville-Neil 	cxgb_pcpu_shutdown_threads(sc);
7133cf138bbSGeorge V. Neville-Neil 
7143cf138bbSGeorge V. Neville-Neil 	ADAPTER_LOCK(sc);
715bb38cd2fSKip Macy 	cxgb_down_locked(sc);
7163cf138bbSGeorge V. Neville-Neil 	ADAPTER_UNLOCK(sc);
7173cf138bbSGeorge V. Neville-Neil 
7183cf138bbSGeorge V. Neville-Neil 	t3_sge_deinit_sw(sc);
7193cf138bbSGeorge V. Neville-Neil 	/*
7203cf138bbSGeorge V. Neville-Neil 	 * Wait for last callout
7213cf138bbSGeorge V. Neville-Neil 	 */
7223cf138bbSGeorge V. Neville-Neil 
7233cf138bbSGeorge V. Neville-Neil 	DELAY(hz*100);
7243cf138bbSGeorge V. Neville-Neil 
7253cf138bbSGeorge V. Neville-Neil 	bus_generic_detach(sc->dev);
7263cf138bbSGeorge V. Neville-Neil 
7273cf138bbSGeorge V. Neville-Neil 	for (i = 0; i < (sc)->params.nports; i++) {
728c2009a4cSGeorge V. Neville-Neil 		if (sc->portdev[i] &&
729c2009a4cSGeorge V. Neville-Neil 		    device_delete_child(sc->dev, sc->portdev[i]) != 0)
7303cf138bbSGeorge V. Neville-Neil 			device_printf(sc->dev, "failed to delete child port\n");
7313cf138bbSGeorge V. Neville-Neil 	}
732d722cab4SKip Macy 
733d722cab4SKip Macy #ifdef MSI_SUPPORTED
734d722cab4SKip Macy 	if (sc->flags & (USING_MSI | USING_MSIX)) {
735d722cab4SKip Macy 		device_printf(sc->dev, "releasing msi message(s)\n");
736d722cab4SKip Macy 		pci_release_msi(sc->dev);
737d722cab4SKip Macy 	} else {
738d722cab4SKip Macy 		device_printf(sc->dev, "no msi message to release\n");
739d722cab4SKip Macy 	}
740d722cab4SKip Macy #endif
741d722cab4SKip Macy 	if (sc->msix_regs_res != NULL) {
742d722cab4SKip Macy 		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid,
743d722cab4SKip Macy 		    sc->msix_regs_res);
744d722cab4SKip Macy 	}
745d722cab4SKip Macy 
7468e10660fSKip Macy 	if (sc->tq != NULL) {
7477ac2e6c3SKip Macy 		taskqueue_free(sc->tq);
7488e10660fSKip Macy 		sc->tq = NULL;
7498e10660fSKip Macy 	}
7508e10660fSKip Macy 
751d722cab4SKip Macy 	if (is_offload(sc)) {
752d722cab4SKip Macy 		cxgb_adapter_unofld(sc);
753d722cab4SKip Macy 		if (isset(&sc->open_device_map,	OFFLOAD_DEVMAP_BIT))
754d722cab4SKip Macy 			offload_close(&sc->tdev);
7558090c9f5SKip Macy 		else
7568090c9f5SKip Macy 			printf("cxgb_free: DEVMAP_BIT not set\n");
7578090c9f5SKip Macy 	} else
7588090c9f5SKip Macy 		printf("not offloading set\n");
75946b0a854SKip Macy #ifdef notyet
7608e10660fSKip Macy 	if (sc->flags & CXGB_OFLD_INIT)
7618e10660fSKip Macy 		cxgb_offload_deactivate(sc);
76246b0a854SKip Macy #endif
763ac3a6d9cSKip Macy 	free(sc->filters, M_DEVBUF);
764b6d90eb7SKip Macy 	t3_sge_free(sc);
765b6d90eb7SKip Macy 
766bb38cd2fSKip Macy 	cxgb_offload_exit();
767bb38cd2fSKip Macy 
7688e10660fSKip Macy 	if (sc->udbs_res != NULL)
7698e10660fSKip Macy 		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->udbs_rid,
7708e10660fSKip Macy 		    sc->udbs_res);
7718e10660fSKip Macy 
772b6d90eb7SKip Macy 	if (sc->regs_res != NULL)
773b6d90eb7SKip Macy 		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->regs_rid,
774b6d90eb7SKip Macy 		    sc->regs_res);
775b6d90eb7SKip Macy 
776bb38cd2fSKip Macy 	MTX_DESTROY(&sc->mdio_lock);
777bb38cd2fSKip Macy 	MTX_DESTROY(&sc->sge.reg_lock);
778bb38cd2fSKip Macy 	MTX_DESTROY(&sc->elmer_lock);
779bb38cd2fSKip Macy 	ADAPTER_LOCK_DEINIT(sc);
780b6d90eb7SKip Macy }
781b6d90eb7SKip Macy 
782b6d90eb7SKip Macy /**
783b6d90eb7SKip Macy  *	setup_sge_qsets - configure SGE Tx/Rx/response queues
784b6d90eb7SKip Macy  *	@sc: the controller softc
785b6d90eb7SKip Macy  *
786b6d90eb7SKip Macy  *	Determines how many sets of SGE queues to use and initializes them.
787b6d90eb7SKip Macy  *	We support multiple queue sets per port if we have MSI-X, otherwise
788b6d90eb7SKip Macy  *	just one queue set per port.
789b6d90eb7SKip Macy  */
790b6d90eb7SKip Macy static int
791b6d90eb7SKip Macy setup_sge_qsets(adapter_t *sc)
792b6d90eb7SKip Macy {
7935c5df3daSKip Macy 	int i, j, err, irq_idx = 0, qset_idx = 0;
794d722cab4SKip Macy 	u_int ntxq = SGE_TXQ_PER_SET;
795b6d90eb7SKip Macy 
796b6d90eb7SKip Macy 	if ((err = t3_sge_alloc(sc)) != 0) {
797693d746cSKip Macy 		device_printf(sc->dev, "t3_sge_alloc returned %d\n", err);
798b6d90eb7SKip Macy 		return (err);
799b6d90eb7SKip Macy 	}
800b6d90eb7SKip Macy 
801b6d90eb7SKip Macy 	if (sc->params.rev > 0 && !(sc->flags & USING_MSI))
802b6d90eb7SKip Macy 		irq_idx = -1;
803b6d90eb7SKip Macy 
8045c5df3daSKip Macy 	for (i = 0; i < (sc)->params.nports; i++) {
805b6d90eb7SKip Macy 		struct port_info *pi = &sc->port[i];
806b6d90eb7SKip Macy 
8077ac2e6c3SKip Macy 		for (j = 0; j < pi->nqsets; j++, qset_idx++) {
808693d746cSKip Macy 			err = t3_sge_alloc_qset(sc, qset_idx, (sc)->params.nports,
809b6d90eb7SKip Macy 			    (sc->flags & USING_MSIX) ? qset_idx + 1 : irq_idx,
810b6d90eb7SKip Macy 			    &sc->params.sge.qset[qset_idx], ntxq, pi);
811b6d90eb7SKip Macy 			if (err) {
812b6d90eb7SKip Macy 				t3_free_sge_resources(sc);
8137ac2e6c3SKip Macy 				device_printf(sc->dev, "t3_sge_alloc_qset failed with %d\n",
8147ac2e6c3SKip Macy 				    err);
815b6d90eb7SKip Macy 				return (err);
816b6d90eb7SKip Macy 			}
817b6d90eb7SKip Macy 		}
818b6d90eb7SKip Macy 	}
819b6d90eb7SKip Macy 
820b6d90eb7SKip Macy 	return (0);
821b6d90eb7SKip Macy }
822b6d90eb7SKip Macy 
823ef72318fSKip Macy static void
824ef72318fSKip Macy cxgb_teardown_msix(adapter_t *sc)
825ef72318fSKip Macy {
826ef72318fSKip Macy 	int i, nqsets;
827ef72318fSKip Macy 
828ef72318fSKip Macy 	for (nqsets = i = 0; i < (sc)->params.nports; i++)
829ef72318fSKip Macy 		nqsets += sc->port[i].nqsets;
830ef72318fSKip Macy 
831ef72318fSKip Macy 	for (i = 0; i < nqsets; i++) {
832ef72318fSKip Macy 		if (sc->msix_intr_tag[i] != NULL) {
833ef72318fSKip Macy 			bus_teardown_intr(sc->dev, sc->msix_irq_res[i],
834ef72318fSKip Macy 			    sc->msix_intr_tag[i]);
835ef72318fSKip Macy 			sc->msix_intr_tag[i] = NULL;
836ef72318fSKip Macy 		}
837ef72318fSKip Macy 		if (sc->msix_irq_res[i] != NULL) {
838ef72318fSKip Macy 			bus_release_resource(sc->dev, SYS_RES_IRQ,
839ef72318fSKip Macy 			    sc->msix_irq_rid[i], sc->msix_irq_res[i]);
840ef72318fSKip Macy 			sc->msix_irq_res[i] = NULL;
841ef72318fSKip Macy 		}
842ef72318fSKip Macy 	}
843ef72318fSKip Macy }
844ef72318fSKip Macy 
845b6d90eb7SKip Macy static int
846b6d90eb7SKip Macy cxgb_setup_msix(adapter_t *sc, int msix_count)
847b6d90eb7SKip Macy {
848b6d90eb7SKip Macy 	int i, j, k, nqsets, rid;
849b6d90eb7SKip Macy 
850b6d90eb7SKip Macy 	/* The first message indicates link changes and error conditions */
851b6d90eb7SKip Macy 	sc->irq_rid = 1;
852b6d90eb7SKip Macy 	if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
853b6d90eb7SKip Macy 	   &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
854b6d90eb7SKip Macy 		device_printf(sc->dev, "Cannot allocate msix interrupt\n");
855b6d90eb7SKip Macy 		return (EINVAL);
856b6d90eb7SKip Macy 	}
857693d746cSKip Macy 
858b6d90eb7SKip Macy 	if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET,
859b6d90eb7SKip Macy #ifdef INTR_FILTERS
860b6d90eb7SKip Macy 		NULL,
861b6d90eb7SKip Macy #endif
862b6d90eb7SKip Macy 		cxgb_async_intr, sc, &sc->intr_tag)) {
863b6d90eb7SKip Macy 		device_printf(sc->dev, "Cannot set up interrupt\n");
864b6d90eb7SKip Macy 		return (EINVAL);
865b6d90eb7SKip Macy 	}
866ef72318fSKip Macy 	for (i = k = 0; i < (sc)->params.nports; i++) {
867b6d90eb7SKip Macy 		nqsets = sc->port[i].nqsets;
868ef72318fSKip Macy 		for (j = 0; j < nqsets; j++, k++) {
869b6d90eb7SKip Macy 			struct sge_qset *qs = &sc->sge.qs[k];
870b6d90eb7SKip Macy 
871b6d90eb7SKip Macy 			rid = k + 2;
872b6d90eb7SKip Macy 			if (cxgb_debug)
873b6d90eb7SKip Macy 				printf("rid=%d ", rid);
874b6d90eb7SKip Macy 			if ((sc->msix_irq_res[k] = bus_alloc_resource_any(
875b6d90eb7SKip Macy 			    sc->dev, SYS_RES_IRQ, &rid,
876b6d90eb7SKip Macy 			    RF_SHAREABLE | RF_ACTIVE)) == NULL) {
877b6d90eb7SKip Macy 				device_printf(sc->dev, "Cannot allocate "
878b6d90eb7SKip Macy 				    "interrupt for message %d\n", rid);
879b6d90eb7SKip Macy 				return (EINVAL);
880b6d90eb7SKip Macy 			}
881b6d90eb7SKip Macy 			sc->msix_irq_rid[k] = rid;
882ef72318fSKip Macy 			if (bus_setup_intr(sc->dev, sc->msix_irq_res[k],
883b6d90eb7SKip Macy 				INTR_MPSAFE|INTR_TYPE_NET,
884b6d90eb7SKip Macy #ifdef INTR_FILTERS
885b6d90eb7SKip Macy 				NULL,
886b6d90eb7SKip Macy #endif
887b6d90eb7SKip Macy 				t3_intr_msix, qs, &sc->msix_intr_tag[k])) {
888b6d90eb7SKip Macy 				device_printf(sc->dev, "Cannot set up "
889b6d90eb7SKip Macy 				    "interrupt for message %d\n", rid);
890b6d90eb7SKip Macy 				return (EINVAL);
891a02573bcSKip Macy 
892b6d90eb7SKip Macy 			}
893a02573bcSKip Macy #if 0
8948090c9f5SKip Macy #ifdef IFNET_MULTIQUEUE
895a02573bcSKip Macy 			if (multiq) {
8968090c9f5SKip Macy 				int vector = rman_get_start(sc->msix_irq_res[k]);
8978090c9f5SKip Macy 				if (bootverbose)
8988090c9f5SKip Macy 					device_printf(sc->dev, "binding vector=%d to cpu=%d\n", vector, k % mp_ncpus);
8998090c9f5SKip Macy 				intr_bind(vector, k % mp_ncpus);
9008090c9f5SKip Macy 			}
9018090c9f5SKip Macy #endif
902a02573bcSKip Macy #endif
903b6d90eb7SKip Macy 		}
904b6d90eb7SKip Macy 	}
905693d746cSKip Macy 
906b6d90eb7SKip Macy 	return (0);
907b6d90eb7SKip Macy }
908b6d90eb7SKip Macy 
909b6d90eb7SKip Macy static int
910b6d90eb7SKip Macy cxgb_port_probe(device_t dev)
911b6d90eb7SKip Macy {
912b6d90eb7SKip Macy 	struct port_info *p;
913b6d90eb7SKip Macy 	char buf[80];
9148e10660fSKip Macy 	const char *desc;
915b6d90eb7SKip Macy 
916b6d90eb7SKip Macy 	p = device_get_softc(dev);
9178e10660fSKip Macy 	desc = p->phy.desc;
9188e10660fSKip Macy 	snprintf(buf, sizeof(buf), "Port %d %s", p->port_id, desc);
919b6d90eb7SKip Macy 	device_set_desc_copy(dev, buf);
920b6d90eb7SKip Macy 	return (0);
921b6d90eb7SKip Macy }
922b6d90eb7SKip Macy 
923b6d90eb7SKip Macy 
924b6d90eb7SKip Macy static int
925b6d90eb7SKip Macy cxgb_makedev(struct port_info *pi)
926b6d90eb7SKip Macy {
927b6d90eb7SKip Macy 
928ef72318fSKip Macy 	pi->port_cdev = make_dev(&cxgb_cdevsw, pi->ifp->if_dunit,
929ef72318fSKip Macy 	    UID_ROOT, GID_WHEEL, 0600, if_name(pi->ifp));
930b6d90eb7SKip Macy 
931b6d90eb7SKip Macy 	if (pi->port_cdev == NULL)
932b6d90eb7SKip Macy 		return (ENOMEM);
933b6d90eb7SKip Macy 
934b6d90eb7SKip Macy 	pi->port_cdev->si_drv1 = (void *)pi;
935b6d90eb7SKip Macy 
936b6d90eb7SKip Macy 	return (0);
937b6d90eb7SKip Macy }
938b6d90eb7SKip Macy 
939e97121daSKip Macy #ifndef LRO_SUPPORTED
940e97121daSKip Macy #ifdef IFCAP_LRO
941e97121daSKip Macy #undef IFCAP_LRO
942e97121daSKip Macy #endif
943e97121daSKip Macy #define IFCAP_LRO 0x0
944e97121daSKip Macy #endif
945b6d90eb7SKip Macy 
946b6d90eb7SKip Macy #ifdef TSO_SUPPORTED
94725292debSKip Macy #define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO)
948b6d90eb7SKip Macy /* Don't enable TSO6 yet */
94925292debSKip Macy #define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO4 | IFCAP_JUMBO_MTU | IFCAP_LRO)
950b6d90eb7SKip Macy #else
951b6d90eb7SKip Macy #define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU)
952b6d90eb7SKip Macy /* Don't enable TSO6 yet */
953b6d90eb7SKip Macy #define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM |  IFCAP_JUMBO_MTU)
954b6d90eb7SKip Macy #define IFCAP_TSO4 0x0
9557aff6d8eSKip Macy #define IFCAP_TSO6 0x0
956b6d90eb7SKip Macy #define CSUM_TSO   0x0
957b6d90eb7SKip Macy #endif
958b6d90eb7SKip Macy 
959b6d90eb7SKip Macy 
960b6d90eb7SKip Macy static int
961b6d90eb7SKip Macy cxgb_port_attach(device_t dev)
962b6d90eb7SKip Macy {
963b6d90eb7SKip Macy 	struct port_info *p;
964b6d90eb7SKip Macy 	struct ifnet *ifp;
965ef72318fSKip Macy 	int err, media_flags;
9668e10660fSKip Macy 	struct adapter *sc;
9678e10660fSKip Macy 
968b6d90eb7SKip Macy 
969b6d90eb7SKip Macy 	p = device_get_softc(dev);
9708e10660fSKip Macy 	sc = p->adapter;
971bb38cd2fSKip Macy 	snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d",
9726b68e276SKip Macy 	    device_get_unit(device_get_parent(dev)), p->port_id);
973bb38cd2fSKip Macy 	PORT_LOCK_INIT(p, p->lockbuf);
974b6d90eb7SKip Macy 
975b6d90eb7SKip Macy 	/* Allocate an ifnet object and set it up */
976b6d90eb7SKip Macy 	ifp = p->ifp = if_alloc(IFT_ETHER);
977b6d90eb7SKip Macy 	if (ifp == NULL) {
978b6d90eb7SKip Macy 		device_printf(dev, "Cannot allocate ifnet\n");
979b6d90eb7SKip Macy 		return (ENOMEM);
980b6d90eb7SKip Macy 	}
981b6d90eb7SKip Macy 
982b6d90eb7SKip Macy 	/*
983b6d90eb7SKip Macy 	 * Note that there is currently no watchdog timer.
984b6d90eb7SKip Macy 	 */
985b6d90eb7SKip Macy 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
986b6d90eb7SKip Macy 	ifp->if_init = cxgb_init;
987b6d90eb7SKip Macy 	ifp->if_softc = p;
988b6d90eb7SKip Macy 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
989b6d90eb7SKip Macy 	ifp->if_ioctl = cxgb_ioctl;
990b6d90eb7SKip Macy 	ifp->if_start = cxgb_start;
9918090c9f5SKip Macy 
992a02573bcSKip Macy 
993b6d90eb7SKip Macy 	ifp->if_timer = 0;	/* Disable ifnet watchdog */
994b6d90eb7SKip Macy 	ifp->if_watchdog = NULL;
995b6d90eb7SKip Macy 
996a02573bcSKip Macy 	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
997b6d90eb7SKip Macy 	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
998b6d90eb7SKip Macy 	IFQ_SET_READY(&ifp->if_snd);
999b6d90eb7SKip Macy 
1000b6d90eb7SKip Macy 	ifp->if_hwassist = ifp->if_capabilities = ifp->if_capenable = 0;
1001b6d90eb7SKip Macy 	ifp->if_capabilities |= CXGB_CAP;
1002b6d90eb7SKip Macy 	ifp->if_capenable |= CXGB_CAP_ENABLE;
1003b6d90eb7SKip Macy 	ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO);
1004ac3a6d9cSKip Macy 	/*
1005ac3a6d9cSKip Macy 	 * disable TSO on 4-port - it isn't supported by the firmware yet
1006ac3a6d9cSKip Macy 	 */
1007ac3a6d9cSKip Macy 	if (p->adapter->params.nports > 2) {
1008ac3a6d9cSKip Macy 		ifp->if_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6);
1009ac3a6d9cSKip Macy 		ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TSO6);
1010ac3a6d9cSKip Macy 		ifp->if_hwassist &= ~CSUM_TSO;
1011ac3a6d9cSKip Macy 	}
1012b6d90eb7SKip Macy 
1013b6d90eb7SKip Macy 	ether_ifattach(ifp, p->hw_addr);
10143cf138bbSGeorge V. Neville-Neil 
10155eba27feSKip Macy #ifdef IFNET_MULTIQUEUE
1016a02573bcSKip Macy 	ifp->if_transmit = cxgb_pcpu_transmit;
10175eba27feSKip Macy #endif
1018ac3a6d9cSKip Macy 	/*
1019ac3a6d9cSKip Macy 	 * Only default to jumbo frames on 10GigE
1020ac3a6d9cSKip Macy 	 */
1021ac3a6d9cSKip Macy 	if (p->adapter->params.nports <= 2)
10224af83c8cSKip Macy 		ifp->if_mtu = ETHERMTU_JUMBO;
1023b6d90eb7SKip Macy 	if ((err = cxgb_makedev(p)) != 0) {
1024b6d90eb7SKip Macy 		printf("makedev failed %d\n", err);
1025b6d90eb7SKip Macy 		return (err);
1026b6d90eb7SKip Macy 	}
1027b6d90eb7SKip Macy 	ifmedia_init(&p->media, IFM_IMASK, cxgb_media_change,
1028b6d90eb7SKip Macy 	    cxgb_media_status);
1029b6d90eb7SKip Macy 
10308e10660fSKip Macy 	if (!strcmp(p->phy.desc,	"10GBASE-CX4")) {
1031ef72318fSKip Macy 		media_flags = IFM_ETHER | IFM_10G_CX4 | IFM_FDX;
10328e10660fSKip Macy 	} else if (!strcmp(p->phy.desc, "10GBASE-SR")) {
1033ef72318fSKip Macy 		media_flags = IFM_ETHER | IFM_10G_SR | IFM_FDX;
103419905d6dSKip Macy 	} else if (!strcmp(p->phy.desc, "10GBASE-R")) {
1035837f41b0SGeorge V. Neville-Neil 		media_flags = cxgb_ifm_type(p->phy.modtype);
10368e10660fSKip Macy 	} else if (!strcmp(p->phy.desc, "10/100/1000BASE-T")) {
1037ef72318fSKip Macy 		ifmedia_add(&p->media, IFM_ETHER | IFM_10_T, 0, NULL);
1038ef72318fSKip Macy 		ifmedia_add(&p->media, IFM_ETHER | IFM_10_T | IFM_FDX,
1039ef72318fSKip Macy 			    0, NULL);
1040ef72318fSKip Macy 		ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX,
1041ef72318fSKip Macy 			    0, NULL);
1042ef72318fSKip Macy 		ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX | IFM_FDX,
1043ef72318fSKip Macy 			    0, NULL);
1044ef72318fSKip Macy 		ifmedia_add(&p->media, IFM_ETHER | IFM_1000_T | IFM_FDX,
1045ef72318fSKip Macy 			    0, NULL);
1046ef72318fSKip Macy 		media_flags = 0;
104741509ecdSKip Macy 	} else if (!strcmp(p->phy.desc, "1000BASE-X")) {
104841509ecdSKip Macy 		/*
104941509ecdSKip Macy 		 * XXX: This is not very accurate.  Fix when common code
105041509ecdSKip Macy 		 * returns more specific value - eg 1000BASE-SX, LX, etc.
1051837f41b0SGeorge V. Neville-Neil 		 *
1052837f41b0SGeorge V. Neville-Neil 		 * XXX: In the meantime, don't lie. Consider setting IFM_AUTO
1053837f41b0SGeorge V. Neville-Neil 		 * instead of SX.
105441509ecdSKip Macy 		 */
105541509ecdSKip Macy 		media_flags = IFM_ETHER | IFM_1000_SX | IFM_FDX;
1056ef72318fSKip Macy 	} else {
10578e10660fSKip Macy 	        printf("unsupported media type %s\n", p->phy.desc);
1058b6d90eb7SKip Macy 		return (ENXIO);
1059b6d90eb7SKip Macy 	}
1060ef72318fSKip Macy 	if (media_flags) {
1061837f41b0SGeorge V. Neville-Neil 		/*
1062837f41b0SGeorge V. Neville-Neil 		 * Note the modtype on which we based our flags.  If modtype
1063837f41b0SGeorge V. Neville-Neil 		 * changes, we'll redo the ifmedia for this ifp.  modtype may
1064837f41b0SGeorge V. Neville-Neil 		 * change when transceivers are plugged in/out, and in other
1065837f41b0SGeorge V. Neville-Neil 		 * situations.
1066837f41b0SGeorge V. Neville-Neil 		 */
1067837f41b0SGeorge V. Neville-Neil 		ifmedia_add(&p->media, media_flags, p->phy.modtype, NULL);
1068b6d90eb7SKip Macy 		ifmedia_set(&p->media, media_flags);
1069ef72318fSKip Macy 	} else {
1070ef72318fSKip Macy 		ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL);
1071ef72318fSKip Macy 		ifmedia_set(&p->media, IFM_ETHER | IFM_AUTO);
1072ef72318fSKip Macy 	}
1073ef72318fSKip Macy 
107419905d6dSKip Macy 	/* Get the latest mac address, User can use a LAA */
107519905d6dSKip Macy 	bcopy(IF_LLADDR(p->ifp), p->hw_addr, ETHER_ADDR_LEN);
1076ef72318fSKip Macy 	t3_sge_init_port(p);
1077f2d8ff04SGeorge V. Neville-Neil 
10783cf138bbSGeorge V. Neville-Neil 	/* If it's MSI or INTx, allocate a single interrupt for everything */
10793cf138bbSGeorge V. Neville-Neil 	if ((sc->flags & USING_MSIX) == 0) {
10803cf138bbSGeorge V. Neville-Neil 		if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
10813cf138bbSGeorge V. Neville-Neil 		   &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
10823cf138bbSGeorge V. Neville-Neil 			device_printf(sc->dev, "Cannot allocate interrupt rid=%d\n",
10833cf138bbSGeorge V. Neville-Neil 			    sc->irq_rid);
10843cf138bbSGeorge V. Neville-Neil 			err = EINVAL;
10853cf138bbSGeorge V. Neville-Neil 			goto out;
10863cf138bbSGeorge V. Neville-Neil 		}
10873cf138bbSGeorge V. Neville-Neil 		device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res);
10883cf138bbSGeorge V. Neville-Neil 
10893cf138bbSGeorge V. Neville-Neil 		if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET,
10903cf138bbSGeorge V. Neville-Neil #ifdef INTR_FILTERS
10913cf138bbSGeorge V. Neville-Neil 			NULL,
10923cf138bbSGeorge V. Neville-Neil #endif
10933cf138bbSGeorge V. Neville-Neil 			sc->cxgb_intr, sc, &sc->intr_tag)) {
10943cf138bbSGeorge V. Neville-Neil 			device_printf(sc->dev, "Cannot set up interrupt\n");
10953cf138bbSGeorge V. Neville-Neil 			err = EINVAL;
10963cf138bbSGeorge V. Neville-Neil 			goto irq_err;
10973cf138bbSGeorge V. Neville-Neil 		}
10983cf138bbSGeorge V. Neville-Neil 	} else {
10993cf138bbSGeorge V. Neville-Neil 		cxgb_setup_msix(sc, sc->msi_count);
11003cf138bbSGeorge V. Neville-Neil 	}
11013cf138bbSGeorge V. Neville-Neil 
1102ef027c52SKip Macy #if defined(LINK_ATTACH)
11038e10660fSKip Macy 	cxgb_link_start(p);
11048e10660fSKip Macy 	t3_link_changed(sc, p->port_id);
1105ef027c52SKip Macy #endif
11063cf138bbSGeorge V. Neville-Neil out:
11073cf138bbSGeorge V. Neville-Neil 	return (err);
11083cf138bbSGeorge V. Neville-Neil irq_err:
11093cf138bbSGeorge V. Neville-Neil 	CH_ERR(sc, "request_irq failed, err %d\n", err);
11103cf138bbSGeorge V. Neville-Neil 	goto out;
1111b6d90eb7SKip Macy }
1112b6d90eb7SKip Macy 
11133cf138bbSGeorge V. Neville-Neil /*
11143cf138bbSGeorge V. Neville-Neil  * cxgb_port_detach() is called via the device_detach methods when
11153cf138bbSGeorge V. Neville-Neil  * cxgb_free() calls the bus_generic_detach.  It is responsible for
11163cf138bbSGeorge V. Neville-Neil  * removing the device from the view of the kernel, i.e. from all
11173cf138bbSGeorge V. Neville-Neil  * interfaces lists etc.  This routine is only called when the driver is
11183cf138bbSGeorge V. Neville-Neil  * being unloaded, not when the link goes down.
11193cf138bbSGeorge V. Neville-Neil  *
11203cf138bbSGeorge V. Neville-Neil  */
1121b6d90eb7SKip Macy static int
1122b6d90eb7SKip Macy cxgb_port_detach(device_t dev)
1123b6d90eb7SKip Macy {
1124b6d90eb7SKip Macy 	struct port_info *p;
11253cf138bbSGeorge V. Neville-Neil 	struct adapter *sc;
1126b6d90eb7SKip Macy 
1127b6d90eb7SKip Macy 	p = device_get_softc(dev);
11283cf138bbSGeorge V. Neville-Neil 	sc = p->adapter;
11293cf138bbSGeorge V. Neville-Neil 
11303cf138bbSGeorge V. Neville-Neil 	if (p->port_cdev != NULL)
11313cf138bbSGeorge V. Neville-Neil 		destroy_dev(p->port_cdev);
11323cf138bbSGeorge V. Neville-Neil 
11333cf138bbSGeorge V. Neville-Neil 	ether_ifdetach(p->ifp);
11343cf138bbSGeorge V. Neville-Neil 	printf("waiting for callout to stop ...");
11353cf138bbSGeorge V. Neville-Neil 	printf("done\n");
1136d722cab4SKip Macy 
1137d722cab4SKip Macy 	PORT_LOCK(p);
1138ef72318fSKip Macy 	if (p->ifp->if_drv_flags & IFF_DRV_RUNNING)
1139d722cab4SKip Macy 		cxgb_stop_locked(p);
1140d722cab4SKip Macy 	PORT_UNLOCK(p);
1141d722cab4SKip Macy 
11423cf138bbSGeorge V. Neville-Neil 	if (sc->intr_tag != NULL) {
11433cf138bbSGeorge V. Neville-Neil 		bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag);
11443cf138bbSGeorge V. Neville-Neil 		sc->intr_tag = NULL;
11453cf138bbSGeorge V. Neville-Neil 	}
11463cf138bbSGeorge V. Neville-Neil 	if (sc->irq_res != NULL) {
11473cf138bbSGeorge V. Neville-Neil 		device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n",
11483cf138bbSGeorge V. Neville-Neil 		    sc->irq_rid, sc->irq_res);
11493cf138bbSGeorge V. Neville-Neil 		bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
11503cf138bbSGeorge V. Neville-Neil 		    sc->irq_res);
11513cf138bbSGeorge V. Neville-Neil 		sc->irq_res = NULL;
11523cf138bbSGeorge V. Neville-Neil 	}
11533cf138bbSGeorge V. Neville-Neil 
11543cf138bbSGeorge V. Neville-Neil 	if (sc->flags & USING_MSIX)
11553cf138bbSGeorge V. Neville-Neil 		cxgb_teardown_msix(sc);
11563cf138bbSGeorge V. Neville-Neil 
11573cf138bbSGeorge V. Neville-Neil 	callout_drain(&sc->cxgb_tick_ch);
11583cf138bbSGeorge V. Neville-Neil 	callout_drain(&sc->sge_timer_ch);
11593cf138bbSGeorge V. Neville-Neil 
11603cf138bbSGeorge V. Neville-Neil 	if (sc->tq != NULL) {
11613cf138bbSGeorge V. Neville-Neil 		printf("draining slow intr\n");
11623cf138bbSGeorge V. Neville-Neil 
11633cf138bbSGeorge V. Neville-Neil 		taskqueue_drain(sc->tq, &sc->slow_intr_task);
11643cf138bbSGeorge V. Neville-Neil 			printf("draining ext intr\n");
11653cf138bbSGeorge V. Neville-Neil 		taskqueue_drain(sc->tq, &sc->ext_intr_task);
11663cf138bbSGeorge V. Neville-Neil 		printf("draining tick task\n");
11673cf138bbSGeorge V. Neville-Neil 		taskqueue_drain(sc->tq, &sc->tick_task);
11683cf138bbSGeorge V. Neville-Neil 	}
11693cf138bbSGeorge V. Neville-Neil 
11707ac2e6c3SKip Macy 	/*
11717ac2e6c3SKip Macy 	 * the lock may be acquired in ifdetach
11727ac2e6c3SKip Macy 	 */
11737ac2e6c3SKip Macy 	PORT_LOCK_DEINIT(p);
1174b6d90eb7SKip Macy 	if_free(p->ifp);
1175b6d90eb7SKip Macy 
1176b6d90eb7SKip Macy 	return (0);
1177b6d90eb7SKip Macy }
1178b6d90eb7SKip Macy 
1179b6d90eb7SKip Macy void
1180b6d90eb7SKip Macy t3_fatal_err(struct adapter *sc)
1181b6d90eb7SKip Macy {
1182b6d90eb7SKip Macy 	u_int fw_status[4];
1183b6d90eb7SKip Macy 
11845c5df3daSKip Macy 	if (sc->flags & FULL_INIT_DONE) {
11855c5df3daSKip Macy 		t3_sge_stop(sc);
11865c5df3daSKip Macy 		t3_write_reg(sc, A_XGM_TX_CTRL, 0);
11875c5df3daSKip Macy 		t3_write_reg(sc, A_XGM_RX_CTRL, 0);
11885c5df3daSKip Macy 		t3_write_reg(sc, XGM_REG(A_XGM_TX_CTRL, 1), 0);
11895c5df3daSKip Macy 		t3_write_reg(sc, XGM_REG(A_XGM_RX_CTRL, 1), 0);
11905c5df3daSKip Macy 		t3_intr_disable(sc);
11915c5df3daSKip Macy 	}
1192b6d90eb7SKip Macy 	device_printf(sc->dev,"encountered fatal error, operation suspended\n");
1193b6d90eb7SKip Macy 	if (!t3_cim_ctl_blk_read(sc, 0xa0, 4, fw_status))
1194b6d90eb7SKip Macy 		device_printf(sc->dev, "FW_ status: 0x%x, 0x%x, 0x%x, 0x%x\n",
1195b6d90eb7SKip Macy 		    fw_status[0], fw_status[1], fw_status[2], fw_status[3]);
1196b6d90eb7SKip Macy }
1197b6d90eb7SKip Macy 
1198b6d90eb7SKip Macy int
1199b6d90eb7SKip Macy t3_os_find_pci_capability(adapter_t *sc, int cap)
1200b6d90eb7SKip Macy {
1201b6d90eb7SKip Macy 	device_t dev;
1202b6d90eb7SKip Macy 	struct pci_devinfo *dinfo;
1203b6d90eb7SKip Macy 	pcicfgregs *cfg;
1204b6d90eb7SKip Macy 	uint32_t status;
1205b6d90eb7SKip Macy 	uint8_t ptr;
1206b6d90eb7SKip Macy 
1207b6d90eb7SKip Macy 	dev = sc->dev;
1208b6d90eb7SKip Macy 	dinfo = device_get_ivars(dev);
1209b6d90eb7SKip Macy 	cfg = &dinfo->cfg;
1210b6d90eb7SKip Macy 
1211b6d90eb7SKip Macy 	status = pci_read_config(dev, PCIR_STATUS, 2);
1212b6d90eb7SKip Macy 	if (!(status & PCIM_STATUS_CAPPRESENT))
1213b6d90eb7SKip Macy 		return (0);
1214b6d90eb7SKip Macy 
1215b6d90eb7SKip Macy 	switch (cfg->hdrtype & PCIM_HDRTYPE) {
1216b6d90eb7SKip Macy 	case 0:
1217b6d90eb7SKip Macy 	case 1:
1218b6d90eb7SKip Macy 		ptr = PCIR_CAP_PTR;
1219b6d90eb7SKip Macy 		break;
1220b6d90eb7SKip Macy 	case 2:
1221b6d90eb7SKip Macy 		ptr = PCIR_CAP_PTR_2;
1222b6d90eb7SKip Macy 		break;
1223b6d90eb7SKip Macy 	default:
1224b6d90eb7SKip Macy 		return (0);
1225b6d90eb7SKip Macy 		break;
1226b6d90eb7SKip Macy 	}
1227b6d90eb7SKip Macy 	ptr = pci_read_config(dev, ptr, 1);
1228b6d90eb7SKip Macy 
1229b6d90eb7SKip Macy 	while (ptr != 0) {
1230b6d90eb7SKip Macy 		if (pci_read_config(dev, ptr + PCICAP_ID, 1) == cap)
1231b6d90eb7SKip Macy 			return (ptr);
1232b6d90eb7SKip Macy 		ptr = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1);
1233b6d90eb7SKip Macy 	}
1234b6d90eb7SKip Macy 
1235b6d90eb7SKip Macy 	return (0);
1236b6d90eb7SKip Macy }
1237b6d90eb7SKip Macy 
1238b6d90eb7SKip Macy int
1239b6d90eb7SKip Macy t3_os_pci_save_state(struct adapter *sc)
1240b6d90eb7SKip Macy {
1241b6d90eb7SKip Macy 	device_t dev;
1242b6d90eb7SKip Macy 	struct pci_devinfo *dinfo;
1243b6d90eb7SKip Macy 
1244b6d90eb7SKip Macy 	dev = sc->dev;
1245b6d90eb7SKip Macy 	dinfo = device_get_ivars(dev);
1246b6d90eb7SKip Macy 
1247b6d90eb7SKip Macy 	pci_cfg_save(dev, dinfo, 0);
1248b6d90eb7SKip Macy 	return (0);
1249b6d90eb7SKip Macy }
1250b6d90eb7SKip Macy 
1251b6d90eb7SKip Macy int
1252b6d90eb7SKip Macy t3_os_pci_restore_state(struct adapter *sc)
1253b6d90eb7SKip Macy {
1254b6d90eb7SKip Macy 	device_t dev;
1255b6d90eb7SKip Macy 	struct pci_devinfo *dinfo;
1256b6d90eb7SKip Macy 
1257b6d90eb7SKip Macy 	dev = sc->dev;
1258b6d90eb7SKip Macy 	dinfo = device_get_ivars(dev);
1259b6d90eb7SKip Macy 
1260b6d90eb7SKip Macy 	pci_cfg_restore(dev, dinfo);
1261b6d90eb7SKip Macy 	return (0);
1262b6d90eb7SKip Macy }
1263b6d90eb7SKip Macy 
1264b6d90eb7SKip Macy /**
1265b6d90eb7SKip Macy  *	t3_os_link_changed - handle link status changes
1266b6d90eb7SKip Macy  *	@adapter: the adapter associated with the link change
1267b6d90eb7SKip Macy  *	@port_id: the port index whose limk status has changed
126819905d6dSKip Macy  *	@link_status: the new status of the link
1269b6d90eb7SKip Macy  *	@speed: the new speed setting
1270b6d90eb7SKip Macy  *	@duplex: the new duplex setting
1271b6d90eb7SKip Macy  *	@fc: the new flow-control setting
1272b6d90eb7SKip Macy  *
1273b6d90eb7SKip Macy  *	This is the OS-dependent handler for link status changes.  The OS
1274b6d90eb7SKip Macy  *	neutral handler takes care of most of the processing for these events,
1275b6d90eb7SKip Macy  *	then calls this handler for any OS-specific processing.
1276b6d90eb7SKip Macy  */
1277b6d90eb7SKip Macy void
1278b6d90eb7SKip Macy t3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed,
1279b6d90eb7SKip Macy      int duplex, int fc)
1280b6d90eb7SKip Macy {
1281b6d90eb7SKip Macy 	struct port_info *pi = &adapter->port[port_id];
1282b6d90eb7SKip Macy 
1283d722cab4SKip Macy 	if (link_status) {
12840bbdea77SGeorge V. Neville-Neil 		pi->ifp->if_baudrate = IF_Mbps(speed);
1285f2d8ff04SGeorge V. Neville-Neil 		if_link_state_change(pi->ifp, LINK_STATE_UP);
12860bbdea77SGeorge V. Neville-Neil 	} else
12878e10660fSKip Macy 		if_link_state_change(pi->ifp, LINK_STATE_DOWN);
1288d722cab4SKip Macy }
1289b6d90eb7SKip Macy 
12909b4de886SKip Macy /**
12919b4de886SKip Macy  *	t3_os_phymod_changed - handle PHY module changes
12929b4de886SKip Macy  *	@phy: the PHY reporting the module change
12939b4de886SKip Macy  *	@mod_type: new module type
12949b4de886SKip Macy  *
12959b4de886SKip Macy  *	This is the OS-dependent handler for PHY module changes.  It is
12969b4de886SKip Macy  *	invoked when a PHY module is removed or inserted for any OS-specific
12979b4de886SKip Macy  *	processing.
12989b4de886SKip Macy  */
12999b4de886SKip Macy void t3_os_phymod_changed(struct adapter *adap, int port_id)
13009b4de886SKip Macy {
13019b4de886SKip Macy 	static const char *mod_str[] = {
13029b4de886SKip Macy 		NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown"
13039b4de886SKip Macy 	};
13049b4de886SKip Macy 
13059b4de886SKip Macy 	struct port_info *pi = &adap->port[port_id];
13069b4de886SKip Macy 
13079b4de886SKip Macy 	if (pi->phy.modtype == phy_modtype_none)
13089b4de886SKip Macy 		device_printf(adap->dev, "PHY module unplugged\n");
13099b4de886SKip Macy 	else {
13109b4de886SKip Macy 		KASSERT(pi->phy.modtype < ARRAY_SIZE(mod_str),
13119b4de886SKip Macy 		    ("invalid PHY module type %d", pi->phy.modtype));
13129b4de886SKip Macy 		device_printf(adap->dev, "%s PHY module inserted\n",
13139b4de886SKip Macy 		    mod_str[pi->phy.modtype]);
13149b4de886SKip Macy 	}
13159b4de886SKip Macy }
13169b4de886SKip Macy 
1317b6d90eb7SKip Macy /*
1318b6d90eb7SKip Macy  * Interrupt-context handler for external (PHY) interrupts.
1319b6d90eb7SKip Macy  */
1320b6d90eb7SKip Macy void
1321b6d90eb7SKip Macy t3_os_ext_intr_handler(adapter_t *sc)
1322b6d90eb7SKip Macy {
1323b6d90eb7SKip Macy 	if (cxgb_debug)
1324b6d90eb7SKip Macy 		printf("t3_os_ext_intr_handler\n");
1325b6d90eb7SKip Macy 	/*
1326b6d90eb7SKip Macy 	 * Schedule a task to handle external interrupts as they may be slow
1327b6d90eb7SKip Macy 	 * and we use a mutex to protect MDIO registers.  We disable PHY
1328b6d90eb7SKip Macy 	 * interrupts in the meantime and let the task reenable them when
1329b6d90eb7SKip Macy 	 * it's done.
1330b6d90eb7SKip Macy 	 */
1331d722cab4SKip Macy 	ADAPTER_LOCK(sc);
1332b6d90eb7SKip Macy 	if (sc->slow_intr_mask) {
1333b6d90eb7SKip Macy 		sc->slow_intr_mask &= ~F_T3DBG;
1334b6d90eb7SKip Macy 		t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
1335b6d90eb7SKip Macy 		taskqueue_enqueue(sc->tq, &sc->ext_intr_task);
1336b6d90eb7SKip Macy 	}
1337d722cab4SKip Macy 	ADAPTER_UNLOCK(sc);
1338b6d90eb7SKip Macy }
1339b6d90eb7SKip Macy 
1340b6d90eb7SKip Macy void
1341b6d90eb7SKip Macy t3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[])
1342b6d90eb7SKip Macy {
1343b6d90eb7SKip Macy 
1344b6d90eb7SKip Macy 	/*
1345b6d90eb7SKip Macy 	 * The ifnet might not be allocated before this gets called,
1346b6d90eb7SKip Macy 	 * as this is called early on in attach by t3_prep_adapter
1347b6d90eb7SKip Macy 	 * save the address off in the port structure
1348b6d90eb7SKip Macy 	 */
1349b6d90eb7SKip Macy 	if (cxgb_debug)
1350b6d90eb7SKip Macy 		printf("set_hw_addr on idx %d addr %6D\n", port_idx, hw_addr, ":");
1351b6d90eb7SKip Macy 	bcopy(hw_addr, adapter->port[port_idx].hw_addr, ETHER_ADDR_LEN);
1352b6d90eb7SKip Macy }
1353b6d90eb7SKip Macy 
1354b6d90eb7SKip Macy /**
1355b6d90eb7SKip Macy  *	link_start - enable a port
1356b6d90eb7SKip Macy  *	@p: the port to enable
1357b6d90eb7SKip Macy  *
1358b6d90eb7SKip Macy  *	Performs the MAC and PHY actions needed to enable a port.
1359b6d90eb7SKip Macy  */
1360b6d90eb7SKip Macy static void
1361b6d90eb7SKip Macy cxgb_link_start(struct port_info *p)
1362b6d90eb7SKip Macy {
1363b6d90eb7SKip Macy 	struct ifnet *ifp;
1364b6d90eb7SKip Macy 	struct t3_rx_mode rm;
1365b6d90eb7SKip Macy 	struct cmac *mac = &p->mac;
13664af83c8cSKip Macy 	int mtu, hwtagging;
1367b6d90eb7SKip Macy 
1368b6d90eb7SKip Macy 	ifp = p->ifp;
1369b6d90eb7SKip Macy 
13704af83c8cSKip Macy 	bcopy(IF_LLADDR(ifp), p->hw_addr, ETHER_ADDR_LEN);
13714af83c8cSKip Macy 
13724af83c8cSKip Macy 	mtu = ifp->if_mtu;
13734af83c8cSKip Macy 	if (ifp->if_capenable & IFCAP_VLAN_MTU)
13744af83c8cSKip Macy 		mtu += ETHER_VLAN_ENCAP_LEN;
13754af83c8cSKip Macy 
13764af83c8cSKip Macy 	hwtagging = (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0;
13774af83c8cSKip Macy 
1378b6d90eb7SKip Macy 	t3_init_rx_mode(&rm, p);
13797ac2e6c3SKip Macy 	if (!mac->multiport)
1380b6d90eb7SKip Macy 		t3_mac_reset(mac);
13814af83c8cSKip Macy 	t3_mac_set_mtu(mac, mtu);
13824af83c8cSKip Macy 	t3_set_vlan_accel(p->adapter, 1 << p->tx_chan, hwtagging);
1383b6d90eb7SKip Macy 	t3_mac_set_address(mac, 0, p->hw_addr);
1384b6d90eb7SKip Macy 	t3_mac_set_rx_mode(mac, &rm);
1385b6d90eb7SKip Macy 	t3_link_start(&p->phy, mac, &p->link_config);
1386b6d90eb7SKip Macy 	t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
1387b6d90eb7SKip Macy }
1388b6d90eb7SKip Macy 
13898e10660fSKip Macy 
13908e10660fSKip Macy static int
13918e10660fSKip Macy await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
13928e10660fSKip Macy 			      unsigned long n)
13938e10660fSKip Macy {
13948e10660fSKip Macy 	int attempts = 5;
13958e10660fSKip Macy 
13968e10660fSKip Macy 	while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
13978e10660fSKip Macy 		if (!--attempts)
13988e10660fSKip Macy 			return (ETIMEDOUT);
13998e10660fSKip Macy 		t3_os_sleep(10);
14008e10660fSKip Macy 	}
14018e10660fSKip Macy 	return 0;
14028e10660fSKip Macy }
14038e10660fSKip Macy 
14048e10660fSKip Macy static int
14058e10660fSKip Macy init_tp_parity(struct adapter *adap)
14068e10660fSKip Macy {
14078e10660fSKip Macy 	int i;
14088e10660fSKip Macy 	struct mbuf *m;
14098e10660fSKip Macy 	struct cpl_set_tcb_field *greq;
14108e10660fSKip Macy 	unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts;
14118e10660fSKip Macy 
14128e10660fSKip Macy 	t3_tp_set_offload_mode(adap, 1);
14138e10660fSKip Macy 
14148e10660fSKip Macy 	for (i = 0; i < 16; i++) {
14158e10660fSKip Macy 		struct cpl_smt_write_req *req;
14168e10660fSKip Macy 
14178e10660fSKip Macy 		m = m_gethdr(M_WAITOK, MT_DATA);
14188e10660fSKip Macy 		req = mtod(m, struct cpl_smt_write_req *);
14198e10660fSKip Macy 		m->m_len = m->m_pkthdr.len = sizeof(*req);
14208e10660fSKip Macy 		memset(req, 0, sizeof(*req));
14218e10660fSKip Macy 		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
14228e10660fSKip Macy 		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
14238e10660fSKip Macy 		req->iff = i;
14248e10660fSKip Macy 		t3_mgmt_tx(adap, m);
14258e10660fSKip Macy 	}
14268e10660fSKip Macy 
14278e10660fSKip Macy 	for (i = 0; i < 2048; i++) {
14288e10660fSKip Macy 		struct cpl_l2t_write_req *req;
14298e10660fSKip Macy 
14308e10660fSKip Macy 		m = m_gethdr(M_WAITOK, MT_DATA);
14318e10660fSKip Macy 		req = mtod(m, struct cpl_l2t_write_req *);
14328e10660fSKip Macy 		m->m_len = m->m_pkthdr.len = sizeof(*req);
14338e10660fSKip Macy 		memset(req, 0, sizeof(*req));
14348e10660fSKip Macy 		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
14358e10660fSKip Macy 		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
14368e10660fSKip Macy 		req->params = htonl(V_L2T_W_IDX(i));
14378e10660fSKip Macy 		t3_mgmt_tx(adap, m);
14388e10660fSKip Macy 	}
14398e10660fSKip Macy 
14408e10660fSKip Macy 	for (i = 0; i < 2048; i++) {
14418e10660fSKip Macy 		struct cpl_rte_write_req *req;
14428e10660fSKip Macy 
14438e10660fSKip Macy 		m = m_gethdr(M_WAITOK, MT_DATA);
14448e10660fSKip Macy 		req = mtod(m, struct cpl_rte_write_req *);
14458e10660fSKip Macy 		m->m_len = m->m_pkthdr.len = sizeof(*req);
14468e10660fSKip Macy 		memset(req, 0, sizeof(*req));
14478e10660fSKip Macy 		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
14488e10660fSKip Macy 		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
14498e10660fSKip Macy 		req->l2t_idx = htonl(V_L2T_W_IDX(i));
14508e10660fSKip Macy 		t3_mgmt_tx(adap, m);
14518e10660fSKip Macy 	}
14528e10660fSKip Macy 
14538e10660fSKip Macy 	m = m_gethdr(M_WAITOK, MT_DATA);
14548e10660fSKip Macy 	greq = mtod(m, struct cpl_set_tcb_field *);
14558e10660fSKip Macy 	m->m_len = m->m_pkthdr.len = sizeof(*greq);
14568e10660fSKip Macy 	memset(greq, 0, sizeof(*greq));
14578e10660fSKip Macy 	greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
14588e10660fSKip Macy 	OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0));
14598e10660fSKip Macy 	greq->mask = htobe64(1);
14608e10660fSKip Macy 	t3_mgmt_tx(adap, m);
14618e10660fSKip Macy 
14628e10660fSKip Macy 	i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
14638e10660fSKip Macy 	t3_tp_set_offload_mode(adap, 0);
14648e10660fSKip Macy 	return (i);
14658e10660fSKip Macy }
14668e10660fSKip Macy 
1467b6d90eb7SKip Macy /**
1468b6d90eb7SKip Macy  *	setup_rss - configure Receive Side Steering (per-queue connection demux)
1469b6d90eb7SKip Macy  *	@adap: the adapter
1470b6d90eb7SKip Macy  *
1471b6d90eb7SKip Macy  *	Sets up RSS to distribute packets to multiple receive queues.  We
1472b6d90eb7SKip Macy  *	configure the RSS CPU lookup table to distribute to the number of HW
1473b6d90eb7SKip Macy  *	receive queues, and the response queue lookup table to narrow that
1474b6d90eb7SKip Macy  *	down to the response queues actually configured for each port.
1475b6d90eb7SKip Macy  *	We always configure the RSS mapping for two ports since the mapping
1476b6d90eb7SKip Macy  *	table has plenty of entries.
1477b6d90eb7SKip Macy  */
1478b6d90eb7SKip Macy static void
1479b6d90eb7SKip Macy setup_rss(adapter_t *adap)
1480b6d90eb7SKip Macy {
1481b6d90eb7SKip Macy 	int i;
1482ac3a6d9cSKip Macy 	u_int nq[2];
1483b6d90eb7SKip Macy 	uint8_t cpus[SGE_QSETS + 1];
1484b6d90eb7SKip Macy 	uint16_t rspq_map[RSS_TABLE_SIZE];
14855c5df3daSKip Macy 
1486b6d90eb7SKip Macy 	for (i = 0; i < SGE_QSETS; ++i)
1487b6d90eb7SKip Macy 		cpus[i] = i;
1488b6d90eb7SKip Macy 	cpus[SGE_QSETS] = 0xff;
1489b6d90eb7SKip Macy 
14907ac2e6c3SKip Macy 	nq[0] = nq[1] = 0;
14917ac2e6c3SKip Macy 	for_each_port(adap, i) {
14927ac2e6c3SKip Macy 		const struct port_info *pi = adap2pinfo(adap, i);
14937ac2e6c3SKip Macy 
14947ac2e6c3SKip Macy 		nq[pi->tx_chan] += pi->nqsets;
14957ac2e6c3SKip Macy 	}
1496b6d90eb7SKip Macy 	for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
14978e10660fSKip Macy 		rspq_map[i] = nq[0] ? i % nq[0] : 0;
14988e10660fSKip Macy 		rspq_map[i + RSS_TABLE_SIZE / 2] = nq[1] ? i % nq[1] + nq[0] : 0;
1499b6d90eb7SKip Macy 	}
1500ac3a6d9cSKip Macy 	/* Calculate the reverse RSS map table */
1501ac3a6d9cSKip Macy 	for (i = 0; i < RSS_TABLE_SIZE; ++i)
1502ac3a6d9cSKip Macy 		if (adap->rrss_map[rspq_map[i]] == 0xff)
1503ac3a6d9cSKip Macy 			adap->rrss_map[rspq_map[i]] = i;
1504b6d90eb7SKip Macy 
1505b6d90eb7SKip Macy 	t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
1506ac3a6d9cSKip Macy 		      F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | F_OFDMAPEN |
15078e10660fSKip Macy 	              F_RRCPLMAPEN | V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ,
15088e10660fSKip Macy 	              cpus, rspq_map);
1509ac3a6d9cSKip Macy 
1510b6d90eb7SKip Macy }
1511b6d90eb7SKip Macy 
1512d722cab4SKip Macy /*
1513d722cab4SKip Macy  * Sends an mbuf to an offload queue driver
1514d722cab4SKip Macy  * after dealing with any active network taps.
1515d722cab4SKip Macy  */
1516d722cab4SKip Macy static inline int
15173e96c7e7SKip Macy offload_tx(struct t3cdev *tdev, struct mbuf *m)
1518d722cab4SKip Macy {
1519d722cab4SKip Macy 	int ret;
1520d722cab4SKip Macy 
1521d722cab4SKip Macy 	ret = t3_offload_tx(tdev, m);
1522ef72318fSKip Macy 	return (ret);
1523d722cab4SKip Macy }
1524d722cab4SKip Macy 
1525d722cab4SKip Macy static int
1526d722cab4SKip Macy write_smt_entry(struct adapter *adapter, int idx)
1527d722cab4SKip Macy {
1528d722cab4SKip Macy 	struct port_info *pi = &adapter->port[idx];
1529d722cab4SKip Macy 	struct cpl_smt_write_req *req;
1530d722cab4SKip Macy 	struct mbuf *m;
1531d722cab4SKip Macy 
1532d722cab4SKip Macy 	if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
1533d722cab4SKip Macy 		return (ENOMEM);
1534d722cab4SKip Macy 
1535d722cab4SKip Macy 	req = mtod(m, struct cpl_smt_write_req *);
15368090c9f5SKip Macy 	m->m_pkthdr.len = m->m_len = sizeof(struct cpl_smt_write_req);
15378090c9f5SKip Macy 
1538d722cab4SKip Macy 	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1539d722cab4SKip Macy 	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
1540d722cab4SKip Macy 	req->mtu_idx = NMTUS - 1;  /* should be 0 but there's a T3 bug */
1541d722cab4SKip Macy 	req->iff = idx;
1542d722cab4SKip Macy 	memset(req->src_mac1, 0, sizeof(req->src_mac1));
1543d722cab4SKip Macy 	memcpy(req->src_mac0, pi->hw_addr, ETHER_ADDR_LEN);
1544d722cab4SKip Macy 
1545d722cab4SKip Macy 	m_set_priority(m, 1);
1546d722cab4SKip Macy 
1547d722cab4SKip Macy 	offload_tx(&adapter->tdev, m);
1548d722cab4SKip Macy 
1549d722cab4SKip Macy 	return (0);
1550d722cab4SKip Macy }
1551d722cab4SKip Macy 
1552d722cab4SKip Macy static int
1553d722cab4SKip Macy init_smt(struct adapter *adapter)
1554d722cab4SKip Macy {
1555d722cab4SKip Macy 	int i;
1556d722cab4SKip Macy 
1557d722cab4SKip Macy 	for_each_port(adapter, i)
1558d722cab4SKip Macy 		write_smt_entry(adapter, i);
1559d722cab4SKip Macy 	return 0;
1560d722cab4SKip Macy }
1561d722cab4SKip Macy 
1562d722cab4SKip Macy static void
1563d722cab4SKip Macy init_port_mtus(adapter_t *adapter)
1564d722cab4SKip Macy {
1565d722cab4SKip Macy 	unsigned int mtus = adapter->port[0].ifp->if_mtu;
1566d722cab4SKip Macy 
1567d722cab4SKip Macy 	if (adapter->port[1].ifp)
1568d722cab4SKip Macy 		mtus |= adapter->port[1].ifp->if_mtu << 16;
1569d722cab4SKip Macy 	t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
1570d722cab4SKip Macy }
1571d722cab4SKip Macy 
1572b6d90eb7SKip Macy static void
1573b6d90eb7SKip Macy send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
1574b6d90eb7SKip Macy 			      int hi, int port)
1575b6d90eb7SKip Macy {
1576b6d90eb7SKip Macy 	struct mbuf *m;
1577b6d90eb7SKip Macy 	struct mngt_pktsched_wr *req;
1578b6d90eb7SKip Macy 
1579ac3a6d9cSKip Macy 	m = m_gethdr(M_DONTWAIT, MT_DATA);
158020fe52b8SKip Macy 	if (m) {
1581d722cab4SKip Macy 		req = mtod(m, struct mngt_pktsched_wr *);
1582b6d90eb7SKip Macy 		req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
1583b6d90eb7SKip Macy 		req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
1584b6d90eb7SKip Macy 		req->sched = sched;
1585b6d90eb7SKip Macy 		req->idx = qidx;
1586b6d90eb7SKip Macy 		req->min = lo;
1587b6d90eb7SKip Macy 		req->max = hi;
1588b6d90eb7SKip Macy 		req->binding = port;
1589b6d90eb7SKip Macy 		m->m_len = m->m_pkthdr.len = sizeof(*req);
1590b6d90eb7SKip Macy 		t3_mgmt_tx(adap, m);
1591b6d90eb7SKip Macy 	}
159220fe52b8SKip Macy }
1593b6d90eb7SKip Macy 
1594b6d90eb7SKip Macy static void
1595b6d90eb7SKip Macy bind_qsets(adapter_t *sc)
1596b6d90eb7SKip Macy {
1597b6d90eb7SKip Macy 	int i, j;
1598b6d90eb7SKip Macy 
15998090c9f5SKip Macy 	cxgb_pcpu_startup_threads(sc);
1600b6d90eb7SKip Macy 	for (i = 0; i < (sc)->params.nports; ++i) {
1601b6d90eb7SKip Macy 		const struct port_info *pi = adap2pinfo(sc, i);
1602b6d90eb7SKip Macy 
16035c5df3daSKip Macy 		for (j = 0; j < pi->nqsets; ++j) {
1604b6d90eb7SKip Macy 			send_pktsched_cmd(sc, 1, pi->first_qset + j, -1,
16055c5df3daSKip Macy 					  -1, pi->tx_chan);
16065c5df3daSKip Macy 
16075c5df3daSKip Macy 		}
1608b6d90eb7SKip Macy 	}
1609b6d90eb7SKip Macy }
1610b6d90eb7SKip Macy 
1611ac3a6d9cSKip Macy static void
1612ac3a6d9cSKip Macy update_tpeeprom(struct adapter *adap)
1613ac3a6d9cSKip Macy {
16142de1fa86SKip Macy #ifdef FIRMWARE_LATEST
1615ac3a6d9cSKip Macy 	const struct firmware *tpeeprom;
16162de1fa86SKip Macy #else
16172de1fa86SKip Macy 	struct firmware *tpeeprom;
16182de1fa86SKip Macy #endif
16192de1fa86SKip Macy 
1620ac3a6d9cSKip Macy 	uint32_t version;
1621ac3a6d9cSKip Macy 	unsigned int major, minor;
1622ac3a6d9cSKip Macy 	int ret, len;
1623f2d8ff04SGeorge V. Neville-Neil 	char rev, name[32];
1624ac3a6d9cSKip Macy 
1625ac3a6d9cSKip Macy 	t3_seeprom_read(adap, TP_SRAM_OFFSET, &version);
1626ac3a6d9cSKip Macy 
1627ac3a6d9cSKip Macy 	major = G_TP_VERSION_MAJOR(version);
1628ac3a6d9cSKip Macy 	minor = G_TP_VERSION_MINOR(version);
1629ac3a6d9cSKip Macy 	if (major == TP_VERSION_MAJOR  && minor == TP_VERSION_MINOR)
1630ac3a6d9cSKip Macy 		return;
1631ac3a6d9cSKip Macy 
1632ac3a6d9cSKip Macy 	rev = t3rev2char(adap);
1633f2d8ff04SGeorge V. Neville-Neil 	snprintf(name, sizeof(name), TPEEPROM_NAME, rev);
1634ac3a6d9cSKip Macy 
1635f2d8ff04SGeorge V. Neville-Neil 	tpeeprom = firmware_get(name);
1636ac3a6d9cSKip Macy 	if (tpeeprom == NULL) {
16370c1ff9c6SGeorge V. Neville-Neil 		device_printf(adap->dev,
16380c1ff9c6SGeorge V. Neville-Neil 			      "could not load TP EEPROM: unable to load %s\n",
16390c1ff9c6SGeorge V. Neville-Neil 			      name);
1640ac3a6d9cSKip Macy 		return;
1641ac3a6d9cSKip Macy 	}
1642ac3a6d9cSKip Macy 
1643ac3a6d9cSKip Macy 	len = tpeeprom->datasize - 4;
1644ac3a6d9cSKip Macy 
1645ac3a6d9cSKip Macy 	ret = t3_check_tpsram(adap, tpeeprom->data, tpeeprom->datasize);
1646ac3a6d9cSKip Macy 	if (ret)
1647ac3a6d9cSKip Macy 		goto release_tpeeprom;
1648ac3a6d9cSKip Macy 
1649ac3a6d9cSKip Macy 	if (len != TP_SRAM_LEN) {
16500c1ff9c6SGeorge V. Neville-Neil 		device_printf(adap->dev,
16510c1ff9c6SGeorge V. Neville-Neil 			      "%s length is wrong len=%d expected=%d\n", name,
16520c1ff9c6SGeorge V. Neville-Neil 			      len, TP_SRAM_LEN);
1653ac3a6d9cSKip Macy 		return;
1654ac3a6d9cSKip Macy 	}
1655ac3a6d9cSKip Macy 
1656ac3a6d9cSKip Macy 	ret = set_eeprom(&adap->port[0], tpeeprom->data, tpeeprom->datasize,
1657ac3a6d9cSKip Macy 	    TP_SRAM_OFFSET);
1658ac3a6d9cSKip Macy 
1659ac3a6d9cSKip Macy 	if (!ret) {
1660ac3a6d9cSKip Macy 		device_printf(adap->dev,
1661ac3a6d9cSKip Macy 			"Protocol SRAM image updated in EEPROM to %d.%d.%d\n",
1662ac3a6d9cSKip Macy 			 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1663ac3a6d9cSKip Macy 	} else
16640c1ff9c6SGeorge V. Neville-Neil 		device_printf(adap->dev,
16650c1ff9c6SGeorge V. Neville-Neil 			      "Protocol SRAM image update in EEPROM failed\n");
1666ac3a6d9cSKip Macy 
1667ac3a6d9cSKip Macy release_tpeeprom:
1668ac3a6d9cSKip Macy 	firmware_put(tpeeprom, FIRMWARE_UNLOAD);
1669ac3a6d9cSKip Macy 
1670ac3a6d9cSKip Macy 	return;
1671ac3a6d9cSKip Macy }
1672ac3a6d9cSKip Macy 
1673ac3a6d9cSKip Macy static int
1674ac3a6d9cSKip Macy update_tpsram(struct adapter *adap)
1675ac3a6d9cSKip Macy {
16762de1fa86SKip Macy #ifdef FIRMWARE_LATEST
1677ac3a6d9cSKip Macy 	const struct firmware *tpsram;
16782de1fa86SKip Macy #else
16792de1fa86SKip Macy 	struct firmware *tpsram;
16802de1fa86SKip Macy #endif
1681ac3a6d9cSKip Macy 	int ret;
1682f2d8ff04SGeorge V. Neville-Neil 	char rev, name[32];
1683ac3a6d9cSKip Macy 
1684ac3a6d9cSKip Macy 	rev = t3rev2char(adap);
1685f2d8ff04SGeorge V. Neville-Neil 	snprintf(name, sizeof(name), TPSRAM_NAME, rev);
1686ac3a6d9cSKip Macy 
1687ac3a6d9cSKip Macy 	update_tpeeprom(adap);
1688ac3a6d9cSKip Macy 
1689f2d8ff04SGeorge V. Neville-Neil 	tpsram = firmware_get(name);
1690ac3a6d9cSKip Macy 	if (tpsram == NULL){
169164a37133SKip Macy 		device_printf(adap->dev, "could not load TP SRAM\n");
1692ac3a6d9cSKip Macy 		return (EINVAL);
1693ac3a6d9cSKip Macy 	} else
169464a37133SKip Macy 		device_printf(adap->dev, "updating TP SRAM\n");
1695ac3a6d9cSKip Macy 
1696ac3a6d9cSKip Macy 	ret = t3_check_tpsram(adap, tpsram->data, tpsram->datasize);
1697ac3a6d9cSKip Macy 	if (ret)
1698ac3a6d9cSKip Macy 		goto release_tpsram;
1699ac3a6d9cSKip Macy 
1700ac3a6d9cSKip Macy 	ret = t3_set_proto_sram(adap, tpsram->data);
1701ac3a6d9cSKip Macy 	if (ret)
1702ac3a6d9cSKip Macy 		device_printf(adap->dev, "loading protocol SRAM failed\n");
1703ac3a6d9cSKip Macy 
1704ac3a6d9cSKip Macy release_tpsram:
1705ac3a6d9cSKip Macy 	firmware_put(tpsram, FIRMWARE_UNLOAD);
1706ac3a6d9cSKip Macy 
1707ac3a6d9cSKip Macy 	return ret;
1708ac3a6d9cSKip Macy }
1709ac3a6d9cSKip Macy 
1710d722cab4SKip Macy /**
1711d722cab4SKip Macy  *	cxgb_up - enable the adapter
1712d722cab4SKip Macy  *	@adap: adapter being enabled
1713d722cab4SKip Macy  *
1714d722cab4SKip Macy  *	Called when the first port is enabled, this function performs the
1715d722cab4SKip Macy  *	actions necessary to make an adapter operational, such as completing
1716d722cab4SKip Macy  *	the initialization of HW modules, and enabling interrupts.
1717d722cab4SKip Macy  */
1718d722cab4SKip Macy static int
1719d722cab4SKip Macy cxgb_up(struct adapter *sc)
1720d722cab4SKip Macy {
1721d722cab4SKip Macy 	int err = 0;
1722d722cab4SKip Macy 
1723d722cab4SKip Macy 	if ((sc->flags & FULL_INIT_DONE) == 0) {
1724d722cab4SKip Macy 
1725d722cab4SKip Macy 		if ((sc->flags & FW_UPTODATE) == 0)
1726ac3a6d9cSKip Macy 			if ((err = upgrade_fw(sc)))
1727d722cab4SKip Macy 				goto out;
1728ac3a6d9cSKip Macy 		if ((sc->flags & TPS_UPTODATE) == 0)
1729ac3a6d9cSKip Macy 			if ((err = update_tpsram(sc)))
1730ac3a6d9cSKip Macy 				goto out;
1731d722cab4SKip Macy 		err = t3_init_hw(sc, 0);
1732d722cab4SKip Macy 		if (err)
1733d722cab4SKip Macy 			goto out;
1734d722cab4SKip Macy 
17358e10660fSKip Macy 		t3_set_reg_field(sc, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT);
1736d722cab4SKip Macy 		t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
1737d722cab4SKip Macy 
1738d722cab4SKip Macy 		err = setup_sge_qsets(sc);
1739d722cab4SKip Macy 		if (err)
1740d722cab4SKip Macy 			goto out;
1741d722cab4SKip Macy 
1742d722cab4SKip Macy 		setup_rss(sc);
17438090c9f5SKip Macy 		t3_add_configured_sysctls(sc);
1744d722cab4SKip Macy 		sc->flags |= FULL_INIT_DONE;
1745d722cab4SKip Macy 	}
1746d722cab4SKip Macy 
1747d722cab4SKip Macy 	t3_intr_clear(sc);
1748d722cab4SKip Macy 
1749d722cab4SKip Macy 	t3_sge_start(sc);
1750d722cab4SKip Macy 	t3_intr_enable(sc);
1751d722cab4SKip Macy 
17528e10660fSKip Macy 	if (sc->params.rev >= T3_REV_C && !(sc->flags & TP_PARITY_INIT) &&
17538e10660fSKip Macy 	    is_offload(sc) && init_tp_parity(sc) == 0)
17548e10660fSKip Macy 		sc->flags |= TP_PARITY_INIT;
17558e10660fSKip Macy 
17568e10660fSKip Macy 	if (sc->flags & TP_PARITY_INIT) {
17578e10660fSKip Macy 		t3_write_reg(sc, A_TP_INT_CAUSE,
17588e10660fSKip Macy 				F_CMCACHEPERR | F_ARPLUTPERR);
17598e10660fSKip Macy 		t3_write_reg(sc, A_TP_INT_ENABLE, 0x7fbfffff);
17608e10660fSKip Macy 	}
17618e10660fSKip Macy 
17628e10660fSKip Macy 
17635c5df3daSKip Macy 	if (!(sc->flags & QUEUES_BOUND)) {
1764d722cab4SKip Macy 		bind_qsets(sc);
1765d722cab4SKip Macy 		sc->flags |= QUEUES_BOUND;
1766ac3a6d9cSKip Macy 	}
1767d722cab4SKip Macy out:
1768d722cab4SKip Macy 	return (err);
1769d722cab4SKip Macy }
1770d722cab4SKip Macy 
1771d722cab4SKip Macy 
1772d722cab4SKip Macy /*
1773c2009a4cSGeorge V. Neville-Neil  * Bring down the interface but do not free any resources.
1774d722cab4SKip Macy  */
1775d722cab4SKip Macy static void
1776bb38cd2fSKip Macy cxgb_down_locked(struct adapter *sc)
1777d722cab4SKip Macy {
1778d722cab4SKip Macy 
1779d722cab4SKip Macy 	t3_sge_stop(sc);
1780d722cab4SKip Macy 	t3_intr_disable(sc);
1781d722cab4SKip Macy 
17828090c9f5SKip Macy 	callout_stop(&sc->cxgb_tick_ch);
17838090c9f5SKip Macy 	callout_stop(&sc->sge_timer_ch);
1784d722cab4SKip Macy }
1785d722cab4SKip Macy 
1786d722cab4SKip Macy static int
1787d722cab4SKip Macy offload_open(struct port_info *pi)
1788d722cab4SKip Macy {
1789d722cab4SKip Macy 	struct adapter *adapter = pi->adapter;
17908090c9f5SKip Macy 	struct t3cdev *tdev = &adapter->tdev;
1791af9b081cSKip Macy 
1792d722cab4SKip Macy 	int adap_up = adapter->open_device_map & PORT_MASK;
1793d722cab4SKip Macy 	int err = 0;
1794d722cab4SKip Macy 
1795d722cab4SKip Macy 	if (atomic_cmpset_int(&adapter->open_device_map,
17968090c9f5SKip Macy 		(adapter->open_device_map & ~(1<<OFFLOAD_DEVMAP_BIT)),
17978090c9f5SKip Macy 		(adapter->open_device_map | (1<<OFFLOAD_DEVMAP_BIT))) == 0)
1798d722cab4SKip Macy 		return (0);
1799d722cab4SKip Macy 
18008090c9f5SKip Macy 	if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT))
1801af9b081cSKip Macy 		printf("offload_open: DEVMAP_BIT did not get set 0x%x\n",
1802af9b081cSKip Macy 		    adapter->open_device_map);
1803d722cab4SKip Macy 	ADAPTER_LOCK(pi->adapter);
1804d722cab4SKip Macy 	if (!adap_up)
1805d722cab4SKip Macy 		err = cxgb_up(adapter);
1806d722cab4SKip Macy 	ADAPTER_UNLOCK(pi->adapter);
1807ac3a6d9cSKip Macy 	if (err)
1808d722cab4SKip Macy 		return (err);
1809d722cab4SKip Macy 
1810d722cab4SKip Macy 	t3_tp_set_offload_mode(adapter, 1);
18118090c9f5SKip Macy 	tdev->lldev = pi->ifp;
1812d722cab4SKip Macy 
1813d722cab4SKip Macy 	init_port_mtus(adapter);
1814d722cab4SKip Macy 	t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
1815d722cab4SKip Macy 		     adapter->params.b_wnd,
1816d722cab4SKip Macy 		     adapter->params.rev == 0 ?
1817d722cab4SKip Macy 		       adapter->port[0].ifp->if_mtu : 0xffff);
1818d722cab4SKip Macy 	init_smt(adapter);
1819ed0fb18dSKip Macy 	/* Call back all registered clients */
1820ed0fb18dSKip Macy 	cxgb_add_clients(tdev);
1821ed0fb18dSKip Macy 
1822d722cab4SKip Macy 	/* restore them in case the offload module has changed them */
1823d722cab4SKip Macy 	if (err) {
1824d722cab4SKip Macy 		t3_tp_set_offload_mode(adapter, 0);
1825d722cab4SKip Macy 		clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT);
1826d722cab4SKip Macy 		cxgb_set_dummy_ops(tdev);
1827d722cab4SKip Macy 	}
1828d722cab4SKip Macy 	return (err);
1829d722cab4SKip Macy }
18308090c9f5SKip Macy 
1831d722cab4SKip Macy static int
18328090c9f5SKip Macy offload_close(struct t3cdev *tdev)
1833d722cab4SKip Macy {
1834d722cab4SKip Macy 	struct adapter *adapter = tdev2adap(tdev);
1835d722cab4SKip Macy 
18368e10660fSKip Macy 	if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT))
1837ef72318fSKip Macy 		return (0);
1838d722cab4SKip Macy 
1839ed0fb18dSKip Macy 	/* Call back all registered clients */
1840ed0fb18dSKip Macy 	cxgb_remove_clients(tdev);
1841ed0fb18dSKip Macy 
1842d722cab4SKip Macy 	tdev->lldev = NULL;
1843d722cab4SKip Macy 	cxgb_set_dummy_ops(tdev);
1844d722cab4SKip Macy 	t3_tp_set_offload_mode(adapter, 0);
1845d722cab4SKip Macy 	clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT);
1846d722cab4SKip Macy 
18478090c9f5SKip Macy 	ADAPTER_LOCK(adapter);
1848d722cab4SKip Macy 	if (!adapter->open_device_map)
18498090c9f5SKip Macy 		cxgb_down_locked(adapter);
18503cf138bbSGeorge V. Neville-Neil 
18518090c9f5SKip Macy 	ADAPTER_UNLOCK(adapter);
18523cf138bbSGeorge V. Neville-Neil 
1853ef72318fSKip Macy 	return (0);
1854d722cab4SKip Macy }
18558090c9f5SKip Macy 
1856d722cab4SKip Macy 
1857b6d90eb7SKip Macy static void
1858b6d90eb7SKip Macy cxgb_init(void *arg)
1859b6d90eb7SKip Macy {
1860b6d90eb7SKip Macy 	struct port_info *p = arg;
1861b6d90eb7SKip Macy 
1862b6d90eb7SKip Macy 	PORT_LOCK(p);
1863b6d90eb7SKip Macy 	cxgb_init_locked(p);
1864b6d90eb7SKip Macy 	PORT_UNLOCK(p);
1865b6d90eb7SKip Macy }
1866b6d90eb7SKip Macy 
1867b6d90eb7SKip Macy static void
1868b6d90eb7SKip Macy cxgb_init_locked(struct port_info *p)
1869b6d90eb7SKip Macy {
1870b6d90eb7SKip Macy 	struct ifnet *ifp;
1871b6d90eb7SKip Macy 	adapter_t *sc = p->adapter;
1872d722cab4SKip Macy 	int err;
1873b6d90eb7SKip Macy 
1874bb38cd2fSKip Macy 	PORT_LOCK_ASSERT_OWNED(p);
1875b6d90eb7SKip Macy 	ifp = p->ifp;
1876d722cab4SKip Macy 
1877d722cab4SKip Macy 	ADAPTER_LOCK(p->adapter);
1878ac3a6d9cSKip Macy 	if ((sc->open_device_map == 0) && (err = cxgb_up(sc))) {
1879d722cab4SKip Macy 		ADAPTER_UNLOCK(p->adapter);
1880d722cab4SKip Macy 		cxgb_stop_locked(p);
1881b6d90eb7SKip Macy 		return;
1882b6d90eb7SKip Macy 	}
1883bb38cd2fSKip Macy 	if (p->adapter->open_device_map == 0) {
1884b6d90eb7SKip Macy 		t3_intr_clear(sc);
1885bb38cd2fSKip Macy 	}
18866b68e276SKip Macy 	setbit(&p->adapter->open_device_map, p->port_id);
1887b6d90eb7SKip Macy 	ADAPTER_UNLOCK(p->adapter);
1888ef72318fSKip Macy 
1889d722cab4SKip Macy 	if (is_offload(sc) && !ofld_disable) {
1890d722cab4SKip Macy 		err = offload_open(p);
1891d722cab4SKip Macy 		if (err)
1892d722cab4SKip Macy 			log(LOG_WARNING,
1893d722cab4SKip Macy 			    "Could not initialize offload capabilities\n");
1894d722cab4SKip Macy 	}
18950bbdea77SGeorge V. Neville-Neil 
18960bbdea77SGeorge V. Neville-Neil 	device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id);
18970bbdea77SGeorge V. Neville-Neil 	t3_port_intr_enable(sc, p->port_id);
18980bbdea77SGeorge V. Neville-Neil 
1899ef027c52SKip Macy #if !defined(LINK_ATTACH)
1900ef027c52SKip Macy 	cxgb_link_start(p);
1901ef027c52SKip Macy 	t3_link_changed(sc, p->port_id);
1902ef027c52SKip Macy #endif
1903837f41b0SGeorge V. Neville-Neil 	ifp->if_baudrate = IF_Mbps(p->link_config.speed);
1904ef72318fSKip Macy 
19056b6e256aSGeorge V. Neville-Neil  	callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc);
19069330dbc3SKip Macy 	t3_sge_reset_adapter(sc);
1907b6d90eb7SKip Macy 
1908c2009a4cSGeorge V. Neville-Neil 	sc->flags &= ~CXGB_SHUTDOWN;
1909b6d90eb7SKip Macy 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1910b6d90eb7SKip Macy 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1911b6d90eb7SKip Macy }
1912b6d90eb7SKip Macy 
1913b6d90eb7SKip Macy static void
1914b6d90eb7SKip Macy cxgb_set_rxmode(struct port_info *p)
1915b6d90eb7SKip Macy {
1916b6d90eb7SKip Macy 	struct t3_rx_mode rm;
1917b6d90eb7SKip Macy 	struct cmac *mac = &p->mac;
1918b6d90eb7SKip Macy 
1919b6d90eb7SKip Macy 	t3_init_rx_mode(&rm, p);
19208e10660fSKip Macy 	mtx_lock(&p->adapter->mdio_lock);
1921b6d90eb7SKip Macy 	t3_mac_set_rx_mode(mac, &rm);
19228e10660fSKip Macy 	mtx_unlock(&p->adapter->mdio_lock);
1923b6d90eb7SKip Macy }
1924b6d90eb7SKip Macy 
1925b6d90eb7SKip Macy static void
192619905d6dSKip Macy cxgb_stop_locked(struct port_info *pi)
1927b6d90eb7SKip Macy {
1928b6d90eb7SKip Macy 	struct ifnet *ifp;
1929c2009a4cSGeorge V. Neville-Neil 	adapter_t *sc = pi->adapter;
1930b6d90eb7SKip Macy 
193119905d6dSKip Macy 	PORT_LOCK_ASSERT_OWNED(pi);
193219905d6dSKip Macy 	ADAPTER_LOCK_ASSERT_NOTOWNED(pi->adapter);
193377f07749SKip Macy 
1934c2009a4cSGeorge V. Neville-Neil 	sc->flags |= CXGB_SHUTDOWN;
1935c2009a4cSGeorge V. Neville-Neil 
193619905d6dSKip Macy 	ifp = pi->ifp;
193719905d6dSKip Macy 	t3_port_intr_disable(pi->adapter, pi->port_id);
1938d722cab4SKip Macy 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1939b6d90eb7SKip Macy 
194019905d6dSKip Macy 	/* disable pause frames */
194119905d6dSKip Macy 	t3_set_reg_field(pi->adapter, A_XGM_TX_CFG + pi->mac.offset,
194219905d6dSKip Macy 			 F_TXPAUSEEN, 0);
1943bb38cd2fSKip Macy 
194419905d6dSKip Macy 	/* Reset RX FIFO HWM */
194519905d6dSKip Macy         t3_set_reg_field(pi->adapter, A_XGM_RXFIFO_CFG +  pi->mac.offset,
194619905d6dSKip Macy 			 V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM), 0);
194719905d6dSKip Macy 
194819905d6dSKip Macy 
194919905d6dSKip Macy 	ADAPTER_LOCK(pi->adapter);
195019905d6dSKip Macy 	clrbit(&pi->adapter->open_device_map, pi->port_id);
195119905d6dSKip Macy 
19523cf138bbSGeorge V. Neville-Neil 	if (pi->adapter->open_device_map == 0)
195319905d6dSKip Macy 		cxgb_down_locked(pi->adapter);
19543cf138bbSGeorge V. Neville-Neil 
195519905d6dSKip Macy 	ADAPTER_UNLOCK(pi->adapter);
195619905d6dSKip Macy 
1957ef027c52SKip Macy #if !defined(LINK_ATTACH)
195819905d6dSKip Macy 	DELAY(100);
195919905d6dSKip Macy 
196019905d6dSKip Macy 	/* Wait for TXFIFO empty */
196119905d6dSKip Macy 	t3_wait_op_done(pi->adapter, A_XGM_TXFIFO_CFG + pi->mac.offset,
196219905d6dSKip Macy 			F_TXFIFO_EMPTY, 1, 20, 5);
196319905d6dSKip Macy 
196419905d6dSKip Macy 	DELAY(100);
196519905d6dSKip Macy 	t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
196619905d6dSKip Macy 
196719905d6dSKip Macy 	pi->phy.ops->power_down(&pi->phy, 1);
1968ef027c52SKip Macy #endif
1969bb38cd2fSKip Macy 
1970b6d90eb7SKip Macy }
1971b6d90eb7SKip Macy 
1972b6d90eb7SKip Macy static int
1973ef72318fSKip Macy cxgb_set_mtu(struct port_info *p, int mtu)
1974ef72318fSKip Macy {
1975ef72318fSKip Macy 	struct ifnet *ifp = p->ifp;
1976ef72318fSKip Macy 	int error = 0;
1977ef72318fSKip Macy 
19784af83c8cSKip Macy 	if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO))
1979ef72318fSKip Macy 		error = EINVAL;
1980ef72318fSKip Macy 	else if (ifp->if_mtu != mtu) {
1981ef72318fSKip Macy 		PORT_LOCK(p);
1982ef72318fSKip Macy 		ifp->if_mtu = mtu;
1983ef72318fSKip Macy 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1984ef72318fSKip Macy 			cxgb_stop_locked(p);
1985ef72318fSKip Macy 			cxgb_init_locked(p);
1986ef72318fSKip Macy 		}
1987ef72318fSKip Macy 		PORT_UNLOCK(p);
1988ef72318fSKip Macy 	}
1989ef72318fSKip Macy 	return (error);
1990ef72318fSKip Macy }
1991ef72318fSKip Macy 
1992e97121daSKip Macy #ifdef LRO_SUPPORTED
199325292debSKip Macy /*
199425292debSKip Macy  * Mark lro enabled or disabled in all qsets for this port
199525292debSKip Macy  */
199625292debSKip Macy static int
199725292debSKip Macy cxgb_set_lro(struct port_info *p, int enabled)
199825292debSKip Macy {
199925292debSKip Macy 	int i;
200025292debSKip Macy 	struct adapter *adp = p->adapter;
200125292debSKip Macy 	struct sge_qset *q;
200225292debSKip Macy 
200325292debSKip Macy 	PORT_LOCK_ASSERT_OWNED(p);
200425292debSKip Macy 	for (i = 0; i < p->nqsets; i++) {
200525292debSKip Macy 		q = &adp->sge.qs[p->first_qset + i];
200625292debSKip Macy 		q->lro.enabled = (enabled != 0);
200725292debSKip Macy 	}
200825292debSKip Macy 	return (0);
200925292debSKip Macy }
2010e97121daSKip Macy #endif
201125292debSKip Macy 
2012ef72318fSKip Macy static int
2013b6d90eb7SKip Macy cxgb_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data)
2014b6d90eb7SKip Macy {
2015b6d90eb7SKip Macy 	struct port_info *p = ifp->if_softc;
201634627f93SBjoern A. Zeeb #ifdef INET
2017b6d90eb7SKip Macy 	struct ifaddr *ifa = (struct ifaddr *)data;
201834627f93SBjoern A. Zeeb #endif
2019b6d90eb7SKip Macy 	struct ifreq *ifr = (struct ifreq *)data;
20204af83c8cSKip Macy 	int flags, error = 0, reinit = 0;
2021b6d90eb7SKip Macy 	uint32_t mask;
2022b6d90eb7SKip Macy 
202351580731SKip Macy 	/*
202451580731SKip Macy 	 * XXX need to check that we aren't in the middle of an unload
202551580731SKip Macy 	 */
2026b6d90eb7SKip Macy 	switch (command) {
2027b6d90eb7SKip Macy 	case SIOCSIFMTU:
2028ef72318fSKip Macy 		error = cxgb_set_mtu(p, ifr->ifr_mtu);
2029b6d90eb7SKip Macy 		break;
2030b6d90eb7SKip Macy 	case SIOCSIFADDR:
203134627f93SBjoern A. Zeeb #ifdef INET
2032b6d90eb7SKip Macy 		if (ifa->ifa_addr->sa_family == AF_INET) {
2033b6d90eb7SKip Macy 			ifp->if_flags |= IFF_UP;
20348e10660fSKip Macy 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
20358e10660fSKip Macy 				PORT_LOCK(p);
2036ef72318fSKip Macy 				cxgb_init_locked(p);
20374f6a96aeSKip Macy 				PORT_UNLOCK(p);
20388e10660fSKip Macy 			}
20398e10660fSKip Macy 			arp_ifinit(ifp, ifa);
2040b6d90eb7SKip Macy 		} else
204134627f93SBjoern A. Zeeb #endif
2042b6d90eb7SKip Macy 			error = ether_ioctl(ifp, command, data);
2043b6d90eb7SKip Macy 		break;
2044b6d90eb7SKip Macy 	case SIOCSIFFLAGS:
2045693d746cSKip Macy 		PORT_LOCK(p);
2046ef72318fSKip Macy 		if (ifp->if_flags & IFF_UP) {
2047b6d90eb7SKip Macy 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2048b6d90eb7SKip Macy 				flags = p->if_flags;
2049b6d90eb7SKip Macy 				if (((ifp->if_flags ^ flags) & IFF_PROMISC) ||
2050b6d90eb7SKip Macy 				    ((ifp->if_flags ^ flags) & IFF_ALLMULTI))
2051b6d90eb7SKip Macy 					cxgb_set_rxmode(p);
2052b6d90eb7SKip Macy 			} else
2053b6d90eb7SKip Macy 				cxgb_init_locked(p);
2054b6d90eb7SKip Macy 			p->if_flags = ifp->if_flags;
2055bb38cd2fSKip Macy 		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2056693d746cSKip Macy 			cxgb_stop_locked(p);
2057bb38cd2fSKip Macy 
2058ef72318fSKip Macy 		PORT_UNLOCK(p);
2059b6d90eb7SKip Macy 		break;
20608e10660fSKip Macy 	case SIOCADDMULTI:
20618e10660fSKip Macy 	case SIOCDELMULTI:
20628e10660fSKip Macy 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
20638e10660fSKip Macy 			cxgb_set_rxmode(p);
20648e10660fSKip Macy 		}
20658e10660fSKip Macy 		break;
2066b6d90eb7SKip Macy 	case SIOCSIFMEDIA:
2067b6d90eb7SKip Macy 	case SIOCGIFMEDIA:
2068837f41b0SGeorge V. Neville-Neil 		PORT_LOCK(p);
2069b6d90eb7SKip Macy 		error = ifmedia_ioctl(ifp, ifr, &p->media, command);
2070837f41b0SGeorge V. Neville-Neil 		PORT_UNLOCK(p);
2071b6d90eb7SKip Macy 		break;
2072b6d90eb7SKip Macy 	case SIOCSIFCAP:
2073b6d90eb7SKip Macy 		PORT_LOCK(p);
2074b6d90eb7SKip Macy 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
2075b6d90eb7SKip Macy 		if (mask & IFCAP_TXCSUM) {
2076b6d90eb7SKip Macy 			if (IFCAP_TXCSUM & ifp->if_capenable) {
2077b6d90eb7SKip Macy 				ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4);
2078b6d90eb7SKip Macy 				ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP
20794af83c8cSKip Macy 				    | CSUM_IP | CSUM_TSO);
2080b6d90eb7SKip Macy 			} else {
2081b6d90eb7SKip Macy 				ifp->if_capenable |= IFCAP_TXCSUM;
20824af83c8cSKip Macy 				ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP
20834af83c8cSKip Macy 				    | CSUM_IP);
2084b6d90eb7SKip Macy 			}
2085b6d90eb7SKip Macy 		}
20864af83c8cSKip Macy 		if (mask & IFCAP_RXCSUM) {
20874af83c8cSKip Macy 			ifp->if_capenable ^= IFCAP_RXCSUM;
2088b6d90eb7SKip Macy 		}
2089b6d90eb7SKip Macy 		if (mask & IFCAP_TSO4) {
2090b6d90eb7SKip Macy 			if (IFCAP_TSO4 & ifp->if_capenable) {
2091b6d90eb7SKip Macy 				ifp->if_capenable &= ~IFCAP_TSO4;
2092b6d90eb7SKip Macy 				ifp->if_hwassist &= ~CSUM_TSO;
2093b6d90eb7SKip Macy 			} else if (IFCAP_TXCSUM & ifp->if_capenable) {
2094b6d90eb7SKip Macy 				ifp->if_capenable |= IFCAP_TSO4;
2095b6d90eb7SKip Macy 				ifp->if_hwassist |= CSUM_TSO;
2096b6d90eb7SKip Macy 			} else {
2097b6d90eb7SKip Macy 				if (cxgb_debug)
2098b6d90eb7SKip Macy 					printf("cxgb requires tx checksum offload"
2099b6d90eb7SKip Macy 					    " be enabled to use TSO\n");
2100b6d90eb7SKip Macy 				error = EINVAL;
2101b6d90eb7SKip Macy 			}
2102b6d90eb7SKip Macy 		}
2103e97121daSKip Macy #ifdef LRO_SUPPORTED
210425292debSKip Macy 		if (mask & IFCAP_LRO) {
210525292debSKip Macy 			ifp->if_capenable ^= IFCAP_LRO;
210625292debSKip Macy 
210725292debSKip Macy 			/* Safe to do this even if cxgb_up not called yet */
210825292debSKip Macy 			cxgb_set_lro(p, ifp->if_capenable & IFCAP_LRO);
210925292debSKip Macy 		}
2110e97121daSKip Macy #endif
21114af83c8cSKip Macy 		if (mask & IFCAP_VLAN_HWTAGGING) {
21124af83c8cSKip Macy 			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
21134af83c8cSKip Macy 			reinit = ifp->if_drv_flags & IFF_DRV_RUNNING;
21144af83c8cSKip Macy 		}
21154af83c8cSKip Macy 		if (mask & IFCAP_VLAN_MTU) {
21164af83c8cSKip Macy 			ifp->if_capenable ^= IFCAP_VLAN_MTU;
21174af83c8cSKip Macy 			reinit = ifp->if_drv_flags & IFF_DRV_RUNNING;
21184af83c8cSKip Macy 		}
21194af83c8cSKip Macy 		if (mask & IFCAP_VLAN_HWCSUM) {
21204af83c8cSKip Macy 			ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
21214af83c8cSKip Macy 		}
21224af83c8cSKip Macy 		if (reinit) {
21234af83c8cSKip Macy 			cxgb_stop_locked(p);
21244af83c8cSKip Macy 			cxgb_init_locked(p);
21254af83c8cSKip Macy 		}
2126b6d90eb7SKip Macy 		PORT_UNLOCK(p);
21274af83c8cSKip Macy 
21284af83c8cSKip Macy #ifdef VLAN_CAPABILITIES
21294af83c8cSKip Macy 		VLAN_CAPABILITIES(ifp);
21304af83c8cSKip Macy #endif
2131b6d90eb7SKip Macy 		break;
2132b6d90eb7SKip Macy 	default:
2133b6d90eb7SKip Macy 		error = ether_ioctl(ifp, command, data);
2134b6d90eb7SKip Macy 		break;
2135b6d90eb7SKip Macy 	}
2136b6d90eb7SKip Macy 	return (error);
2137b6d90eb7SKip Macy }
2138b6d90eb7SKip Macy 
2139b6d90eb7SKip Macy static int
2140b6d90eb7SKip Macy cxgb_media_change(struct ifnet *ifp)
2141b6d90eb7SKip Macy {
2142b6d90eb7SKip Macy 	if_printf(ifp, "media change not supported\n");
2143b6d90eb7SKip Macy 	return (ENXIO);
2144b6d90eb7SKip Macy }
2145b6d90eb7SKip Macy 
2146837f41b0SGeorge V. Neville-Neil /*
2147837f41b0SGeorge V. Neville-Neil  * Translates from phy->modtype to IFM_TYPE.
2148837f41b0SGeorge V. Neville-Neil  */
2149837f41b0SGeorge V. Neville-Neil static int
2150837f41b0SGeorge V. Neville-Neil cxgb_ifm_type(int phymod)
2151837f41b0SGeorge V. Neville-Neil {
2152837f41b0SGeorge V. Neville-Neil 	int rc = IFM_ETHER | IFM_FDX;
2153837f41b0SGeorge V. Neville-Neil 
2154837f41b0SGeorge V. Neville-Neil 	switch (phymod) {
2155837f41b0SGeorge V. Neville-Neil 	case phy_modtype_sr:
2156837f41b0SGeorge V. Neville-Neil 		rc |= IFM_10G_SR;
2157837f41b0SGeorge V. Neville-Neil 		break;
2158837f41b0SGeorge V. Neville-Neil 	case phy_modtype_lr:
2159837f41b0SGeorge V. Neville-Neil 		rc |= IFM_10G_LR;
2160837f41b0SGeorge V. Neville-Neil 		break;
2161837f41b0SGeorge V. Neville-Neil 	case phy_modtype_lrm:
2162837f41b0SGeorge V. Neville-Neil #ifdef IFM_10G_LRM
2163837f41b0SGeorge V. Neville-Neil 		rc |= IFM_10G_LRM;
2164837f41b0SGeorge V. Neville-Neil #endif
2165837f41b0SGeorge V. Neville-Neil 		break;
2166837f41b0SGeorge V. Neville-Neil 	case phy_modtype_twinax:
2167837f41b0SGeorge V. Neville-Neil #ifdef IFM_10G_TWINAX
2168837f41b0SGeorge V. Neville-Neil 		rc |= IFM_10G_TWINAX;
2169837f41b0SGeorge V. Neville-Neil #endif
2170837f41b0SGeorge V. Neville-Neil 		break;
2171837f41b0SGeorge V. Neville-Neil 	case phy_modtype_twinax_long:
2172837f41b0SGeorge V. Neville-Neil #ifdef IFM_10G_TWINAX_LONG
2173837f41b0SGeorge V. Neville-Neil 		rc |= IFM_10G_TWINAX_LONG;
2174837f41b0SGeorge V. Neville-Neil #endif
2175837f41b0SGeorge V. Neville-Neil 		break;
2176837f41b0SGeorge V. Neville-Neil 	case phy_modtype_none:
2177837f41b0SGeorge V. Neville-Neil 		rc = IFM_ETHER | IFM_NONE;
2178837f41b0SGeorge V. Neville-Neil 		break;
2179837f41b0SGeorge V. Neville-Neil 	case phy_modtype_unknown:
2180837f41b0SGeorge V. Neville-Neil 		break;
2181837f41b0SGeorge V. Neville-Neil 	}
2182837f41b0SGeorge V. Neville-Neil 
2183837f41b0SGeorge V. Neville-Neil 	return (rc);
2184837f41b0SGeorge V. Neville-Neil }
2185837f41b0SGeorge V. Neville-Neil 
2186b6d90eb7SKip Macy static void
2187b6d90eb7SKip Macy cxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
2188b6d90eb7SKip Macy {
2189b6d90eb7SKip Macy 	struct port_info *p = ifp->if_softc;
2190837f41b0SGeorge V. Neville-Neil 	struct ifmedia_entry *cur = p->media.ifm_cur;
2191837f41b0SGeorge V. Neville-Neil 	int m;
2192837f41b0SGeorge V. Neville-Neil 
2193837f41b0SGeorge V. Neville-Neil 	if (cur->ifm_data != p->phy.modtype) {
2194837f41b0SGeorge V. Neville-Neil 		/* p->media about to be rebuilt, must hold lock */
2195837f41b0SGeorge V. Neville-Neil 		PORT_LOCK_ASSERT_OWNED(p);
2196837f41b0SGeorge V. Neville-Neil 
2197837f41b0SGeorge V. Neville-Neil 		m = cxgb_ifm_type(p->phy.modtype);
2198837f41b0SGeorge V. Neville-Neil 		ifmedia_removeall(&p->media);
2199837f41b0SGeorge V. Neville-Neil 		ifmedia_add(&p->media, m, p->phy.modtype, NULL);
2200837f41b0SGeorge V. Neville-Neil 		ifmedia_set(&p->media, m);
2201837f41b0SGeorge V. Neville-Neil 		cur = p->media.ifm_cur; /* ifmedia_set modified ifm_cur */
2202837f41b0SGeorge V. Neville-Neil 		ifmr->ifm_current = m;
2203837f41b0SGeorge V. Neville-Neil 	}
2204b6d90eb7SKip Macy 
2205b6d90eb7SKip Macy 	ifmr->ifm_status = IFM_AVALID;
2206b6d90eb7SKip Macy 	ifmr->ifm_active = IFM_ETHER;
2207b6d90eb7SKip Macy 
2208b6d90eb7SKip Macy 	if (!p->link_config.link_ok)
2209b6d90eb7SKip Macy 		return;
2210b6d90eb7SKip Macy 
2211b6d90eb7SKip Macy 	ifmr->ifm_status |= IFM_ACTIVE;
2212b6d90eb7SKip Macy 
2213ef72318fSKip Macy 	switch (p->link_config.speed) {
2214ef72318fSKip Macy 	case 10:
2215ef72318fSKip Macy 		ifmr->ifm_active |= IFM_10_T;
2216ef72318fSKip Macy 		break;
2217ef72318fSKip Macy 	case 100:
2218ef72318fSKip Macy 		ifmr->ifm_active |= IFM_100_TX;
2219ef72318fSKip Macy 			break;
2220ef72318fSKip Macy 	case 1000:
2221ef72318fSKip Macy 		ifmr->ifm_active |= IFM_1000_T;
2222ef72318fSKip Macy 		break;
2223837f41b0SGeorge V. Neville-Neil 	case 10000:
2224837f41b0SGeorge V. Neville-Neil 		ifmr->ifm_active |= IFM_SUBTYPE(cur->ifm_media);
2225837f41b0SGeorge V. Neville-Neil 		break;
2226ef72318fSKip Macy 	}
2227ef72318fSKip Macy 
2228b6d90eb7SKip Macy 	if (p->link_config.duplex)
2229b6d90eb7SKip Macy 		ifmr->ifm_active |= IFM_FDX;
2230b6d90eb7SKip Macy 	else
2231b6d90eb7SKip Macy 		ifmr->ifm_active |= IFM_HDX;
2232b6d90eb7SKip Macy }
2233b6d90eb7SKip Macy 
2234b6d90eb7SKip Macy static void
2235b6d90eb7SKip Macy cxgb_async_intr(void *data)
2236b6d90eb7SKip Macy {
2237693d746cSKip Macy 	adapter_t *sc = data;
2238693d746cSKip Macy 
2239b6d90eb7SKip Macy 	if (cxgb_debug)
2240693d746cSKip Macy 		device_printf(sc->dev, "cxgb_async_intr\n");
2241bb38cd2fSKip Macy 	/*
2242bb38cd2fSKip Macy 	 * May need to sleep - defer to taskqueue
2243bb38cd2fSKip Macy 	 */
2244bb38cd2fSKip Macy 	taskqueue_enqueue(sc->tq, &sc->slow_intr_task);
2245b6d90eb7SKip Macy }
2246b6d90eb7SKip Macy 
2247b6d90eb7SKip Macy static void
2248b6d90eb7SKip Macy cxgb_ext_intr_handler(void *arg, int count)
2249b6d90eb7SKip Macy {
2250b6d90eb7SKip Macy 	adapter_t *sc = (adapter_t *)arg;
2251b6d90eb7SKip Macy 
2252b6d90eb7SKip Macy 	if (cxgb_debug)
2253b6d90eb7SKip Macy 		printf("cxgb_ext_intr_handler\n");
2254b6d90eb7SKip Macy 
2255b6d90eb7SKip Macy 	t3_phy_intr_handler(sc);
2256b6d90eb7SKip Macy 
2257b6d90eb7SKip Macy 	/* Now reenable external interrupts */
2258d722cab4SKip Macy 	ADAPTER_LOCK(sc);
2259b6d90eb7SKip Macy 	if (sc->slow_intr_mask) {
2260b6d90eb7SKip Macy 		sc->slow_intr_mask |= F_T3DBG;
2261b6d90eb7SKip Macy 		t3_write_reg(sc, A_PL_INT_CAUSE0, F_T3DBG);
2262b6d90eb7SKip Macy 		t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
2263b6d90eb7SKip Macy 	}
2264d722cab4SKip Macy 	ADAPTER_UNLOCK(sc);
2265b6d90eb7SKip Macy }
2266b6d90eb7SKip Macy 
2267b6d90eb7SKip Macy static void
2268b6d90eb7SKip Macy check_link_status(adapter_t *sc)
2269b6d90eb7SKip Macy {
2270b6d90eb7SKip Macy 	int i;
2271b6d90eb7SKip Macy 
22720bbdea77SGeorge V. Neville-Neil 	/* For synchronized access to open_device_map */
22730bbdea77SGeorge V. Neville-Neil 	ADAPTER_LOCK_ASSERT_OWNED(sc);
22740bbdea77SGeorge V. Neville-Neil 
2275b6d90eb7SKip Macy 	for (i = 0; i < (sc)->params.nports; ++i) {
2276b6d90eb7SKip Macy 		struct port_info *p = &sc->port[i];
22770bbdea77SGeorge V. Neville-Neil 		struct link_config *lc = &p->link_config;
2278b6d90eb7SKip Macy 
22790bbdea77SGeorge V. Neville-Neil 		if (!isset(&sc->open_device_map, p->port_id)) {
22800bbdea77SGeorge V. Neville-Neil 			/*
22810bbdea77SGeorge V. Neville-Neil 			 * port is down, report link down too.  Note
22820bbdea77SGeorge V. Neville-Neil 			 * that we do this for IRQ based PHYs too.
22830bbdea77SGeorge V. Neville-Neil 			 */
22840bbdea77SGeorge V. Neville-Neil 			lc->link_ok = 0;
22850bbdea77SGeorge V. Neville-Neil 			t3_os_link_changed(sc, i, lc->link_ok, lc->speed,
22860bbdea77SGeorge V. Neville-Neil 					   lc->duplex, lc->fc);
22870bbdea77SGeorge V. Neville-Neil 		} else if (p->link_fault || !(p->phy.caps & SUPPORTED_IRQ))
2288b6d90eb7SKip Macy 			t3_link_changed(sc, i);
2289b6d90eb7SKip Macy 	}
2290b6d90eb7SKip Macy }
2291b6d90eb7SKip Macy 
2292577e9bbeSKip Macy static void
2293577e9bbeSKip Macy check_t3b2_mac(struct adapter *adapter)
2294577e9bbeSKip Macy {
2295577e9bbeSKip Macy 	int i;
2296577e9bbeSKip Macy 
22978e10660fSKip Macy 	if(adapter->flags & CXGB_SHUTDOWN)
22988e10660fSKip Macy 		return;
22998e10660fSKip Macy 
2300577e9bbeSKip Macy 	for_each_port(adapter, i) {
2301577e9bbeSKip Macy 		struct port_info *p = &adapter->port[i];
2302577e9bbeSKip Macy 		struct ifnet *ifp = p->ifp;
2303577e9bbeSKip Macy 		int status;
2304577e9bbeSKip Macy 
23058e10660fSKip Macy 		if(adapter->flags & CXGB_SHUTDOWN)
23068e10660fSKip Macy 			return;
23078e10660fSKip Macy 
2308577e9bbeSKip Macy 		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
2309577e9bbeSKip Macy 			continue;
2310577e9bbeSKip Macy 
2311577e9bbeSKip Macy 		status = 0;
2312577e9bbeSKip Macy 		PORT_LOCK(p);
2313577e9bbeSKip Macy 		if ((ifp->if_drv_flags & IFF_DRV_RUNNING))
2314577e9bbeSKip Macy 			status = t3b2_mac_watchdog_task(&p->mac);
2315577e9bbeSKip Macy 		if (status == 1)
2316577e9bbeSKip Macy 			p->mac.stats.num_toggled++;
2317577e9bbeSKip Macy 		else if (status == 2) {
2318577e9bbeSKip Macy 			struct cmac *mac = &p->mac;
23194af83c8cSKip Macy 			int mtu = ifp->if_mtu;
2320577e9bbeSKip Macy 
23214af83c8cSKip Macy 			if (ifp->if_capenable & IFCAP_VLAN_MTU)
23224af83c8cSKip Macy 				mtu += ETHER_VLAN_ENCAP_LEN;
23234af83c8cSKip Macy 			t3_mac_set_mtu(mac, mtu);
2324577e9bbeSKip Macy 			t3_mac_set_address(mac, 0, p->hw_addr);
2325577e9bbeSKip Macy 			cxgb_set_rxmode(p);
2326577e9bbeSKip Macy 			t3_link_start(&p->phy, mac, &p->link_config);
2327577e9bbeSKip Macy 			t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
23286b68e276SKip Macy 			t3_port_intr_enable(adapter, p->port_id);
2329577e9bbeSKip Macy 			p->mac.stats.num_resets++;
2330577e9bbeSKip Macy 		}
2331577e9bbeSKip Macy 		PORT_UNLOCK(p);
2332577e9bbeSKip Macy 	}
2333577e9bbeSKip Macy }
2334577e9bbeSKip Macy 
2335577e9bbeSKip Macy static void
2336577e9bbeSKip Macy cxgb_tick(void *arg)
2337577e9bbeSKip Macy {
2338577e9bbeSKip Macy 	adapter_t *sc = (adapter_t *)arg;
23398090c9f5SKip Macy 
23408e10660fSKip Macy 	if(sc->flags & CXGB_SHUTDOWN)
23418090c9f5SKip Macy 		return;
2342577e9bbeSKip Macy 
2343bb38cd2fSKip Macy 	taskqueue_enqueue(sc->tq, &sc->tick_task);
2344706cb31fSKip Macy 	callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc);
2345bb38cd2fSKip Macy }
2346bb38cd2fSKip Macy 
2347bb38cd2fSKip Macy static void
2348bb38cd2fSKip Macy cxgb_tick_handler(void *arg, int count)
2349bb38cd2fSKip Macy {
2350bb38cd2fSKip Macy 	adapter_t *sc = (adapter_t *)arg;
2351bb38cd2fSKip Macy 	const struct adapter_params *p = &sc->params;
2352706cb31fSKip Macy 	int i;
2353f2d8ff04SGeorge V. Neville-Neil 	uint32_t cause, reset;
2354bb38cd2fSKip Macy 
23550bbdea77SGeorge V. Neville-Neil 	if(sc->flags & CXGB_SHUTDOWN || !(sc->flags & FULL_INIT_DONE))
23568e10660fSKip Macy 		return;
23578e10660fSKip Macy 
2358bb38cd2fSKip Macy 	ADAPTER_LOCK(sc);
23590bbdea77SGeorge V. Neville-Neil 
2360bb38cd2fSKip Macy 	check_link_status(sc);
2361577e9bbeSKip Macy 
2362f35c2d65SKip Macy 	sc->check_task_cnt++;
2363f35c2d65SKip Macy 
2364f35c2d65SKip Macy 	/*
2365f35c2d65SKip Macy 	 * adapter lock can currently only be acquired after the
2366f35c2d65SKip Macy 	 * port lock
2367f35c2d65SKip Macy 	 */
2368f35c2d65SKip Macy 	ADAPTER_UNLOCK(sc);
2369f35c2d65SKip Macy 
2370f35c2d65SKip Macy 	if (p->rev == T3_REV_B2 && p->nports < 4 && sc->open_device_map)
2371f35c2d65SKip Macy 		check_t3b2_mac(sc);
2372f35c2d65SKip Macy 
2373f2d8ff04SGeorge V. Neville-Neil 	cause = t3_read_reg(sc, A_SG_INT_CAUSE);
2374f2d8ff04SGeorge V. Neville-Neil 	reset = 0;
2375f2d8ff04SGeorge V. Neville-Neil 	if (cause & F_FLEMPTY) {
2376f2d8ff04SGeorge V. Neville-Neil 		struct sge_qset *qs = &sc->sge.qs[0];
2377f2d8ff04SGeorge V. Neville-Neil 
2378f2d8ff04SGeorge V. Neville-Neil 		i = 0;
2379f2d8ff04SGeorge V. Neville-Neil 		reset |= F_FLEMPTY;
2380f2d8ff04SGeorge V. Neville-Neil 
2381f2d8ff04SGeorge V. Neville-Neil 		cause = (t3_read_reg(sc, A_SG_RSPQ_FL_STATUS) >>
2382f2d8ff04SGeorge V. Neville-Neil 			 S_FL0EMPTY) & 0xffff;
2383f2d8ff04SGeorge V. Neville-Neil 		while (cause) {
2384f2d8ff04SGeorge V. Neville-Neil 			qs->fl[i].empty += (cause & 1);
2385f2d8ff04SGeorge V. Neville-Neil 			if (i)
2386f2d8ff04SGeorge V. Neville-Neil 				qs++;
2387f2d8ff04SGeorge V. Neville-Neil 			i ^= 1;
2388f2d8ff04SGeorge V. Neville-Neil 			cause >>= 1;
2389f2d8ff04SGeorge V. Neville-Neil 		}
2390f2d8ff04SGeorge V. Neville-Neil 	}
2391f2d8ff04SGeorge V. Neville-Neil 	t3_write_reg(sc, A_SG_INT_CAUSE, reset);
2392f2d8ff04SGeorge V. Neville-Neil 
2393ceac50ebSKip Macy 	for (i = 0; i < sc->params.nports; i++) {
2394ceac50ebSKip Macy 		struct port_info *pi = &sc->port[i];
2395ceac50ebSKip Macy 		struct ifnet *ifp = pi->ifp;
2396f2d8ff04SGeorge V. Neville-Neil 		struct cmac *mac = &pi->mac;
2397f2d8ff04SGeorge V. Neville-Neil 		struct mac_stats *mstats = &mac->stats;
2398f35c2d65SKip Macy 		PORT_LOCK(pi);
2399f2d8ff04SGeorge V. Neville-Neil 		t3_mac_update_stats(mac);
2400f35c2d65SKip Macy 		PORT_UNLOCK(pi);
2401f35c2d65SKip Macy 
2402ceac50ebSKip Macy 		ifp->if_opackets =
2403ceac50ebSKip Macy 		    mstats->tx_frames_64 +
2404ceac50ebSKip Macy 		    mstats->tx_frames_65_127 +
2405ceac50ebSKip Macy 		    mstats->tx_frames_128_255 +
2406ceac50ebSKip Macy 		    mstats->tx_frames_256_511 +
2407ceac50ebSKip Macy 		    mstats->tx_frames_512_1023 +
2408ceac50ebSKip Macy 		    mstats->tx_frames_1024_1518 +
2409ceac50ebSKip Macy 		    mstats->tx_frames_1519_max;
2410ceac50ebSKip Macy 
2411ceac50ebSKip Macy 		ifp->if_ipackets =
2412ceac50ebSKip Macy 		    mstats->rx_frames_64 +
2413ceac50ebSKip Macy 		    mstats->rx_frames_65_127 +
2414ceac50ebSKip Macy 		    mstats->rx_frames_128_255 +
2415ceac50ebSKip Macy 		    mstats->rx_frames_256_511 +
2416ceac50ebSKip Macy 		    mstats->rx_frames_512_1023 +
2417ceac50ebSKip Macy 		    mstats->rx_frames_1024_1518 +
2418ceac50ebSKip Macy 		    mstats->rx_frames_1519_max;
2419ceac50ebSKip Macy 
2420ceac50ebSKip Macy 		ifp->if_obytes = mstats->tx_octets;
2421ceac50ebSKip Macy 		ifp->if_ibytes = mstats->rx_octets;
2422ceac50ebSKip Macy 		ifp->if_omcasts = mstats->tx_mcast_frames;
2423ceac50ebSKip Macy 		ifp->if_imcasts = mstats->rx_mcast_frames;
2424ceac50ebSKip Macy 
2425ceac50ebSKip Macy 		ifp->if_collisions =
2426ceac50ebSKip Macy 		    mstats->tx_total_collisions;
2427ceac50ebSKip Macy 
2428ceac50ebSKip Macy 		ifp->if_iqdrops = mstats->rx_cong_drops;
2429ceac50ebSKip Macy 
2430ceac50ebSKip Macy 		ifp->if_oerrors =
2431ceac50ebSKip Macy 		    mstats->tx_excess_collisions +
2432ceac50ebSKip Macy 		    mstats->tx_underrun +
2433ceac50ebSKip Macy 		    mstats->tx_len_errs +
2434ceac50ebSKip Macy 		    mstats->tx_mac_internal_errs +
2435ceac50ebSKip Macy 		    mstats->tx_excess_deferral +
2436ceac50ebSKip Macy 		    mstats->tx_fcs_errs;
2437ceac50ebSKip Macy 		ifp->if_ierrors =
2438ceac50ebSKip Macy 		    mstats->rx_jabber +
2439ceac50ebSKip Macy 		    mstats->rx_data_errs +
2440ceac50ebSKip Macy 		    mstats->rx_sequence_errs +
2441ceac50ebSKip Macy 		    mstats->rx_runt +
2442ceac50ebSKip Macy 		    mstats->rx_too_long +
2443ceac50ebSKip Macy 		    mstats->rx_mac_internal_errs +
2444ceac50ebSKip Macy 		    mstats->rx_short +
2445ceac50ebSKip Macy 		    mstats->rx_fcs_errs;
2446f2d8ff04SGeorge V. Neville-Neil 
2447f2d8ff04SGeorge V. Neville-Neil 		if (mac->multiport)
2448f2d8ff04SGeorge V. Neville-Neil 			continue;
2449f2d8ff04SGeorge V. Neville-Neil 
2450f2d8ff04SGeorge V. Neville-Neil 		/* Count rx fifo overflows, once per second */
2451f2d8ff04SGeorge V. Neville-Neil 		cause = t3_read_reg(sc, A_XGM_INT_CAUSE + mac->offset);
2452f2d8ff04SGeorge V. Neville-Neil 		reset = 0;
2453f2d8ff04SGeorge V. Neville-Neil 		if (cause & F_RXFIFO_OVERFLOW) {
2454f2d8ff04SGeorge V. Neville-Neil 			mac->stats.rx_fifo_ovfl++;
2455f2d8ff04SGeorge V. Neville-Neil 			reset |= F_RXFIFO_OVERFLOW;
2456f2d8ff04SGeorge V. Neville-Neil 		}
2457f2d8ff04SGeorge V. Neville-Neil 		t3_write_reg(sc, A_XGM_INT_CAUSE + mac->offset, reset);
2458ceac50ebSKip Macy 	}
2459577e9bbeSKip Macy }
2460577e9bbeSKip Macy 
24617ac2e6c3SKip Macy static void
24627ac2e6c3SKip Macy touch_bars(device_t dev)
24637ac2e6c3SKip Macy {
24647ac2e6c3SKip Macy 	/*
24657ac2e6c3SKip Macy 	 * Don't enable yet
24667ac2e6c3SKip Macy 	 */
24677ac2e6c3SKip Macy #if !defined(__LP64__) && 0
24687ac2e6c3SKip Macy 	u32 v;
24697ac2e6c3SKip Macy 
24707ac2e6c3SKip Macy 	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &v);
24717ac2e6c3SKip Macy 	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, v);
24727ac2e6c3SKip Macy 	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3, &v);
24737ac2e6c3SKip Macy 	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_3, v);
24747ac2e6c3SKip Macy 	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &v);
24757ac2e6c3SKip Macy 	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_5, v);
24767ac2e6c3SKip Macy #endif
24777ac2e6c3SKip Macy }
24787ac2e6c3SKip Macy 
2479ac3a6d9cSKip Macy static int
2480ac3a6d9cSKip Macy set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset)
2481ac3a6d9cSKip Macy {
2482ac3a6d9cSKip Macy 	uint8_t *buf;
2483ac3a6d9cSKip Macy 	int err = 0;
2484ac3a6d9cSKip Macy 	u32 aligned_offset, aligned_len, *p;
2485ac3a6d9cSKip Macy 	struct adapter *adapter = pi->adapter;
2486ac3a6d9cSKip Macy 
2487ac3a6d9cSKip Macy 
2488ac3a6d9cSKip Macy 	aligned_offset = offset & ~3;
2489ac3a6d9cSKip Macy 	aligned_len = (len + (offset & 3) + 3) & ~3;
2490ac3a6d9cSKip Macy 
2491ac3a6d9cSKip Macy 	if (aligned_offset != offset || aligned_len != len) {
2492ac3a6d9cSKip Macy 		buf = malloc(aligned_len, M_DEVBUF, M_WAITOK|M_ZERO);
2493ac3a6d9cSKip Macy 		if (!buf)
2494ac3a6d9cSKip Macy 			return (ENOMEM);
2495ac3a6d9cSKip Macy 		err = t3_seeprom_read(adapter, aligned_offset, (u32 *)buf);
2496ac3a6d9cSKip Macy 		if (!err && aligned_len > 4)
2497ac3a6d9cSKip Macy 			err = t3_seeprom_read(adapter,
2498ac3a6d9cSKip Macy 					      aligned_offset + aligned_len - 4,
2499ac3a6d9cSKip Macy 					      (u32 *)&buf[aligned_len - 4]);
2500ac3a6d9cSKip Macy 		if (err)
2501ac3a6d9cSKip Macy 			goto out;
2502ac3a6d9cSKip Macy 		memcpy(buf + (offset & 3), data, len);
2503ac3a6d9cSKip Macy 	} else
2504ac3a6d9cSKip Macy 		buf = (uint8_t *)(uintptr_t)data;
2505ac3a6d9cSKip Macy 
2506ac3a6d9cSKip Macy 	err = t3_seeprom_wp(adapter, 0);
2507ac3a6d9cSKip Macy 	if (err)
2508ac3a6d9cSKip Macy 		goto out;
2509ac3a6d9cSKip Macy 
2510ac3a6d9cSKip Macy 	for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) {
2511ac3a6d9cSKip Macy 		err = t3_seeprom_write(adapter, aligned_offset, *p);
2512ac3a6d9cSKip Macy 		aligned_offset += 4;
2513ac3a6d9cSKip Macy 	}
2514ac3a6d9cSKip Macy 
2515ac3a6d9cSKip Macy 	if (!err)
2516ac3a6d9cSKip Macy 		err = t3_seeprom_wp(adapter, 1);
2517ac3a6d9cSKip Macy out:
2518ac3a6d9cSKip Macy 	if (buf != data)
2519ac3a6d9cSKip Macy 		free(buf, M_DEVBUF);
2520ac3a6d9cSKip Macy 	return err;
2521ac3a6d9cSKip Macy }
2522ac3a6d9cSKip Macy 
2523ac3a6d9cSKip Macy 
2524b6d90eb7SKip Macy static int
2525b6d90eb7SKip Macy in_range(int val, int lo, int hi)
2526b6d90eb7SKip Macy {
2527b6d90eb7SKip Macy 	return val < 0 || (val <= hi && val >= lo);
2528b6d90eb7SKip Macy }
2529b6d90eb7SKip Macy 
2530b6d90eb7SKip Macy static int
253100b4e54aSWarner Losh cxgb_extension_open(struct cdev *dev, int flags, int fmp, struct thread *td)
2532ef72318fSKip Macy {
2533ef72318fSKip Macy        return (0);
2534ef72318fSKip Macy }
2535ef72318fSKip Macy 
2536ef72318fSKip Macy static int
253700b4e54aSWarner Losh cxgb_extension_close(struct cdev *dev, int flags, int fmt, struct thread *td)
2538ef72318fSKip Macy {
2539ef72318fSKip Macy        return (0);
2540ef72318fSKip Macy }
2541ef72318fSKip Macy 
2542ef72318fSKip Macy static int
2543b6d90eb7SKip Macy cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
2544b6d90eb7SKip Macy     int fflag, struct thread *td)
2545b6d90eb7SKip Macy {
2546b6d90eb7SKip Macy 	int mmd, error = 0;
2547b6d90eb7SKip Macy 	struct port_info *pi = dev->si_drv1;
2548b6d90eb7SKip Macy 	adapter_t *sc = pi->adapter;
2549b6d90eb7SKip Macy 
2550b6d90eb7SKip Macy #ifdef PRIV_SUPPORTED
2551b6d90eb7SKip Macy 	if (priv_check(td, PRIV_DRIVER)) {
2552b6d90eb7SKip Macy 		if (cxgb_debug)
2553b6d90eb7SKip Macy 			printf("user does not have access to privileged ioctls\n");
2554b6d90eb7SKip Macy 		return (EPERM);
2555b6d90eb7SKip Macy 	}
2556b6d90eb7SKip Macy #else
2557b6d90eb7SKip Macy 	if (suser(td)) {
2558b6d90eb7SKip Macy 		if (cxgb_debug)
2559b6d90eb7SKip Macy 			printf("user does not have access to privileged ioctls\n");
2560b6d90eb7SKip Macy 		return (EPERM);
2561b6d90eb7SKip Macy 	}
2562b6d90eb7SKip Macy #endif
2563b6d90eb7SKip Macy 
2564b6d90eb7SKip Macy 	switch (cmd) {
25651ffd6e58SKip Macy 	case CHELSIO_GET_MIIREG: {
2566b6d90eb7SKip Macy 		uint32_t val;
2567b6d90eb7SKip Macy 		struct cphy *phy = &pi->phy;
25681ffd6e58SKip Macy 		struct ch_mii_data *mid = (struct ch_mii_data *)data;
2569b6d90eb7SKip Macy 
2570b6d90eb7SKip Macy 		if (!phy->mdio_read)
2571b6d90eb7SKip Macy 			return (EOPNOTSUPP);
2572b6d90eb7SKip Macy 		if (is_10G(sc)) {
2573b6d90eb7SKip Macy 			mmd = mid->phy_id >> 8;
2574b6d90eb7SKip Macy 			if (!mmd)
2575b6d90eb7SKip Macy 				mmd = MDIO_DEV_PCS;
25760c1ff9c6SGeorge V. Neville-Neil 			else if (mmd > MDIO_DEV_VEND2)
2577ac3a6d9cSKip Macy 				return (EINVAL);
2578b6d90eb7SKip Macy 
2579b6d90eb7SKip Macy 			error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd,
2580b6d90eb7SKip Macy 					     mid->reg_num, &val);
2581b6d90eb7SKip Macy 		} else
2582b6d90eb7SKip Macy 		        error = phy->mdio_read(sc, mid->phy_id & 0x1f, 0,
2583b6d90eb7SKip Macy 					     mid->reg_num & 0x1f, &val);
2584b6d90eb7SKip Macy 		if (error == 0)
2585b6d90eb7SKip Macy 			mid->val_out = val;
2586b6d90eb7SKip Macy 		break;
2587b6d90eb7SKip Macy 	}
25881ffd6e58SKip Macy 	case CHELSIO_SET_MIIREG: {
2589b6d90eb7SKip Macy 		struct cphy *phy = &pi->phy;
25901ffd6e58SKip Macy 		struct ch_mii_data *mid = (struct ch_mii_data *)data;
2591b6d90eb7SKip Macy 
2592b6d90eb7SKip Macy 		if (!phy->mdio_write)
2593b6d90eb7SKip Macy 			return (EOPNOTSUPP);
2594b6d90eb7SKip Macy 		if (is_10G(sc)) {
2595b6d90eb7SKip Macy 			mmd = mid->phy_id >> 8;
2596b6d90eb7SKip Macy 			if (!mmd)
2597b6d90eb7SKip Macy 				mmd = MDIO_DEV_PCS;
25980c1ff9c6SGeorge V. Neville-Neil 			else if (mmd > MDIO_DEV_VEND2)
2599b6d90eb7SKip Macy 				return (EINVAL);
2600b6d90eb7SKip Macy 
2601b6d90eb7SKip Macy 			error = phy->mdio_write(sc, mid->phy_id & 0x1f,
2602b6d90eb7SKip Macy 					      mmd, mid->reg_num, mid->val_in);
2603b6d90eb7SKip Macy 		} else
2604b6d90eb7SKip Macy 			error = phy->mdio_write(sc, mid->phy_id & 0x1f, 0,
2605b6d90eb7SKip Macy 					      mid->reg_num & 0x1f,
2606b6d90eb7SKip Macy 					      mid->val_in);
2607b6d90eb7SKip Macy 		break;
2608b6d90eb7SKip Macy 	}
2609b6d90eb7SKip Macy 	case CHELSIO_SETREG: {
2610b6d90eb7SKip Macy 		struct ch_reg *edata = (struct ch_reg *)data;
2611b6d90eb7SKip Macy 		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2612b6d90eb7SKip Macy 			return (EFAULT);
2613b6d90eb7SKip Macy 		t3_write_reg(sc, edata->addr, edata->val);
2614b6d90eb7SKip Macy 		break;
2615b6d90eb7SKip Macy 	}
2616b6d90eb7SKip Macy 	case CHELSIO_GETREG: {
2617b6d90eb7SKip Macy 		struct ch_reg *edata = (struct ch_reg *)data;
2618b6d90eb7SKip Macy 		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2619b6d90eb7SKip Macy 			return (EFAULT);
2620b6d90eb7SKip Macy 		edata->val = t3_read_reg(sc, edata->addr);
2621b6d90eb7SKip Macy 		break;
2622b6d90eb7SKip Macy 	}
2623b6d90eb7SKip Macy 	case CHELSIO_GET_SGE_CONTEXT: {
2624b6d90eb7SKip Macy 		struct ch_cntxt *ecntxt = (struct ch_cntxt *)data;
26258e10660fSKip Macy 		mtx_lock_spin(&sc->sge.reg_lock);
2626b6d90eb7SKip Macy 		switch (ecntxt->cntxt_type) {
2627b6d90eb7SKip Macy 		case CNTXT_TYPE_EGRESS:
26281ffd6e58SKip Macy 			error = -t3_sge_read_ecntxt(sc, ecntxt->cntxt_id,
2629b6d90eb7SKip Macy 			    ecntxt->data);
2630b6d90eb7SKip Macy 			break;
2631b6d90eb7SKip Macy 		case CNTXT_TYPE_FL:
26321ffd6e58SKip Macy 			error = -t3_sge_read_fl(sc, ecntxt->cntxt_id,
2633b6d90eb7SKip Macy 			    ecntxt->data);
2634b6d90eb7SKip Macy 			break;
2635b6d90eb7SKip Macy 		case CNTXT_TYPE_RSP:
26361ffd6e58SKip Macy 			error = -t3_sge_read_rspq(sc, ecntxt->cntxt_id,
2637b6d90eb7SKip Macy 			    ecntxt->data);
2638b6d90eb7SKip Macy 			break;
2639b6d90eb7SKip Macy 		case CNTXT_TYPE_CQ:
26401ffd6e58SKip Macy 			error = -t3_sge_read_cq(sc, ecntxt->cntxt_id,
2641b6d90eb7SKip Macy 			    ecntxt->data);
2642b6d90eb7SKip Macy 			break;
2643b6d90eb7SKip Macy 		default:
2644b6d90eb7SKip Macy 			error = EINVAL;
2645b6d90eb7SKip Macy 			break;
2646b6d90eb7SKip Macy 		}
26478e10660fSKip Macy 		mtx_unlock_spin(&sc->sge.reg_lock);
2648b6d90eb7SKip Macy 		break;
2649b6d90eb7SKip Macy 	}
2650b6d90eb7SKip Macy 	case CHELSIO_GET_SGE_DESC: {
2651b6d90eb7SKip Macy 		struct ch_desc *edesc = (struct ch_desc *)data;
2652b6d90eb7SKip Macy 		int ret;
2653b6d90eb7SKip Macy 		if (edesc->queue_num >= SGE_QSETS * 6)
2654b6d90eb7SKip Macy 			return (EINVAL);
2655b6d90eb7SKip Macy 		ret = t3_get_desc(&sc->sge.qs[edesc->queue_num / 6],
2656b6d90eb7SKip Macy 		    edesc->queue_num % 6, edesc->idx, edesc->data);
2657b6d90eb7SKip Macy 		if (ret < 0)
2658b6d90eb7SKip Macy 			return (EINVAL);
2659b6d90eb7SKip Macy 		edesc->size = ret;
2660b6d90eb7SKip Macy 		break;
2661b6d90eb7SKip Macy 	}
2662b6d90eb7SKip Macy 	case CHELSIO_GET_QSET_PARAMS: {
2663b6d90eb7SKip Macy 		struct qset_params *q;
2664b6d90eb7SKip Macy 		struct ch_qset_params *t = (struct ch_qset_params *)data;
26651ffd6e58SKip Macy 		int q1 = pi->first_qset;
26661ffd6e58SKip Macy 		int nqsets = pi->nqsets;
26671ffd6e58SKip Macy 		int i;
2668b6d90eb7SKip Macy 
26691ffd6e58SKip Macy 		if (t->qset_idx >= nqsets)
26701ffd6e58SKip Macy 			return EINVAL;
2671b6d90eb7SKip Macy 
26721ffd6e58SKip Macy 		i = q1 + t->qset_idx;
26731ffd6e58SKip Macy 		q = &sc->params.sge.qset[i];
2674b6d90eb7SKip Macy 		t->rspq_size   = q->rspq_size;
2675b6d90eb7SKip Macy 		t->txq_size[0] = q->txq_size[0];
2676b6d90eb7SKip Macy 		t->txq_size[1] = q->txq_size[1];
2677b6d90eb7SKip Macy 		t->txq_size[2] = q->txq_size[2];
2678b6d90eb7SKip Macy 		t->fl_size[0]  = q->fl_size;
2679b6d90eb7SKip Macy 		t->fl_size[1]  = q->jumbo_size;
2680b6d90eb7SKip Macy 		t->polling     = q->polling;
26811ffd6e58SKip Macy 		t->lro         = q->lro;
26824af83c8cSKip Macy 		t->intr_lat    = q->coalesce_usecs;
2683b6d90eb7SKip Macy 		t->cong_thres  = q->cong_thres;
26841ffd6e58SKip Macy 		t->qnum        = i;
2685b6d90eb7SKip Macy 
26861ffd6e58SKip Macy 		if (sc->flags & USING_MSIX)
26871ffd6e58SKip Macy 			t->vector = rman_get_start(sc->msix_irq_res[i]);
26881ffd6e58SKip Macy 		else
26891ffd6e58SKip Macy 			t->vector = rman_get_start(sc->irq_res);
26901ffd6e58SKip Macy 
2691b6d90eb7SKip Macy 		break;
2692b6d90eb7SKip Macy 	}
2693b6d90eb7SKip Macy 	case CHELSIO_GET_QSET_NUM: {
2694b6d90eb7SKip Macy 		struct ch_reg *edata = (struct ch_reg *)data;
2695b6d90eb7SKip Macy 		edata->val = pi->nqsets;
2696b6d90eb7SKip Macy 		break;
2697b6d90eb7SKip Macy 	}
26981ffd6e58SKip Macy 	case CHELSIO_LOAD_FW: {
26991ffd6e58SKip Macy 		uint8_t *fw_data;
27001ffd6e58SKip Macy 		uint32_t vers;
27011ffd6e58SKip Macy 		struct ch_mem_range *t = (struct ch_mem_range *)data;
27021ffd6e58SKip Macy 
27031ffd6e58SKip Macy 		/*
27041ffd6e58SKip Macy 		 * You're allowed to load a firmware only before FULL_INIT_DONE
27051ffd6e58SKip Macy 		 *
27061ffd6e58SKip Macy 		 * FW_UPTODATE is also set so the rest of the initialization
27071ffd6e58SKip Macy 		 * will not overwrite what was loaded here.  This gives you the
27081ffd6e58SKip Macy 		 * flexibility to load any firmware (and maybe shoot yourself in
27091ffd6e58SKip Macy 		 * the foot).
27101ffd6e58SKip Macy 		 */
27111ffd6e58SKip Macy 
27121ffd6e58SKip Macy 		ADAPTER_LOCK(sc);
27131ffd6e58SKip Macy 		if (sc->open_device_map || sc->flags & FULL_INIT_DONE) {
27141ffd6e58SKip Macy 			ADAPTER_UNLOCK(sc);
27151ffd6e58SKip Macy 			return (EBUSY);
27161ffd6e58SKip Macy 		}
27171ffd6e58SKip Macy 
27181ffd6e58SKip Macy 		fw_data = malloc(t->len, M_DEVBUF, M_NOWAIT);
27191ffd6e58SKip Macy 		if (!fw_data)
27201ffd6e58SKip Macy 			error = ENOMEM;
27211ffd6e58SKip Macy 		else
27221ffd6e58SKip Macy 			error = copyin(t->buf, fw_data, t->len);
27231ffd6e58SKip Macy 
27241ffd6e58SKip Macy 		if (!error)
27251ffd6e58SKip Macy 			error = -t3_load_fw(sc, fw_data, t->len);
27261ffd6e58SKip Macy 
27271ffd6e58SKip Macy 		if (t3_get_fw_version(sc, &vers) == 0) {
27281ffd6e58SKip Macy 			snprintf(&sc->fw_version[0], sizeof(sc->fw_version),
27291ffd6e58SKip Macy 			    "%d.%d.%d", G_FW_VERSION_MAJOR(vers),
27301ffd6e58SKip Macy 			    G_FW_VERSION_MINOR(vers), G_FW_VERSION_MICRO(vers));
27311ffd6e58SKip Macy 		}
27321ffd6e58SKip Macy 
27331ffd6e58SKip Macy 		if (!error)
27341ffd6e58SKip Macy 			sc->flags |= FW_UPTODATE;
27351ffd6e58SKip Macy 
27361ffd6e58SKip Macy 		free(fw_data, M_DEVBUF);
27371ffd6e58SKip Macy 		ADAPTER_UNLOCK(sc);
2738b6d90eb7SKip Macy 		break;
27391ffd6e58SKip Macy 	}
27401ffd6e58SKip Macy 	case CHELSIO_LOAD_BOOT: {
27411ffd6e58SKip Macy 		uint8_t *boot_data;
27421ffd6e58SKip Macy 		struct ch_mem_range *t = (struct ch_mem_range *)data;
27431ffd6e58SKip Macy 
27441ffd6e58SKip Macy 		boot_data = malloc(t->len, M_DEVBUF, M_NOWAIT);
27451ffd6e58SKip Macy 		if (!boot_data)
27461ffd6e58SKip Macy 			return ENOMEM;
27471ffd6e58SKip Macy 
27481ffd6e58SKip Macy 		error = copyin(t->buf, boot_data, t->len);
27491ffd6e58SKip Macy 		if (!error)
27501ffd6e58SKip Macy 			error = -t3_load_boot(sc, boot_data, t->len);
27511ffd6e58SKip Macy 
27521ffd6e58SKip Macy 		free(boot_data, M_DEVBUF);
27531ffd6e58SKip Macy 		break;
27541ffd6e58SKip Macy 	}
27551ffd6e58SKip Macy 	case CHELSIO_GET_PM: {
27561ffd6e58SKip Macy 		struct ch_pm *m = (struct ch_pm *)data;
27571ffd6e58SKip Macy 		struct tp_params *p = &sc->params.tp;
27581ffd6e58SKip Macy 
27591ffd6e58SKip Macy 		if (!is_offload(sc))
27601ffd6e58SKip Macy 			return (EOPNOTSUPP);
27611ffd6e58SKip Macy 
27621ffd6e58SKip Macy 		m->tx_pg_sz = p->tx_pg_size;
27631ffd6e58SKip Macy 		m->tx_num_pg = p->tx_num_pgs;
27641ffd6e58SKip Macy 		m->rx_pg_sz  = p->rx_pg_size;
27651ffd6e58SKip Macy 		m->rx_num_pg = p->rx_num_pgs;
27661ffd6e58SKip Macy 		m->pm_total  = p->pmtx_size + p->chan_rx_size * p->nchan;
27671ffd6e58SKip Macy 
27681ffd6e58SKip Macy 		break;
27691ffd6e58SKip Macy 	}
27701ffd6e58SKip Macy 	case CHELSIO_SET_PM: {
27711ffd6e58SKip Macy 		struct ch_pm *m = (struct ch_pm *)data;
27721ffd6e58SKip Macy 		struct tp_params *p = &sc->params.tp;
27731ffd6e58SKip Macy 
27741ffd6e58SKip Macy 		if (!is_offload(sc))
27751ffd6e58SKip Macy 			return (EOPNOTSUPP);
27761ffd6e58SKip Macy 		if (sc->flags & FULL_INIT_DONE)
27771ffd6e58SKip Macy 			return (EBUSY);
27781ffd6e58SKip Macy 
27791ffd6e58SKip Macy 		if (!m->rx_pg_sz || (m->rx_pg_sz & (m->rx_pg_sz - 1)) ||
27801ffd6e58SKip Macy 		    !m->tx_pg_sz || (m->tx_pg_sz & (m->tx_pg_sz - 1)))
27811ffd6e58SKip Macy 			return (EINVAL);	/* not power of 2 */
27821ffd6e58SKip Macy 		if (!(m->rx_pg_sz & 0x14000))
27831ffd6e58SKip Macy 			return (EINVAL);	/* not 16KB or 64KB */
27841ffd6e58SKip Macy 		if (!(m->tx_pg_sz & 0x1554000))
27851ffd6e58SKip Macy 			return (EINVAL);
27861ffd6e58SKip Macy 		if (m->tx_num_pg == -1)
27871ffd6e58SKip Macy 			m->tx_num_pg = p->tx_num_pgs;
27881ffd6e58SKip Macy 		if (m->rx_num_pg == -1)
27891ffd6e58SKip Macy 			m->rx_num_pg = p->rx_num_pgs;
27901ffd6e58SKip Macy 		if (m->tx_num_pg % 24 || m->rx_num_pg % 24)
27911ffd6e58SKip Macy 			return (EINVAL);
27921ffd6e58SKip Macy 		if (m->rx_num_pg * m->rx_pg_sz > p->chan_rx_size ||
27931ffd6e58SKip Macy 		    m->tx_num_pg * m->tx_pg_sz > p->chan_tx_size)
27941ffd6e58SKip Macy 			return (EINVAL);
27951ffd6e58SKip Macy 
27961ffd6e58SKip Macy 		p->rx_pg_size = m->rx_pg_sz;
27971ffd6e58SKip Macy 		p->tx_pg_size = m->tx_pg_sz;
27981ffd6e58SKip Macy 		p->rx_num_pgs = m->rx_num_pg;
27991ffd6e58SKip Macy 		p->tx_num_pgs = m->tx_num_pg;
28001ffd6e58SKip Macy 		break;
28011ffd6e58SKip Macy 	}
2802d722cab4SKip Macy 	case CHELSIO_SETMTUTAB: {
2803d722cab4SKip Macy 		struct ch_mtus *m = (struct ch_mtus *)data;
2804d722cab4SKip Macy 		int i;
2805d722cab4SKip Macy 
2806d722cab4SKip Macy 		if (!is_offload(sc))
2807d722cab4SKip Macy 			return (EOPNOTSUPP);
2808d722cab4SKip Macy 		if (offload_running(sc))
2809d722cab4SKip Macy 			return (EBUSY);
2810d722cab4SKip Macy 		if (m->nmtus != NMTUS)
2811d722cab4SKip Macy 			return (EINVAL);
2812d722cab4SKip Macy 		if (m->mtus[0] < 81)         /* accommodate SACK */
2813d722cab4SKip Macy 			return (EINVAL);
2814d722cab4SKip Macy 
2815d722cab4SKip Macy 		/*
2816d722cab4SKip Macy 		 * MTUs must be in ascending order
2817d722cab4SKip Macy 		 */
2818d722cab4SKip Macy 		for (i = 1; i < NMTUS; ++i)
2819d722cab4SKip Macy 			if (m->mtus[i] < m->mtus[i - 1])
2820d722cab4SKip Macy 				return (EINVAL);
2821d722cab4SKip Macy 
28221ffd6e58SKip Macy 		memcpy(sc->params.mtus, m->mtus, sizeof(sc->params.mtus));
2823d722cab4SKip Macy 		break;
2824d722cab4SKip Macy 	}
2825d722cab4SKip Macy 	case CHELSIO_GETMTUTAB: {
2826d722cab4SKip Macy 		struct ch_mtus *m = (struct ch_mtus *)data;
2827d722cab4SKip Macy 
2828d722cab4SKip Macy 		if (!is_offload(sc))
2829d722cab4SKip Macy 			return (EOPNOTSUPP);
2830d722cab4SKip Macy 
2831d722cab4SKip Macy 		memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus));
2832d722cab4SKip Macy 		m->nmtus = NMTUS;
2833d722cab4SKip Macy 		break;
2834d722cab4SKip Macy 	}
2835b6d90eb7SKip Macy 	case CHELSIO_GET_MEM: {
2836b6d90eb7SKip Macy 		struct ch_mem_range *t = (struct ch_mem_range *)data;
2837b6d90eb7SKip Macy 		struct mc7 *mem;
2838b6d90eb7SKip Macy 		uint8_t *useraddr;
2839b6d90eb7SKip Macy 		u64 buf[32];
2840b6d90eb7SKip Macy 
28411ffd6e58SKip Macy 		/*
28421ffd6e58SKip Macy 		 * Use these to avoid modifying len/addr in the the return
28431ffd6e58SKip Macy 		 * struct
28441ffd6e58SKip Macy 		 */
28451ffd6e58SKip Macy 		uint32_t len = t->len, addr = t->addr;
28461ffd6e58SKip Macy 
2847b6d90eb7SKip Macy 		if (!is_offload(sc))
2848b6d90eb7SKip Macy 			return (EOPNOTSUPP);
2849b6d90eb7SKip Macy 		if (!(sc->flags & FULL_INIT_DONE))
2850b6d90eb7SKip Macy 			return (EIO);         /* need the memory controllers */
28511ffd6e58SKip Macy 		if ((addr & 0x7) || (len & 0x7))
2852b6d90eb7SKip Macy 			return (EINVAL);
2853b6d90eb7SKip Macy 		if (t->mem_id == MEM_CM)
2854b6d90eb7SKip Macy 			mem = &sc->cm;
2855b6d90eb7SKip Macy 		else if (t->mem_id == MEM_PMRX)
2856b6d90eb7SKip Macy 			mem = &sc->pmrx;
2857b6d90eb7SKip Macy 		else if (t->mem_id == MEM_PMTX)
2858b6d90eb7SKip Macy 			mem = &sc->pmtx;
2859b6d90eb7SKip Macy 		else
2860b6d90eb7SKip Macy 			return (EINVAL);
2861b6d90eb7SKip Macy 
2862b6d90eb7SKip Macy 		/*
2863b6d90eb7SKip Macy 		 * Version scheme:
2864b6d90eb7SKip Macy 		 * bits 0..9: chip version
2865b6d90eb7SKip Macy 		 * bits 10..15: chip revision
2866b6d90eb7SKip Macy 		 */
2867b6d90eb7SKip Macy 		t->version = 3 | (sc->params.rev << 10);
2868b6d90eb7SKip Macy 
2869b6d90eb7SKip Macy 		/*
2870b6d90eb7SKip Macy 		 * Read 256 bytes at a time as len can be large and we don't
2871b6d90eb7SKip Macy 		 * want to use huge intermediate buffers.
2872b6d90eb7SKip Macy 		 */
28738090c9f5SKip Macy 		useraddr = (uint8_t *)t->buf;
28741ffd6e58SKip Macy 		while (len) {
28751ffd6e58SKip Macy 			unsigned int chunk = min(len, sizeof(buf));
2876b6d90eb7SKip Macy 
28771ffd6e58SKip Macy 			error = t3_mc7_bd_read(mem, addr / 8, chunk / 8, buf);
2878b6d90eb7SKip Macy 			if (error)
2879b6d90eb7SKip Macy 				return (-error);
2880b6d90eb7SKip Macy 			if (copyout(buf, useraddr, chunk))
2881b6d90eb7SKip Macy 				return (EFAULT);
2882b6d90eb7SKip Macy 			useraddr += chunk;
28831ffd6e58SKip Macy 			addr += chunk;
28841ffd6e58SKip Macy 			len -= chunk;
2885b6d90eb7SKip Macy 		}
2886b6d90eb7SKip Macy 		break;
2887b6d90eb7SKip Macy 	}
2888d722cab4SKip Macy 	case CHELSIO_READ_TCAM_WORD: {
2889d722cab4SKip Macy 		struct ch_tcam_word *t = (struct ch_tcam_word *)data;
2890d722cab4SKip Macy 
2891d722cab4SKip Macy 		if (!is_offload(sc))
2892d722cab4SKip Macy 			return (EOPNOTSUPP);
2893ac3a6d9cSKip Macy 		if (!(sc->flags & FULL_INIT_DONE))
2894ac3a6d9cSKip Macy 			return (EIO);         /* need MC5 */
2895d722cab4SKip Macy 		return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf);
2896d722cab4SKip Macy 		break;
2897d722cab4SKip Macy 	}
2898b6d90eb7SKip Macy 	case CHELSIO_SET_TRACE_FILTER: {
2899b6d90eb7SKip Macy 		struct ch_trace *t = (struct ch_trace *)data;
2900b6d90eb7SKip Macy 		const struct trace_params *tp;
2901b6d90eb7SKip Macy 
2902b6d90eb7SKip Macy 		tp = (const struct trace_params *)&t->sip;
2903b6d90eb7SKip Macy 		if (t->config_tx)
2904b6d90eb7SKip Macy 			t3_config_trace_filter(sc, tp, 0, t->invert_match,
2905b6d90eb7SKip Macy 					       t->trace_tx);
2906b6d90eb7SKip Macy 		if (t->config_rx)
2907b6d90eb7SKip Macy 			t3_config_trace_filter(sc, tp, 1, t->invert_match,
2908b6d90eb7SKip Macy 					       t->trace_rx);
2909b6d90eb7SKip Macy 		break;
2910b6d90eb7SKip Macy 	}
2911b6d90eb7SKip Macy 	case CHELSIO_SET_PKTSCHED: {
2912b6d90eb7SKip Macy 		struct ch_pktsched_params *p = (struct ch_pktsched_params *)data;
2913b6d90eb7SKip Macy 		if (sc->open_device_map == 0)
2914b6d90eb7SKip Macy 			return (EAGAIN);
2915b6d90eb7SKip Macy 		send_pktsched_cmd(sc, p->sched, p->idx, p->min, p->max,
2916b6d90eb7SKip Macy 		    p->binding);
2917b6d90eb7SKip Macy 		break;
2918b6d90eb7SKip Macy 	}
2919b6d90eb7SKip Macy 	case CHELSIO_IFCONF_GETREGS: {
29201ffd6e58SKip Macy 		struct ch_ifconf_regs *regs = (struct ch_ifconf_regs *)data;
2921b6d90eb7SKip Macy 		int reglen = cxgb_get_regs_len();
29221ffd6e58SKip Macy 		uint8_t *buf = malloc(reglen, M_DEVBUF, M_NOWAIT);
2923b6d90eb7SKip Macy 		if (buf == NULL) {
2924b6d90eb7SKip Macy 			return (ENOMEM);
2925b6d90eb7SKip Macy 		}
29261ffd6e58SKip Macy 		if (regs->len > reglen)
29271ffd6e58SKip Macy 			regs->len = reglen;
29281ffd6e58SKip Macy 		else if (regs->len < reglen)
2929f2d8ff04SGeorge V. Neville-Neil 			error = ENOBUFS;
29301ffd6e58SKip Macy 
29311ffd6e58SKip Macy 		if (!error) {
2932b6d90eb7SKip Macy 			cxgb_get_regs(sc, regs, buf);
2933b6d90eb7SKip Macy 			error = copyout(buf, regs->data, reglen);
29341ffd6e58SKip Macy 		}
2935b6d90eb7SKip Macy 		free(buf, M_DEVBUF);
2936b6d90eb7SKip Macy 
2937b6d90eb7SKip Macy 		break;
2938b6d90eb7SKip Macy 	}
2939d722cab4SKip Macy 	case CHELSIO_SET_HW_SCHED: {
2940d722cab4SKip Macy 		struct ch_hw_sched *t = (struct ch_hw_sched *)data;
2941d722cab4SKip Macy 		unsigned int ticks_per_usec = core_ticks_per_usec(sc);
2942d722cab4SKip Macy 
2943d722cab4SKip Macy 		if ((sc->flags & FULL_INIT_DONE) == 0)
2944d722cab4SKip Macy 			return (EAGAIN);       /* need TP to be initialized */
2945d722cab4SKip Macy 		if (t->sched >= NTX_SCHED || !in_range(t->mode, 0, 1) ||
2946d722cab4SKip Macy 		    !in_range(t->channel, 0, 1) ||
2947d722cab4SKip Macy 		    !in_range(t->kbps, 0, 10000000) ||
2948d722cab4SKip Macy 		    !in_range(t->class_ipg, 0, 10000 * 65535 / ticks_per_usec) ||
2949d722cab4SKip Macy 		    !in_range(t->flow_ipg, 0,
2950d722cab4SKip Macy 			      dack_ticks_to_usec(sc, 0x7ff)))
2951d722cab4SKip Macy 			return (EINVAL);
2952d722cab4SKip Macy 
2953d722cab4SKip Macy 		if (t->kbps >= 0) {
2954d722cab4SKip Macy 			error = t3_config_sched(sc, t->kbps, t->sched);
2955d722cab4SKip Macy 			if (error < 0)
2956d722cab4SKip Macy 				return (-error);
2957d722cab4SKip Macy 		}
2958d722cab4SKip Macy 		if (t->class_ipg >= 0)
2959d722cab4SKip Macy 			t3_set_sched_ipg(sc, t->sched, t->class_ipg);
2960d722cab4SKip Macy 		if (t->flow_ipg >= 0) {
2961d722cab4SKip Macy 			t->flow_ipg *= 1000;     /* us -> ns */
2962d722cab4SKip Macy 			t3_set_pace_tbl(sc, &t->flow_ipg, t->sched, 1);
2963d722cab4SKip Macy 		}
2964d722cab4SKip Macy 		if (t->mode >= 0) {
2965d722cab4SKip Macy 			int bit = 1 << (S_TX_MOD_TIMER_MODE + t->sched);
2966d722cab4SKip Macy 
2967d722cab4SKip Macy 			t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2968d722cab4SKip Macy 					 bit, t->mode ? bit : 0);
2969d722cab4SKip Macy 		}
2970d722cab4SKip Macy 		if (t->channel >= 0)
2971d722cab4SKip Macy 			t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2972d722cab4SKip Macy 					 1 << t->sched, t->channel << t->sched);
2973d722cab4SKip Macy 		break;
2974d722cab4SKip Macy 	}
29751ffd6e58SKip Macy 	case CHELSIO_GET_EEPROM: {
29761ffd6e58SKip Macy 		int i;
29771ffd6e58SKip Macy 		struct ch_eeprom *e = (struct ch_eeprom *)data;
29781ffd6e58SKip Macy 		uint8_t *buf = malloc(EEPROMSIZE, M_DEVBUF, M_NOWAIT);
29791ffd6e58SKip Macy 
29801ffd6e58SKip Macy 		if (buf == NULL) {
29811ffd6e58SKip Macy 			return (ENOMEM);
29821ffd6e58SKip Macy 		}
29831ffd6e58SKip Macy 		e->magic = EEPROM_MAGIC;
29841ffd6e58SKip Macy 		for (i = e->offset & ~3; !error && i < e->offset + e->len; i += 4)
29851ffd6e58SKip Macy 			error = -t3_seeprom_read(sc, i, (uint32_t *)&buf[i]);
29861ffd6e58SKip Macy 
29871ffd6e58SKip Macy 		if (!error)
29881ffd6e58SKip Macy 			error = copyout(buf + e->offset, e->data, e->len);
29891ffd6e58SKip Macy 
29901ffd6e58SKip Macy 		free(buf, M_DEVBUF);
29911ffd6e58SKip Macy 		break;
29921ffd6e58SKip Macy 	}
29931ffd6e58SKip Macy 	case CHELSIO_CLEAR_STATS: {
29941ffd6e58SKip Macy 		if (!(sc->flags & FULL_INIT_DONE))
29951ffd6e58SKip Macy 			return EAGAIN;
29961ffd6e58SKip Macy 
29971ffd6e58SKip Macy 		PORT_LOCK(pi);
29981ffd6e58SKip Macy 		t3_mac_update_stats(&pi->mac);
29991ffd6e58SKip Macy 		memset(&pi->mac.stats, 0, sizeof(pi->mac.stats));
30001ffd6e58SKip Macy 		PORT_UNLOCK(pi);
30011ffd6e58SKip Macy 		break;
30021ffd6e58SKip Macy 	}
3003f2d8ff04SGeorge V. Neville-Neil 	case CHELSIO_GET_UP_LA: {
3004f2d8ff04SGeorge V. Neville-Neil 		struct ch_up_la *la = (struct ch_up_la *)data;
3005f2d8ff04SGeorge V. Neville-Neil 		uint8_t *buf = malloc(LA_BUFSIZE, M_DEVBUF, M_NOWAIT);
3006f2d8ff04SGeorge V. Neville-Neil 		if (buf == NULL) {
3007f2d8ff04SGeorge V. Neville-Neil 			return (ENOMEM);
3008f2d8ff04SGeorge V. Neville-Neil 		}
3009f2d8ff04SGeorge V. Neville-Neil 		if (la->bufsize < LA_BUFSIZE)
3010f2d8ff04SGeorge V. Neville-Neil 			error = ENOBUFS;
3011f2d8ff04SGeorge V. Neville-Neil 
3012f2d8ff04SGeorge V. Neville-Neil 		if (!error)
3013f2d8ff04SGeorge V. Neville-Neil 			error = -t3_get_up_la(sc, &la->stopped, &la->idx,
3014f2d8ff04SGeorge V. Neville-Neil 					      &la->bufsize, buf);
3015f2d8ff04SGeorge V. Neville-Neil 		if (!error)
3016f2d8ff04SGeorge V. Neville-Neil 			error = copyout(buf, la->data, la->bufsize);
3017f2d8ff04SGeorge V. Neville-Neil 
3018f2d8ff04SGeorge V. Neville-Neil 		free(buf, M_DEVBUF);
3019f2d8ff04SGeorge V. Neville-Neil 		break;
3020f2d8ff04SGeorge V. Neville-Neil 	}
3021f2d8ff04SGeorge V. Neville-Neil 	case CHELSIO_GET_UP_IOQS: {
3022f2d8ff04SGeorge V. Neville-Neil 		struct ch_up_ioqs *ioqs = (struct ch_up_ioqs *)data;
3023f2d8ff04SGeorge V. Neville-Neil 		uint8_t *buf = malloc(IOQS_BUFSIZE, M_DEVBUF, M_NOWAIT);
3024f2d8ff04SGeorge V. Neville-Neil 		uint32_t *v;
3025f2d8ff04SGeorge V. Neville-Neil 
3026f2d8ff04SGeorge V. Neville-Neil 		if (buf == NULL) {
3027f2d8ff04SGeorge V. Neville-Neil 			return (ENOMEM);
3028f2d8ff04SGeorge V. Neville-Neil 		}
3029f2d8ff04SGeorge V. Neville-Neil 		if (ioqs->bufsize < IOQS_BUFSIZE)
3030f2d8ff04SGeorge V. Neville-Neil 			error = ENOBUFS;
3031f2d8ff04SGeorge V. Neville-Neil 
3032f2d8ff04SGeorge V. Neville-Neil 		if (!error)
3033f2d8ff04SGeorge V. Neville-Neil 			error = -t3_get_up_ioqs(sc, &ioqs->bufsize, buf);
3034f2d8ff04SGeorge V. Neville-Neil 
3035f2d8ff04SGeorge V. Neville-Neil 		if (!error) {
3036f2d8ff04SGeorge V. Neville-Neil 			v = (uint32_t *)buf;
3037f2d8ff04SGeorge V. Neville-Neil 
3038f2d8ff04SGeorge V. Neville-Neil 			ioqs->bufsize -= 4 * sizeof(uint32_t);
3039f2d8ff04SGeorge V. Neville-Neil 			ioqs->ioq_rx_enable = *v++;
3040f2d8ff04SGeorge V. Neville-Neil 			ioqs->ioq_tx_enable = *v++;
3041f2d8ff04SGeorge V. Neville-Neil 			ioqs->ioq_rx_status = *v++;
3042f2d8ff04SGeorge V. Neville-Neil 			ioqs->ioq_tx_status = *v++;
3043f2d8ff04SGeorge V. Neville-Neil 
3044f2d8ff04SGeorge V. Neville-Neil 			error = copyout(v, ioqs->data, ioqs->bufsize);
3045f2d8ff04SGeorge V. Neville-Neil 		}
3046f2d8ff04SGeorge V. Neville-Neil 
3047f2d8ff04SGeorge V. Neville-Neil 		free(buf, M_DEVBUF);
3048f2d8ff04SGeorge V. Neville-Neil 		break;
3049f2d8ff04SGeorge V. Neville-Neil 	}
3050b6d90eb7SKip Macy 	default:
3051b6d90eb7SKip Macy 		return (EOPNOTSUPP);
3052b6d90eb7SKip Macy 		break;
3053b6d90eb7SKip Macy 	}
3054b6d90eb7SKip Macy 
3055b6d90eb7SKip Macy 	return (error);
3056b6d90eb7SKip Macy }
3057b6d90eb7SKip Macy 
3058b6d90eb7SKip Macy static __inline void
3059b6d90eb7SKip Macy reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
3060b6d90eb7SKip Macy     unsigned int end)
3061b6d90eb7SKip Macy {
30621ffd6e58SKip Macy 	uint32_t *p = (uint32_t *)(buf + start);
3063b6d90eb7SKip Macy 
3064b6d90eb7SKip Macy 	for ( ; start <= end; start += sizeof(uint32_t))
3065b6d90eb7SKip Macy 		*p++ = t3_read_reg(ap, start);
3066b6d90eb7SKip Macy }
3067b6d90eb7SKip Macy 
3068b6d90eb7SKip Macy #define T3_REGMAP_SIZE (3 * 1024)
3069b6d90eb7SKip Macy static int
3070b6d90eb7SKip Macy cxgb_get_regs_len(void)
3071b6d90eb7SKip Macy {
3072b6d90eb7SKip Macy 	return T3_REGMAP_SIZE;
3073b6d90eb7SKip Macy }
3074b6d90eb7SKip Macy 
3075b6d90eb7SKip Macy static void
30761ffd6e58SKip Macy cxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf)
3077b6d90eb7SKip Macy {
3078b6d90eb7SKip Macy 
3079b6d90eb7SKip Macy 	/*
3080b6d90eb7SKip Macy 	 * Version scheme:
3081b6d90eb7SKip Macy 	 * bits 0..9: chip version
3082b6d90eb7SKip Macy 	 * bits 10..15: chip revision
3083b6d90eb7SKip Macy 	 * bit 31: set for PCIe cards
3084b6d90eb7SKip Macy 	 */
3085b6d90eb7SKip Macy 	regs->version = 3 | (sc->params.rev << 10) | (is_pcie(sc) << 31);
3086b6d90eb7SKip Macy 
3087b6d90eb7SKip Macy 	/*
3088b6d90eb7SKip Macy 	 * We skip the MAC statistics registers because they are clear-on-read.
3089b6d90eb7SKip Macy 	 * Also reading multi-register stats would need to synchronize with the
3090b6d90eb7SKip Macy 	 * periodic mac stats accumulation.  Hard to justify the complexity.
3091b6d90eb7SKip Macy 	 */
30921ffd6e58SKip Macy 	memset(buf, 0, cxgb_get_regs_len());
3093b6d90eb7SKip Macy 	reg_block_dump(sc, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
3094b6d90eb7SKip Macy 	reg_block_dump(sc, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
3095b6d90eb7SKip Macy 	reg_block_dump(sc, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
3096b6d90eb7SKip Macy 	reg_block_dump(sc, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
3097b6d90eb7SKip Macy 	reg_block_dump(sc, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
3098b6d90eb7SKip Macy 	reg_block_dump(sc, buf, A_XGM_SERDES_STATUS0,
3099b6d90eb7SKip Macy 		       XGM_REG(A_XGM_SERDES_STAT3, 1));
3100b6d90eb7SKip Macy 	reg_block_dump(sc, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
3101b6d90eb7SKip Macy 		       XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
3102b6d90eb7SKip Macy }
3103404825a7SKip Macy 
3104404825a7SKip Macy 
3105404825a7SKip Macy MODULE_DEPEND(if_cxgb, cxgb_t3fw, 1, 1, 1);
3106