cxgb_main.c revision 192450
1167514Skmacy/**************************************************************************
2167514Skmacy
3189643SgnnCopyright (c) 2007-2009, Chelsio Inc.
4167514SkmacyAll rights reserved.
5167514Skmacy
6167514SkmacyRedistribution and use in source and binary forms, with or without
7167514Skmacymodification, are permitted provided that the following conditions are met:
8167514Skmacy
9167514Skmacy 1. Redistributions of source code must retain the above copyright notice,
10167514Skmacy    this list of conditions and the following disclaimer.
11167514Skmacy
12178302Skmacy 2. Neither the name of the Chelsio Corporation nor the names of its
13167514Skmacy    contributors may be used to endorse or promote products derived from
14167514Skmacy    this software without specific prior written permission.
15167514Skmacy
16167514SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17167514SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18167514SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19167514SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20167514SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21167514SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22167514SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23167514SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24167514SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25167514SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26167514SkmacyPOSSIBILITY OF SUCH DAMAGE.
27167514Skmacy
28167514Skmacy***************************************************************************/
29167514Skmacy
30167514Skmacy#include <sys/cdefs.h>
31167514Skmacy__FBSDID("$FreeBSD: head/sys/dev/cxgb/cxgb_main.c 192450 2009-05-20 17:29:21Z imp $");
32167514Skmacy
33167514Skmacy#include <sys/param.h>
34167514Skmacy#include <sys/systm.h>
35167514Skmacy#include <sys/kernel.h>
36167514Skmacy#include <sys/bus.h>
37167514Skmacy#include <sys/module.h>
38167514Skmacy#include <sys/pciio.h>
39167514Skmacy#include <sys/conf.h>
40167514Skmacy#include <machine/bus.h>
41167514Skmacy#include <machine/resource.h>
42167514Skmacy#include <sys/bus_dma.h>
43176472Skmacy#include <sys/ktr.h>
44167514Skmacy#include <sys/rman.h>
45167514Skmacy#include <sys/ioccom.h>
46167514Skmacy#include <sys/mbuf.h>
47167514Skmacy#include <sys/linker.h>
48167514Skmacy#include <sys/firmware.h>
49167514Skmacy#include <sys/socket.h>
50167514Skmacy#include <sys/sockio.h>
51167514Skmacy#include <sys/smp.h>
52167514Skmacy#include <sys/sysctl.h>
53174708Skmacy#include <sys/syslog.h>
54167514Skmacy#include <sys/queue.h>
55167514Skmacy#include <sys/taskqueue.h>
56174708Skmacy#include <sys/proc.h>
57167514Skmacy
58167514Skmacy#include <net/bpf.h>
59167514Skmacy#include <net/ethernet.h>
60167514Skmacy#include <net/if.h>
61167514Skmacy#include <net/if_arp.h>
62167514Skmacy#include <net/if_dl.h>
63167514Skmacy#include <net/if_media.h>
64167514Skmacy#include <net/if_types.h>
65180583Skmacy#include <net/if_vlan_var.h>
66167514Skmacy
67167514Skmacy#include <netinet/in_systm.h>
68167514Skmacy#include <netinet/in.h>
69167514Skmacy#include <netinet/if_ether.h>
70167514Skmacy#include <netinet/ip.h>
71167514Skmacy#include <netinet/ip.h>
72167514Skmacy#include <netinet/tcp.h>
73167514Skmacy#include <netinet/udp.h>
74167514Skmacy
75167514Skmacy#include <dev/pci/pcireg.h>
76167514Skmacy#include <dev/pci/pcivar.h>
77167514Skmacy#include <dev/pci/pci_private.h>
78167514Skmacy
79170076Skmacy#include <cxgb_include.h>
80167514Skmacy
81167514Skmacy#ifdef PRIV_SUPPORTED
82167514Skmacy#include <sys/priv.h>
83167514Skmacy#endif
84167514Skmacy
85167514Skmacystatic int cxgb_setup_msix(adapter_t *, int);
86170654Skmacystatic void cxgb_teardown_msix(adapter_t *);
87167514Skmacystatic void cxgb_init(void *);
88167514Skmacystatic void cxgb_init_locked(struct port_info *);
89167734Skmacystatic void cxgb_stop_locked(struct port_info *);
90167514Skmacystatic void cxgb_set_rxmode(struct port_info *);
91167514Skmacystatic int cxgb_ioctl(struct ifnet *, unsigned long, caddr_t);
92167514Skmacystatic int cxgb_media_change(struct ifnet *);
93186282Sgnnstatic int cxgb_ifm_type(int);
94167514Skmacystatic void cxgb_media_status(struct ifnet *, struct ifmediareq *);
95167514Skmacystatic int setup_sge_qsets(adapter_t *);
96167514Skmacystatic void cxgb_async_intr(void *);
97167514Skmacystatic void cxgb_ext_intr_handler(void *, int);
98170869Skmacystatic void cxgb_tick_handler(void *, int);
99170869Skmacystatic void cxgb_down_locked(struct adapter *sc);
100167514Skmacystatic void cxgb_tick(void *);
101167514Skmacystatic void setup_rss(adapter_t *sc);
102167514Skmacy
103167514Skmacy/* Attachment glue for the PCI controller end of the device.  Each port of
104167514Skmacy * the device is attached separately, as defined later.
105167514Skmacy */
106167514Skmacystatic int cxgb_controller_probe(device_t);
107167514Skmacystatic int cxgb_controller_attach(device_t);
108167514Skmacystatic int cxgb_controller_detach(device_t);
109167514Skmacystatic void cxgb_free(struct adapter *);
110167514Skmacystatic __inline void reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
111167514Skmacy    unsigned int end);
112182679Skmacystatic void cxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf);
113167514Skmacystatic int cxgb_get_regs_len(void);
114169978Skmacystatic int offload_open(struct port_info *pi);
115171978Skmacystatic void touch_bars(device_t dev);
116174626Skmacystatic int offload_close(struct t3cdev *tdev);
117176472Skmacystatic void cxgb_link_start(struct port_info *p);
118189643Sgnnstatic void cxgb_link_fault(void *arg, int ncount);
119167514Skmacy
120167514Skmacystatic device_method_t cxgb_controller_methods[] = {
121167514Skmacy	DEVMETHOD(device_probe,		cxgb_controller_probe),
122167514Skmacy	DEVMETHOD(device_attach,	cxgb_controller_attach),
123167514Skmacy	DEVMETHOD(device_detach,	cxgb_controller_detach),
124167514Skmacy
125167514Skmacy	/* bus interface */
126167514Skmacy	DEVMETHOD(bus_print_child,	bus_generic_print_child),
127167514Skmacy	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
128167514Skmacy
129167514Skmacy	{ 0, 0 }
130167514Skmacy};
131167514Skmacy
132167514Skmacystatic driver_t cxgb_controller_driver = {
133167514Skmacy	"cxgbc",
134167514Skmacy	cxgb_controller_methods,
135167514Skmacy	sizeof(struct adapter)
136167514Skmacy};
137167514Skmacy
138167514Skmacystatic devclass_t	cxgb_controller_devclass;
139167514SkmacyDRIVER_MODULE(cxgbc, pci, cxgb_controller_driver, cxgb_controller_devclass, 0, 0);
140167514Skmacy
141167514Skmacy/*
142167514Skmacy * Attachment glue for the ports.  Attachment is done directly to the
143167514Skmacy * controller device.
144167514Skmacy */
145167514Skmacystatic int cxgb_port_probe(device_t);
146167514Skmacystatic int cxgb_port_attach(device_t);
147167514Skmacystatic int cxgb_port_detach(device_t);
148167514Skmacy
149167514Skmacystatic device_method_t cxgb_port_methods[] = {
150167514Skmacy	DEVMETHOD(device_probe,		cxgb_port_probe),
151167514Skmacy	DEVMETHOD(device_attach,	cxgb_port_attach),
152167514Skmacy	DEVMETHOD(device_detach,	cxgb_port_detach),
153167514Skmacy	{ 0, 0 }
154167514Skmacy};
155167514Skmacy
156167514Skmacystatic driver_t cxgb_port_driver = {
157167514Skmacy	"cxgb",
158167514Skmacy	cxgb_port_methods,
159167514Skmacy	0
160167514Skmacy};
161167514Skmacy
162167514Skmacystatic d_ioctl_t cxgb_extension_ioctl;
163170654Skmacystatic d_open_t cxgb_extension_open;
164170654Skmacystatic d_close_t cxgb_extension_close;
165167514Skmacy
166170654Skmacystatic struct cdevsw cxgb_cdevsw = {
167170654Skmacy       .d_version =    D_VERSION,
168170654Skmacy       .d_flags =      0,
169170654Skmacy       .d_open =       cxgb_extension_open,
170170654Skmacy       .d_close =      cxgb_extension_close,
171170654Skmacy       .d_ioctl =      cxgb_extension_ioctl,
172170654Skmacy       .d_name =       "cxgb",
173170654Skmacy};
174170654Skmacy
175167514Skmacystatic devclass_t	cxgb_port_devclass;
176167514SkmacyDRIVER_MODULE(cxgb, cxgbc, cxgb_port_driver, cxgb_port_devclass, 0, 0);
177167514Skmacy
178167514Skmacy#define SGE_MSIX_COUNT (SGE_QSETS + 1)
179167514Skmacy
180167514Skmacy/*
181167514Skmacy * The driver uses the best interrupt scheme available on a platform in the
182167514Skmacy * order MSI-X, MSI, legacy pin interrupts.  This parameter determines which
183167514Skmacy * of these schemes the driver may consider as follows:
184167514Skmacy *
185167514Skmacy * msi = 2: choose from among all three options
186167514Skmacy * msi = 1 : only consider MSI and pin interrupts
187167514Skmacy * msi = 0: force pin interrupts
188167514Skmacy */
189167760Skmacystatic int msi_allowed = 2;
190170083Skmacy
191167514SkmacyTUNABLE_INT("hw.cxgb.msi_allowed", &msi_allowed);
192167514SkmacySYSCTL_NODE(_hw, OID_AUTO, cxgb, CTLFLAG_RD, 0, "CXGB driver parameters");
193167514SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, msi_allowed, CTLFLAG_RDTUN, &msi_allowed, 0,
194167514Skmacy    "MSI-X, MSI, INTx selector");
195169978Skmacy
196169053Skmacy/*
197169978Skmacy * The driver enables offload as a default.
198169978Skmacy * To disable it, use ofld_disable = 1.
199169053Skmacy */
200169978Skmacystatic int ofld_disable = 0;
201169978SkmacyTUNABLE_INT("hw.cxgb.ofld_disable", &ofld_disable);
202169978SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, ofld_disable, CTLFLAG_RDTUN, &ofld_disable, 0,
203169978Skmacy    "disable ULP offload");
204169978Skmacy
205169978Skmacy/*
206169978Skmacy * The driver uses an auto-queue algorithm by default.
207185165Skmacy * To disable it and force a single queue-set per port, use multiq = 0
208169978Skmacy */
209185165Skmacystatic int multiq = 1;
210185165SkmacyTUNABLE_INT("hw.cxgb.multiq", &multiq);
211185165SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, multiq, CTLFLAG_RDTUN, &multiq, 0,
212185165Skmacy    "use min(ncpus/ports, 8) queue-sets per port");
213167514Skmacy
214176572Skmacy/*
215185165Skmacy * By default the driver will not update the firmware unless
216185165Skmacy * it was compiled against a newer version
217185165Skmacy *
218176572Skmacy */
219176572Skmacystatic int force_fw_update = 0;
220176572SkmacyTUNABLE_INT("hw.cxgb.force_fw_update", &force_fw_update);
221176572SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, force_fw_update, CTLFLAG_RDTUN, &force_fw_update, 0,
222176572Skmacy    "update firmware even if up to date");
223175200Skmacy
224183059Skmacyint cxgb_use_16k_clusters = 1;
225175200SkmacyTUNABLE_INT("hw.cxgb.use_16k_clusters", &cxgb_use_16k_clusters);
226175200SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, use_16k_clusters, CTLFLAG_RDTUN,
227175200Skmacy    &cxgb_use_16k_clusters, 0, "use 16kB clusters for the jumbo queue ");
228175200Skmacy
229167514Skmacyenum {
230167514Skmacy	MAX_TXQ_ENTRIES      = 16384,
231167514Skmacy	MAX_CTRL_TXQ_ENTRIES = 1024,
232167514Skmacy	MAX_RSPQ_ENTRIES     = 16384,
233167514Skmacy	MAX_RX_BUFFERS       = 16384,
234167514Skmacy	MAX_RX_JUMBO_BUFFERS = 16384,
235167514Skmacy	MIN_TXQ_ENTRIES      = 4,
236167514Skmacy	MIN_CTRL_TXQ_ENTRIES = 4,
237167514Skmacy	MIN_RSPQ_ENTRIES     = 32,
238172096Skmacy	MIN_FL_ENTRIES       = 32,
239172096Skmacy	MIN_FL_JUMBO_ENTRIES = 32
240167514Skmacy};
241167514Skmacy
242171471Skmacystruct filter_info {
243171471Skmacy	u32 sip;
244171471Skmacy	u32 sip_mask;
245171471Skmacy	u32 dip;
246171471Skmacy	u16 sport;
247171471Skmacy	u16 dport;
248171471Skmacy	u32 vlan:12;
249171471Skmacy	u32 vlan_prio:3;
250171471Skmacy	u32 mac_hit:1;
251171471Skmacy	u32 mac_idx:4;
252171471Skmacy	u32 mac_vld:1;
253171471Skmacy	u32 pkt_type:2;
254171471Skmacy	u32 report_filter_id:1;
255171471Skmacy	u32 pass:1;
256171471Skmacy	u32 rss:1;
257171471Skmacy	u32 qset:3;
258171471Skmacy	u32 locked:1;
259171471Skmacy	u32 valid:1;
260171471Skmacy};
261171471Skmacy
262171471Skmacyenum { FILTER_NO_VLAN_PRI = 7 };
263171471Skmacy
264182679Skmacy#define EEPROM_MAGIC 0x38E2F10C
265182679Skmacy
266167514Skmacy#define PORT_MASK ((1 << MAX_NPORTS) - 1)
267167514Skmacy
268167514Skmacy/* Table for probing the cards.  The desc field isn't actually used */
269167514Skmacystruct cxgb_ident {
270167514Skmacy	uint16_t	vendor;
271167514Skmacy	uint16_t	device;
272167514Skmacy	int		index;
273167514Skmacy	char		*desc;
274167514Skmacy} cxgb_identifiers[] = {
275167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0020, 0, "PE9000"},
276167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0021, 1, "T302E"},
277167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0022, 2, "T310E"},
278167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0023, 3, "T320X"},
279167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0024, 1, "T302X"},
280167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0025, 3, "T320E"},
281167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0026, 2, "T310X"},
282167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0030, 2, "T3B10"},
283167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0031, 3, "T3B20"},
284167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0032, 1, "T3B02"},
285170654Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0033, 4, "T3B04"},
286185662Sgnn	{PCI_VENDOR_ID_CHELSIO, 0x0035, 6, "N310E"},
287167514Skmacy	{0, 0, 0, NULL}
288167514Skmacy};
289167514Skmacy
290171471Skmacystatic int set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset);
291171471Skmacy
292176472Skmacy
293174708Skmacystatic __inline char
294171471Skmacyt3rev2char(struct adapter *adapter)
295171471Skmacy{
296171471Skmacy	char rev = 'z';
297171471Skmacy
298171471Skmacy	switch(adapter->params.rev) {
299171471Skmacy	case T3_REV_A:
300171471Skmacy		rev = 'a';
301171471Skmacy		break;
302171471Skmacy	case T3_REV_B:
303171471Skmacy	case T3_REV_B2:
304171471Skmacy		rev = 'b';
305171471Skmacy		break;
306171471Skmacy	case T3_REV_C:
307171471Skmacy		rev = 'c';
308171471Skmacy		break;
309171471Skmacy	}
310171471Skmacy	return rev;
311171471Skmacy}
312171471Skmacy
313167514Skmacystatic struct cxgb_ident *
314167514Skmacycxgb_get_ident(device_t dev)
315167514Skmacy{
316167514Skmacy	struct cxgb_ident *id;
317167514Skmacy
318167514Skmacy	for (id = cxgb_identifiers; id->desc != NULL; id++) {
319167514Skmacy		if ((id->vendor == pci_get_vendor(dev)) &&
320167514Skmacy		    (id->device == pci_get_device(dev))) {
321167514Skmacy			return (id);
322167514Skmacy		}
323167514Skmacy	}
324167514Skmacy	return (NULL);
325167514Skmacy}
326167514Skmacy
327167514Skmacystatic const struct adapter_info *
328167514Skmacycxgb_get_adapter_info(device_t dev)
329167514Skmacy{
330167514Skmacy	struct cxgb_ident *id;
331167514Skmacy	const struct adapter_info *ai;
332183063Skmacy
333167514Skmacy	id = cxgb_get_ident(dev);
334167514Skmacy	if (id == NULL)
335167514Skmacy		return (NULL);
336167514Skmacy
337167514Skmacy	ai = t3_get_adapter_info(id->index);
338167514Skmacy
339167514Skmacy	return (ai);
340167514Skmacy}
341167514Skmacy
342167514Skmacystatic int
343167514Skmacycxgb_controller_probe(device_t dev)
344167514Skmacy{
345167514Skmacy	const struct adapter_info *ai;
346167514Skmacy	char *ports, buf[80];
347170654Skmacy	int nports;
348182695Skmacy	struct adapter *sc = device_get_softc(dev);
349183063Skmacy
350167514Skmacy	ai = cxgb_get_adapter_info(dev);
351167514Skmacy	if (ai == NULL)
352167514Skmacy		return (ENXIO);
353167514Skmacy
354170654Skmacy	nports = ai->nports0 + ai->nports1;
355170654Skmacy	if (nports == 1)
356167514Skmacy		ports = "port";
357167514Skmacy	else
358167514Skmacy		ports = "ports";
359167514Skmacy
360182695Skmacy	snprintf(buf, sizeof(buf), "%s %sNIC, rev: %d nports: %d %s",
361185165Skmacy	    ai->desc, is_offload(sc) ? "R" : "",
362185165Skmacy	    sc->params.rev, nports, ports);
363167514Skmacy	device_set_desc_copy(dev, buf);
364167514Skmacy	return (BUS_PROBE_DEFAULT);
365167514Skmacy}
366167514Skmacy
367176572Skmacy#define FW_FNAME "cxgb_t3fw"
368190330Sgnn#define TPEEPROM_NAME "cxgb_t3%c_tp_eeprom"
369190330Sgnn#define TPSRAM_NAME "cxgb_t3%c_protocol_sram"
370171471Skmacy
371167514Skmacystatic int
372169978Skmacyupgrade_fw(adapter_t *sc)
373167514Skmacy{
374167514Skmacy#ifdef FIRMWARE_LATEST
375167514Skmacy	const struct firmware *fw;
376167514Skmacy#else
377167514Skmacy	struct firmware *fw;
378167514Skmacy#endif
379167514Skmacy	int status;
380167514Skmacy
381176572Skmacy	if ((fw = firmware_get(FW_FNAME)) == NULL)  {
382176572Skmacy		device_printf(sc->dev, "Could not find firmware image %s\n", FW_FNAME);
383169978Skmacy		return (ENOENT);
384171471Skmacy	} else
385176572Skmacy		device_printf(sc->dev, "updating firmware on card\n");
386167514Skmacy	status = t3_load_fw(sc, (const uint8_t *)fw->data, fw->datasize);
387167514Skmacy
388171471Skmacy	device_printf(sc->dev, "firmware update returned %s %d\n", (status == 0) ? "success" : "fail", status);
389171471Skmacy
390167514Skmacy	firmware_put(fw, FIRMWARE_UNLOAD);
391167514Skmacy
392167514Skmacy	return (status);
393167514Skmacy}
394167514Skmacy
395167514Skmacystatic int
396167514Skmacycxgb_controller_attach(device_t dev)
397167514Skmacy{
398167514Skmacy	device_t child;
399167514Skmacy	const struct adapter_info *ai;
400167514Skmacy	struct adapter *sc;
401172109Skmacy	int i, error = 0;
402167514Skmacy	uint32_t vers;
403167760Skmacy	int port_qsets = 1;
404171868Skmacy#ifdef MSI_SUPPORTED
405172109Skmacy	int msi_needed, reg;
406176472Skmacy#endif
407185655Sgnn	char buf[80];
408185655Sgnn
409167514Skmacy	sc = device_get_softc(dev);
410167514Skmacy	sc->dev = dev;
411169978Skmacy	sc->msi_count = 0;
412172109Skmacy	ai = cxgb_get_adapter_info(dev);
413172109Skmacy
414172109Skmacy	/*
415172109Skmacy	 * XXX not really related but a recent addition
416172109Skmacy	 */
417172109Skmacy#ifdef MSI_SUPPORTED
418167840Skmacy	/* find the PCIe link width and set max read request to 4KB*/
419167840Skmacy	if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
420167840Skmacy		uint16_t lnk, pectl;
421167840Skmacy		lnk = pci_read_config(dev, reg + 0x12, 2);
422167840Skmacy		sc->link_width = (lnk >> 4) & 0x3f;
423167840Skmacy
424167840Skmacy		pectl = pci_read_config(dev, reg + 0x8, 2);
425167840Skmacy		pectl = (pectl & ~0x7000) | (5 << 12);
426167840Skmacy		pci_write_config(dev, reg + 0x8, pectl, 2);
427167840Skmacy	}
428171471Skmacy
429171471Skmacy	if (sc->link_width != 0 && sc->link_width <= 4 &&
430171471Skmacy	    (ai->nports0 + ai->nports1) <= 2) {
431167840Skmacy		device_printf(sc->dev,
432167862Skmacy		    "PCIe x%d Link, expect reduced performance\n",
433167840Skmacy		    sc->link_width);
434167840Skmacy	}
435172109Skmacy#endif
436171978Skmacy	touch_bars(dev);
437167514Skmacy	pci_enable_busmaster(dev);
438167514Skmacy	/*
439167514Skmacy	 * Allocate the registers and make them available to the driver.
440167514Skmacy	 * The registers that we care about for NIC mode are in BAR 0
441167514Skmacy	 */
442167514Skmacy	sc->regs_rid = PCIR_BAR(0);
443167514Skmacy	if ((sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
444167514Skmacy	    &sc->regs_rid, RF_ACTIVE)) == NULL) {
445176472Skmacy		device_printf(dev, "Cannot allocate BAR region 0\n");
446167514Skmacy		return (ENXIO);
447167514Skmacy	}
448176472Skmacy	sc->udbs_rid = PCIR_BAR(2);
449185662Sgnn	sc->udbs_res = NULL;
450185662Sgnn	if (is_offload(sc) &&
451185662Sgnn	    ((sc->udbs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
452185662Sgnn		   &sc->udbs_rid, RF_ACTIVE)) == NULL)) {
453176472Skmacy		device_printf(dev, "Cannot allocate BAR region 1\n");
454176472Skmacy		error = ENXIO;
455176472Skmacy		goto out;
456185662Sgnn	}
457167514Skmacy
458170869Skmacy	snprintf(sc->lockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb controller lock %d",
459170869Skmacy	    device_get_unit(dev));
460170869Skmacy	ADAPTER_LOCK_INIT(sc, sc->lockbuf);
461170869Skmacy
462170869Skmacy	snprintf(sc->reglockbuf, ADAPTER_LOCK_NAME_LEN, "SGE reg lock %d",
463170869Skmacy	    device_get_unit(dev));
464170869Skmacy	snprintf(sc->mdiolockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb mdio lock %d",
465170869Skmacy	    device_get_unit(dev));
466170869Skmacy	snprintf(sc->elmerlockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb elmer lock %d",
467170869Skmacy	    device_get_unit(dev));
468167514Skmacy
469176472Skmacy	MTX_INIT(&sc->sge.reg_lock, sc->reglockbuf, NULL, MTX_SPIN);
470170869Skmacy	MTX_INIT(&sc->mdio_lock, sc->mdiolockbuf, NULL, MTX_DEF);
471170869Skmacy	MTX_INIT(&sc->elmer_lock, sc->elmerlockbuf, NULL, MTX_DEF);
472170869Skmacy
473167514Skmacy	sc->bt = rman_get_bustag(sc->regs_res);
474167514Skmacy	sc->bh = rman_get_bushandle(sc->regs_res);
475167514Skmacy	sc->mmio_len = rman_get_size(sc->regs_res);
476167769Skmacy
477167769Skmacy	if (t3_prep_adapter(sc, ai, 1) < 0) {
478170654Skmacy		printf("prep adapter failed\n");
479167769Skmacy		error = ENODEV;
480167769Skmacy		goto out;
481167769Skmacy	}
482177464Skmacy        /* Allocate the BAR for doing MSI-X.  If it succeeds, try to allocate
483167514Skmacy	 * enough messages for the queue sets.  If that fails, try falling
484167514Skmacy	 * back to MSI.  If that fails, then try falling back to the legacy
485167514Skmacy	 * interrupt pin model.
486167514Skmacy	 */
487167514Skmacy#ifdef MSI_SUPPORTED
488167760Skmacy
489167514Skmacy	sc->msix_regs_rid = 0x20;
490167514Skmacy	if ((msi_allowed >= 2) &&
491167514Skmacy	    (sc->msix_regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
492167514Skmacy	    &sc->msix_regs_rid, RF_ACTIVE)) != NULL) {
493167514Skmacy
494169978Skmacy		msi_needed = sc->msi_count = SGE_MSIX_COUNT;
495167760Skmacy
496169978Skmacy		if (((error = pci_alloc_msix(dev, &sc->msi_count)) != 0) ||
497169978Skmacy		    (sc->msi_count != msi_needed)) {
498169978Skmacy			device_printf(dev, "msix allocation failed - msi_count = %d"
499169978Skmacy			    " msi_needed=%d will try msi err=%d\n", sc->msi_count,
500169978Skmacy			    msi_needed, error);
501169978Skmacy			sc->msi_count = 0;
502167514Skmacy			pci_release_msi(dev);
503167514Skmacy			bus_release_resource(dev, SYS_RES_MEMORY,
504167514Skmacy			    sc->msix_regs_rid, sc->msix_regs_res);
505167514Skmacy			sc->msix_regs_res = NULL;
506167514Skmacy		} else {
507167514Skmacy			sc->flags |= USING_MSIX;
508170081Skmacy			sc->cxgb_intr = t3_intr_msix;
509167514Skmacy		}
510167514Skmacy	}
511167514Skmacy
512169978Skmacy	if ((msi_allowed >= 1) && (sc->msi_count == 0)) {
513169978Skmacy		sc->msi_count = 1;
514169978Skmacy		if (pci_alloc_msi(dev, &sc->msi_count)) {
515167760Skmacy			device_printf(dev, "alloc msi failed - will try INTx\n");
516169978Skmacy			sc->msi_count = 0;
517167514Skmacy			pci_release_msi(dev);
518167514Skmacy		} else {
519167514Skmacy			sc->flags |= USING_MSI;
520167514Skmacy			sc->irq_rid = 1;
521170081Skmacy			sc->cxgb_intr = t3_intr_msi;
522167514Skmacy		}
523167514Skmacy	}
524167514Skmacy#endif
525169978Skmacy	if (sc->msi_count == 0) {
526167760Skmacy		device_printf(dev, "using line interrupts\n");
527167514Skmacy		sc->irq_rid = 0;
528170081Skmacy		sc->cxgb_intr = t3b_intr;
529167514Skmacy	}
530167514Skmacy
531185165Skmacy	if ((sc->flags & USING_MSIX) && multiq)
532177464Skmacy		port_qsets = min((SGE_QSETS/(sc)->params.nports), mp_ncpus);
533177464Skmacy
534167514Skmacy	/* Create a private taskqueue thread for handling driver events */
535167514Skmacy#ifdef TASKQUEUE_CURRENT
536167514Skmacy	sc->tq = taskqueue_create("cxgb_taskq", M_NOWAIT,
537167514Skmacy	    taskqueue_thread_enqueue, &sc->tq);
538167514Skmacy#else
539167514Skmacy	sc->tq = taskqueue_create_fast("cxgb_taskq", M_NOWAIT,
540167514Skmacy	    taskqueue_thread_enqueue, &sc->tq);
541167514Skmacy#endif
542167514Skmacy	if (sc->tq == NULL) {
543167514Skmacy		device_printf(dev, "failed to allocate controller task queue\n");
544167514Skmacy		goto out;
545167514Skmacy	}
546171804Skmacy
547167514Skmacy	taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq",
548167514Skmacy	    device_get_nameunit(dev));
549167514Skmacy	TASK_INIT(&sc->ext_intr_task, 0, cxgb_ext_intr_handler, sc);
550170869Skmacy	TASK_INIT(&sc->tick_task, 0, cxgb_tick_handler, sc);
551167514Skmacy
552167514Skmacy
553167514Skmacy	/* Create a periodic callout for checking adapter status */
554170869Skmacy	callout_init(&sc->cxgb_tick_ch, TRUE);
555167514Skmacy
556189643Sgnn	if (t3_check_fw_version(sc) < 0 || force_fw_update) {
557167514Skmacy		/*
558167514Skmacy		 * Warn user that a firmware update will be attempted in init.
559167514Skmacy		 */
560169978Skmacy		device_printf(dev, "firmware needs to be updated to version %d.%d.%d\n",
561169978Skmacy		    FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
562167514Skmacy		sc->flags &= ~FW_UPTODATE;
563167514Skmacy	} else {
564167514Skmacy		sc->flags |= FW_UPTODATE;
565167514Skmacy	}
566171471Skmacy
567189643Sgnn	if (t3_check_tpsram_version(sc) < 0) {
568171471Skmacy		/*
569171471Skmacy		 * Warn user that a firmware update will be attempted in init.
570171471Skmacy		 */
571171471Skmacy		device_printf(dev, "SRAM needs to be updated to version %c-%d.%d.%d\n",
572171471Skmacy		    t3rev2char(sc), TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
573171471Skmacy		sc->flags &= ~TPS_UPTODATE;
574171471Skmacy	} else {
575171471Skmacy		sc->flags |= TPS_UPTODATE;
576171471Skmacy	}
577167514Skmacy
578167514Skmacy	/*
579167514Skmacy	 * Create a child device for each MAC.  The ethernet attachment
580167514Skmacy	 * will be done in these children.
581167760Skmacy	 */
582167760Skmacy	for (i = 0; i < (sc)->params.nports; i++) {
583171978Skmacy		struct port_info *pi;
584171978Skmacy
585167514Skmacy		if ((child = device_add_child(dev, "cxgb", -1)) == NULL) {
586167514Skmacy			device_printf(dev, "failed to add child port\n");
587167514Skmacy			error = EINVAL;
588167514Skmacy			goto out;
589167514Skmacy		}
590171978Skmacy		pi = &sc->port[i];
591171978Skmacy		pi->adapter = sc;
592171978Skmacy		pi->nqsets = port_qsets;
593171978Skmacy		pi->first_qset = i*port_qsets;
594171978Skmacy		pi->port_id = i;
595171978Skmacy		pi->tx_chan = i >= ai->nports0;
596171978Skmacy		pi->txpkt_intf = pi->tx_chan ? 2 * (i - ai->nports0) + 1 : 2 * i;
597171978Skmacy		sc->rxpkt_map[pi->txpkt_intf] = i;
598174708Skmacy		sc->port[i].tx_chan = i >= ai->nports0;
599171471Skmacy		sc->portdev[i] = child;
600171978Skmacy		device_set_softc(child, pi);
601167514Skmacy	}
602167514Skmacy	if ((error = bus_generic_attach(dev)) != 0)
603167514Skmacy		goto out;
604167514Skmacy
605167514Skmacy	/* initialize sge private state */
606170654Skmacy	t3_sge_init_adapter(sc);
607167514Skmacy
608167514Skmacy	t3_led_ready(sc);
609169978Skmacy
610169978Skmacy	cxgb_offload_init();
611169978Skmacy	if (is_offload(sc)) {
612169978Skmacy		setbit(&sc->registered_device_map, OFFLOAD_DEVMAP_BIT);
613169978Skmacy		cxgb_adapter_ofld(sc);
614169978Skmacy        }
615167514Skmacy	error = t3_get_fw_version(sc, &vers);
616167514Skmacy	if (error)
617167514Skmacy		goto out;
618167514Skmacy
619169978Skmacy	snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d.%d",
620169978Skmacy	    G_FW_VERSION_MAJOR(vers), G_FW_VERSION_MINOR(vers),
621169978Skmacy	    G_FW_VERSION_MICRO(vers));
622169978Skmacy
623185655Sgnn	snprintf(buf, sizeof(buf), "%s\t E/C: %s S/N: %s",
624185655Sgnn		 ai->desc,
625185655Sgnn		 sc->params.vpd.ec, sc->params.vpd.sn);
626185655Sgnn	device_set_desc_copy(dev, buf);
627185655Sgnn
628176472Skmacy	device_printf(sc->dev, "Firmware Version %s\n", &sc->fw_version[0]);
629181652Skmacy	callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc);
630174708Skmacy	t3_add_attach_sysctls(sc);
631167514Skmacyout:
632167514Skmacy	if (error)
633167514Skmacy		cxgb_free(sc);
634167514Skmacy
635167514Skmacy	return (error);
636167514Skmacy}
637167514Skmacy
638167514Skmacystatic int
639167514Skmacycxgb_controller_detach(device_t dev)
640167514Skmacy{
641167514Skmacy	struct adapter *sc;
642167514Skmacy
643167514Skmacy	sc = device_get_softc(dev);
644167514Skmacy
645167514Skmacy	cxgb_free(sc);
646167514Skmacy
647167514Skmacy	return (0);
648167514Skmacy}
649167514Skmacy
650167514Skmacystatic void
651167514Skmacycxgb_free(struct adapter *sc)
652167514Skmacy{
653167514Skmacy	int i;
654167514Skmacy
655176472Skmacy	ADAPTER_LOCK(sc);
656176472Skmacy	sc->flags |= CXGB_SHUTDOWN;
657176472Skmacy	ADAPTER_UNLOCK(sc);
658174708Skmacy	cxgb_pcpu_shutdown_threads(sc);
659170869Skmacy	ADAPTER_LOCK(sc);
660176472Skmacy
661174708Skmacy/*
662174708Skmacy * drops the lock
663174708Skmacy */
664170869Skmacy	cxgb_down_locked(sc);
665169978Skmacy
666169978Skmacy#ifdef MSI_SUPPORTED
667169978Skmacy	if (sc->flags & (USING_MSI | USING_MSIX)) {
668169978Skmacy		device_printf(sc->dev, "releasing msi message(s)\n");
669169978Skmacy		pci_release_msi(sc->dev);
670169978Skmacy	} else {
671169978Skmacy		device_printf(sc->dev, "no msi message to release\n");
672169978Skmacy	}
673169978Skmacy#endif
674169978Skmacy	if (sc->msix_regs_res != NULL) {
675169978Skmacy		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid,
676169978Skmacy		    sc->msix_regs_res);
677169978Skmacy	}
678176472Skmacy
679171978Skmacy	t3_sge_deinit_sw(sc);
680171978Skmacy	/*
681171978Skmacy	 * Wait for last callout
682171978Skmacy	 */
683171978Skmacy
684174708Skmacy	DELAY(hz*100);
685170869Skmacy
686167760Skmacy	for (i = 0; i < (sc)->params.nports; ++i) {
687167760Skmacy		if (sc->portdev[i] != NULL)
688167760Skmacy			device_delete_child(sc->dev, sc->portdev[i]);
689167760Skmacy	}
690167760Skmacy
691167514Skmacy	bus_generic_detach(sc->dev);
692176472Skmacy	if (sc->tq != NULL) {
693171978Skmacy		taskqueue_free(sc->tq);
694176472Skmacy		sc->tq = NULL;
695176472Skmacy	}
696176472Skmacy
697169978Skmacy	if (is_offload(sc)) {
698169978Skmacy		cxgb_adapter_unofld(sc);
699169978Skmacy		if (isset(&sc->open_device_map,	OFFLOAD_DEVMAP_BIT))
700169978Skmacy			offload_close(&sc->tdev);
701174708Skmacy		else
702174708Skmacy			printf("cxgb_free: DEVMAP_BIT not set\n");
703174708Skmacy	} else
704174708Skmacy		printf("not offloading set\n");
705183059Skmacy#ifdef notyet
706176472Skmacy	if (sc->flags & CXGB_OFLD_INIT)
707176472Skmacy		cxgb_offload_deactivate(sc);
708178302Skmacy#endif
709171471Skmacy	free(sc->filters, M_DEVBUF);
710167514Skmacy	t3_sge_free(sc);
711170869Skmacy
712170869Skmacy	cxgb_offload_exit();
713176472Skmacy
714176472Skmacy	if (sc->udbs_res != NULL)
715176472Skmacy		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->udbs_rid,
716176472Skmacy		    sc->udbs_res);
717176472Skmacy
718167514Skmacy	if (sc->regs_res != NULL)
719167514Skmacy		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->regs_rid,
720167514Skmacy		    sc->regs_res);
721167514Skmacy
722170869Skmacy	MTX_DESTROY(&sc->mdio_lock);
723170869Skmacy	MTX_DESTROY(&sc->sge.reg_lock);
724170869Skmacy	MTX_DESTROY(&sc->elmer_lock);
725170869Skmacy	ADAPTER_LOCK_DEINIT(sc);
726167514Skmacy}
727167514Skmacy
728167514Skmacy/**
729167514Skmacy *	setup_sge_qsets - configure SGE Tx/Rx/response queues
730167514Skmacy *	@sc: the controller softc
731167514Skmacy *
732167514Skmacy *	Determines how many sets of SGE queues to use and initializes them.
733167514Skmacy *	We support multiple queue sets per port if we have MSI-X, otherwise
734167514Skmacy *	just one queue set per port.
735167514Skmacy */
736167514Skmacystatic int
737167514Skmacysetup_sge_qsets(adapter_t *sc)
738167514Skmacy{
739172096Skmacy	int i, j, err, irq_idx = 0, qset_idx = 0;
740169978Skmacy	u_int ntxq = SGE_TXQ_PER_SET;
741167514Skmacy
742167514Skmacy	if ((err = t3_sge_alloc(sc)) != 0) {
743167760Skmacy		device_printf(sc->dev, "t3_sge_alloc returned %d\n", err);
744167514Skmacy		return (err);
745167514Skmacy	}
746167514Skmacy
747167514Skmacy	if (sc->params.rev > 0 && !(sc->flags & USING_MSI))
748167514Skmacy		irq_idx = -1;
749167514Skmacy
750172096Skmacy	for (i = 0; i < (sc)->params.nports; i++) {
751167514Skmacy		struct port_info *pi = &sc->port[i];
752167514Skmacy
753171978Skmacy		for (j = 0; j < pi->nqsets; j++, qset_idx++) {
754167760Skmacy			err = t3_sge_alloc_qset(sc, qset_idx, (sc)->params.nports,
755167514Skmacy			    (sc->flags & USING_MSIX) ? qset_idx + 1 : irq_idx,
756167514Skmacy			    &sc->params.sge.qset[qset_idx], ntxq, pi);
757167514Skmacy			if (err) {
758167514Skmacy				t3_free_sge_resources(sc);
759171978Skmacy				device_printf(sc->dev, "t3_sge_alloc_qset failed with %d\n",
760171978Skmacy				    err);
761167514Skmacy				return (err);
762167514Skmacy			}
763167514Skmacy		}
764167514Skmacy	}
765167514Skmacy
766167514Skmacy	return (0);
767167514Skmacy}
768167514Skmacy
769170654Skmacystatic void
770170654Skmacycxgb_teardown_msix(adapter_t *sc)
771170654Skmacy{
772170654Skmacy	int i, nqsets;
773170654Skmacy
774170654Skmacy	for (nqsets = i = 0; i < (sc)->params.nports; i++)
775170654Skmacy		nqsets += sc->port[i].nqsets;
776170654Skmacy
777170654Skmacy	for (i = 0; i < nqsets; i++) {
778170654Skmacy		if (sc->msix_intr_tag[i] != NULL) {
779170654Skmacy			bus_teardown_intr(sc->dev, sc->msix_irq_res[i],
780170654Skmacy			    sc->msix_intr_tag[i]);
781170654Skmacy			sc->msix_intr_tag[i] = NULL;
782170654Skmacy		}
783170654Skmacy		if (sc->msix_irq_res[i] != NULL) {
784170654Skmacy			bus_release_resource(sc->dev, SYS_RES_IRQ,
785170654Skmacy			    sc->msix_irq_rid[i], sc->msix_irq_res[i]);
786170654Skmacy			sc->msix_irq_res[i] = NULL;
787170654Skmacy		}
788170654Skmacy	}
789170654Skmacy}
790170654Skmacy
791167514Skmacystatic int
792167514Skmacycxgb_setup_msix(adapter_t *sc, int msix_count)
793167514Skmacy{
794167514Skmacy	int i, j, k, nqsets, rid;
795167514Skmacy
796167514Skmacy	/* The first message indicates link changes and error conditions */
797167514Skmacy	sc->irq_rid = 1;
798167514Skmacy	if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
799167514Skmacy	   &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
800167514Skmacy		device_printf(sc->dev, "Cannot allocate msix interrupt\n");
801167514Skmacy		return (EINVAL);
802167514Skmacy	}
803167760Skmacy
804167514Skmacy	if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET,
805167514Skmacy#ifdef INTR_FILTERS
806171978Skmacy		NULL,
807167514Skmacy#endif
808167514Skmacy		cxgb_async_intr, sc, &sc->intr_tag)) {
809167514Skmacy		device_printf(sc->dev, "Cannot set up interrupt\n");
810167514Skmacy		return (EINVAL);
811167514Skmacy	}
812170654Skmacy	for (i = k = 0; i < (sc)->params.nports; i++) {
813167514Skmacy		nqsets = sc->port[i].nqsets;
814170654Skmacy		for (j = 0; j < nqsets; j++, k++) {
815167514Skmacy			struct sge_qset *qs = &sc->sge.qs[k];
816171804Skmacy
817167514Skmacy			rid = k + 2;
818167514Skmacy			if (cxgb_debug)
819167514Skmacy				printf("rid=%d ", rid);
820167514Skmacy			if ((sc->msix_irq_res[k] = bus_alloc_resource_any(
821167514Skmacy			    sc->dev, SYS_RES_IRQ, &rid,
822167514Skmacy			    RF_SHAREABLE | RF_ACTIVE)) == NULL) {
823167514Skmacy				device_printf(sc->dev, "Cannot allocate "
824167514Skmacy				    "interrupt for message %d\n", rid);
825167514Skmacy				return (EINVAL);
826167514Skmacy			}
827167514Skmacy			sc->msix_irq_rid[k] = rid;
828170654Skmacy			if (bus_setup_intr(sc->dev, sc->msix_irq_res[k],
829174708Skmacy				INTR_MPSAFE|INTR_TYPE_NET,
830167514Skmacy#ifdef INTR_FILTERS
831171978Skmacy				NULL,
832167514Skmacy#endif
833167514Skmacy				t3_intr_msix, qs, &sc->msix_intr_tag[k])) {
834167514Skmacy				device_printf(sc->dev, "Cannot set up "
835167514Skmacy				    "interrupt for message %d\n", rid);
836167514Skmacy				return (EINVAL);
837185165Skmacy
838167514Skmacy			}
839185165Skmacy#if 0
840174708Skmacy#ifdef IFNET_MULTIQUEUE
841185165Skmacy			if (multiq) {
842174708Skmacy				int vector = rman_get_start(sc->msix_irq_res[k]);
843174708Skmacy				if (bootverbose)
844174708Skmacy					device_printf(sc->dev, "binding vector=%d to cpu=%d\n", vector, k % mp_ncpus);
845174708Skmacy				intr_bind(vector, k % mp_ncpus);
846174708Skmacy			}
847185165Skmacy#endif
848185165Skmacy#endif
849167514Skmacy		}
850167514Skmacy	}
851167760Skmacy
852167514Skmacy	return (0);
853167514Skmacy}
854167514Skmacy
855167514Skmacystatic int
856167514Skmacycxgb_port_probe(device_t dev)
857167514Skmacy{
858167514Skmacy	struct port_info *p;
859167514Skmacy	char buf[80];
860176472Skmacy	const char *desc;
861176472Skmacy
862167514Skmacy	p = device_get_softc(dev);
863176472Skmacy	desc = p->phy.desc;
864176472Skmacy	snprintf(buf, sizeof(buf), "Port %d %s", p->port_id, desc);
865167514Skmacy	device_set_desc_copy(dev, buf);
866167514Skmacy	return (0);
867167514Skmacy}
868167514Skmacy
869167514Skmacy
870167514Skmacystatic int
871167514Skmacycxgb_makedev(struct port_info *pi)
872167514Skmacy{
873167514Skmacy
874170654Skmacy	pi->port_cdev = make_dev(&cxgb_cdevsw, pi->ifp->if_dunit,
875170654Skmacy	    UID_ROOT, GID_WHEEL, 0600, if_name(pi->ifp));
876167514Skmacy
877167514Skmacy	if (pi->port_cdev == NULL)
878167514Skmacy		return (ENOMEM);
879167514Skmacy
880167514Skmacy	pi->port_cdev->si_drv1 = (void *)pi;
881167514Skmacy
882167514Skmacy	return (0);
883167514Skmacy}
884167514Skmacy
885183289Skmacy#ifndef LRO_SUPPORTED
886183289Skmacy#ifdef IFCAP_LRO
887183289Skmacy#undef IFCAP_LRO
888183289Skmacy#endif
889183289Skmacy#define IFCAP_LRO 0x0
890183289Skmacy#endif
891167514Skmacy
892167514Skmacy#ifdef TSO_SUPPORTED
893181616Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO)
894167514Skmacy/* Don't enable TSO6 yet */
895181616Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO4 | IFCAP_JUMBO_MTU | IFCAP_LRO)
896167514Skmacy#else
897167514Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU)
898167514Skmacy/* Don't enable TSO6 yet */
899167514Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM |  IFCAP_JUMBO_MTU)
900167514Skmacy#define IFCAP_TSO4 0x0
901171868Skmacy#define IFCAP_TSO6 0x0
902167514Skmacy#define CSUM_TSO   0x0
903167514Skmacy#endif
904167514Skmacy
905167514Skmacy
906167514Skmacystatic int
907167514Skmacycxgb_port_attach(device_t dev)
908167514Skmacy{
909167514Skmacy	struct port_info *p;
910167514Skmacy	struct ifnet *ifp;
911170654Skmacy	int err, media_flags;
912176472Skmacy	struct adapter *sc;
913167514Skmacy
914176472Skmacy
915167514Skmacy	p = device_get_softc(dev);
916176472Skmacy	sc = p->adapter;
917170869Skmacy	snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d",
918171803Skmacy	    device_get_unit(device_get_parent(dev)), p->port_id);
919170869Skmacy	PORT_LOCK_INIT(p, p->lockbuf);
920167514Skmacy
921167514Skmacy	/* Allocate an ifnet object and set it up */
922167514Skmacy	ifp = p->ifp = if_alloc(IFT_ETHER);
923167514Skmacy	if (ifp == NULL) {
924167514Skmacy		device_printf(dev, "Cannot allocate ifnet\n");
925167514Skmacy		return (ENOMEM);
926167514Skmacy	}
927167514Skmacy
928167514Skmacy	/*
929167514Skmacy	 * Note that there is currently no watchdog timer.
930167514Skmacy	 */
931167514Skmacy	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
932167514Skmacy	ifp->if_init = cxgb_init;
933167514Skmacy	ifp->if_softc = p;
934167514Skmacy	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
935167514Skmacy	ifp->if_ioctl = cxgb_ioctl;
936167514Skmacy	ifp->if_start = cxgb_start;
937174708Skmacy
938185165Skmacy
939167514Skmacy	ifp->if_timer = 0;	/* Disable ifnet watchdog */
940167514Skmacy	ifp->if_watchdog = NULL;
941167514Skmacy
942185165Skmacy	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
943167514Skmacy	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
944167514Skmacy	IFQ_SET_READY(&ifp->if_snd);
945167514Skmacy
946167514Skmacy	ifp->if_hwassist = ifp->if_capabilities = ifp->if_capenable = 0;
947167514Skmacy	ifp->if_capabilities |= CXGB_CAP;
948167514Skmacy	ifp->if_capenable |= CXGB_CAP_ENABLE;
949167514Skmacy	ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO);
950171471Skmacy	/*
951171471Skmacy	 * disable TSO on 4-port - it isn't supported by the firmware yet
952171471Skmacy	 */
953171471Skmacy	if (p->adapter->params.nports > 2) {
954171471Skmacy		ifp->if_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6);
955171471Skmacy		ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TSO6);
956171471Skmacy		ifp->if_hwassist &= ~CSUM_TSO;
957171471Skmacy	}
958171471Skmacy
959167514Skmacy	ether_ifattach(ifp, p->hw_addr);
960185199Skmacy#ifdef IFNET_MULTIQUEUE
961185165Skmacy	ifp->if_transmit = cxgb_pcpu_transmit;
962185199Skmacy#endif
963171471Skmacy	/*
964171471Skmacy	 * Only default to jumbo frames on 10GigE
965171471Skmacy	 */
966171471Skmacy	if (p->adapter->params.nports <= 2)
967180583Skmacy		ifp->if_mtu = ETHERMTU_JUMBO;
968167514Skmacy	if ((err = cxgb_makedev(p)) != 0) {
969167514Skmacy		printf("makedev failed %d\n", err);
970167514Skmacy		return (err);
971167514Skmacy	}
972167514Skmacy	ifmedia_init(&p->media, IFM_IMASK, cxgb_media_change,
973167514Skmacy	    cxgb_media_status);
974176472Skmacy
975176472Skmacy	if (!strcmp(p->phy.desc,	"10GBASE-CX4")) {
976170654Skmacy		media_flags = IFM_ETHER | IFM_10G_CX4 | IFM_FDX;
977176472Skmacy	} else if (!strcmp(p->phy.desc, "10GBASE-SR")) {
978170654Skmacy		media_flags = IFM_ETHER | IFM_10G_SR | IFM_FDX;
979177340Skmacy	} else if (!strcmp(p->phy.desc, "10GBASE-R")) {
980186282Sgnn		media_flags = cxgb_ifm_type(p->phy.modtype);
981176472Skmacy	} else if (!strcmp(p->phy.desc, "10/100/1000BASE-T")) {
982170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_10_T, 0, NULL);
983170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_10_T | IFM_FDX,
984170654Skmacy			    0, NULL);
985170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX,
986170654Skmacy			    0, NULL);
987170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX | IFM_FDX,
988170654Skmacy			    0, NULL);
989170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_1000_T | IFM_FDX,
990170654Skmacy			    0, NULL);
991170654Skmacy		media_flags = 0;
992183506Skmacy	} else if (!strcmp(p->phy.desc, "1000BASE-X")) {
993183506Skmacy		/*
994183506Skmacy		 * XXX: This is not very accurate.  Fix when common code
995183506Skmacy		 * returns more specific value - eg 1000BASE-SX, LX, etc.
996186282Sgnn		 *
997186282Sgnn		 * XXX: In the meantime, don't lie. Consider setting IFM_AUTO
998186282Sgnn		 * instead of SX.
999183506Skmacy		 */
1000183506Skmacy		media_flags = IFM_ETHER | IFM_1000_SX | IFM_FDX;
1001170654Skmacy	} else {
1002176472Skmacy	        printf("unsupported media type %s\n", p->phy.desc);
1003167514Skmacy		return (ENXIO);
1004167514Skmacy	}
1005170654Skmacy	if (media_flags) {
1006186282Sgnn		/*
1007186282Sgnn		 * Note the modtype on which we based our flags.  If modtype
1008186282Sgnn		 * changes, we'll redo the ifmedia for this ifp.  modtype may
1009186282Sgnn		 * change when transceivers are plugged in/out, and in other
1010186282Sgnn		 * situations.
1011186282Sgnn		 */
1012186282Sgnn		ifmedia_add(&p->media, media_flags, p->phy.modtype, NULL);
1013170654Skmacy		ifmedia_set(&p->media, media_flags);
1014170654Skmacy	} else {
1015170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL);
1016170654Skmacy		ifmedia_set(&p->media, IFM_ETHER | IFM_AUTO);
1017170654Skmacy	}
1018167514Skmacy
1019177340Skmacy	/* Get the latest mac address, User can use a LAA */
1020177340Skmacy	bcopy(IF_LLADDR(p->ifp), p->hw_addr, ETHER_ADDR_LEN);
1021170654Skmacy	t3_sge_init_port(p);
1022189643Sgnn
1023189643Sgnn	TASK_INIT(&p->link_fault_task, 0, cxgb_link_fault, p);
1024189643Sgnn
1025177415Skmacy#if defined(LINK_ATTACH)
1026176472Skmacy	cxgb_link_start(p);
1027176472Skmacy	t3_link_changed(sc, p->port_id);
1028177415Skmacy#endif
1029167514Skmacy	return (0);
1030167514Skmacy}
1031167514Skmacy
1032167514Skmacystatic int
1033167514Skmacycxgb_port_detach(device_t dev)
1034167514Skmacy{
1035167514Skmacy	struct port_info *p;
1036167514Skmacy
1037167514Skmacy	p = device_get_softc(dev);
1038169978Skmacy
1039169978Skmacy	PORT_LOCK(p);
1040170654Skmacy	if (p->ifp->if_drv_flags & IFF_DRV_RUNNING)
1041170654Skmacy		cxgb_stop_locked(p);
1042169978Skmacy	PORT_UNLOCK(p);
1043169978Skmacy
1044171978Skmacy	ether_ifdetach(p->ifp);
1045174708Skmacy	printf("waiting for callout to stop ...");
1046174708Skmacy	DELAY(1000000);
1047174708Skmacy	printf("done\n");
1048171978Skmacy	/*
1049171978Skmacy	 * the lock may be acquired in ifdetach
1050171978Skmacy	 */
1051170869Skmacy	PORT_LOCK_DEINIT(p);
1052167514Skmacy	if_free(p->ifp);
1053167514Skmacy
1054170654Skmacy	if (p->port_cdev != NULL)
1055170654Skmacy		destroy_dev(p->port_cdev);
1056170654Skmacy
1057167514Skmacy	return (0);
1058167514Skmacy}
1059167514Skmacy
1060167514Skmacyvoid
1061167514Skmacyt3_fatal_err(struct adapter *sc)
1062167514Skmacy{
1063167514Skmacy	u_int fw_status[4];
1064183062Skmacy
1065172096Skmacy	if (sc->flags & FULL_INIT_DONE) {
1066172096Skmacy		t3_sge_stop(sc);
1067172096Skmacy		t3_write_reg(sc, A_XGM_TX_CTRL, 0);
1068172096Skmacy		t3_write_reg(sc, A_XGM_RX_CTRL, 0);
1069172096Skmacy		t3_write_reg(sc, XGM_REG(A_XGM_TX_CTRL, 1), 0);
1070172096Skmacy		t3_write_reg(sc, XGM_REG(A_XGM_RX_CTRL, 1), 0);
1071172096Skmacy		t3_intr_disable(sc);
1072172096Skmacy	}
1073167514Skmacy	device_printf(sc->dev,"encountered fatal error, operation suspended\n");
1074167514Skmacy	if (!t3_cim_ctl_blk_read(sc, 0xa0, 4, fw_status))
1075167514Skmacy		device_printf(sc->dev, "FW_ status: 0x%x, 0x%x, 0x%x, 0x%x\n",
1076167514Skmacy		    fw_status[0], fw_status[1], fw_status[2], fw_status[3]);
1077167514Skmacy}
1078167514Skmacy
1079167514Skmacyint
1080167514Skmacyt3_os_find_pci_capability(adapter_t *sc, int cap)
1081167514Skmacy{
1082167514Skmacy	device_t dev;
1083167514Skmacy	struct pci_devinfo *dinfo;
1084167514Skmacy	pcicfgregs *cfg;
1085167514Skmacy	uint32_t status;
1086167514Skmacy	uint8_t ptr;
1087167514Skmacy
1088167514Skmacy	dev = sc->dev;
1089167514Skmacy	dinfo = device_get_ivars(dev);
1090167514Skmacy	cfg = &dinfo->cfg;
1091167514Skmacy
1092167514Skmacy	status = pci_read_config(dev, PCIR_STATUS, 2);
1093167514Skmacy	if (!(status & PCIM_STATUS_CAPPRESENT))
1094167514Skmacy		return (0);
1095167514Skmacy
1096167514Skmacy	switch (cfg->hdrtype & PCIM_HDRTYPE) {
1097167514Skmacy	case 0:
1098167514Skmacy	case 1:
1099167514Skmacy		ptr = PCIR_CAP_PTR;
1100167514Skmacy		break;
1101167514Skmacy	case 2:
1102167514Skmacy		ptr = PCIR_CAP_PTR_2;
1103167514Skmacy		break;
1104167514Skmacy	default:
1105167514Skmacy		return (0);
1106167514Skmacy		break;
1107167514Skmacy	}
1108167514Skmacy	ptr = pci_read_config(dev, ptr, 1);
1109167514Skmacy
1110167514Skmacy	while (ptr != 0) {
1111167514Skmacy		if (pci_read_config(dev, ptr + PCICAP_ID, 1) == cap)
1112167514Skmacy			return (ptr);
1113167514Skmacy		ptr = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1);
1114167514Skmacy	}
1115167514Skmacy
1116167514Skmacy	return (0);
1117167514Skmacy}
1118167514Skmacy
1119167514Skmacyint
1120167514Skmacyt3_os_pci_save_state(struct adapter *sc)
1121167514Skmacy{
1122167514Skmacy	device_t dev;
1123167514Skmacy	struct pci_devinfo *dinfo;
1124167514Skmacy
1125167514Skmacy	dev = sc->dev;
1126167514Skmacy	dinfo = device_get_ivars(dev);
1127167514Skmacy
1128167514Skmacy	pci_cfg_save(dev, dinfo, 0);
1129167514Skmacy	return (0);
1130167514Skmacy}
1131167514Skmacy
1132167514Skmacyint
1133167514Skmacyt3_os_pci_restore_state(struct adapter *sc)
1134167514Skmacy{
1135167514Skmacy	device_t dev;
1136167514Skmacy	struct pci_devinfo *dinfo;
1137167514Skmacy
1138167514Skmacy	dev = sc->dev;
1139167514Skmacy	dinfo = device_get_ivars(dev);
1140167514Skmacy
1141167514Skmacy	pci_cfg_restore(dev, dinfo);
1142167514Skmacy	return (0);
1143167514Skmacy}
1144167514Skmacy
1145189643Sgnnvoid t3_os_link_fault(struct adapter *adap, int port_id, int state)
1146189643Sgnn{
1147189643Sgnn	struct port_info *pi = &adap->port[port_id];
1148189643Sgnn
1149189643Sgnn	if (!state) {
1150189643Sgnn		if_link_state_change(pi->ifp, LINK_STATE_DOWN);
1151189643Sgnn		return;
1152189643Sgnn	}
1153189643Sgnn
1154189643Sgnn	if (adap->params.nports <= 2) {
1155189643Sgnn		struct cmac *mac = &pi->mac;
1156189643Sgnn
1157189643Sgnn		/* Clear local faults */
1158189643Sgnn		t3_xgm_intr_disable(adap, port_id);
1159189643Sgnn		t3_read_reg(adap, A_XGM_INT_STATUS + pi->mac.offset);
1160189643Sgnn		t3_write_reg(adap, A_XGM_INT_CAUSE + pi->mac.offset, F_XGM_INT);
1161189643Sgnn
1162189643Sgnn		t3_set_reg_field(adap, A_XGM_INT_ENABLE + pi->mac.offset,
1163189643Sgnn				 F_XGM_INT, F_XGM_INT);
1164189643Sgnn		t3_xgm_intr_enable(adap, pi->port_id);
1165189643Sgnn		t3_mac_enable(mac, MAC_DIRECTION_TX);
1166189643Sgnn	}
1167189643Sgnn
1168189643Sgnn	if_link_state_change(pi->ifp, LINK_STATE_UP);
1169189643Sgnn}
1170189643Sgnn
1171167514Skmacy/**
1172167514Skmacy *	t3_os_link_changed - handle link status changes
1173167514Skmacy *	@adapter: the adapter associated with the link change
1174167514Skmacy *	@port_id: the port index whose limk status has changed
1175177340Skmacy *	@link_status: the new status of the link
1176167514Skmacy *	@speed: the new speed setting
1177167514Skmacy *	@duplex: the new duplex setting
1178167514Skmacy *	@fc: the new flow-control setting
1179167514Skmacy *
1180167514Skmacy *	This is the OS-dependent handler for link status changes.  The OS
1181167514Skmacy *	neutral handler takes care of most of the processing for these events,
1182167514Skmacy *	then calls this handler for any OS-specific processing.
1183167514Skmacy */
1184167514Skmacyvoid
1185167514Skmacyt3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed,
1186167514Skmacy     int duplex, int fc)
1187167514Skmacy{
1188167514Skmacy	struct port_info *pi = &adapter->port[port_id];
1189169978Skmacy	struct cmac *mac = &adapter->port[port_id].mac;
1190167514Skmacy
1191169978Skmacy	if (link_status) {
1192177340Skmacy		DELAY(10);
1193177340Skmacy		t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
1194189643Sgnn		/* Clear errors created by MAC enable */
1195189643Sgnn		t3_set_reg_field(adapter, A_XGM_STAT_CTRL + pi->mac.offset,
1196189643Sgnn				 F_CLRSTATS, 1);
1197189643Sgnn
1198189643Sgnn		if (adapter->params.nports <= 2) {
1199189643Sgnn			/* Clear local faults */
1200189643Sgnn			t3_xgm_intr_disable(adapter, pi->port_id);
1201189643Sgnn			t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
1202189643Sgnn			t3_write_reg(adapter, A_XGM_INT_CAUSE + pi->mac.offset,
1203189643Sgnn				     F_XGM_INT);
1204189643Sgnn
1205177340Skmacy			t3_set_reg_field(adapter,
1206189643Sgnn					 A_XGM_INT_ENABLE + pi->mac.offset,
1207189643Sgnn					 F_XGM_INT, F_XGM_INT);
1208189643Sgnn			t3_xgm_intr_enable(adapter, pi->port_id);
1209189643Sgnn		}
1210189643Sgnn
1211167514Skmacy		if_link_state_change(pi->ifp, LINK_STATE_UP);
1212189643Sgnn	} else {
1213189643Sgnn		t3_xgm_intr_disable(adapter, pi->port_id);
1214189643Sgnn		t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
1215189643Sgnn		if (adapter->params.nports <= 2) {
1216189643Sgnn			t3_set_reg_field(adapter,
1217189643Sgnn					 A_XGM_INT_ENABLE + pi->mac.offset,
1218189643Sgnn					 F_XGM_INT, 0);
1219189643Sgnn		}
1220177340Skmacy
1221189643Sgnn		/* PR 5666. We shouldn't power down 1G phys */
1222189643Sgnn		if (is_10G(adapter))
1223189643Sgnn			pi->phy.ops->power_down(&pi->phy, 1);
1224189643Sgnn
1225189643Sgnn		t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
1226169978Skmacy		t3_mac_disable(mac, MAC_DIRECTION_RX);
1227169978Skmacy		t3_link_start(&pi->phy, mac, &pi->link_config);
1228189643Sgnn
1229176472Skmacy		if_link_state_change(pi->ifp, LINK_STATE_DOWN);
1230169978Skmacy	}
1231167514Skmacy}
1232167514Skmacy
1233181614Skmacy/**
1234181614Skmacy *	t3_os_phymod_changed - handle PHY module changes
1235181614Skmacy *	@phy: the PHY reporting the module change
1236181614Skmacy *	@mod_type: new module type
1237181614Skmacy *
1238181614Skmacy *	This is the OS-dependent handler for PHY module changes.  It is
1239181614Skmacy *	invoked when a PHY module is removed or inserted for any OS-specific
1240181614Skmacy *	processing.
1241181614Skmacy */
1242181614Skmacyvoid t3_os_phymod_changed(struct adapter *adap, int port_id)
1243181614Skmacy{
1244181614Skmacy	static const char *mod_str[] = {
1245181614Skmacy		NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown"
1246181614Skmacy	};
1247181614Skmacy
1248181614Skmacy	struct port_info *pi = &adap->port[port_id];
1249181614Skmacy
1250181614Skmacy	if (pi->phy.modtype == phy_modtype_none)
1251181614Skmacy		device_printf(adap->dev, "PHY module unplugged\n");
1252181614Skmacy	else {
1253181614Skmacy		KASSERT(pi->phy.modtype < ARRAY_SIZE(mod_str),
1254181614Skmacy		    ("invalid PHY module type %d", pi->phy.modtype));
1255181614Skmacy		device_printf(adap->dev, "%s PHY module inserted\n",
1256181614Skmacy		    mod_str[pi->phy.modtype]);
1257181614Skmacy	}
1258181614Skmacy}
1259181614Skmacy
1260167514Skmacy/*
1261167514Skmacy * Interrupt-context handler for external (PHY) interrupts.
1262167514Skmacy */
1263167514Skmacyvoid
1264167514Skmacyt3_os_ext_intr_handler(adapter_t *sc)
1265167514Skmacy{
1266167514Skmacy	if (cxgb_debug)
1267167514Skmacy		printf("t3_os_ext_intr_handler\n");
1268167514Skmacy	/*
1269167514Skmacy	 * Schedule a task to handle external interrupts as they may be slow
1270167514Skmacy	 * and we use a mutex to protect MDIO registers.  We disable PHY
1271167514Skmacy	 * interrupts in the meantime and let the task reenable them when
1272167514Skmacy	 * it's done.
1273167514Skmacy	 */
1274169978Skmacy	ADAPTER_LOCK(sc);
1275167514Skmacy	if (sc->slow_intr_mask) {
1276167514Skmacy		sc->slow_intr_mask &= ~F_T3DBG;
1277167514Skmacy		t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
1278167514Skmacy		taskqueue_enqueue(sc->tq, &sc->ext_intr_task);
1279167514Skmacy	}
1280169978Skmacy	ADAPTER_UNLOCK(sc);
1281167514Skmacy}
1282167514Skmacy
1283189643Sgnnstatic void
1284189643Sgnncxgb_link_fault(void *arg, int ncount)
1285189643Sgnn{
1286189643Sgnn	struct port_info *pi = arg;
1287189643Sgnn
1288189643Sgnn	t3_link_fault(pi->adapter, pi->port_id);
1289189643Sgnn}
1290189643Sgnn
1291189643Sgnnvoid t3_os_link_fault_handler(struct adapter *sc, int port_id)
1292189643Sgnn{
1293189643Sgnn	struct port_info *pi = &sc->port[port_id];
1294189643Sgnn
1295189643Sgnn	pi->link_fault = 1;
1296189643Sgnn	taskqueue_enqueue(sc->tq, &pi->link_fault_task);
1297189643Sgnn}
1298189643Sgnn
1299167514Skmacyvoid
1300167514Skmacyt3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[])
1301167514Skmacy{
1302167514Skmacy
1303167514Skmacy	/*
1304167514Skmacy	 * The ifnet might not be allocated before this gets called,
1305167514Skmacy	 * as this is called early on in attach by t3_prep_adapter
1306167514Skmacy	 * save the address off in the port structure
1307167514Skmacy	 */
1308167514Skmacy	if (cxgb_debug)
1309167514Skmacy		printf("set_hw_addr on idx %d addr %6D\n", port_idx, hw_addr, ":");
1310167514Skmacy	bcopy(hw_addr, adapter->port[port_idx].hw_addr, ETHER_ADDR_LEN);
1311167514Skmacy}
1312167514Skmacy
1313167514Skmacy/**
1314167514Skmacy *	link_start - enable a port
1315167514Skmacy *	@p: the port to enable
1316167514Skmacy *
1317167514Skmacy *	Performs the MAC and PHY actions needed to enable a port.
1318167514Skmacy */
1319167514Skmacystatic void
1320167514Skmacycxgb_link_start(struct port_info *p)
1321167514Skmacy{
1322167514Skmacy	struct ifnet *ifp;
1323167514Skmacy	struct t3_rx_mode rm;
1324167514Skmacy	struct cmac *mac = &p->mac;
1325180583Skmacy	int mtu, hwtagging;
1326167514Skmacy
1327167514Skmacy	ifp = p->ifp;
1328167514Skmacy
1329180583Skmacy	bcopy(IF_LLADDR(ifp), p->hw_addr, ETHER_ADDR_LEN);
1330180583Skmacy
1331180583Skmacy	mtu = ifp->if_mtu;
1332180583Skmacy	if (ifp->if_capenable & IFCAP_VLAN_MTU)
1333180583Skmacy		mtu += ETHER_VLAN_ENCAP_LEN;
1334180583Skmacy
1335180583Skmacy	hwtagging = (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0;
1336180583Skmacy
1337167514Skmacy	t3_init_rx_mode(&rm, p);
1338172096Skmacy	if (!mac->multiport)
1339171978Skmacy		t3_mac_reset(mac);
1340180583Skmacy	t3_mac_set_mtu(mac, mtu);
1341180583Skmacy	t3_set_vlan_accel(p->adapter, 1 << p->tx_chan, hwtagging);
1342167514Skmacy	t3_mac_set_address(mac, 0, p->hw_addr);
1343167514Skmacy	t3_mac_set_rx_mode(mac, &rm);
1344167514Skmacy	t3_link_start(&p->phy, mac, &p->link_config);
1345167514Skmacy	t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
1346167514Skmacy}
1347167514Skmacy
1348176472Skmacy
1349176472Skmacystatic int
1350176472Skmacyawait_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
1351176472Skmacy			      unsigned long n)
1352176472Skmacy{
1353176472Skmacy	int attempts = 5;
1354176472Skmacy
1355176472Skmacy	while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
1356176472Skmacy		if (!--attempts)
1357176472Skmacy			return (ETIMEDOUT);
1358176472Skmacy		t3_os_sleep(10);
1359176472Skmacy	}
1360176472Skmacy	return 0;
1361176472Skmacy}
1362176472Skmacy
1363176472Skmacystatic int
1364176472Skmacyinit_tp_parity(struct adapter *adap)
1365176472Skmacy{
1366176472Skmacy	int i;
1367176472Skmacy	struct mbuf *m;
1368176472Skmacy	struct cpl_set_tcb_field *greq;
1369176472Skmacy	unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts;
1370176472Skmacy
1371176472Skmacy	t3_tp_set_offload_mode(adap, 1);
1372176472Skmacy
1373176472Skmacy	for (i = 0; i < 16; i++) {
1374176472Skmacy		struct cpl_smt_write_req *req;
1375176472Skmacy
1376176472Skmacy		m = m_gethdr(M_WAITOK, MT_DATA);
1377176472Skmacy		req = mtod(m, struct cpl_smt_write_req *);
1378176472Skmacy		m->m_len = m->m_pkthdr.len = sizeof(*req);
1379176472Skmacy		memset(req, 0, sizeof(*req));
1380176472Skmacy		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1381176472Skmacy		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
1382176472Skmacy		req->iff = i;
1383176472Skmacy		t3_mgmt_tx(adap, m);
1384176472Skmacy	}
1385176472Skmacy
1386176472Skmacy	for (i = 0; i < 2048; i++) {
1387176472Skmacy		struct cpl_l2t_write_req *req;
1388176472Skmacy
1389176472Skmacy		m = m_gethdr(M_WAITOK, MT_DATA);
1390176472Skmacy		req = mtod(m, struct cpl_l2t_write_req *);
1391176472Skmacy		m->m_len = m->m_pkthdr.len = sizeof(*req);
1392176472Skmacy		memset(req, 0, sizeof(*req));
1393176472Skmacy		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1394176472Skmacy		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
1395176472Skmacy		req->params = htonl(V_L2T_W_IDX(i));
1396176472Skmacy		t3_mgmt_tx(adap, m);
1397176472Skmacy	}
1398176472Skmacy
1399176472Skmacy	for (i = 0; i < 2048; i++) {
1400176472Skmacy		struct cpl_rte_write_req *req;
1401176472Skmacy
1402176472Skmacy		m = m_gethdr(M_WAITOK, MT_DATA);
1403176472Skmacy		req = mtod(m, struct cpl_rte_write_req *);
1404176472Skmacy		m->m_len = m->m_pkthdr.len = sizeof(*req);
1405176472Skmacy		memset(req, 0, sizeof(*req));
1406176472Skmacy		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1407176472Skmacy		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
1408176472Skmacy		req->l2t_idx = htonl(V_L2T_W_IDX(i));
1409176472Skmacy		t3_mgmt_tx(adap, m);
1410176472Skmacy	}
1411176472Skmacy
1412176472Skmacy	m = m_gethdr(M_WAITOK, MT_DATA);
1413176472Skmacy	greq = mtod(m, struct cpl_set_tcb_field *);
1414176472Skmacy	m->m_len = m->m_pkthdr.len = sizeof(*greq);
1415176472Skmacy	memset(greq, 0, sizeof(*greq));
1416176472Skmacy	greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1417176472Skmacy	OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0));
1418176472Skmacy	greq->mask = htobe64(1);
1419176472Skmacy	t3_mgmt_tx(adap, m);
1420176472Skmacy
1421176472Skmacy	i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
1422176472Skmacy	t3_tp_set_offload_mode(adap, 0);
1423176472Skmacy	return (i);
1424176472Skmacy}
1425176472Skmacy
1426167514Skmacy/**
1427167514Skmacy *	setup_rss - configure Receive Side Steering (per-queue connection demux)
1428167514Skmacy *	@adap: the adapter
1429167514Skmacy *
1430167514Skmacy *	Sets up RSS to distribute packets to multiple receive queues.  We
1431167514Skmacy *	configure the RSS CPU lookup table to distribute to the number of HW
1432167514Skmacy *	receive queues, and the response queue lookup table to narrow that
1433167514Skmacy *	down to the response queues actually configured for each port.
1434167514Skmacy *	We always configure the RSS mapping for two ports since the mapping
1435167514Skmacy *	table has plenty of entries.
1436167514Skmacy */
1437167514Skmacystatic void
1438167514Skmacysetup_rss(adapter_t *adap)
1439167514Skmacy{
1440167514Skmacy	int i;
1441171471Skmacy	u_int nq[2];
1442167514Skmacy	uint8_t cpus[SGE_QSETS + 1];
1443167514Skmacy	uint16_t rspq_map[RSS_TABLE_SIZE];
1444171471Skmacy
1445167514Skmacy	for (i = 0; i < SGE_QSETS; ++i)
1446167514Skmacy		cpus[i] = i;
1447167514Skmacy	cpus[SGE_QSETS] = 0xff;
1448167514Skmacy
1449171978Skmacy	nq[0] = nq[1] = 0;
1450171978Skmacy	for_each_port(adap, i) {
1451171978Skmacy		const struct port_info *pi = adap2pinfo(adap, i);
1452171978Skmacy
1453171978Skmacy		nq[pi->tx_chan] += pi->nqsets;
1454171978Skmacy	}
1455167514Skmacy	for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
1456176472Skmacy		rspq_map[i] = nq[0] ? i % nq[0] : 0;
1457176472Skmacy		rspq_map[i + RSS_TABLE_SIZE / 2] = nq[1] ? i % nq[1] + nq[0] : 0;
1458167514Skmacy	}
1459171471Skmacy	/* Calculate the reverse RSS map table */
1460171471Skmacy	for (i = 0; i < RSS_TABLE_SIZE; ++i)
1461171471Skmacy		if (adap->rrss_map[rspq_map[i]] == 0xff)
1462171471Skmacy			adap->rrss_map[rspq_map[i]] = i;
1463167514Skmacy
1464167514Skmacy	t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
1465171471Skmacy		      F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | F_OFDMAPEN |
1466176472Skmacy	              F_RRCPLMAPEN | V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ,
1467176472Skmacy	              cpus, rspq_map);
1468171471Skmacy
1469167514Skmacy}
1470167514Skmacy
1471169978Skmacy/*
1472169978Skmacy * Sends an mbuf to an offload queue driver
1473169978Skmacy * after dealing with any active network taps.
1474169978Skmacy */
1475169978Skmacystatic inline int
1476174626Skmacyoffload_tx(struct t3cdev *tdev, struct mbuf *m)
1477169978Skmacy{
1478169978Skmacy	int ret;
1479169978Skmacy
1480169978Skmacy	ret = t3_offload_tx(tdev, m);
1481170654Skmacy	return (ret);
1482169978Skmacy}
1483169978Skmacy
1484169978Skmacystatic int
1485169978Skmacywrite_smt_entry(struct adapter *adapter, int idx)
1486169978Skmacy{
1487169978Skmacy	struct port_info *pi = &adapter->port[idx];
1488169978Skmacy	struct cpl_smt_write_req *req;
1489169978Skmacy	struct mbuf *m;
1490169978Skmacy
1491169978Skmacy	if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
1492169978Skmacy		return (ENOMEM);
1493169978Skmacy
1494169978Skmacy	req = mtod(m, struct cpl_smt_write_req *);
1495174708Skmacy	m->m_pkthdr.len = m->m_len = sizeof(struct cpl_smt_write_req);
1496174708Skmacy
1497169978Skmacy	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1498169978Skmacy	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
1499169978Skmacy	req->mtu_idx = NMTUS - 1;  /* should be 0 but there's a T3 bug */
1500169978Skmacy	req->iff = idx;
1501169978Skmacy	memset(req->src_mac1, 0, sizeof(req->src_mac1));
1502169978Skmacy	memcpy(req->src_mac0, pi->hw_addr, ETHER_ADDR_LEN);
1503169978Skmacy
1504169978Skmacy	m_set_priority(m, 1);
1505169978Skmacy
1506169978Skmacy	offload_tx(&adapter->tdev, m);
1507169978Skmacy
1508169978Skmacy	return (0);
1509169978Skmacy}
1510169978Skmacy
1511169978Skmacystatic int
1512169978Skmacyinit_smt(struct adapter *adapter)
1513169978Skmacy{
1514169978Skmacy	int i;
1515169978Skmacy
1516169978Skmacy	for_each_port(adapter, i)
1517169978Skmacy		write_smt_entry(adapter, i);
1518169978Skmacy	return 0;
1519169978Skmacy}
1520169978Skmacy
1521167514Skmacystatic void
1522169978Skmacyinit_port_mtus(adapter_t *adapter)
1523169978Skmacy{
1524169978Skmacy	unsigned int mtus = adapter->port[0].ifp->if_mtu;
1525169978Skmacy
1526169978Skmacy	if (adapter->port[1].ifp)
1527169978Skmacy		mtus |= adapter->port[1].ifp->if_mtu << 16;
1528169978Skmacy	t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
1529169978Skmacy}
1530169978Skmacy
1531169978Skmacystatic void
1532167514Skmacysend_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
1533167514Skmacy			      int hi, int port)
1534167514Skmacy{
1535167514Skmacy	struct mbuf *m;
1536167514Skmacy	struct mngt_pktsched_wr *req;
1537167514Skmacy
1538171471Skmacy	m = m_gethdr(M_DONTWAIT, MT_DATA);
1539167848Skmacy	if (m) {
1540169978Skmacy		req = mtod(m, struct mngt_pktsched_wr *);
1541167848Skmacy		req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
1542167848Skmacy		req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
1543167848Skmacy		req->sched = sched;
1544167848Skmacy		req->idx = qidx;
1545167848Skmacy		req->min = lo;
1546167848Skmacy		req->max = hi;
1547167848Skmacy		req->binding = port;
1548167848Skmacy		m->m_len = m->m_pkthdr.len = sizeof(*req);
1549167848Skmacy		t3_mgmt_tx(adap, m);
1550167848Skmacy	}
1551167514Skmacy}
1552167514Skmacy
1553167514Skmacystatic void
1554167514Skmacybind_qsets(adapter_t *sc)
1555167514Skmacy{
1556167514Skmacy	int i, j;
1557167514Skmacy
1558174708Skmacy	cxgb_pcpu_startup_threads(sc);
1559167514Skmacy	for (i = 0; i < (sc)->params.nports; ++i) {
1560167514Skmacy		const struct port_info *pi = adap2pinfo(sc, i);
1561167514Skmacy
1562172096Skmacy		for (j = 0; j < pi->nqsets; ++j) {
1563167514Skmacy			send_pktsched_cmd(sc, 1, pi->first_qset + j, -1,
1564172096Skmacy					  -1, pi->tx_chan);
1565172096Skmacy
1566172096Skmacy		}
1567167514Skmacy	}
1568167514Skmacy}
1569167514Skmacy
1570171471Skmacystatic void
1571171471Skmacyupdate_tpeeprom(struct adapter *adap)
1572171471Skmacy{
1573172109Skmacy#ifdef FIRMWARE_LATEST
1574171471Skmacy	const struct firmware *tpeeprom;
1575172109Skmacy#else
1576172109Skmacy	struct firmware *tpeeprom;
1577172109Skmacy#endif
1578172109Skmacy
1579171471Skmacy	uint32_t version;
1580171471Skmacy	unsigned int major, minor;
1581171471Skmacy	int ret, len;
1582189643Sgnn	char rev, name[32];
1583171471Skmacy
1584171471Skmacy	t3_seeprom_read(adap, TP_SRAM_OFFSET, &version);
1585171471Skmacy
1586171471Skmacy	major = G_TP_VERSION_MAJOR(version);
1587171471Skmacy	minor = G_TP_VERSION_MINOR(version);
1588171471Skmacy	if (major == TP_VERSION_MAJOR  && minor == TP_VERSION_MINOR)
1589171471Skmacy		return;
1590171471Skmacy
1591171471Skmacy	rev = t3rev2char(adap);
1592189643Sgnn	snprintf(name, sizeof(name), TPEEPROM_NAME, rev);
1593171471Skmacy
1594189643Sgnn	tpeeprom = firmware_get(name);
1595171471Skmacy	if (tpeeprom == NULL) {
1596190330Sgnn		device_printf(adap->dev,
1597190330Sgnn			      "could not load TP EEPROM: unable to load %s\n",
1598190330Sgnn			      name);
1599171471Skmacy		return;
1600171471Skmacy	}
1601171471Skmacy
1602171471Skmacy	len = tpeeprom->datasize - 4;
1603171471Skmacy
1604171471Skmacy	ret = t3_check_tpsram(adap, tpeeprom->data, tpeeprom->datasize);
1605171471Skmacy	if (ret)
1606171471Skmacy		goto release_tpeeprom;
1607171471Skmacy
1608171471Skmacy	if (len != TP_SRAM_LEN) {
1609190330Sgnn		device_printf(adap->dev,
1610190330Sgnn			      "%s length is wrong len=%d expected=%d\n", name,
1611190330Sgnn			      len, TP_SRAM_LEN);
1612171471Skmacy		return;
1613171471Skmacy	}
1614171471Skmacy
1615171471Skmacy	ret = set_eeprom(&adap->port[0], tpeeprom->data, tpeeprom->datasize,
1616171471Skmacy	    TP_SRAM_OFFSET);
1617171471Skmacy
1618171471Skmacy	if (!ret) {
1619171471Skmacy		device_printf(adap->dev,
1620171471Skmacy			"Protocol SRAM image updated in EEPROM to %d.%d.%d\n",
1621171471Skmacy			 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1622171471Skmacy	} else
1623190330Sgnn		device_printf(adap->dev,
1624190330Sgnn			      "Protocol SRAM image update in EEPROM failed\n");
1625171471Skmacy
1626171471Skmacyrelease_tpeeprom:
1627171471Skmacy	firmware_put(tpeeprom, FIRMWARE_UNLOAD);
1628171471Skmacy
1629171471Skmacy	return;
1630171471Skmacy}
1631171471Skmacy
1632171471Skmacystatic int
1633171471Skmacyupdate_tpsram(struct adapter *adap)
1634171471Skmacy{
1635172109Skmacy#ifdef FIRMWARE_LATEST
1636171471Skmacy	const struct firmware *tpsram;
1637172109Skmacy#else
1638172109Skmacy	struct firmware *tpsram;
1639172109Skmacy#endif
1640171471Skmacy	int ret;
1641189643Sgnn	char rev, name[32];
1642171471Skmacy
1643171471Skmacy	rev = t3rev2char(adap);
1644189643Sgnn	snprintf(name, sizeof(name), TPSRAM_NAME, rev);
1645171471Skmacy
1646171471Skmacy	update_tpeeprom(adap);
1647171471Skmacy
1648189643Sgnn	tpsram = firmware_get(name);
1649171471Skmacy	if (tpsram == NULL){
1650176613Skmacy		device_printf(adap->dev, "could not load TP SRAM\n");
1651171471Skmacy		return (EINVAL);
1652171471Skmacy	} else
1653176613Skmacy		device_printf(adap->dev, "updating TP SRAM\n");
1654171471Skmacy
1655171471Skmacy	ret = t3_check_tpsram(adap, tpsram->data, tpsram->datasize);
1656171471Skmacy	if (ret)
1657171471Skmacy		goto release_tpsram;
1658171471Skmacy
1659171471Skmacy	ret = t3_set_proto_sram(adap, tpsram->data);
1660171471Skmacy	if (ret)
1661171471Skmacy		device_printf(adap->dev, "loading protocol SRAM failed\n");
1662171471Skmacy
1663171471Skmacyrelease_tpsram:
1664171471Skmacy	firmware_put(tpsram, FIRMWARE_UNLOAD);
1665171471Skmacy
1666171471Skmacy	return ret;
1667171471Skmacy}
1668171471Skmacy
1669169978Skmacy/**
1670169978Skmacy *	cxgb_up - enable the adapter
1671169978Skmacy *	@adap: adapter being enabled
1672169978Skmacy *
1673169978Skmacy *	Called when the first port is enabled, this function performs the
1674169978Skmacy *	actions necessary to make an adapter operational, such as completing
1675169978Skmacy *	the initialization of HW modules, and enabling interrupts.
1676169978Skmacy */
1677169978Skmacystatic int
1678169978Skmacycxgb_up(struct adapter *sc)
1679169978Skmacy{
1680169978Skmacy	int err = 0;
1681169978Skmacy
1682169978Skmacy	if ((sc->flags & FULL_INIT_DONE) == 0) {
1683169978Skmacy
1684169978Skmacy		if ((sc->flags & FW_UPTODATE) == 0)
1685171471Skmacy			if ((err = upgrade_fw(sc)))
1686171471Skmacy				goto out;
1687171471Skmacy		if ((sc->flags & TPS_UPTODATE) == 0)
1688171471Skmacy			if ((err = update_tpsram(sc)))
1689171471Skmacy				goto out;
1690169978Skmacy		err = t3_init_hw(sc, 0);
1691169978Skmacy		if (err)
1692169978Skmacy			goto out;
1693169978Skmacy
1694176472Skmacy		t3_set_reg_field(sc, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT);
1695169978Skmacy		t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
1696169978Skmacy
1697169978Skmacy		err = setup_sge_qsets(sc);
1698169978Skmacy		if (err)
1699169978Skmacy			goto out;
1700169978Skmacy
1701169978Skmacy		setup_rss(sc);
1702174708Skmacy		t3_add_configured_sysctls(sc);
1703169978Skmacy		sc->flags |= FULL_INIT_DONE;
1704169978Skmacy	}
1705169978Skmacy
1706169978Skmacy	t3_intr_clear(sc);
1707169978Skmacy
1708169978Skmacy	/* If it's MSI or INTx, allocate a single interrupt for everything */
1709169978Skmacy	if ((sc->flags & USING_MSIX) == 0) {
1710169978Skmacy		if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
1711169978Skmacy		   &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
1712171978Skmacy			device_printf(sc->dev, "Cannot allocate interrupt rid=%d\n",
1713171978Skmacy			    sc->irq_rid);
1714169978Skmacy			err = EINVAL;
1715169978Skmacy			goto out;
1716169978Skmacy		}
1717169978Skmacy		device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res);
1718169978Skmacy
1719169978Skmacy		if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET,
1720169978Skmacy#ifdef INTR_FILTERS
1721169978Skmacy			NULL,
1722169978Skmacy#endif
1723169978Skmacy			sc->cxgb_intr, sc, &sc->intr_tag)) {
1724169978Skmacy			device_printf(sc->dev, "Cannot set up interrupt\n");
1725169978Skmacy			err = EINVAL;
1726169978Skmacy			goto irq_err;
1727169978Skmacy		}
1728169978Skmacy	} else {
1729169978Skmacy		cxgb_setup_msix(sc, sc->msi_count);
1730169978Skmacy	}
1731169978Skmacy
1732169978Skmacy	t3_sge_start(sc);
1733169978Skmacy	t3_intr_enable(sc);
1734169978Skmacy
1735176472Skmacy	if (sc->params.rev >= T3_REV_C && !(sc->flags & TP_PARITY_INIT) &&
1736176472Skmacy	    is_offload(sc) && init_tp_parity(sc) == 0)
1737176472Skmacy		sc->flags |= TP_PARITY_INIT;
1738176472Skmacy
1739176472Skmacy	if (sc->flags & TP_PARITY_INIT) {
1740176472Skmacy		t3_write_reg(sc, A_TP_INT_CAUSE,
1741176472Skmacy				F_CMCACHEPERR | F_ARPLUTPERR);
1742176472Skmacy		t3_write_reg(sc, A_TP_INT_ENABLE, 0x7fbfffff);
1743176472Skmacy	}
1744176472Skmacy
1745176472Skmacy
1746172096Skmacy	if (!(sc->flags & QUEUES_BOUND)) {
1747169978Skmacy		bind_qsets(sc);
1748171471Skmacy		sc->flags |= QUEUES_BOUND;
1749171471Skmacy	}
1750169978Skmacyout:
1751169978Skmacy	return (err);
1752169978Skmacyirq_err:
1753169978Skmacy	CH_ERR(sc, "request_irq failed, err %d\n", err);
1754169978Skmacy	goto out;
1755169978Skmacy}
1756169978Skmacy
1757169978Skmacy
1758169978Skmacy/*
1759169978Skmacy * Release resources when all the ports and offloading have been stopped.
1760169978Skmacy */
1761167514Skmacystatic void
1762170869Skmacycxgb_down_locked(struct adapter *sc)
1763169978Skmacy{
1764170654Skmacy
1765169978Skmacy	t3_sge_stop(sc);
1766169978Skmacy	t3_intr_disable(sc);
1767189643Sgnn
1768169978Skmacy	if (sc->intr_tag != NULL) {
1769169978Skmacy		bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag);
1770169978Skmacy		sc->intr_tag = NULL;
1771169978Skmacy	}
1772169978Skmacy	if (sc->irq_res != NULL) {
1773169978Skmacy		device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n",
1774169978Skmacy		    sc->irq_rid, sc->irq_res);
1775169978Skmacy		bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
1776169978Skmacy		    sc->irq_res);
1777169978Skmacy		sc->irq_res = NULL;
1778169978Skmacy	}
1779170654Skmacy
1780176472Skmacy	if (sc->flags & USING_MSIX)
1781170654Skmacy		cxgb_teardown_msix(sc);
1782176472Skmacy
1783174708Skmacy	callout_stop(&sc->cxgb_tick_ch);
1784174708Skmacy	callout_stop(&sc->sge_timer_ch);
1785170869Skmacy	callout_drain(&sc->cxgb_tick_ch);
1786169978Skmacy	callout_drain(&sc->sge_timer_ch);
1787170869Skmacy
1788171978Skmacy	if (sc->tq != NULL) {
1789176472Skmacy		printf("draining slow intr\n");
1790176472Skmacy
1791170654Skmacy		taskqueue_drain(sc->tq, &sc->slow_intr_task);
1792176472Skmacy			printf("draining ext intr\n");
1793176472Skmacy		taskqueue_drain(sc->tq, &sc->ext_intr_task);
1794176472Skmacy		printf("draining tick task\n");
1795176472Skmacy		taskqueue_drain(sc->tq, &sc->tick_task);
1796171978Skmacy	}
1797176472Skmacy	ADAPTER_UNLOCK(sc);
1798169978Skmacy}
1799169978Skmacy
1800169978Skmacystatic int
1801169978Skmacyoffload_open(struct port_info *pi)
1802169978Skmacy{
1803169978Skmacy	struct adapter *adapter = pi->adapter;
1804174708Skmacy	struct t3cdev *tdev = &adapter->tdev;
1805183059Skmacy
1806169978Skmacy	int adap_up = adapter->open_device_map & PORT_MASK;
1807169978Skmacy	int err = 0;
1808169978Skmacy
1809169978Skmacy	if (atomic_cmpset_int(&adapter->open_device_map,
1810174708Skmacy		(adapter->open_device_map & ~(1<<OFFLOAD_DEVMAP_BIT)),
1811174708Skmacy		(adapter->open_device_map | (1<<OFFLOAD_DEVMAP_BIT))) == 0)
1812169978Skmacy		return (0);
1813169978Skmacy
1814174708Skmacy	if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT))
1815183059Skmacy		printf("offload_open: DEVMAP_BIT did not get set 0x%x\n",
1816183059Skmacy		    adapter->open_device_map);
1817169978Skmacy	ADAPTER_LOCK(pi->adapter);
1818169978Skmacy	if (!adap_up)
1819169978Skmacy		err = cxgb_up(adapter);
1820169978Skmacy	ADAPTER_UNLOCK(pi->adapter);
1821171471Skmacy	if (err)
1822169978Skmacy		return (err);
1823169978Skmacy
1824169978Skmacy	t3_tp_set_offload_mode(adapter, 1);
1825174708Skmacy	tdev->lldev = pi->ifp;
1826169978Skmacy
1827169978Skmacy	init_port_mtus(adapter);
1828169978Skmacy	t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
1829169978Skmacy		     adapter->params.b_wnd,
1830169978Skmacy		     adapter->params.rev == 0 ?
1831169978Skmacy		       adapter->port[0].ifp->if_mtu : 0xffff);
1832169978Skmacy	init_smt(adapter);
1833178767Skmacy	/* Call back all registered clients */
1834178767Skmacy	cxgb_add_clients(tdev);
1835178767Skmacy
1836169978Skmacy	/* restore them in case the offload module has changed them */
1837169978Skmacy	if (err) {
1838169978Skmacy		t3_tp_set_offload_mode(adapter, 0);
1839169978Skmacy		clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT);
1840169978Skmacy		cxgb_set_dummy_ops(tdev);
1841169978Skmacy	}
1842169978Skmacy	return (err);
1843169978Skmacy}
1844174708Skmacy
1845169978Skmacystatic int
1846174708Skmacyoffload_close(struct t3cdev *tdev)
1847169978Skmacy{
1848169978Skmacy	struct adapter *adapter = tdev2adap(tdev);
1849169978Skmacy
1850176472Skmacy	if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT))
1851170654Skmacy		return (0);
1852178767Skmacy
1853178767Skmacy	/* Call back all registered clients */
1854178767Skmacy	cxgb_remove_clients(tdev);
1855178767Skmacy
1856169978Skmacy	tdev->lldev = NULL;
1857169978Skmacy	cxgb_set_dummy_ops(tdev);
1858169978Skmacy	t3_tp_set_offload_mode(adapter, 0);
1859169978Skmacy	clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT);
1860169978Skmacy
1861174708Skmacy	ADAPTER_LOCK(adapter);
1862169978Skmacy	if (!adapter->open_device_map)
1863174708Skmacy		cxgb_down_locked(adapter);
1864174708Skmacy	else
1865174708Skmacy		ADAPTER_UNLOCK(adapter);
1866170654Skmacy	return (0);
1867169978Skmacy}
1868169978Skmacy
1869174708Skmacy
1870169978Skmacystatic void
1871167514Skmacycxgb_init(void *arg)
1872167514Skmacy{
1873167514Skmacy	struct port_info *p = arg;
1874167514Skmacy
1875167514Skmacy	PORT_LOCK(p);
1876167514Skmacy	cxgb_init_locked(p);
1877167514Skmacy	PORT_UNLOCK(p);
1878167514Skmacy}
1879167514Skmacy
1880167514Skmacystatic void
1881167514Skmacycxgb_init_locked(struct port_info *p)
1882167514Skmacy{
1883167514Skmacy	struct ifnet *ifp;
1884167514Skmacy	adapter_t *sc = p->adapter;
1885169978Skmacy	int err;
1886167514Skmacy
1887170869Skmacy	PORT_LOCK_ASSERT_OWNED(p);
1888167514Skmacy	ifp = p->ifp;
1889167514Skmacy
1890167514Skmacy	ADAPTER_LOCK(p->adapter);
1891171471Skmacy	if ((sc->open_device_map == 0) && (err = cxgb_up(sc))) {
1892169978Skmacy		ADAPTER_UNLOCK(p->adapter);
1893169978Skmacy		cxgb_stop_locked(p);
1894169978Skmacy		return;
1895169978Skmacy	}
1896170869Skmacy	if (p->adapter->open_device_map == 0) {
1897167514Skmacy		t3_intr_clear(sc);
1898170869Skmacy	}
1899171803Skmacy	setbit(&p->adapter->open_device_map, p->port_id);
1900170654Skmacy	ADAPTER_UNLOCK(p->adapter);
1901169978Skmacy
1902169978Skmacy	if (is_offload(sc) && !ofld_disable) {
1903169978Skmacy		err = offload_open(p);
1904169978Skmacy		if (err)
1905169978Skmacy			log(LOG_WARNING,
1906169978Skmacy			    "Could not initialize offload capabilities\n");
1907169978Skmacy	}
1908177415Skmacy#if !defined(LINK_ATTACH)
1909177415Skmacy	cxgb_link_start(p);
1910177415Skmacy	t3_link_changed(sc, p->port_id);
1911177415Skmacy#endif
1912186282Sgnn	ifp->if_baudrate = IF_Mbps(p->link_config.speed);
1913171978Skmacy
1914172096Skmacy	device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id);
1915171803Skmacy	t3_port_intr_enable(sc, p->port_id);
1916167760Skmacy
1917190206Sgnn 	callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc);
1918175224Skmacy	t3_sge_reset_adapter(sc);
1919170869Skmacy
1920167514Skmacy	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1921167514Skmacy	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1922167514Skmacy}
1923167514Skmacy
1924167514Skmacystatic void
1925167514Skmacycxgb_set_rxmode(struct port_info *p)
1926167514Skmacy{
1927167514Skmacy	struct t3_rx_mode rm;
1928167514Skmacy	struct cmac *mac = &p->mac;
1929167760Skmacy
1930167514Skmacy	t3_init_rx_mode(&rm, p);
1931176472Skmacy	mtx_lock(&p->adapter->mdio_lock);
1932167514Skmacy	t3_mac_set_rx_mode(mac, &rm);
1933176472Skmacy	mtx_unlock(&p->adapter->mdio_lock);
1934167514Skmacy}
1935167514Skmacy
1936167514Skmacystatic void
1937177340Skmacycxgb_stop_locked(struct port_info *pi)
1938167514Skmacy{
1939167514Skmacy	struct ifnet *ifp;
1940167514Skmacy
1941177340Skmacy	PORT_LOCK_ASSERT_OWNED(pi);
1942177340Skmacy	ADAPTER_LOCK_ASSERT_NOTOWNED(pi->adapter);
1943170654Skmacy
1944177340Skmacy	ifp = pi->ifp;
1945177340Skmacy	t3_port_intr_disable(pi->adapter, pi->port_id);
1946169978Skmacy	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1947169978Skmacy
1948177340Skmacy	/* disable pause frames */
1949177340Skmacy	t3_set_reg_field(pi->adapter, A_XGM_TX_CFG + pi->mac.offset,
1950177340Skmacy			 F_TXPAUSEEN, 0);
1951170869Skmacy
1952177340Skmacy	/* Reset RX FIFO HWM */
1953177340Skmacy        t3_set_reg_field(pi->adapter, A_XGM_RXFIFO_CFG +  pi->mac.offset,
1954177340Skmacy			 V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM), 0);
1955177340Skmacy
1956177340Skmacy
1957177340Skmacy	ADAPTER_LOCK(pi->adapter);
1958177340Skmacy	clrbit(&pi->adapter->open_device_map, pi->port_id);
1959177340Skmacy
1960177340Skmacy	if (pi->adapter->open_device_map == 0) {
1961177340Skmacy		cxgb_down_locked(pi->adapter);
1962170869Skmacy	} else
1963177340Skmacy		ADAPTER_UNLOCK(pi->adapter);
1964170869Skmacy
1965177415Skmacy#if !defined(LINK_ATTACH)
1966177340Skmacy	DELAY(100);
1967177340Skmacy
1968177340Skmacy	/* Wait for TXFIFO empty */
1969177340Skmacy	t3_wait_op_done(pi->adapter, A_XGM_TXFIFO_CFG + pi->mac.offset,
1970177340Skmacy			F_TXFIFO_EMPTY, 1, 20, 5);
1971177340Skmacy
1972177340Skmacy	DELAY(100);
1973177340Skmacy	t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
1974177340Skmacy
1975177340Skmacy	pi->phy.ops->power_down(&pi->phy, 1);
1976177415Skmacy#endif
1977177340Skmacy
1978167514Skmacy}
1979167514Skmacy
1980167514Skmacystatic int
1981170654Skmacycxgb_set_mtu(struct port_info *p, int mtu)
1982170654Skmacy{
1983170654Skmacy	struct ifnet *ifp = p->ifp;
1984170654Skmacy	int error = 0;
1985170654Skmacy
1986180583Skmacy	if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO))
1987170654Skmacy		error = EINVAL;
1988170654Skmacy	else if (ifp->if_mtu != mtu) {
1989170654Skmacy		PORT_LOCK(p);
1990170654Skmacy		ifp->if_mtu = mtu;
1991170654Skmacy		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1992170654Skmacy			cxgb_stop_locked(p);
1993170654Skmacy			cxgb_init_locked(p);
1994170654Skmacy		}
1995170654Skmacy		PORT_UNLOCK(p);
1996170654Skmacy	}
1997170654Skmacy	return (error);
1998170654Skmacy}
1999170654Skmacy
2000183289Skmacy#ifdef LRO_SUPPORTED
2001181616Skmacy/*
2002181616Skmacy * Mark lro enabled or disabled in all qsets for this port
2003181616Skmacy */
2004170654Skmacystatic int
2005181616Skmacycxgb_set_lro(struct port_info *p, int enabled)
2006181616Skmacy{
2007181616Skmacy	int i;
2008181616Skmacy	struct adapter *adp = p->adapter;
2009181616Skmacy	struct sge_qset *q;
2010181616Skmacy
2011181616Skmacy	PORT_LOCK_ASSERT_OWNED(p);
2012181616Skmacy	for (i = 0; i < p->nqsets; i++) {
2013181616Skmacy		q = &adp->sge.qs[p->first_qset + i];
2014181616Skmacy		q->lro.enabled = (enabled != 0);
2015181616Skmacy	}
2016181616Skmacy	return (0);
2017181616Skmacy}
2018183289Skmacy#endif
2019181616Skmacy
2020181616Skmacystatic int
2021167514Skmacycxgb_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data)
2022167514Skmacy{
2023167514Skmacy	struct port_info *p = ifp->if_softc;
2024184714Sbz#ifdef INET
2025167514Skmacy	struct ifaddr *ifa = (struct ifaddr *)data;
2026184714Sbz#endif
2027167514Skmacy	struct ifreq *ifr = (struct ifreq *)data;
2028180583Skmacy	int flags, error = 0, reinit = 0;
2029167514Skmacy	uint32_t mask;
2030167514Skmacy
2031168737Skmacy	/*
2032168737Skmacy	 * XXX need to check that we aren't in the middle of an unload
2033168737Skmacy	 */
2034167514Skmacy	switch (command) {
2035167514Skmacy	case SIOCSIFMTU:
2036170654Skmacy		error = cxgb_set_mtu(p, ifr->ifr_mtu);
2037167514Skmacy		break;
2038167514Skmacy	case SIOCSIFADDR:
2039184714Sbz#ifdef INET
2040167514Skmacy		if (ifa->ifa_addr->sa_family == AF_INET) {
2041167514Skmacy			ifp->if_flags |= IFF_UP;
2042176472Skmacy			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
2043176472Skmacy				PORT_LOCK(p);
2044170654Skmacy				cxgb_init_locked(p);
2045176472Skmacy				PORT_UNLOCK(p);
2046176472Skmacy			}
2047167514Skmacy			arp_ifinit(ifp, ifa);
2048167514Skmacy		} else
2049184714Sbz#endif
2050167514Skmacy			error = ether_ioctl(ifp, command, data);
2051167514Skmacy		break;
2052167514Skmacy	case SIOCSIFFLAGS:
2053170869Skmacy		PORT_LOCK(p);
2054167514Skmacy		if (ifp->if_flags & IFF_UP) {
2055167514Skmacy			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2056167514Skmacy				flags = p->if_flags;
2057167514Skmacy				if (((ifp->if_flags ^ flags) & IFF_PROMISC) ||
2058167514Skmacy				    ((ifp->if_flags ^ flags) & IFF_ALLMULTI))
2059167514Skmacy					cxgb_set_rxmode(p);
2060167514Skmacy			} else
2061167514Skmacy				cxgb_init_locked(p);
2062167760Skmacy			p->if_flags = ifp->if_flags;
2063170869Skmacy		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
2064170869Skmacy			cxgb_stop_locked(p);
2065170869Skmacy
2066176472Skmacy		PORT_UNLOCK(p);
2067176472Skmacy		break;
2068176472Skmacy	case SIOCADDMULTI:
2069176472Skmacy	case SIOCDELMULTI:
2070170869Skmacy		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
2071176472Skmacy			cxgb_set_rxmode(p);
2072167514Skmacy		}
2073167514Skmacy		break;
2074167514Skmacy	case SIOCSIFMEDIA:
2075167514Skmacy	case SIOCGIFMEDIA:
2076186282Sgnn		PORT_LOCK(p);
2077167514Skmacy		error = ifmedia_ioctl(ifp, ifr, &p->media, command);
2078186282Sgnn		PORT_UNLOCK(p);
2079167514Skmacy		break;
2080167514Skmacy	case SIOCSIFCAP:
2081167514Skmacy		PORT_LOCK(p);
2082167514Skmacy		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
2083167514Skmacy		if (mask & IFCAP_TXCSUM) {
2084167514Skmacy			if (IFCAP_TXCSUM & ifp->if_capenable) {
2085167514Skmacy				ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4);
2086167514Skmacy				ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP
2087180583Skmacy				    | CSUM_IP | CSUM_TSO);
2088167514Skmacy			} else {
2089167514Skmacy				ifp->if_capenable |= IFCAP_TXCSUM;
2090180583Skmacy				ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP
2091180583Skmacy				    | CSUM_IP);
2092167514Skmacy			}
2093167514Skmacy		}
2094180583Skmacy		if (mask & IFCAP_RXCSUM) {
2095180583Skmacy			ifp->if_capenable ^= IFCAP_RXCSUM;
2096180583Skmacy		}
2097167514Skmacy		if (mask & IFCAP_TSO4) {
2098167514Skmacy			if (IFCAP_TSO4 & ifp->if_capenable) {
2099167514Skmacy				ifp->if_capenable &= ~IFCAP_TSO4;
2100167514Skmacy				ifp->if_hwassist &= ~CSUM_TSO;
2101167514Skmacy			} else if (IFCAP_TXCSUM & ifp->if_capenable) {
2102167514Skmacy				ifp->if_capenable |= IFCAP_TSO4;
2103167514Skmacy				ifp->if_hwassist |= CSUM_TSO;
2104167514Skmacy			} else {
2105167514Skmacy				if (cxgb_debug)
2106167514Skmacy					printf("cxgb requires tx checksum offload"
2107167514Skmacy					    " be enabled to use TSO\n");
2108167514Skmacy				error = EINVAL;
2109167514Skmacy			}
2110167514Skmacy		}
2111183289Skmacy#ifdef LRO_SUPPORTED
2112181616Skmacy		if (mask & IFCAP_LRO) {
2113181616Skmacy			ifp->if_capenable ^= IFCAP_LRO;
2114181616Skmacy
2115181616Skmacy			/* Safe to do this even if cxgb_up not called yet */
2116181616Skmacy			cxgb_set_lro(p, ifp->if_capenable & IFCAP_LRO);
2117181616Skmacy		}
2118183289Skmacy#endif
2119180583Skmacy		if (mask & IFCAP_VLAN_HWTAGGING) {
2120180583Skmacy			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
2121180583Skmacy			reinit = ifp->if_drv_flags & IFF_DRV_RUNNING;
2122180583Skmacy		}
2123180583Skmacy		if (mask & IFCAP_VLAN_MTU) {
2124180583Skmacy			ifp->if_capenable ^= IFCAP_VLAN_MTU;
2125180583Skmacy			reinit = ifp->if_drv_flags & IFF_DRV_RUNNING;
2126180583Skmacy		}
2127180583Skmacy		if (mask & IFCAP_VLAN_HWCSUM) {
2128180583Skmacy			ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
2129180583Skmacy		}
2130180583Skmacy		if (reinit) {
2131180583Skmacy			cxgb_stop_locked(p);
2132180583Skmacy			cxgb_init_locked(p);
2133180583Skmacy		}
2134167514Skmacy		PORT_UNLOCK(p);
2135180583Skmacy
2136180583Skmacy#ifdef VLAN_CAPABILITIES
2137180583Skmacy		VLAN_CAPABILITIES(ifp);
2138180583Skmacy#endif
2139167514Skmacy		break;
2140167514Skmacy	default:
2141167514Skmacy		error = ether_ioctl(ifp, command, data);
2142167514Skmacy		break;
2143167514Skmacy	}
2144167514Skmacy	return (error);
2145167514Skmacy}
2146167514Skmacy
2147174708Skmacystatic int
2148167514Skmacycxgb_media_change(struct ifnet *ifp)
2149167514Skmacy{
2150167514Skmacy	if_printf(ifp, "media change not supported\n");
2151167514Skmacy	return (ENXIO);
2152167514Skmacy}
2153167514Skmacy
2154186282Sgnn/*
2155186282Sgnn * Translates from phy->modtype to IFM_TYPE.
2156186282Sgnn */
2157186282Sgnnstatic int
2158186282Sgnncxgb_ifm_type(int phymod)
2159186282Sgnn{
2160186282Sgnn	int rc = IFM_ETHER | IFM_FDX;
2161186282Sgnn
2162186282Sgnn	switch (phymod) {
2163186282Sgnn	case phy_modtype_sr:
2164186282Sgnn		rc |= IFM_10G_SR;
2165186282Sgnn		break;
2166186282Sgnn	case phy_modtype_lr:
2167186282Sgnn		rc |= IFM_10G_LR;
2168186282Sgnn		break;
2169186282Sgnn	case phy_modtype_lrm:
2170186282Sgnn#ifdef IFM_10G_LRM
2171186282Sgnn		rc |= IFM_10G_LRM;
2172186282Sgnn#endif
2173186282Sgnn		break;
2174186282Sgnn	case phy_modtype_twinax:
2175186282Sgnn#ifdef IFM_10G_TWINAX
2176186282Sgnn		rc |= IFM_10G_TWINAX;
2177186282Sgnn#endif
2178186282Sgnn		break;
2179186282Sgnn	case phy_modtype_twinax_long:
2180186282Sgnn#ifdef IFM_10G_TWINAX_LONG
2181186282Sgnn		rc |= IFM_10G_TWINAX_LONG;
2182186282Sgnn#endif
2183186282Sgnn		break;
2184186282Sgnn	case phy_modtype_none:
2185186282Sgnn		rc = IFM_ETHER | IFM_NONE;
2186186282Sgnn		break;
2187186282Sgnn	case phy_modtype_unknown:
2188186282Sgnn		break;
2189186282Sgnn	}
2190186282Sgnn
2191186282Sgnn	return (rc);
2192186282Sgnn}
2193186282Sgnn
2194167514Skmacystatic void
2195167514Skmacycxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
2196167514Skmacy{
2197167514Skmacy	struct port_info *p = ifp->if_softc;
2198186282Sgnn	struct ifmedia_entry *cur = p->media.ifm_cur;
2199186282Sgnn	int m;
2200167514Skmacy
2201186282Sgnn	if (cur->ifm_data != p->phy.modtype) {
2202186282Sgnn		/* p->media about to be rebuilt, must hold lock */
2203186282Sgnn		PORT_LOCK_ASSERT_OWNED(p);
2204186282Sgnn
2205186282Sgnn		m = cxgb_ifm_type(p->phy.modtype);
2206186282Sgnn		ifmedia_removeall(&p->media);
2207186282Sgnn		ifmedia_add(&p->media, m, p->phy.modtype, NULL);
2208186282Sgnn		ifmedia_set(&p->media, m);
2209186282Sgnn		cur = p->media.ifm_cur; /* ifmedia_set modified ifm_cur */
2210186282Sgnn		ifmr->ifm_current = m;
2211186282Sgnn	}
2212186282Sgnn
2213167514Skmacy	ifmr->ifm_status = IFM_AVALID;
2214167514Skmacy	ifmr->ifm_active = IFM_ETHER;
2215167514Skmacy
2216167514Skmacy	if (!p->link_config.link_ok)
2217167514Skmacy		return;
2218167514Skmacy
2219167514Skmacy	ifmr->ifm_status |= IFM_ACTIVE;
2220167514Skmacy
2221170654Skmacy	switch (p->link_config.speed) {
2222170654Skmacy	case 10:
2223170654Skmacy		ifmr->ifm_active |= IFM_10_T;
2224170654Skmacy		break;
2225170654Skmacy	case 100:
2226170654Skmacy		ifmr->ifm_active |= IFM_100_TX;
2227170654Skmacy			break;
2228170654Skmacy	case 1000:
2229170654Skmacy		ifmr->ifm_active |= IFM_1000_T;
2230170654Skmacy		break;
2231186282Sgnn	case 10000:
2232186282Sgnn		ifmr->ifm_active |= IFM_SUBTYPE(cur->ifm_media);
2233186282Sgnn		break;
2234170654Skmacy	}
2235170654Skmacy
2236167514Skmacy	if (p->link_config.duplex)
2237167514Skmacy		ifmr->ifm_active |= IFM_FDX;
2238167514Skmacy	else
2239167514Skmacy		ifmr->ifm_active |= IFM_HDX;
2240167514Skmacy}
2241167514Skmacy
2242167514Skmacystatic void
2243167514Skmacycxgb_async_intr(void *data)
2244167514Skmacy{
2245167760Skmacy	adapter_t *sc = data;
2246167760Skmacy
2247167514Skmacy	if (cxgb_debug)
2248167760Skmacy		device_printf(sc->dev, "cxgb_async_intr\n");
2249170869Skmacy	/*
2250170869Skmacy	 * May need to sleep - defer to taskqueue
2251170869Skmacy	 */
2252170869Skmacy	taskqueue_enqueue(sc->tq, &sc->slow_intr_task);
2253167514Skmacy}
2254167514Skmacy
2255167514Skmacystatic void
2256167514Skmacycxgb_ext_intr_handler(void *arg, int count)
2257167514Skmacy{
2258167514Skmacy	adapter_t *sc = (adapter_t *)arg;
2259167514Skmacy
2260167514Skmacy	if (cxgb_debug)
2261167514Skmacy		printf("cxgb_ext_intr_handler\n");
2262167514Skmacy
2263167514Skmacy	t3_phy_intr_handler(sc);
2264167514Skmacy
2265167514Skmacy	/* Now reenable external interrupts */
2266169978Skmacy	ADAPTER_LOCK(sc);
2267167514Skmacy	if (sc->slow_intr_mask) {
2268167514Skmacy		sc->slow_intr_mask |= F_T3DBG;
2269167514Skmacy		t3_write_reg(sc, A_PL_INT_CAUSE0, F_T3DBG);
2270167514Skmacy		t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
2271167514Skmacy	}
2272169978Skmacy	ADAPTER_UNLOCK(sc);
2273167514Skmacy}
2274167514Skmacy
2275167514Skmacystatic void
2276167746Skmacycheck_link_status(adapter_t *sc)
2277167514Skmacy{
2278167746Skmacy	int i;
2279167514Skmacy
2280167746Skmacy	for (i = 0; i < (sc)->params.nports; ++i) {
2281167746Skmacy		struct port_info *p = &sc->port[i];
2282167514Skmacy
2283176472Skmacy		if (!(p->phy.caps & SUPPORTED_IRQ))
2284167746Skmacy			t3_link_changed(sc, i);
2285186282Sgnn		p->ifp->if_baudrate = IF_Mbps(p->link_config.speed);
2286167746Skmacy	}
2287167514Skmacy}
2288167514Skmacy
2289167514Skmacystatic void
2290167746Skmacycheck_t3b2_mac(struct adapter *adapter)
2291167514Skmacy{
2292167514Skmacy	int i;
2293167514Skmacy
2294176472Skmacy	if(adapter->flags & CXGB_SHUTDOWN)
2295176472Skmacy		return;
2296176472Skmacy
2297167746Skmacy	for_each_port(adapter, i) {
2298167746Skmacy		struct port_info *p = &adapter->port[i];
2299167746Skmacy		struct ifnet *ifp = p->ifp;
2300167746Skmacy		int status;
2301176472Skmacy
2302176472Skmacy		if(adapter->flags & CXGB_SHUTDOWN)
2303176472Skmacy			return;
2304176472Skmacy
2305167746Skmacy		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
2306167746Skmacy			continue;
2307167746Skmacy
2308167746Skmacy		status = 0;
2309167746Skmacy		PORT_LOCK(p);
2310167746Skmacy		if ((ifp->if_drv_flags & IFF_DRV_RUNNING))
2311167746Skmacy			status = t3b2_mac_watchdog_task(&p->mac);
2312167746Skmacy		if (status == 1)
2313167746Skmacy			p->mac.stats.num_toggled++;
2314167746Skmacy		else if (status == 2) {
2315167746Skmacy			struct cmac *mac = &p->mac;
2316180583Skmacy			int mtu = ifp->if_mtu;
2317167746Skmacy
2318180583Skmacy			if (ifp->if_capenable & IFCAP_VLAN_MTU)
2319180583Skmacy				mtu += ETHER_VLAN_ENCAP_LEN;
2320180583Skmacy			t3_mac_set_mtu(mac, mtu);
2321167746Skmacy			t3_mac_set_address(mac, 0, p->hw_addr);
2322167746Skmacy			cxgb_set_rxmode(p);
2323167746Skmacy			t3_link_start(&p->phy, mac, &p->link_config);
2324167746Skmacy			t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
2325171803Skmacy			t3_port_intr_enable(adapter, p->port_id);
2326167746Skmacy			p->mac.stats.num_resets++;
2327167746Skmacy		}
2328167746Skmacy		PORT_UNLOCK(p);
2329167514Skmacy	}
2330167514Skmacy}
2331167514Skmacy
2332167746Skmacystatic void
2333167746Skmacycxgb_tick(void *arg)
2334167746Skmacy{
2335167746Skmacy	adapter_t *sc = (adapter_t *)arg;
2336170869Skmacy
2337176472Skmacy	if(sc->flags & CXGB_SHUTDOWN)
2338176472Skmacy		return;
2339174708Skmacy
2340185508Skmacy	taskqueue_enqueue(sc->tq, &sc->tick_task);
2341181652Skmacy	callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc);
2342170869Skmacy}
2343170869Skmacy
2344170869Skmacystatic void
2345170869Skmacycxgb_tick_handler(void *arg, int count)
2346170869Skmacy{
2347170869Skmacy	adapter_t *sc = (adapter_t *)arg;
2348167746Skmacy	const struct adapter_params *p = &sc->params;
2349181652Skmacy	int i;
2350189643Sgnn	uint32_t cause, reset;
2351167746Skmacy
2352176472Skmacy	if(sc->flags & CXGB_SHUTDOWN)
2353176472Skmacy		return;
2354176472Skmacy
2355170869Skmacy	ADAPTER_LOCK(sc);
2356167746Skmacy	if (p->linkpoll_period)
2357167746Skmacy		check_link_status(sc);
2358167746Skmacy
2359185508Skmacy	sc->check_task_cnt++;
2360185508Skmacy
2361185508Skmacy	/*
2362185508Skmacy	 * adapter lock can currently only be acquired after the
2363185508Skmacy	 * port lock
2364185508Skmacy	 */
2365185508Skmacy	ADAPTER_UNLOCK(sc);
2366185508Skmacy
2367185508Skmacy	if (p->rev == T3_REV_B2 && p->nports < 4 && sc->open_device_map)
2368185508Skmacy		check_t3b2_mac(sc);
2369185508Skmacy
2370189643Sgnn	cause = t3_read_reg(sc, A_SG_INT_CAUSE);
2371189643Sgnn	reset = 0;
2372189643Sgnn	if (cause & F_FLEMPTY) {
2373189643Sgnn		struct sge_qset *qs = &sc->sge.qs[0];
2374189643Sgnn
2375189643Sgnn		i = 0;
2376189643Sgnn		reset |= F_FLEMPTY;
2377189643Sgnn
2378189643Sgnn		cause = (t3_read_reg(sc, A_SG_RSPQ_FL_STATUS) >>
2379189643Sgnn			 S_FL0EMPTY) & 0xffff;
2380189643Sgnn		while (cause) {
2381189643Sgnn			qs->fl[i].empty += (cause & 1);
2382189643Sgnn			if (i)
2383189643Sgnn				qs++;
2384189643Sgnn			i ^= 1;
2385189643Sgnn			cause >>= 1;
2386189643Sgnn		}
2387189643Sgnn	}
2388189643Sgnn	t3_write_reg(sc, A_SG_INT_CAUSE, reset);
2389189643Sgnn
2390185506Skmacy	for (i = 0; i < sc->params.nports; i++) {
2391185506Skmacy		struct port_info *pi = &sc->port[i];
2392185506Skmacy		struct ifnet *ifp = pi->ifp;
2393189643Sgnn		struct cmac *mac = &pi->mac;
2394189643Sgnn		struct mac_stats *mstats = &mac->stats;
2395185508Skmacy		PORT_LOCK(pi);
2396189643Sgnn		t3_mac_update_stats(mac);
2397185508Skmacy		PORT_UNLOCK(pi);
2398185508Skmacy
2399189643Sgnn		if (pi->link_fault)
2400189643Sgnn			taskqueue_enqueue(sc->tq, &pi->link_fault_task);
2401189643Sgnn
2402185506Skmacy		ifp->if_opackets =
2403185506Skmacy		    mstats->tx_frames_64 +
2404185506Skmacy		    mstats->tx_frames_65_127 +
2405185506Skmacy		    mstats->tx_frames_128_255 +
2406185506Skmacy		    mstats->tx_frames_256_511 +
2407185506Skmacy		    mstats->tx_frames_512_1023 +
2408185506Skmacy		    mstats->tx_frames_1024_1518 +
2409185506Skmacy		    mstats->tx_frames_1519_max;
2410185506Skmacy
2411185506Skmacy		ifp->if_ipackets =
2412185506Skmacy		    mstats->rx_frames_64 +
2413185506Skmacy		    mstats->rx_frames_65_127 +
2414185506Skmacy		    mstats->rx_frames_128_255 +
2415185506Skmacy		    mstats->rx_frames_256_511 +
2416185506Skmacy		    mstats->rx_frames_512_1023 +
2417185506Skmacy		    mstats->rx_frames_1024_1518 +
2418185506Skmacy		    mstats->rx_frames_1519_max;
2419185506Skmacy
2420185506Skmacy		ifp->if_obytes = mstats->tx_octets;
2421185506Skmacy		ifp->if_ibytes = mstats->rx_octets;
2422185506Skmacy		ifp->if_omcasts = mstats->tx_mcast_frames;
2423185506Skmacy		ifp->if_imcasts = mstats->rx_mcast_frames;
2424185506Skmacy
2425185506Skmacy		ifp->if_collisions =
2426185506Skmacy		    mstats->tx_total_collisions;
2427185506Skmacy
2428185506Skmacy		ifp->if_iqdrops = mstats->rx_cong_drops;
2429185506Skmacy
2430185506Skmacy		ifp->if_oerrors =
2431185506Skmacy		    mstats->tx_excess_collisions +
2432185506Skmacy		    mstats->tx_underrun +
2433185506Skmacy		    mstats->tx_len_errs +
2434185506Skmacy		    mstats->tx_mac_internal_errs +
2435185506Skmacy		    mstats->tx_excess_deferral +
2436185506Skmacy		    mstats->tx_fcs_errs;
2437185506Skmacy		ifp->if_ierrors =
2438185506Skmacy		    mstats->rx_jabber +
2439185506Skmacy		    mstats->rx_data_errs +
2440185506Skmacy		    mstats->rx_sequence_errs +
2441185506Skmacy		    mstats->rx_runt +
2442185506Skmacy		    mstats->rx_too_long +
2443185506Skmacy		    mstats->rx_mac_internal_errs +
2444185506Skmacy		    mstats->rx_short +
2445185506Skmacy		    mstats->rx_fcs_errs;
2446189643Sgnn
2447189643Sgnn		if (mac->multiport)
2448189643Sgnn			continue;
2449189643Sgnn
2450189643Sgnn		/* Count rx fifo overflows, once per second */
2451189643Sgnn		cause = t3_read_reg(sc, A_XGM_INT_CAUSE + mac->offset);
2452189643Sgnn		reset = 0;
2453189643Sgnn		if (cause & F_RXFIFO_OVERFLOW) {
2454189643Sgnn			mac->stats.rx_fifo_ovfl++;
2455189643Sgnn			reset |= F_RXFIFO_OVERFLOW;
2456189643Sgnn		}
2457189643Sgnn		t3_write_reg(sc, A_XGM_INT_CAUSE + mac->offset, reset);
2458185506Skmacy	}
2459167746Skmacy}
2460167746Skmacy
2461171978Skmacystatic void
2462171978Skmacytouch_bars(device_t dev)
2463171978Skmacy{
2464171978Skmacy	/*
2465171978Skmacy	 * Don't enable yet
2466171978Skmacy	 */
2467171978Skmacy#if !defined(__LP64__) && 0
2468171978Skmacy	u32 v;
2469171978Skmacy
2470171978Skmacy	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &v);
2471171978Skmacy	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, v);
2472171978Skmacy	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3, &v);
2473171978Skmacy	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_3, v);
2474171978Skmacy	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &v);
2475171978Skmacy	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_5, v);
2476171978Skmacy#endif
2477171978Skmacy}
2478171978Skmacy
2479167514Skmacystatic int
2480171471Skmacyset_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset)
2481171471Skmacy{
2482171471Skmacy	uint8_t *buf;
2483171471Skmacy	int err = 0;
2484171471Skmacy	u32 aligned_offset, aligned_len, *p;
2485171471Skmacy	struct adapter *adapter = pi->adapter;
2486171471Skmacy
2487171471Skmacy
2488171471Skmacy	aligned_offset = offset & ~3;
2489171471Skmacy	aligned_len = (len + (offset & 3) + 3) & ~3;
2490171471Skmacy
2491171471Skmacy	if (aligned_offset != offset || aligned_len != len) {
2492171471Skmacy		buf = malloc(aligned_len, M_DEVBUF, M_WAITOK|M_ZERO);
2493171471Skmacy		if (!buf)
2494171471Skmacy			return (ENOMEM);
2495171471Skmacy		err = t3_seeprom_read(adapter, aligned_offset, (u32 *)buf);
2496171471Skmacy		if (!err && aligned_len > 4)
2497171471Skmacy			err = t3_seeprom_read(adapter,
2498171471Skmacy					      aligned_offset + aligned_len - 4,
2499171471Skmacy					      (u32 *)&buf[aligned_len - 4]);
2500171471Skmacy		if (err)
2501171471Skmacy			goto out;
2502171471Skmacy		memcpy(buf + (offset & 3), data, len);
2503171471Skmacy	} else
2504171471Skmacy		buf = (uint8_t *)(uintptr_t)data;
2505171471Skmacy
2506171471Skmacy	err = t3_seeprom_wp(adapter, 0);
2507171471Skmacy	if (err)
2508171471Skmacy		goto out;
2509171471Skmacy
2510171471Skmacy	for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) {
2511171471Skmacy		err = t3_seeprom_write(adapter, aligned_offset, *p);
2512171471Skmacy		aligned_offset += 4;
2513171471Skmacy	}
2514171471Skmacy
2515171471Skmacy	if (!err)
2516171471Skmacy		err = t3_seeprom_wp(adapter, 1);
2517171471Skmacyout:
2518171471Skmacy	if (buf != data)
2519171471Skmacy		free(buf, M_DEVBUF);
2520171471Skmacy	return err;
2521171471Skmacy}
2522171471Skmacy
2523171471Skmacy
2524171471Skmacystatic int
2525167514Skmacyin_range(int val, int lo, int hi)
2526167514Skmacy{
2527167514Skmacy	return val < 0 || (val <= hi && val >= lo);
2528167514Skmacy}
2529167514Skmacy
2530167514Skmacystatic int
2531192450Simpcxgb_extension_open(struct cdev *dev, int flags, int fmp, struct thread *td)
2532170654Skmacy{
2533170654Skmacy       return (0);
2534170654Skmacy}
2535170654Skmacy
2536170654Skmacystatic int
2537192450Simpcxgb_extension_close(struct cdev *dev, int flags, int fmt, struct thread *td)
2538170654Skmacy{
2539170654Skmacy       return (0);
2540170654Skmacy}
2541170654Skmacy
2542170654Skmacystatic int
2543167514Skmacycxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
2544167514Skmacy    int fflag, struct thread *td)
2545167514Skmacy{
2546167514Skmacy	int mmd, error = 0;
2547167514Skmacy	struct port_info *pi = dev->si_drv1;
2548167514Skmacy	adapter_t *sc = pi->adapter;
2549167514Skmacy
2550167514Skmacy#ifdef PRIV_SUPPORTED
2551167514Skmacy	if (priv_check(td, PRIV_DRIVER)) {
2552167514Skmacy		if (cxgb_debug)
2553167514Skmacy			printf("user does not have access to privileged ioctls\n");
2554167514Skmacy		return (EPERM);
2555167514Skmacy	}
2556167514Skmacy#else
2557167514Skmacy	if (suser(td)) {
2558167514Skmacy		if (cxgb_debug)
2559167514Skmacy			printf("user does not have access to privileged ioctls\n");
2560167514Skmacy		return (EPERM);
2561167514Skmacy	}
2562167514Skmacy#endif
2563167514Skmacy
2564167514Skmacy	switch (cmd) {
2565182679Skmacy	case CHELSIO_GET_MIIREG: {
2566167514Skmacy		uint32_t val;
2567167514Skmacy		struct cphy *phy = &pi->phy;
2568182679Skmacy		struct ch_mii_data *mid = (struct ch_mii_data *)data;
2569167514Skmacy
2570167514Skmacy		if (!phy->mdio_read)
2571167514Skmacy			return (EOPNOTSUPP);
2572167514Skmacy		if (is_10G(sc)) {
2573167514Skmacy			mmd = mid->phy_id >> 8;
2574167514Skmacy			if (!mmd)
2575167514Skmacy				mmd = MDIO_DEV_PCS;
2576190330Sgnn			else if (mmd > MDIO_DEV_VEND2)
2577171471Skmacy				return (EINVAL);
2578167514Skmacy
2579167514Skmacy			error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd,
2580167514Skmacy					     mid->reg_num, &val);
2581167514Skmacy		} else
2582167514Skmacy		        error = phy->mdio_read(sc, mid->phy_id & 0x1f, 0,
2583167514Skmacy					     mid->reg_num & 0x1f, &val);
2584167514Skmacy		if (error == 0)
2585167514Skmacy			mid->val_out = val;
2586167514Skmacy		break;
2587167514Skmacy	}
2588182679Skmacy	case CHELSIO_SET_MIIREG: {
2589167514Skmacy		struct cphy *phy = &pi->phy;
2590182679Skmacy		struct ch_mii_data *mid = (struct ch_mii_data *)data;
2591167514Skmacy
2592167514Skmacy		if (!phy->mdio_write)
2593167514Skmacy			return (EOPNOTSUPP);
2594167514Skmacy		if (is_10G(sc)) {
2595167514Skmacy			mmd = mid->phy_id >> 8;
2596167514Skmacy			if (!mmd)
2597167514Skmacy				mmd = MDIO_DEV_PCS;
2598190330Sgnn			else if (mmd > MDIO_DEV_VEND2)
2599167514Skmacy				return (EINVAL);
2600167514Skmacy
2601167514Skmacy			error = phy->mdio_write(sc, mid->phy_id & 0x1f,
2602167514Skmacy					      mmd, mid->reg_num, mid->val_in);
2603167514Skmacy		} else
2604167514Skmacy			error = phy->mdio_write(sc, mid->phy_id & 0x1f, 0,
2605167514Skmacy					      mid->reg_num & 0x1f,
2606167514Skmacy					      mid->val_in);
2607167514Skmacy		break;
2608167514Skmacy	}
2609167514Skmacy	case CHELSIO_SETREG: {
2610167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
2611167514Skmacy		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2612167514Skmacy			return (EFAULT);
2613167514Skmacy		t3_write_reg(sc, edata->addr, edata->val);
2614167514Skmacy		break;
2615167514Skmacy	}
2616167514Skmacy	case CHELSIO_GETREG: {
2617167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
2618167514Skmacy		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2619167514Skmacy			return (EFAULT);
2620167514Skmacy		edata->val = t3_read_reg(sc, edata->addr);
2621167514Skmacy		break;
2622167514Skmacy	}
2623167514Skmacy	case CHELSIO_GET_SGE_CONTEXT: {
2624167514Skmacy		struct ch_cntxt *ecntxt = (struct ch_cntxt *)data;
2625176472Skmacy		mtx_lock_spin(&sc->sge.reg_lock);
2626167514Skmacy		switch (ecntxt->cntxt_type) {
2627167514Skmacy		case CNTXT_TYPE_EGRESS:
2628182679Skmacy			error = -t3_sge_read_ecntxt(sc, ecntxt->cntxt_id,
2629167514Skmacy			    ecntxt->data);
2630167514Skmacy			break;
2631167514Skmacy		case CNTXT_TYPE_FL:
2632182679Skmacy			error = -t3_sge_read_fl(sc, ecntxt->cntxt_id,
2633167514Skmacy			    ecntxt->data);
2634167514Skmacy			break;
2635167514Skmacy		case CNTXT_TYPE_RSP:
2636182679Skmacy			error = -t3_sge_read_rspq(sc, ecntxt->cntxt_id,
2637167514Skmacy			    ecntxt->data);
2638167514Skmacy			break;
2639167514Skmacy		case CNTXT_TYPE_CQ:
2640182679Skmacy			error = -t3_sge_read_cq(sc, ecntxt->cntxt_id,
2641167514Skmacy			    ecntxt->data);
2642167514Skmacy			break;
2643167514Skmacy		default:
2644167514Skmacy			error = EINVAL;
2645167514Skmacy			break;
2646167514Skmacy		}
2647176472Skmacy		mtx_unlock_spin(&sc->sge.reg_lock);
2648167514Skmacy		break;
2649167514Skmacy	}
2650167514Skmacy	case CHELSIO_GET_SGE_DESC: {
2651167514Skmacy		struct ch_desc *edesc = (struct ch_desc *)data;
2652167514Skmacy		int ret;
2653167514Skmacy		if (edesc->queue_num >= SGE_QSETS * 6)
2654167514Skmacy			return (EINVAL);
2655167514Skmacy		ret = t3_get_desc(&sc->sge.qs[edesc->queue_num / 6],
2656167514Skmacy		    edesc->queue_num % 6, edesc->idx, edesc->data);
2657167514Skmacy		if (ret < 0)
2658167514Skmacy			return (EINVAL);
2659167514Skmacy		edesc->size = ret;
2660167514Skmacy		break;
2661167514Skmacy	}
2662182679Skmacy	case CHELSIO_GET_QSET_PARAMS: {
2663167514Skmacy		struct qset_params *q;
2664167514Skmacy		struct ch_qset_params *t = (struct ch_qset_params *)data;
2665182679Skmacy		int q1 = pi->first_qset;
2666182679Skmacy		int nqsets = pi->nqsets;
2667176472Skmacy		int i;
2668176472Skmacy
2669182679Skmacy		if (t->qset_idx >= nqsets)
2670182679Skmacy			return EINVAL;
2671167514Skmacy
2672182679Skmacy		i = q1 + t->qset_idx;
2673182679Skmacy		q = &sc->params.sge.qset[i];
2674167514Skmacy		t->rspq_size   = q->rspq_size;
2675167514Skmacy		t->txq_size[0] = q->txq_size[0];
2676167514Skmacy		t->txq_size[1] = q->txq_size[1];
2677167514Skmacy		t->txq_size[2] = q->txq_size[2];
2678167514Skmacy		t->fl_size[0]  = q->fl_size;
2679167514Skmacy		t->fl_size[1]  = q->jumbo_size;
2680167514Skmacy		t->polling     = q->polling;
2681182679Skmacy		t->lro         = q->lro;
2682180583Skmacy		t->intr_lat    = q->coalesce_usecs;
2683167514Skmacy		t->cong_thres  = q->cong_thres;
2684182679Skmacy		t->qnum        = i;
2685182679Skmacy
2686182679Skmacy		if (sc->flags & USING_MSIX)
2687182679Skmacy			t->vector = rman_get_start(sc->msix_irq_res[i]);
2688182679Skmacy		else
2689182679Skmacy			t->vector = rman_get_start(sc->irq_res);
2690182679Skmacy
2691167514Skmacy		break;
2692167514Skmacy	}
2693182679Skmacy	case CHELSIO_GET_QSET_NUM: {
2694167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
2695182679Skmacy		edata->val = pi->nqsets;
2696182679Skmacy		break;
2697182679Skmacy	}
2698182679Skmacy	case CHELSIO_LOAD_FW: {
2699182679Skmacy		uint8_t *fw_data;
2700182679Skmacy		uint32_t vers;
2701182679Skmacy		struct ch_mem_range *t = (struct ch_mem_range *)data;
2702182679Skmacy
2703167514Skmacy		/*
2704182679Skmacy		 * You're allowed to load a firmware only before FULL_INIT_DONE
2705182679Skmacy		 *
2706182679Skmacy		 * FW_UPTODATE is also set so the rest of the initialization
2707182679Skmacy		 * will not overwrite what was loaded here.  This gives you the
2708182679Skmacy		 * flexibility to load any firmware (and maybe shoot yourself in
2709182679Skmacy		 * the foot).
2710167514Skmacy		 */
2711182679Skmacy
2712182679Skmacy		ADAPTER_LOCK(sc);
2713182679Skmacy		if (sc->open_device_map || sc->flags & FULL_INIT_DONE) {
2714182679Skmacy			ADAPTER_UNLOCK(sc);
2715182679Skmacy			return (EBUSY);
2716182679Skmacy		}
2717182679Skmacy
2718182679Skmacy		fw_data = malloc(t->len, M_DEVBUF, M_NOWAIT);
2719182679Skmacy		if (!fw_data)
2720182679Skmacy			error = ENOMEM;
2721182679Skmacy		else
2722182679Skmacy			error = copyin(t->buf, fw_data, t->len);
2723182679Skmacy
2724182679Skmacy		if (!error)
2725182679Skmacy			error = -t3_load_fw(sc, fw_data, t->len);
2726182679Skmacy
2727182679Skmacy		if (t3_get_fw_version(sc, &vers) == 0) {
2728182679Skmacy			snprintf(&sc->fw_version[0], sizeof(sc->fw_version),
2729182679Skmacy			    "%d.%d.%d", G_FW_VERSION_MAJOR(vers),
2730182679Skmacy			    G_FW_VERSION_MINOR(vers), G_FW_VERSION_MICRO(vers));
2731182679Skmacy		}
2732182679Skmacy
2733182679Skmacy		if (!error)
2734182679Skmacy			sc->flags |= FW_UPTODATE;
2735182679Skmacy
2736182679Skmacy		free(fw_data, M_DEVBUF);
2737182679Skmacy		ADAPTER_UNLOCK(sc);
2738167514Skmacy		break;
2739167514Skmacy	}
2740182679Skmacy	case CHELSIO_LOAD_BOOT: {
2741182679Skmacy		uint8_t *boot_data;
2742182679Skmacy		struct ch_mem_range *t = (struct ch_mem_range *)data;
2743182679Skmacy
2744182679Skmacy		boot_data = malloc(t->len, M_DEVBUF, M_NOWAIT);
2745182679Skmacy		if (!boot_data)
2746182679Skmacy			return ENOMEM;
2747182679Skmacy
2748182679Skmacy		error = copyin(t->buf, boot_data, t->len);
2749182679Skmacy		if (!error)
2750182679Skmacy			error = -t3_load_boot(sc, boot_data, t->len);
2751182679Skmacy
2752182679Skmacy		free(boot_data, M_DEVBUF);
2753167514Skmacy		break;
2754167514Skmacy	}
2755182679Skmacy	case CHELSIO_GET_PM: {
2756182679Skmacy		struct ch_pm *m = (struct ch_pm *)data;
2757182679Skmacy		struct tp_params *p = &sc->params.tp;
2758182679Skmacy
2759182679Skmacy		if (!is_offload(sc))
2760182679Skmacy			return (EOPNOTSUPP);
2761182679Skmacy
2762182679Skmacy		m->tx_pg_sz = p->tx_pg_size;
2763182679Skmacy		m->tx_num_pg = p->tx_num_pgs;
2764182679Skmacy		m->rx_pg_sz  = p->rx_pg_size;
2765182679Skmacy		m->rx_num_pg = p->rx_num_pgs;
2766182679Skmacy		m->pm_total  = p->pmtx_size + p->chan_rx_size * p->nchan;
2767182679Skmacy
2768167514Skmacy		break;
2769182679Skmacy	}
2770182679Skmacy	case CHELSIO_SET_PM: {
2771182679Skmacy		struct ch_pm *m = (struct ch_pm *)data;
2772182679Skmacy		struct tp_params *p = &sc->params.tp;
2773182679Skmacy
2774182679Skmacy		if (!is_offload(sc))
2775182679Skmacy			return (EOPNOTSUPP);
2776182679Skmacy		if (sc->flags & FULL_INIT_DONE)
2777182679Skmacy			return (EBUSY);
2778182679Skmacy
2779182679Skmacy		if (!m->rx_pg_sz || (m->rx_pg_sz & (m->rx_pg_sz - 1)) ||
2780182679Skmacy		    !m->tx_pg_sz || (m->tx_pg_sz & (m->tx_pg_sz - 1)))
2781182679Skmacy			return (EINVAL);	/* not power of 2 */
2782182679Skmacy		if (!(m->rx_pg_sz & 0x14000))
2783182679Skmacy			return (EINVAL);	/* not 16KB or 64KB */
2784182679Skmacy		if (!(m->tx_pg_sz & 0x1554000))
2785182679Skmacy			return (EINVAL);
2786182679Skmacy		if (m->tx_num_pg == -1)
2787182679Skmacy			m->tx_num_pg = p->tx_num_pgs;
2788182679Skmacy		if (m->rx_num_pg == -1)
2789182679Skmacy			m->rx_num_pg = p->rx_num_pgs;
2790182679Skmacy		if (m->tx_num_pg % 24 || m->rx_num_pg % 24)
2791182679Skmacy			return (EINVAL);
2792182679Skmacy		if (m->rx_num_pg * m->rx_pg_sz > p->chan_rx_size ||
2793182679Skmacy		    m->tx_num_pg * m->tx_pg_sz > p->chan_tx_size)
2794182679Skmacy			return (EINVAL);
2795182679Skmacy
2796182679Skmacy		p->rx_pg_size = m->rx_pg_sz;
2797182679Skmacy		p->tx_pg_size = m->tx_pg_sz;
2798182679Skmacy		p->rx_num_pgs = m->rx_num_pg;
2799182679Skmacy		p->tx_num_pgs = m->tx_num_pg;
2800182679Skmacy		break;
2801182679Skmacy	}
2802169978Skmacy	case CHELSIO_SETMTUTAB: {
2803169978Skmacy		struct ch_mtus *m = (struct ch_mtus *)data;
2804169978Skmacy		int i;
2805169978Skmacy
2806169978Skmacy		if (!is_offload(sc))
2807169978Skmacy			return (EOPNOTSUPP);
2808169978Skmacy		if (offload_running(sc))
2809169978Skmacy			return (EBUSY);
2810169978Skmacy		if (m->nmtus != NMTUS)
2811169978Skmacy			return (EINVAL);
2812169978Skmacy		if (m->mtus[0] < 81)         /* accommodate SACK */
2813169978Skmacy			return (EINVAL);
2814169978Skmacy
2815169978Skmacy		/*
2816169978Skmacy		 * MTUs must be in ascending order
2817169978Skmacy		 */
2818169978Skmacy		for (i = 1; i < NMTUS; ++i)
2819169978Skmacy			if (m->mtus[i] < m->mtus[i - 1])
2820169978Skmacy				return (EINVAL);
2821169978Skmacy
2822182679Skmacy		memcpy(sc->params.mtus, m->mtus, sizeof(sc->params.mtus));
2823169978Skmacy		break;
2824169978Skmacy	}
2825169978Skmacy	case CHELSIO_GETMTUTAB: {
2826169978Skmacy		struct ch_mtus *m = (struct ch_mtus *)data;
2827169978Skmacy
2828169978Skmacy		if (!is_offload(sc))
2829169978Skmacy			return (EOPNOTSUPP);
2830169978Skmacy
2831169978Skmacy		memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus));
2832169978Skmacy		m->nmtus = NMTUS;
2833169978Skmacy		break;
2834171471Skmacy	}
2835167514Skmacy	case CHELSIO_GET_MEM: {
2836167514Skmacy		struct ch_mem_range *t = (struct ch_mem_range *)data;
2837167514Skmacy		struct mc7 *mem;
2838167514Skmacy		uint8_t *useraddr;
2839167514Skmacy		u64 buf[32];
2840182679Skmacy
2841182679Skmacy		/*
2842182679Skmacy		 * Use these to avoid modifying len/addr in the the return
2843182679Skmacy		 * struct
2844182679Skmacy		 */
2845182679Skmacy		uint32_t len = t->len, addr = t->addr;
2846182679Skmacy
2847167514Skmacy		if (!is_offload(sc))
2848167514Skmacy			return (EOPNOTSUPP);
2849167514Skmacy		if (!(sc->flags & FULL_INIT_DONE))
2850167514Skmacy			return (EIO);         /* need the memory controllers */
2851182679Skmacy		if ((addr & 0x7) || (len & 0x7))
2852167514Skmacy			return (EINVAL);
2853167514Skmacy		if (t->mem_id == MEM_CM)
2854167514Skmacy			mem = &sc->cm;
2855167514Skmacy		else if (t->mem_id == MEM_PMRX)
2856167514Skmacy			mem = &sc->pmrx;
2857167514Skmacy		else if (t->mem_id == MEM_PMTX)
2858167514Skmacy			mem = &sc->pmtx;
2859167514Skmacy		else
2860167514Skmacy			return (EINVAL);
2861167514Skmacy
2862167514Skmacy		/*
2863167514Skmacy		 * Version scheme:
2864167514Skmacy		 * bits 0..9: chip version
2865167514Skmacy		 * bits 10..15: chip revision
2866167514Skmacy		 */
2867167514Skmacy		t->version = 3 | (sc->params.rev << 10);
2868167514Skmacy
2869167514Skmacy		/*
2870167514Skmacy		 * Read 256 bytes at a time as len can be large and we don't
2871167514Skmacy		 * want to use huge intermediate buffers.
2872167514Skmacy		 */
2873174708Skmacy		useraddr = (uint8_t *)t->buf;
2874182679Skmacy		while (len) {
2875182679Skmacy			unsigned int chunk = min(len, sizeof(buf));
2876167514Skmacy
2877182679Skmacy			error = t3_mc7_bd_read(mem, addr / 8, chunk / 8, buf);
2878167514Skmacy			if (error)
2879167514Skmacy				return (-error);
2880167514Skmacy			if (copyout(buf, useraddr, chunk))
2881167514Skmacy				return (EFAULT);
2882167514Skmacy			useraddr += chunk;
2883182679Skmacy			addr += chunk;
2884182679Skmacy			len -= chunk;
2885167514Skmacy		}
2886167514Skmacy		break;
2887167514Skmacy	}
2888169978Skmacy	case CHELSIO_READ_TCAM_WORD: {
2889169978Skmacy		struct ch_tcam_word *t = (struct ch_tcam_word *)data;
2890169978Skmacy
2891169978Skmacy		if (!is_offload(sc))
2892169978Skmacy			return (EOPNOTSUPP);
2893171471Skmacy		if (!(sc->flags & FULL_INIT_DONE))
2894171471Skmacy			return (EIO);         /* need MC5 */
2895169978Skmacy		return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf);
2896169978Skmacy		break;
2897169978Skmacy	}
2898167514Skmacy	case CHELSIO_SET_TRACE_FILTER: {
2899167514Skmacy		struct ch_trace *t = (struct ch_trace *)data;
2900167514Skmacy		const struct trace_params *tp;
2901167514Skmacy
2902167514Skmacy		tp = (const struct trace_params *)&t->sip;
2903167514Skmacy		if (t->config_tx)
2904167514Skmacy			t3_config_trace_filter(sc, tp, 0, t->invert_match,
2905167514Skmacy					       t->trace_tx);
2906167514Skmacy		if (t->config_rx)
2907167514Skmacy			t3_config_trace_filter(sc, tp, 1, t->invert_match,
2908167514Skmacy					       t->trace_rx);
2909167514Skmacy		break;
2910167514Skmacy	}
2911167514Skmacy	case CHELSIO_SET_PKTSCHED: {
2912167514Skmacy		struct ch_pktsched_params *p = (struct ch_pktsched_params *)data;
2913167514Skmacy		if (sc->open_device_map == 0)
2914167514Skmacy			return (EAGAIN);
2915167514Skmacy		send_pktsched_cmd(sc, p->sched, p->idx, p->min, p->max,
2916167514Skmacy		    p->binding);
2917167514Skmacy		break;
2918167514Skmacy	}
2919167514Skmacy	case CHELSIO_IFCONF_GETREGS: {
2920182679Skmacy		struct ch_ifconf_regs *regs = (struct ch_ifconf_regs *)data;
2921167514Skmacy		int reglen = cxgb_get_regs_len();
2922182679Skmacy		uint8_t *buf = malloc(reglen, M_DEVBUF, M_NOWAIT);
2923167514Skmacy		if (buf == NULL) {
2924167514Skmacy			return (ENOMEM);
2925182679Skmacy		}
2926182679Skmacy		if (regs->len > reglen)
2927167514Skmacy			regs->len = reglen;
2928182679Skmacy		else if (regs->len < reglen)
2929189643Sgnn			error = ENOBUFS;
2930182679Skmacy
2931182679Skmacy		if (!error) {
2932182679Skmacy			cxgb_get_regs(sc, regs, buf);
2933182679Skmacy			error = copyout(buf, regs->data, reglen);
2934167514Skmacy		}
2935167514Skmacy		free(buf, M_DEVBUF);
2936167514Skmacy
2937167514Skmacy		break;
2938167514Skmacy	}
2939169978Skmacy	case CHELSIO_SET_HW_SCHED: {
2940169978Skmacy		struct ch_hw_sched *t = (struct ch_hw_sched *)data;
2941169978Skmacy		unsigned int ticks_per_usec = core_ticks_per_usec(sc);
2942169978Skmacy
2943169978Skmacy		if ((sc->flags & FULL_INIT_DONE) == 0)
2944169978Skmacy			return (EAGAIN);       /* need TP to be initialized */
2945169978Skmacy		if (t->sched >= NTX_SCHED || !in_range(t->mode, 0, 1) ||
2946169978Skmacy		    !in_range(t->channel, 0, 1) ||
2947169978Skmacy		    !in_range(t->kbps, 0, 10000000) ||
2948169978Skmacy		    !in_range(t->class_ipg, 0, 10000 * 65535 / ticks_per_usec) ||
2949169978Skmacy		    !in_range(t->flow_ipg, 0,
2950169978Skmacy			      dack_ticks_to_usec(sc, 0x7ff)))
2951169978Skmacy			return (EINVAL);
2952169978Skmacy
2953169978Skmacy		if (t->kbps >= 0) {
2954169978Skmacy			error = t3_config_sched(sc, t->kbps, t->sched);
2955169978Skmacy			if (error < 0)
2956169978Skmacy				return (-error);
2957169978Skmacy		}
2958169978Skmacy		if (t->class_ipg >= 0)
2959169978Skmacy			t3_set_sched_ipg(sc, t->sched, t->class_ipg);
2960169978Skmacy		if (t->flow_ipg >= 0) {
2961169978Skmacy			t->flow_ipg *= 1000;     /* us -> ns */
2962169978Skmacy			t3_set_pace_tbl(sc, &t->flow_ipg, t->sched, 1);
2963169978Skmacy		}
2964169978Skmacy		if (t->mode >= 0) {
2965169978Skmacy			int bit = 1 << (S_TX_MOD_TIMER_MODE + t->sched);
2966169978Skmacy
2967169978Skmacy			t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2968169978Skmacy					 bit, t->mode ? bit : 0);
2969169978Skmacy		}
2970169978Skmacy		if (t->channel >= 0)
2971169978Skmacy			t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2972169978Skmacy					 1 << t->sched, t->channel << t->sched);
2973169978Skmacy		break;
2974182679Skmacy	}
2975182679Skmacy	case CHELSIO_GET_EEPROM: {
2976182679Skmacy		int i;
2977182679Skmacy		struct ch_eeprom *e = (struct ch_eeprom *)data;
2978182679Skmacy		uint8_t *buf = malloc(EEPROMSIZE, M_DEVBUF, M_NOWAIT);
2979182679Skmacy
2980182679Skmacy		if (buf == NULL) {
2981182679Skmacy			return (ENOMEM);
2982182679Skmacy		}
2983182679Skmacy		e->magic = EEPROM_MAGIC;
2984182679Skmacy		for (i = e->offset & ~3; !error && i < e->offset + e->len; i += 4)
2985182679Skmacy			error = -t3_seeprom_read(sc, i, (uint32_t *)&buf[i]);
2986182679Skmacy
2987182679Skmacy		if (!error)
2988182679Skmacy			error = copyout(buf + e->offset, e->data, e->len);
2989182679Skmacy
2990182679Skmacy		free(buf, M_DEVBUF);
2991182679Skmacy		break;
2992182679Skmacy	}
2993182679Skmacy	case CHELSIO_CLEAR_STATS: {
2994182679Skmacy		if (!(sc->flags & FULL_INIT_DONE))
2995182679Skmacy			return EAGAIN;
2996182679Skmacy
2997182679Skmacy		PORT_LOCK(pi);
2998182679Skmacy		t3_mac_update_stats(&pi->mac);
2999182679Skmacy		memset(&pi->mac.stats, 0, sizeof(pi->mac.stats));
3000182679Skmacy		PORT_UNLOCK(pi);
3001182679Skmacy		break;
3002182679Skmacy	}
3003189643Sgnn	case CHELSIO_GET_UP_LA: {
3004189643Sgnn		struct ch_up_la *la = (struct ch_up_la *)data;
3005189643Sgnn		uint8_t *buf = malloc(LA_BUFSIZE, M_DEVBUF, M_NOWAIT);
3006189643Sgnn		if (buf == NULL) {
3007189643Sgnn			return (ENOMEM);
3008189643Sgnn		}
3009189643Sgnn		if (la->bufsize < LA_BUFSIZE)
3010189643Sgnn			error = ENOBUFS;
3011189643Sgnn
3012189643Sgnn		if (!error)
3013189643Sgnn			error = -t3_get_up_la(sc, &la->stopped, &la->idx,
3014189643Sgnn					      &la->bufsize, buf);
3015189643Sgnn		if (!error)
3016189643Sgnn			error = copyout(buf, la->data, la->bufsize);
3017189643Sgnn
3018189643Sgnn		free(buf, M_DEVBUF);
3019189643Sgnn		break;
3020189643Sgnn	}
3021189643Sgnn	case CHELSIO_GET_UP_IOQS: {
3022189643Sgnn		struct ch_up_ioqs *ioqs = (struct ch_up_ioqs *)data;
3023189643Sgnn		uint8_t *buf = malloc(IOQS_BUFSIZE, M_DEVBUF, M_NOWAIT);
3024189643Sgnn		uint32_t *v;
3025189643Sgnn
3026189643Sgnn		if (buf == NULL) {
3027189643Sgnn			return (ENOMEM);
3028189643Sgnn		}
3029189643Sgnn		if (ioqs->bufsize < IOQS_BUFSIZE)
3030189643Sgnn			error = ENOBUFS;
3031189643Sgnn
3032189643Sgnn		if (!error)
3033189643Sgnn			error = -t3_get_up_ioqs(sc, &ioqs->bufsize, buf);
3034189643Sgnn
3035189643Sgnn		if (!error) {
3036189643Sgnn			v = (uint32_t *)buf;
3037189643Sgnn
3038189643Sgnn			ioqs->bufsize -= 4 * sizeof(uint32_t);
3039189643Sgnn			ioqs->ioq_rx_enable = *v++;
3040189643Sgnn			ioqs->ioq_tx_enable = *v++;
3041189643Sgnn			ioqs->ioq_rx_status = *v++;
3042189643Sgnn			ioqs->ioq_tx_status = *v++;
3043189643Sgnn
3044189643Sgnn			error = copyout(v, ioqs->data, ioqs->bufsize);
3045189643Sgnn		}
3046189643Sgnn
3047189643Sgnn		free(buf, M_DEVBUF);
3048189643Sgnn		break;
3049189643Sgnn	}
3050167514Skmacy	default:
3051167514Skmacy		return (EOPNOTSUPP);
3052167514Skmacy		break;
3053167514Skmacy	}
3054167514Skmacy
3055167514Skmacy	return (error);
3056167514Skmacy}
3057167514Skmacy
3058167514Skmacystatic __inline void
3059167514Skmacyreg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
3060167514Skmacy    unsigned int end)
3061167514Skmacy{
3062182679Skmacy	uint32_t *p = (uint32_t *)(buf + start);
3063167514Skmacy
3064167514Skmacy	for ( ; start <= end; start += sizeof(uint32_t))
3065167514Skmacy		*p++ = t3_read_reg(ap, start);
3066167514Skmacy}
3067167514Skmacy
3068167514Skmacy#define T3_REGMAP_SIZE (3 * 1024)
3069167514Skmacystatic int
3070167514Skmacycxgb_get_regs_len(void)
3071167514Skmacy{
3072167514Skmacy	return T3_REGMAP_SIZE;
3073167514Skmacy}
3074167514Skmacy
3075167514Skmacystatic void
3076182679Skmacycxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf)
3077167514Skmacy{
3078167514Skmacy
3079167514Skmacy	/*
3080167514Skmacy	 * Version scheme:
3081167514Skmacy	 * bits 0..9: chip version
3082167514Skmacy	 * bits 10..15: chip revision
3083167514Skmacy	 * bit 31: set for PCIe cards
3084167514Skmacy	 */
3085167514Skmacy	regs->version = 3 | (sc->params.rev << 10) | (is_pcie(sc) << 31);
3086167514Skmacy
3087167514Skmacy	/*
3088167514Skmacy	 * We skip the MAC statistics registers because they are clear-on-read.
3089167514Skmacy	 * Also reading multi-register stats would need to synchronize with the
3090167514Skmacy	 * periodic mac stats accumulation.  Hard to justify the complexity.
3091167514Skmacy	 */
3092182679Skmacy	memset(buf, 0, cxgb_get_regs_len());
3093167514Skmacy	reg_block_dump(sc, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
3094167514Skmacy	reg_block_dump(sc, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
3095167514Skmacy	reg_block_dump(sc, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
3096167514Skmacy	reg_block_dump(sc, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
3097167514Skmacy	reg_block_dump(sc, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
3098167514Skmacy	reg_block_dump(sc, buf, A_XGM_SERDES_STATUS0,
3099167514Skmacy		       XGM_REG(A_XGM_SERDES_STAT3, 1));
3100167514Skmacy	reg_block_dump(sc, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
3101167514Skmacy		       XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
3102167514Skmacy}
3103176572Skmacy
3104176572Skmacy
3105176572SkmacyMODULE_DEPEND(if_cxgb, cxgb_t3fw, 1, 1, 1);
3106