cxgb_main.c revision 174626
1167514Skmacy/**************************************************************************
2167514Skmacy
3167514SkmacyCopyright (c) 2007, 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
12169978Skmacy2. 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 174626 2007-12-15 21:54:59Z kmacy $");
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>
43167514Skmacy#include <sys/rman.h>
44167514Skmacy#include <sys/ioccom.h>
45167514Skmacy#include <sys/mbuf.h>
46167514Skmacy#include <sys/linker.h>
47174626Skmacy#include <sys/syslog.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>
53167514Skmacy#include <sys/queue.h>
54167514Skmacy#include <sys/taskqueue.h>
55167514Skmacy
56167514Skmacy#include <net/bpf.h>
57167514Skmacy#include <net/ethernet.h>
58167514Skmacy#include <net/if.h>
59167514Skmacy#include <net/if_arp.h>
60167514Skmacy#include <net/if_dl.h>
61167514Skmacy#include <net/if_media.h>
62167514Skmacy#include <net/if_types.h>
63167514Skmacy
64167514Skmacy#include <netinet/in_systm.h>
65167514Skmacy#include <netinet/in.h>
66167514Skmacy#include <netinet/if_ether.h>
67167514Skmacy#include <netinet/ip.h>
68167514Skmacy#include <netinet/ip.h>
69167514Skmacy#include <netinet/tcp.h>
70167514Skmacy#include <netinet/udp.h>
71167514Skmacy
72167514Skmacy#include <dev/pci/pcireg.h>
73167514Skmacy#include <dev/pci/pcivar.h>
74167514Skmacy#include <dev/pci/pci_private.h>
75167514Skmacy
76170076Skmacy#ifdef CONFIG_DEFINED
77170076Skmacy#include <cxgb_include.h>
78170076Skmacy#else
79170076Skmacy#include <dev/cxgb/cxgb_include.h>
80170076Skmacy#endif
81167514Skmacy
82167514Skmacy#ifdef PRIV_SUPPORTED
83167514Skmacy#include <sys/priv.h>
84167514Skmacy#endif
85167514Skmacy
86167514Skmacystatic int cxgb_setup_msix(adapter_t *, int);
87170654Skmacystatic void cxgb_teardown_msix(adapter_t *);
88167514Skmacystatic void cxgb_init(void *);
89167514Skmacystatic void cxgb_init_locked(struct port_info *);
90167734Skmacystatic void cxgb_stop_locked(struct port_info *);
91167514Skmacystatic void cxgb_set_rxmode(struct port_info *);
92167514Skmacystatic int cxgb_ioctl(struct ifnet *, unsigned long, caddr_t);
93167514Skmacystatic void cxgb_start(struct ifnet *);
94167514Skmacystatic void cxgb_start_proc(void *, int ncount);
95167514Skmacystatic int cxgb_media_change(struct ifnet *);
96167514Skmacystatic void cxgb_media_status(struct ifnet *, struct ifmediareq *);
97167514Skmacystatic int setup_sge_qsets(adapter_t *);
98167514Skmacystatic void cxgb_async_intr(void *);
99167514Skmacystatic void cxgb_ext_intr_handler(void *, int);
100170869Skmacystatic void cxgb_tick_handler(void *, int);
101170869Skmacystatic void cxgb_down_locked(struct adapter *sc);
102167514Skmacystatic void cxgb_tick(void *);
103167514Skmacystatic void setup_rss(adapter_t *sc);
104167514Skmacy
105167514Skmacy/* Attachment glue for the PCI controller end of the device.  Each port of
106167514Skmacy * the device is attached separately, as defined later.
107167514Skmacy */
108167514Skmacystatic int cxgb_controller_probe(device_t);
109167514Skmacystatic int cxgb_controller_attach(device_t);
110167514Skmacystatic int cxgb_controller_detach(device_t);
111167514Skmacystatic void cxgb_free(struct adapter *);
112167514Skmacystatic __inline void reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
113167514Skmacy    unsigned int end);
114167514Skmacystatic void cxgb_get_regs(adapter_t *sc, struct ifconf_regs *regs, uint8_t *buf);
115167514Skmacystatic int cxgb_get_regs_len(void);
116169978Skmacystatic int offload_open(struct port_info *pi);
117171978Skmacystatic void touch_bars(device_t dev);
118171978Skmacy
119170789Skmacy#ifdef notyet
120174626Skmacystatic int offload_close(struct t3cdev *tdev);
121170789Skmacy#endif
122167514Skmacy
123169978Skmacy
124167514Skmacystatic device_method_t cxgb_controller_methods[] = {
125167514Skmacy	DEVMETHOD(device_probe,		cxgb_controller_probe),
126167514Skmacy	DEVMETHOD(device_attach,	cxgb_controller_attach),
127167514Skmacy	DEVMETHOD(device_detach,	cxgb_controller_detach),
128167514Skmacy
129167514Skmacy	/* bus interface */
130167514Skmacy	DEVMETHOD(bus_print_child,	bus_generic_print_child),
131167514Skmacy	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
132167514Skmacy
133167514Skmacy	{ 0, 0 }
134167514Skmacy};
135167514Skmacy
136167514Skmacystatic driver_t cxgb_controller_driver = {
137167514Skmacy	"cxgbc",
138167514Skmacy	cxgb_controller_methods,
139167514Skmacy	sizeof(struct adapter)
140167514Skmacy};
141167514Skmacy
142167514Skmacystatic devclass_t	cxgb_controller_devclass;
143167514SkmacyDRIVER_MODULE(cxgbc, pci, cxgb_controller_driver, cxgb_controller_devclass, 0, 0);
144167514Skmacy
145167514Skmacy/*
146167514Skmacy * Attachment glue for the ports.  Attachment is done directly to the
147167514Skmacy * controller device.
148167514Skmacy */
149167514Skmacystatic int cxgb_port_probe(device_t);
150167514Skmacystatic int cxgb_port_attach(device_t);
151167514Skmacystatic int cxgb_port_detach(device_t);
152167514Skmacy
153167514Skmacystatic device_method_t cxgb_port_methods[] = {
154167514Skmacy	DEVMETHOD(device_probe,		cxgb_port_probe),
155167514Skmacy	DEVMETHOD(device_attach,	cxgb_port_attach),
156167514Skmacy	DEVMETHOD(device_detach,	cxgb_port_detach),
157167514Skmacy	{ 0, 0 }
158167514Skmacy};
159167514Skmacy
160167514Skmacystatic driver_t cxgb_port_driver = {
161167514Skmacy	"cxgb",
162167514Skmacy	cxgb_port_methods,
163167514Skmacy	0
164167514Skmacy};
165167514Skmacy
166167514Skmacystatic d_ioctl_t cxgb_extension_ioctl;
167170654Skmacystatic d_open_t cxgb_extension_open;
168170654Skmacystatic d_close_t cxgb_extension_close;
169167514Skmacy
170170654Skmacystatic struct cdevsw cxgb_cdevsw = {
171170654Skmacy       .d_version =    D_VERSION,
172170654Skmacy       .d_flags =      0,
173170654Skmacy       .d_open =       cxgb_extension_open,
174170654Skmacy       .d_close =      cxgb_extension_close,
175170654Skmacy       .d_ioctl =      cxgb_extension_ioctl,
176170654Skmacy       .d_name =       "cxgb",
177170654Skmacy};
178170654Skmacy
179167514Skmacystatic devclass_t	cxgb_port_devclass;
180167514SkmacyDRIVER_MODULE(cxgb, cxgbc, cxgb_port_driver, cxgb_port_devclass, 0, 0);
181167514Skmacy
182167514Skmacy#define SGE_MSIX_COUNT (SGE_QSETS + 1)
183167514Skmacy
184168749Skmacyextern int collapse_mbufs;
185167514Skmacy/*
186167514Skmacy * The driver uses the best interrupt scheme available on a platform in the
187167514Skmacy * order MSI-X, MSI, legacy pin interrupts.  This parameter determines which
188167514Skmacy * of these schemes the driver may consider as follows:
189167514Skmacy *
190167514Skmacy * msi = 2: choose from among all three options
191167514Skmacy * msi = 1 : only consider MSI and pin interrupts
192167514Skmacy * msi = 0: force pin interrupts
193167514Skmacy */
194167760Skmacystatic int msi_allowed = 2;
195170083Skmacy
196167514SkmacyTUNABLE_INT("hw.cxgb.msi_allowed", &msi_allowed);
197167514SkmacySYSCTL_NODE(_hw, OID_AUTO, cxgb, CTLFLAG_RD, 0, "CXGB driver parameters");
198167514SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, msi_allowed, CTLFLAG_RDTUN, &msi_allowed, 0,
199167514Skmacy    "MSI-X, MSI, INTx selector");
200169978Skmacy
201169053Skmacy/*
202169978Skmacy * The driver enables offload as a default.
203169978Skmacy * To disable it, use ofld_disable = 1.
204169053Skmacy */
205169978Skmacystatic int ofld_disable = 0;
206169978SkmacyTUNABLE_INT("hw.cxgb.ofld_disable", &ofld_disable);
207169978SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, ofld_disable, CTLFLAG_RDTUN, &ofld_disable, 0,
208169978Skmacy    "disable ULP offload");
209169978Skmacy
210169978Skmacy/*
211169978Skmacy * The driver uses an auto-queue algorithm by default.
212169978Skmacy * To disable it and force a single queue-set per port, use singleq = 1.
213169978Skmacy */
214169053Skmacystatic int singleq = 1;
215169978SkmacyTUNABLE_INT("hw.cxgb.singleq", &singleq);
216169978SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, singleq, CTLFLAG_RDTUN, &singleq, 0,
217169978Skmacy    "use a single queue-set per port");
218167514Skmacy
219167514Skmacyenum {
220167514Skmacy	MAX_TXQ_ENTRIES      = 16384,
221167514Skmacy	MAX_CTRL_TXQ_ENTRIES = 1024,
222167514Skmacy	MAX_RSPQ_ENTRIES     = 16384,
223167514Skmacy	MAX_RX_BUFFERS       = 16384,
224167514Skmacy	MAX_RX_JUMBO_BUFFERS = 16384,
225167514Skmacy	MIN_TXQ_ENTRIES      = 4,
226167514Skmacy	MIN_CTRL_TXQ_ENTRIES = 4,
227167514Skmacy	MIN_RSPQ_ENTRIES     = 32,
228172096Skmacy	MIN_FL_ENTRIES       = 32,
229172096Skmacy	MIN_FL_JUMBO_ENTRIES = 32
230167514Skmacy};
231167514Skmacy
232171471Skmacystruct filter_info {
233171471Skmacy	u32 sip;
234171471Skmacy	u32 sip_mask;
235171471Skmacy	u32 dip;
236171471Skmacy	u16 sport;
237171471Skmacy	u16 dport;
238171471Skmacy	u32 vlan:12;
239171471Skmacy	u32 vlan_prio:3;
240171471Skmacy	u32 mac_hit:1;
241171471Skmacy	u32 mac_idx:4;
242171471Skmacy	u32 mac_vld:1;
243171471Skmacy	u32 pkt_type:2;
244171471Skmacy	u32 report_filter_id:1;
245171471Skmacy	u32 pass:1;
246171471Skmacy	u32 rss:1;
247171471Skmacy	u32 qset:3;
248171471Skmacy	u32 locked:1;
249171471Skmacy	u32 valid:1;
250171471Skmacy};
251171471Skmacy
252171471Skmacyenum { FILTER_NO_VLAN_PRI = 7 };
253171471Skmacy
254167514Skmacy#define PORT_MASK ((1 << MAX_NPORTS) - 1)
255167514Skmacy
256167514Skmacy/* Table for probing the cards.  The desc field isn't actually used */
257167514Skmacystruct cxgb_ident {
258167514Skmacy	uint16_t	vendor;
259167514Skmacy	uint16_t	device;
260167514Skmacy	int		index;
261167514Skmacy	char		*desc;
262167514Skmacy} cxgb_identifiers[] = {
263167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0020, 0, "PE9000"},
264167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0021, 1, "T302E"},
265167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0022, 2, "T310E"},
266167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0023, 3, "T320X"},
267167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0024, 1, "T302X"},
268167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0025, 3, "T320E"},
269167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0026, 2, "T310X"},
270167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0030, 2, "T3B10"},
271167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0031, 3, "T3B20"},
272167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0032, 1, "T3B02"},
273170654Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0033, 4, "T3B04"},
274167514Skmacy	{0, 0, 0, NULL}
275167514Skmacy};
276167514Skmacy
277171471Skmacy
278171471Skmacystatic int set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset);
279171471Skmacy
280171471Skmacystatic inline char
281171471Skmacyt3rev2char(struct adapter *adapter)
282171471Skmacy{
283171471Skmacy	char rev = 'z';
284171471Skmacy
285171471Skmacy	switch(adapter->params.rev) {
286171471Skmacy	case T3_REV_A:
287171471Skmacy		rev = 'a';
288171471Skmacy		break;
289171471Skmacy	case T3_REV_B:
290171471Skmacy	case T3_REV_B2:
291171471Skmacy		rev = 'b';
292171471Skmacy		break;
293171471Skmacy	case T3_REV_C:
294171471Skmacy		rev = 'c';
295171471Skmacy		break;
296171471Skmacy	}
297171471Skmacy	return rev;
298171471Skmacy}
299171471Skmacy
300167514Skmacystatic struct cxgb_ident *
301167514Skmacycxgb_get_ident(device_t dev)
302167514Skmacy{
303167514Skmacy	struct cxgb_ident *id;
304167514Skmacy
305167514Skmacy	for (id = cxgb_identifiers; id->desc != NULL; id++) {
306167514Skmacy		if ((id->vendor == pci_get_vendor(dev)) &&
307167514Skmacy		    (id->device == pci_get_device(dev))) {
308167514Skmacy			return (id);
309167514Skmacy		}
310167514Skmacy	}
311167514Skmacy	return (NULL);
312167514Skmacy}
313167514Skmacy
314167514Skmacystatic const struct adapter_info *
315167514Skmacycxgb_get_adapter_info(device_t dev)
316167514Skmacy{
317167514Skmacy	struct cxgb_ident *id;
318167514Skmacy	const struct adapter_info *ai;
319167514Skmacy
320167514Skmacy	id = cxgb_get_ident(dev);
321167514Skmacy	if (id == NULL)
322167514Skmacy		return (NULL);
323167514Skmacy
324167514Skmacy	ai = t3_get_adapter_info(id->index);
325167514Skmacy
326167514Skmacy	return (ai);
327167514Skmacy}
328167514Skmacy
329167514Skmacystatic int
330167514Skmacycxgb_controller_probe(device_t dev)
331167514Skmacy{
332167514Skmacy	const struct adapter_info *ai;
333167514Skmacy	char *ports, buf[80];
334170654Skmacy	int nports;
335170654Skmacy
336167514Skmacy	ai = cxgb_get_adapter_info(dev);
337167514Skmacy	if (ai == NULL)
338167514Skmacy		return (ENXIO);
339167514Skmacy
340170654Skmacy	nports = ai->nports0 + ai->nports1;
341170654Skmacy	if (nports == 1)
342167514Skmacy		ports = "port";
343167514Skmacy	else
344167514Skmacy		ports = "ports";
345167514Skmacy
346170654Skmacy	snprintf(buf, sizeof(buf), "%s RNIC, %d %s", ai->desc, nports, ports);
347167514Skmacy	device_set_desc_copy(dev, buf);
348167514Skmacy	return (BUS_PROBE_DEFAULT);
349167514Skmacy}
350167514Skmacy
351171471Skmacy#define FW_FNAME "t3fw%d%d%d"
352171471Skmacy#define TPEEPROM_NAME "t3%ctpe%d%d%d"
353171471Skmacy#define TPSRAM_NAME "t3%cps%d%d%d"
354171471Skmacy
355167514Skmacystatic int
356169978Skmacyupgrade_fw(adapter_t *sc)
357167514Skmacy{
358167514Skmacy	char buf[32];
359167514Skmacy#ifdef FIRMWARE_LATEST
360167514Skmacy	const struct firmware *fw;
361167514Skmacy#else
362167514Skmacy	struct firmware *fw;
363167514Skmacy#endif
364167514Skmacy	int status;
365167514Skmacy
366171471Skmacy	snprintf(&buf[0], sizeof(buf), FW_FNAME,  FW_VERSION_MAJOR,
367169978Skmacy	    FW_VERSION_MINOR, FW_VERSION_MICRO);
368167514Skmacy
369167514Skmacy	fw = firmware_get(buf);
370167514Skmacy
371167514Skmacy	if (fw == NULL) {
372169978Skmacy		device_printf(sc->dev, "Could not find firmware image %s\n", buf);
373169978Skmacy		return (ENOENT);
374171471Skmacy	} else
375171471Skmacy		device_printf(sc->dev, "updating firmware on card with %s\n", buf);
376167514Skmacy	status = t3_load_fw(sc, (const uint8_t *)fw->data, fw->datasize);
377167514Skmacy
378171471Skmacy	device_printf(sc->dev, "firmware update returned %s %d\n", (status == 0) ? "success" : "fail", status);
379171471Skmacy
380167514Skmacy	firmware_put(fw, FIRMWARE_UNLOAD);
381167514Skmacy
382167514Skmacy	return (status);
383167514Skmacy}
384167514Skmacy
385167514Skmacystatic int
386167514Skmacycxgb_controller_attach(device_t dev)
387167514Skmacy{
388167514Skmacy	device_t child;
389167514Skmacy	const struct adapter_info *ai;
390167514Skmacy	struct adapter *sc;
391172109Skmacy	int i, error = 0;
392167514Skmacy	uint32_t vers;
393167760Skmacy	int port_qsets = 1;
394171868Skmacy#ifdef MSI_SUPPORTED
395172109Skmacy	int msi_needed, reg;
396171868Skmacy#endif
397167514Skmacy	sc = device_get_softc(dev);
398167514Skmacy	sc->dev = dev;
399169978Skmacy	sc->msi_count = 0;
400172109Skmacy	ai = cxgb_get_adapter_info(dev);
401172109Skmacy
402172109Skmacy	/*
403172109Skmacy	 * XXX not really related but a recent addition
404172109Skmacy	 */
405172109Skmacy#ifdef MSI_SUPPORTED
406167840Skmacy	/* find the PCIe link width and set max read request to 4KB*/
407167840Skmacy	if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
408167840Skmacy		uint16_t lnk, pectl;
409167840Skmacy		lnk = pci_read_config(dev, reg + 0x12, 2);
410167840Skmacy		sc->link_width = (lnk >> 4) & 0x3f;
411167840Skmacy
412167840Skmacy		pectl = pci_read_config(dev, reg + 0x8, 2);
413167840Skmacy		pectl = (pectl & ~0x7000) | (5 << 12);
414167840Skmacy		pci_write_config(dev, reg + 0x8, pectl, 2);
415167840Skmacy	}
416171471Skmacy
417171471Skmacy	if (sc->link_width != 0 && sc->link_width <= 4 &&
418171471Skmacy	    (ai->nports0 + ai->nports1) <= 2) {
419167840Skmacy		device_printf(sc->dev,
420167862Skmacy		    "PCIe x%d Link, expect reduced performance\n",
421167840Skmacy		    sc->link_width);
422167840Skmacy	}
423172109Skmacy#endif
424171978Skmacy	touch_bars(dev);
425167514Skmacy	pci_enable_busmaster(dev);
426167514Skmacy	/*
427167514Skmacy	 * Allocate the registers and make them available to the driver.
428167514Skmacy	 * The registers that we care about for NIC mode are in BAR 0
429167514Skmacy	 */
430167514Skmacy	sc->regs_rid = PCIR_BAR(0);
431167514Skmacy	if ((sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
432167514Skmacy	    &sc->regs_rid, RF_ACTIVE)) == NULL) {
433167514Skmacy		device_printf(dev, "Cannot allocate BAR\n");
434167514Skmacy		return (ENXIO);
435167514Skmacy	}
436167514Skmacy
437170869Skmacy	snprintf(sc->lockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb controller lock %d",
438170869Skmacy	    device_get_unit(dev));
439170869Skmacy	ADAPTER_LOCK_INIT(sc, sc->lockbuf);
440170869Skmacy
441170869Skmacy	snprintf(sc->reglockbuf, ADAPTER_LOCK_NAME_LEN, "SGE reg lock %d",
442170869Skmacy	    device_get_unit(dev));
443170869Skmacy	snprintf(sc->mdiolockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb mdio lock %d",
444170869Skmacy	    device_get_unit(dev));
445170869Skmacy	snprintf(sc->elmerlockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb elmer lock %d",
446170869Skmacy	    device_get_unit(dev));
447167514Skmacy
448170869Skmacy	MTX_INIT(&sc->sge.reg_lock, sc->reglockbuf, NULL, MTX_DEF);
449170869Skmacy	MTX_INIT(&sc->mdio_lock, sc->mdiolockbuf, NULL, MTX_DEF);
450170869Skmacy	MTX_INIT(&sc->elmer_lock, sc->elmerlockbuf, NULL, MTX_DEF);
451170869Skmacy
452167514Skmacy	sc->bt = rman_get_bustag(sc->regs_res);
453167514Skmacy	sc->bh = rman_get_bushandle(sc->regs_res);
454167514Skmacy	sc->mmio_len = rman_get_size(sc->regs_res);
455167769Skmacy
456167769Skmacy	if (t3_prep_adapter(sc, ai, 1) < 0) {
457170654Skmacy		printf("prep adapter failed\n");
458167769Skmacy		error = ENODEV;
459167769Skmacy		goto out;
460167769Skmacy	}
461167514Skmacy	/* Allocate the BAR for doing MSI-X.  If it succeeds, try to allocate
462167514Skmacy	 * enough messages for the queue sets.  If that fails, try falling
463167514Skmacy	 * back to MSI.  If that fails, then try falling back to the legacy
464167514Skmacy	 * interrupt pin model.
465167514Skmacy	 */
466167514Skmacy#ifdef MSI_SUPPORTED
467167760Skmacy
468167514Skmacy	sc->msix_regs_rid = 0x20;
469167514Skmacy	if ((msi_allowed >= 2) &&
470167514Skmacy	    (sc->msix_regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
471167514Skmacy	    &sc->msix_regs_rid, RF_ACTIVE)) != NULL) {
472167514Skmacy
473169978Skmacy		msi_needed = sc->msi_count = SGE_MSIX_COUNT;
474167760Skmacy
475169978Skmacy		if (((error = pci_alloc_msix(dev, &sc->msi_count)) != 0) ||
476169978Skmacy		    (sc->msi_count != msi_needed)) {
477169978Skmacy			device_printf(dev, "msix allocation failed - msi_count = %d"
478169978Skmacy			    " msi_needed=%d will try msi err=%d\n", sc->msi_count,
479169978Skmacy			    msi_needed, error);
480169978Skmacy			sc->msi_count = 0;
481167514Skmacy			pci_release_msi(dev);
482167514Skmacy			bus_release_resource(dev, SYS_RES_MEMORY,
483167514Skmacy			    sc->msix_regs_rid, sc->msix_regs_res);
484167514Skmacy			sc->msix_regs_res = NULL;
485167514Skmacy		} else {
486167514Skmacy			sc->flags |= USING_MSIX;
487170081Skmacy			sc->cxgb_intr = t3_intr_msix;
488167514Skmacy		}
489167514Skmacy	}
490167514Skmacy
491169978Skmacy	if ((msi_allowed >= 1) && (sc->msi_count == 0)) {
492169978Skmacy		sc->msi_count = 1;
493169978Skmacy		if (pci_alloc_msi(dev, &sc->msi_count)) {
494167760Skmacy			device_printf(dev, "alloc msi failed - will try INTx\n");
495169978Skmacy			sc->msi_count = 0;
496167514Skmacy			pci_release_msi(dev);
497167514Skmacy		} else {
498167514Skmacy			sc->flags |= USING_MSI;
499167514Skmacy			sc->irq_rid = 1;
500170081Skmacy			sc->cxgb_intr = t3_intr_msi;
501167514Skmacy		}
502167514Skmacy	}
503167514Skmacy#endif
504169978Skmacy	if (sc->msi_count == 0) {
505167760Skmacy		device_printf(dev, "using line interrupts\n");
506167514Skmacy		sc->irq_rid = 0;
507170081Skmacy		sc->cxgb_intr = t3b_intr;
508167514Skmacy	}
509167514Skmacy
510167514Skmacy
511167514Skmacy	/* Create a private taskqueue thread for handling driver events */
512167514Skmacy#ifdef TASKQUEUE_CURRENT
513167514Skmacy	sc->tq = taskqueue_create("cxgb_taskq", M_NOWAIT,
514167514Skmacy	    taskqueue_thread_enqueue, &sc->tq);
515167514Skmacy#else
516167514Skmacy	sc->tq = taskqueue_create_fast("cxgb_taskq", M_NOWAIT,
517167514Skmacy	    taskqueue_thread_enqueue, &sc->tq);
518167514Skmacy#endif
519167514Skmacy	if (sc->tq == NULL) {
520167514Skmacy		device_printf(dev, "failed to allocate controller task queue\n");
521167514Skmacy		goto out;
522167514Skmacy	}
523171804Skmacy
524167514Skmacy	taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq",
525167514Skmacy	    device_get_nameunit(dev));
526167514Skmacy	TASK_INIT(&sc->ext_intr_task, 0, cxgb_ext_intr_handler, sc);
527170869Skmacy	TASK_INIT(&sc->tick_task, 0, cxgb_tick_handler, sc);
528167514Skmacy
529167514Skmacy
530167514Skmacy	/* Create a periodic callout for checking adapter status */
531170869Skmacy	callout_init(&sc->cxgb_tick_ch, TRUE);
532167514Skmacy
533167514Skmacy	if (t3_check_fw_version(sc) != 0) {
534167514Skmacy		/*
535167514Skmacy		 * Warn user that a firmware update will be attempted in init.
536167514Skmacy		 */
537169978Skmacy		device_printf(dev, "firmware needs to be updated to version %d.%d.%d\n",
538169978Skmacy		    FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
539167514Skmacy		sc->flags &= ~FW_UPTODATE;
540167514Skmacy	} else {
541167514Skmacy		sc->flags |= FW_UPTODATE;
542167514Skmacy	}
543171471Skmacy
544171471Skmacy	if (t3_check_tpsram_version(sc) != 0) {
545171471Skmacy		/*
546171471Skmacy		 * Warn user that a firmware update will be attempted in init.
547171471Skmacy		 */
548171471Skmacy		device_printf(dev, "SRAM needs to be updated to version %c-%d.%d.%d\n",
549171471Skmacy		    t3rev2char(sc), TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
550171471Skmacy		sc->flags &= ~TPS_UPTODATE;
551171471Skmacy	} else {
552171471Skmacy		sc->flags |= TPS_UPTODATE;
553171471Skmacy	}
554167514Skmacy
555169978Skmacy	if ((sc->flags & USING_MSIX) && !singleq)
556167760Skmacy		port_qsets = min((SGE_QSETS/(sc)->params.nports), mp_ncpus);
557167760Skmacy
558167514Skmacy	/*
559167514Skmacy	 * Create a child device for each MAC.  The ethernet attachment
560167514Skmacy	 * will be done in these children.
561167760Skmacy	 */
562167760Skmacy	for (i = 0; i < (sc)->params.nports; i++) {
563171978Skmacy		struct port_info *pi;
564171978Skmacy
565167514Skmacy		if ((child = device_add_child(dev, "cxgb", -1)) == NULL) {
566167514Skmacy			device_printf(dev, "failed to add child port\n");
567167514Skmacy			error = EINVAL;
568167514Skmacy			goto out;
569167514Skmacy		}
570171978Skmacy		pi = &sc->port[i];
571171978Skmacy		pi->adapter = sc;
572171978Skmacy		pi->nqsets = port_qsets;
573171978Skmacy		pi->first_qset = i*port_qsets;
574171978Skmacy		pi->port_id = i;
575171978Skmacy		pi->tx_chan = i >= ai->nports0;
576171978Skmacy		pi->txpkt_intf = pi->tx_chan ? 2 * (i - ai->nports0) + 1 : 2 * i;
577171978Skmacy		sc->rxpkt_map[pi->txpkt_intf] = i;
578171471Skmacy		sc->portdev[i] = child;
579171978Skmacy		device_set_softc(child, pi);
580167514Skmacy	}
581167514Skmacy	if ((error = bus_generic_attach(dev)) != 0)
582167514Skmacy		goto out;
583167514Skmacy
584169978Skmacy	/*
585169978Skmacy	 * XXX need to poll for link status
586169978Skmacy	 */
587167514Skmacy	sc->params.stats_update_period = 1;
588167514Skmacy
589167514Skmacy	/* initialize sge private state */
590170654Skmacy	t3_sge_init_adapter(sc);
591167514Skmacy
592167514Skmacy	t3_led_ready(sc);
593169978Skmacy
594169978Skmacy	cxgb_offload_init();
595169978Skmacy	if (is_offload(sc)) {
596169978Skmacy		setbit(&sc->registered_device_map, OFFLOAD_DEVMAP_BIT);
597169978Skmacy		cxgb_adapter_ofld(sc);
598169978Skmacy        }
599167514Skmacy	error = t3_get_fw_version(sc, &vers);
600167514Skmacy	if (error)
601167514Skmacy		goto out;
602167514Skmacy
603169978Skmacy	snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d.%d",
604169978Skmacy	    G_FW_VERSION_MAJOR(vers), G_FW_VERSION_MINOR(vers),
605169978Skmacy	    G_FW_VERSION_MICRO(vers));
606169978Skmacy
607167514Skmacy	t3_add_sysctls(sc);
608167514Skmacyout:
609167514Skmacy	if (error)
610167514Skmacy		cxgb_free(sc);
611167514Skmacy
612167514Skmacy	return (error);
613167514Skmacy}
614167514Skmacy
615167514Skmacystatic int
616167514Skmacycxgb_controller_detach(device_t dev)
617167514Skmacy{
618167514Skmacy	struct adapter *sc;
619167514Skmacy
620167514Skmacy	sc = device_get_softc(dev);
621167514Skmacy
622167514Skmacy	cxgb_free(sc);
623167514Skmacy
624167514Skmacy	return (0);
625167514Skmacy}
626167514Skmacy
627167514Skmacystatic void
628167514Skmacycxgb_free(struct adapter *sc)
629167514Skmacy{
630167514Skmacy	int i;
631167514Skmacy
632170869Skmacy	ADAPTER_LOCK(sc);
633170869Skmacy	/*
634170869Skmacy	 * drops the lock
635170869Skmacy	 */
636170869Skmacy	cxgb_down_locked(sc);
637169978Skmacy
638169978Skmacy#ifdef MSI_SUPPORTED
639169978Skmacy	if (sc->flags & (USING_MSI | USING_MSIX)) {
640169978Skmacy		device_printf(sc->dev, "releasing msi message(s)\n");
641169978Skmacy		pci_release_msi(sc->dev);
642169978Skmacy	} else {
643169978Skmacy		device_printf(sc->dev, "no msi message to release\n");
644169978Skmacy	}
645169978Skmacy#endif
646169978Skmacy	if (sc->msix_regs_res != NULL) {
647169978Skmacy		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid,
648169978Skmacy		    sc->msix_regs_res);
649169978Skmacy	}
650169978Skmacy
651167514Skmacy	if (sc->tq != NULL) {
652167514Skmacy		taskqueue_drain(sc->tq, &sc->ext_intr_task);
653170869Skmacy		taskqueue_drain(sc->tq, &sc->tick_task);
654171978Skmacy	}
655171978Skmacy	t3_sge_deinit_sw(sc);
656171978Skmacy	/*
657171978Skmacy	 * Wait for last callout
658171978Skmacy	 */
659171978Skmacy
660171978Skmacy	tsleep(&sc, 0, "cxgb unload", 3*hz);
661170869Skmacy
662167760Skmacy	for (i = 0; i < (sc)->params.nports; ++i) {
663167760Skmacy		if (sc->portdev[i] != NULL)
664167760Skmacy			device_delete_child(sc->dev, sc->portdev[i]);
665167760Skmacy	}
666167760Skmacy
667167514Skmacy	bus_generic_detach(sc->dev);
668171978Skmacy	if (sc->tq != NULL)
669171978Skmacy		taskqueue_free(sc->tq);
670170654Skmacy#ifdef notyet
671169978Skmacy	if (is_offload(sc)) {
672169978Skmacy		cxgb_adapter_unofld(sc);
673169978Skmacy		if (isset(&sc->open_device_map,	OFFLOAD_DEVMAP_BIT))
674169978Skmacy			offload_close(&sc->tdev);
675169978Skmacy	}
676171804Skmacy#endif
677171804Skmacy
678167514Skmacy	t3_free_sge_resources(sc);
679171471Skmacy	free(sc->filters, M_DEVBUF);
680167514Skmacy	t3_sge_free(sc);
681170869Skmacy
682170869Skmacy	cxgb_offload_exit();
683170869Skmacy
684167514Skmacy	if (sc->regs_res != NULL)
685167514Skmacy		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->regs_rid,
686167514Skmacy		    sc->regs_res);
687167514Skmacy
688170869Skmacy	MTX_DESTROY(&sc->mdio_lock);
689170869Skmacy	MTX_DESTROY(&sc->sge.reg_lock);
690170869Skmacy	MTX_DESTROY(&sc->elmer_lock);
691170869Skmacy	ADAPTER_LOCK_DEINIT(sc);
692167514Skmacy
693167514Skmacy	return;
694167514Skmacy}
695167514Skmacy
696167514Skmacy/**
697167514Skmacy *	setup_sge_qsets - configure SGE Tx/Rx/response queues
698167514Skmacy *	@sc: the controller softc
699167514Skmacy *
700167514Skmacy *	Determines how many sets of SGE queues to use and initializes them.
701167514Skmacy *	We support multiple queue sets per port if we have MSI-X, otherwise
702167514Skmacy *	just one queue set per port.
703167514Skmacy */
704167514Skmacystatic int
705167514Skmacysetup_sge_qsets(adapter_t *sc)
706167514Skmacy{
707172096Skmacy	int i, j, err, irq_idx = 0, qset_idx = 0;
708169978Skmacy	u_int ntxq = SGE_TXQ_PER_SET;
709167514Skmacy
710167514Skmacy	if ((err = t3_sge_alloc(sc)) != 0) {
711167760Skmacy		device_printf(sc->dev, "t3_sge_alloc returned %d\n", err);
712167514Skmacy		return (err);
713167514Skmacy	}
714167514Skmacy
715167514Skmacy	if (sc->params.rev > 0 && !(sc->flags & USING_MSI))
716167514Skmacy		irq_idx = -1;
717167514Skmacy
718172096Skmacy	for (i = 0; i < (sc)->params.nports; i++) {
719167514Skmacy		struct port_info *pi = &sc->port[i];
720167514Skmacy
721171978Skmacy		for (j = 0; j < pi->nqsets; j++, qset_idx++) {
722167760Skmacy			err = t3_sge_alloc_qset(sc, qset_idx, (sc)->params.nports,
723167514Skmacy			    (sc->flags & USING_MSIX) ? qset_idx + 1 : irq_idx,
724167514Skmacy			    &sc->params.sge.qset[qset_idx], ntxq, pi);
725167514Skmacy			if (err) {
726167514Skmacy				t3_free_sge_resources(sc);
727171978Skmacy				device_printf(sc->dev, "t3_sge_alloc_qset failed with %d\n",
728171978Skmacy				    err);
729167514Skmacy				return (err);
730167514Skmacy			}
731167514Skmacy		}
732167514Skmacy	}
733167514Skmacy
734167514Skmacy	return (0);
735167514Skmacy}
736167514Skmacy
737170654Skmacystatic void
738170654Skmacycxgb_teardown_msix(adapter_t *sc)
739170654Skmacy{
740170654Skmacy	int i, nqsets;
741170654Skmacy
742170654Skmacy	for (nqsets = i = 0; i < (sc)->params.nports; i++)
743170654Skmacy		nqsets += sc->port[i].nqsets;
744170654Skmacy
745170654Skmacy	for (i = 0; i < nqsets; i++) {
746170654Skmacy		if (sc->msix_intr_tag[i] != NULL) {
747170654Skmacy			bus_teardown_intr(sc->dev, sc->msix_irq_res[i],
748170654Skmacy			    sc->msix_intr_tag[i]);
749170654Skmacy			sc->msix_intr_tag[i] = NULL;
750170654Skmacy		}
751170654Skmacy		if (sc->msix_irq_res[i] != NULL) {
752170654Skmacy			bus_release_resource(sc->dev, SYS_RES_IRQ,
753170654Skmacy			    sc->msix_irq_rid[i], sc->msix_irq_res[i]);
754170654Skmacy			sc->msix_irq_res[i] = NULL;
755170654Skmacy		}
756170654Skmacy	}
757170654Skmacy}
758170654Skmacy
759167514Skmacystatic int
760167514Skmacycxgb_setup_msix(adapter_t *sc, int msix_count)
761167514Skmacy{
762167514Skmacy	int i, j, k, nqsets, rid;
763167514Skmacy
764167514Skmacy	/* The first message indicates link changes and error conditions */
765167514Skmacy	sc->irq_rid = 1;
766167514Skmacy	if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
767167514Skmacy	   &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
768167514Skmacy		device_printf(sc->dev, "Cannot allocate msix interrupt\n");
769167514Skmacy		return (EINVAL);
770167514Skmacy	}
771167760Skmacy
772167514Skmacy	if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET,
773167514Skmacy#ifdef INTR_FILTERS
774171978Skmacy		NULL,
775167514Skmacy#endif
776167514Skmacy		cxgb_async_intr, sc, &sc->intr_tag)) {
777167514Skmacy		device_printf(sc->dev, "Cannot set up interrupt\n");
778167514Skmacy		return (EINVAL);
779167514Skmacy	}
780170654Skmacy	for (i = k = 0; i < (sc)->params.nports; i++) {
781167514Skmacy		nqsets = sc->port[i].nqsets;
782170654Skmacy		for (j = 0; j < nqsets; j++, k++) {
783167514Skmacy			struct sge_qset *qs = &sc->sge.qs[k];
784171804Skmacy
785167514Skmacy			rid = k + 2;
786167514Skmacy			if (cxgb_debug)
787167514Skmacy				printf("rid=%d ", rid);
788167514Skmacy			if ((sc->msix_irq_res[k] = bus_alloc_resource_any(
789167514Skmacy			    sc->dev, SYS_RES_IRQ, &rid,
790167514Skmacy			    RF_SHAREABLE | RF_ACTIVE)) == NULL) {
791167514Skmacy				device_printf(sc->dev, "Cannot allocate "
792167514Skmacy				    "interrupt for message %d\n", rid);
793167514Skmacy				return (EINVAL);
794167514Skmacy			}
795167514Skmacy			sc->msix_irq_rid[k] = rid;
796171978Skmacy			printf("setting up interrupt for port=%d\n",
797171978Skmacy			    qs->port->port_id);
798170654Skmacy			if (bus_setup_intr(sc->dev, sc->msix_irq_res[k],
799167514Skmacy			    INTR_MPSAFE|INTR_TYPE_NET,
800167514Skmacy#ifdef INTR_FILTERS
801171978Skmacy				NULL,
802167514Skmacy#endif
803167514Skmacy				t3_intr_msix, qs, &sc->msix_intr_tag[k])) {
804167514Skmacy				device_printf(sc->dev, "Cannot set up "
805167514Skmacy				    "interrupt for message %d\n", rid);
806167514Skmacy				return (EINVAL);
807167514Skmacy			}
808167514Skmacy		}
809167514Skmacy	}
810167760Skmacy
811167760Skmacy
812167514Skmacy	return (0);
813167514Skmacy}
814167514Skmacy
815167514Skmacystatic int
816167514Skmacycxgb_port_probe(device_t dev)
817167514Skmacy{
818167514Skmacy	struct port_info *p;
819167514Skmacy	char buf[80];
820167514Skmacy
821167514Skmacy	p = device_get_softc(dev);
822167514Skmacy
823171803Skmacy	snprintf(buf, sizeof(buf), "Port %d %s", p->port_id, p->port_type->desc);
824167514Skmacy	device_set_desc_copy(dev, buf);
825167514Skmacy	return (0);
826167514Skmacy}
827167514Skmacy
828167514Skmacy
829167514Skmacystatic int
830167514Skmacycxgb_makedev(struct port_info *pi)
831167514Skmacy{
832167514Skmacy
833170654Skmacy	pi->port_cdev = make_dev(&cxgb_cdevsw, pi->ifp->if_dunit,
834170654Skmacy	    UID_ROOT, GID_WHEEL, 0600, if_name(pi->ifp));
835167514Skmacy
836167514Skmacy	if (pi->port_cdev == NULL)
837167514Skmacy		return (ENOMEM);
838167514Skmacy
839167514Skmacy	pi->port_cdev->si_drv1 = (void *)pi;
840167514Skmacy
841167514Skmacy	return (0);
842167514Skmacy}
843167514Skmacy
844167514Skmacy
845167514Skmacy#ifdef TSO_SUPPORTED
846167514Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU)
847167514Skmacy/* Don't enable TSO6 yet */
848167514Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO4 | IFCAP_JUMBO_MTU)
849167514Skmacy#else
850167514Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU)
851167514Skmacy/* Don't enable TSO6 yet */
852167514Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM |  IFCAP_JUMBO_MTU)
853167514Skmacy#define IFCAP_TSO4 0x0
854171868Skmacy#define IFCAP_TSO6 0x0
855167514Skmacy#define CSUM_TSO   0x0
856167514Skmacy#endif
857167514Skmacy
858167514Skmacy
859167514Skmacystatic int
860167514Skmacycxgb_port_attach(device_t dev)
861167514Skmacy{
862167514Skmacy	struct port_info *p;
863167514Skmacy	struct ifnet *ifp;
864170654Skmacy	int err, media_flags;
865167514Skmacy
866167514Skmacy	p = device_get_softc(dev);
867167514Skmacy
868170869Skmacy	snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d",
869171803Skmacy	    device_get_unit(device_get_parent(dev)), p->port_id);
870170869Skmacy	PORT_LOCK_INIT(p, p->lockbuf);
871167514Skmacy
872167514Skmacy	/* Allocate an ifnet object and set it up */
873167514Skmacy	ifp = p->ifp = if_alloc(IFT_ETHER);
874167514Skmacy	if (ifp == NULL) {
875167514Skmacy		device_printf(dev, "Cannot allocate ifnet\n");
876167514Skmacy		return (ENOMEM);
877167514Skmacy	}
878167514Skmacy
879167514Skmacy	/*
880167514Skmacy	 * Note that there is currently no watchdog timer.
881167514Skmacy	 */
882167514Skmacy	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
883167514Skmacy	ifp->if_init = cxgb_init;
884167514Skmacy	ifp->if_softc = p;
885167514Skmacy	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
886167514Skmacy	ifp->if_ioctl = cxgb_ioctl;
887167514Skmacy	ifp->if_start = cxgb_start;
888167514Skmacy	ifp->if_timer = 0;	/* Disable ifnet watchdog */
889167514Skmacy	ifp->if_watchdog = NULL;
890167514Skmacy
891167514Skmacy	ifp->if_snd.ifq_drv_maxlen = TX_ETH_Q_SIZE;
892167514Skmacy	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
893167514Skmacy	IFQ_SET_READY(&ifp->if_snd);
894167514Skmacy
895167514Skmacy	ifp->if_hwassist = ifp->if_capabilities = ifp->if_capenable = 0;
896167514Skmacy	ifp->if_capabilities |= CXGB_CAP;
897167514Skmacy	ifp->if_capenable |= CXGB_CAP_ENABLE;
898167514Skmacy	ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO);
899171471Skmacy	/*
900171471Skmacy	 * disable TSO on 4-port - it isn't supported by the firmware yet
901171471Skmacy	 */
902171471Skmacy	if (p->adapter->params.nports > 2) {
903171471Skmacy		ifp->if_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6);
904171471Skmacy		ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TSO6);
905171471Skmacy		ifp->if_hwassist &= ~CSUM_TSO;
906171471Skmacy	}
907171471Skmacy
908167514Skmacy	ether_ifattach(ifp, p->hw_addr);
909171471Skmacy	/*
910171471Skmacy	 * Only default to jumbo frames on 10GigE
911171471Skmacy	 */
912171471Skmacy	if (p->adapter->params.nports <= 2)
913171471Skmacy		ifp->if_mtu = 9000;
914167514Skmacy	if ((err = cxgb_makedev(p)) != 0) {
915167514Skmacy		printf("makedev failed %d\n", err);
916167514Skmacy		return (err);
917167514Skmacy	}
918167514Skmacy	ifmedia_init(&p->media, IFM_IMASK, cxgb_media_change,
919167514Skmacy	    cxgb_media_status);
920170654Skmacy
921170654Skmacy	if (!strcmp(p->port_type->desc, "10GBASE-CX4")) {
922170654Skmacy		media_flags = IFM_ETHER | IFM_10G_CX4 | IFM_FDX;
923170654Skmacy	} else if (!strcmp(p->port_type->desc, "10GBASE-SR")) {
924170654Skmacy		media_flags = IFM_ETHER | IFM_10G_SR | IFM_FDX;
925170654Skmacy	} else if (!strcmp(p->port_type->desc, "10GBASE-XR")) {
926170654Skmacy		media_flags = IFM_ETHER | IFM_10G_LR | IFM_FDX;
927170654Skmacy	} else if (!strcmp(p->port_type->desc, "10/100/1000BASE-T")) {
928170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_10_T, 0, NULL);
929170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_10_T | IFM_FDX,
930170654Skmacy			    0, NULL);
931170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX,
932170654Skmacy			    0, NULL);
933170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX | IFM_FDX,
934170654Skmacy			    0, NULL);
935170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_1000_T | IFM_FDX,
936170654Skmacy			    0, NULL);
937170654Skmacy		media_flags = 0;
938170654Skmacy	} else {
939167514Skmacy	        printf("unsupported media type %s\n", p->port_type->desc);
940167514Skmacy		return (ENXIO);
941167514Skmacy	}
942170654Skmacy	if (media_flags) {
943170654Skmacy		ifmedia_add(&p->media, media_flags, 0, NULL);
944170654Skmacy		ifmedia_set(&p->media, media_flags);
945170654Skmacy	} else {
946170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL);
947170654Skmacy		ifmedia_set(&p->media, IFM_ETHER | IFM_AUTO);
948170654Skmacy	}
949167514Skmacy
950170654Skmacy
951171803Skmacy	snprintf(p->taskqbuf, TASKQ_NAME_LEN, "cxgb_port_taskq%d", p->port_id);
952167514Skmacy#ifdef TASKQUEUE_CURRENT
953167514Skmacy	/* Create a port for handling TX without starvation */
954170869Skmacy	p->tq = taskqueue_create(p->taskqbuf, M_NOWAIT,
955167514Skmacy	    taskqueue_thread_enqueue, &p->tq);
956167514Skmacy#else
957167514Skmacy	/* Create a port for handling TX without starvation */
958171868Skmacy	p->tq = taskqueue_create_fast(p->taskqbuf, M_NOWAIT,
959167514Skmacy	    taskqueue_thread_enqueue, &p->tq);
960167514Skmacy#endif
961170654Skmacy
962167514Skmacy	if (p->tq == NULL) {
963167514Skmacy		device_printf(dev, "failed to allocate port task queue\n");
964167514Skmacy		return (ENOMEM);
965167514Skmacy	}
966167514Skmacy	taskqueue_start_threads(&p->tq, 1, PI_NET, "%s taskq",
967167514Skmacy	    device_get_nameunit(dev));
968171804Skmacy
969167514Skmacy	TASK_INIT(&p->start_task, 0, cxgb_start_proc, ifp);
970167514Skmacy
971170654Skmacy	t3_sge_init_port(p);
972170654Skmacy
973167514Skmacy	return (0);
974167514Skmacy}
975167514Skmacy
976167514Skmacystatic int
977167514Skmacycxgb_port_detach(device_t dev)
978167514Skmacy{
979167514Skmacy	struct port_info *p;
980167514Skmacy
981167514Skmacy	p = device_get_softc(dev);
982169978Skmacy
983169978Skmacy	PORT_LOCK(p);
984170654Skmacy	if (p->ifp->if_drv_flags & IFF_DRV_RUNNING)
985170654Skmacy		cxgb_stop_locked(p);
986169978Skmacy	PORT_UNLOCK(p);
987169978Skmacy
988167514Skmacy	if (p->tq != NULL) {
989167514Skmacy		taskqueue_drain(p->tq, &p->start_task);
990167514Skmacy		taskqueue_free(p->tq);
991167514Skmacy		p->tq = NULL;
992167514Skmacy	}
993170869Skmacy
994171978Skmacy	ether_ifdetach(p->ifp);
995171978Skmacy	/*
996171978Skmacy	 * the lock may be acquired in ifdetach
997171978Skmacy	 */
998170869Skmacy	PORT_LOCK_DEINIT(p);
999167514Skmacy	if_free(p->ifp);
1000167514Skmacy
1001170654Skmacy	if (p->port_cdev != NULL)
1002170654Skmacy		destroy_dev(p->port_cdev);
1003170654Skmacy
1004167514Skmacy	return (0);
1005167514Skmacy}
1006167514Skmacy
1007167514Skmacyvoid
1008167514Skmacyt3_fatal_err(struct adapter *sc)
1009167514Skmacy{
1010167514Skmacy	u_int fw_status[4];
1011172096Skmacy
1012172096Skmacy	if (sc->flags & FULL_INIT_DONE) {
1013172096Skmacy		t3_sge_stop(sc);
1014172096Skmacy		t3_write_reg(sc, A_XGM_TX_CTRL, 0);
1015172096Skmacy		t3_write_reg(sc, A_XGM_RX_CTRL, 0);
1016172096Skmacy		t3_write_reg(sc, XGM_REG(A_XGM_TX_CTRL, 1), 0);
1017172096Skmacy		t3_write_reg(sc, XGM_REG(A_XGM_RX_CTRL, 1), 0);
1018172096Skmacy		t3_intr_disable(sc);
1019172096Skmacy	}
1020167514Skmacy	device_printf(sc->dev,"encountered fatal error, operation suspended\n");
1021167514Skmacy	if (!t3_cim_ctl_blk_read(sc, 0xa0, 4, fw_status))
1022167514Skmacy		device_printf(sc->dev, "FW_ status: 0x%x, 0x%x, 0x%x, 0x%x\n",
1023167514Skmacy		    fw_status[0], fw_status[1], fw_status[2], fw_status[3]);
1024167514Skmacy}
1025167514Skmacy
1026167514Skmacyint
1027167514Skmacyt3_os_find_pci_capability(adapter_t *sc, int cap)
1028167514Skmacy{
1029167514Skmacy	device_t dev;
1030167514Skmacy	struct pci_devinfo *dinfo;
1031167514Skmacy	pcicfgregs *cfg;
1032167514Skmacy	uint32_t status;
1033167514Skmacy	uint8_t ptr;
1034167514Skmacy
1035167514Skmacy	dev = sc->dev;
1036167514Skmacy	dinfo = device_get_ivars(dev);
1037167514Skmacy	cfg = &dinfo->cfg;
1038167514Skmacy
1039167514Skmacy	status = pci_read_config(dev, PCIR_STATUS, 2);
1040167514Skmacy	if (!(status & PCIM_STATUS_CAPPRESENT))
1041167514Skmacy		return (0);
1042167514Skmacy
1043167514Skmacy	switch (cfg->hdrtype & PCIM_HDRTYPE) {
1044167514Skmacy	case 0:
1045167514Skmacy	case 1:
1046167514Skmacy		ptr = PCIR_CAP_PTR;
1047167514Skmacy		break;
1048167514Skmacy	case 2:
1049167514Skmacy		ptr = PCIR_CAP_PTR_2;
1050167514Skmacy		break;
1051167514Skmacy	default:
1052167514Skmacy		return (0);
1053167514Skmacy		break;
1054167514Skmacy	}
1055167514Skmacy	ptr = pci_read_config(dev, ptr, 1);
1056167514Skmacy
1057167514Skmacy	while (ptr != 0) {
1058167514Skmacy		if (pci_read_config(dev, ptr + PCICAP_ID, 1) == cap)
1059167514Skmacy			return (ptr);
1060167514Skmacy		ptr = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1);
1061167514Skmacy	}
1062167514Skmacy
1063167514Skmacy	return (0);
1064167514Skmacy}
1065167514Skmacy
1066167514Skmacyint
1067167514Skmacyt3_os_pci_save_state(struct adapter *sc)
1068167514Skmacy{
1069167514Skmacy	device_t dev;
1070167514Skmacy	struct pci_devinfo *dinfo;
1071167514Skmacy
1072167514Skmacy	dev = sc->dev;
1073167514Skmacy	dinfo = device_get_ivars(dev);
1074167514Skmacy
1075167514Skmacy	pci_cfg_save(dev, dinfo, 0);
1076167514Skmacy	return (0);
1077167514Skmacy}
1078167514Skmacy
1079167514Skmacyint
1080167514Skmacyt3_os_pci_restore_state(struct adapter *sc)
1081167514Skmacy{
1082167514Skmacy	device_t dev;
1083167514Skmacy	struct pci_devinfo *dinfo;
1084167514Skmacy
1085167514Skmacy	dev = sc->dev;
1086167514Skmacy	dinfo = device_get_ivars(dev);
1087167514Skmacy
1088167514Skmacy	pci_cfg_restore(dev, dinfo);
1089167514Skmacy	return (0);
1090167514Skmacy}
1091167514Skmacy
1092167514Skmacy/**
1093167514Skmacy *	t3_os_link_changed - handle link status changes
1094167514Skmacy *	@adapter: the adapter associated with the link change
1095167514Skmacy *	@port_id: the port index whose limk status has changed
1096167514Skmacy *	@link_stat: the new status of the link
1097167514Skmacy *	@speed: the new speed setting
1098167514Skmacy *	@duplex: the new duplex setting
1099167514Skmacy *	@fc: the new flow-control setting
1100167514Skmacy *
1101167514Skmacy *	This is the OS-dependent handler for link status changes.  The OS
1102167514Skmacy *	neutral handler takes care of most of the processing for these events,
1103167514Skmacy *	then calls this handler for any OS-specific processing.
1104167514Skmacy */
1105167514Skmacyvoid
1106167514Skmacyt3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed,
1107167514Skmacy     int duplex, int fc)
1108167514Skmacy{
1109167514Skmacy	struct port_info *pi = &adapter->port[port_id];
1110169978Skmacy	struct cmac *mac = &adapter->port[port_id].mac;
1111167514Skmacy
1112167514Skmacy	if ((pi->ifp->if_flags & IFF_UP) == 0)
1113167514Skmacy		return;
1114169978Skmacy
1115169978Skmacy	if (link_status) {
1116169978Skmacy		t3_mac_enable(mac, MAC_DIRECTION_RX);
1117167514Skmacy		if_link_state_change(pi->ifp, LINK_STATE_UP);
1118169978Skmacy	} else {
1119167514Skmacy		if_link_state_change(pi->ifp, LINK_STATE_DOWN);
1120169978Skmacy		pi->phy.ops->power_down(&pi->phy, 1);
1121169978Skmacy		t3_mac_disable(mac, MAC_DIRECTION_RX);
1122169978Skmacy		t3_link_start(&pi->phy, mac, &pi->link_config);
1123169978Skmacy	}
1124167514Skmacy}
1125167514Skmacy
1126167514Skmacy/*
1127167514Skmacy * Interrupt-context handler for external (PHY) interrupts.
1128167514Skmacy */
1129167514Skmacyvoid
1130167514Skmacyt3_os_ext_intr_handler(adapter_t *sc)
1131167514Skmacy{
1132167514Skmacy	if (cxgb_debug)
1133167514Skmacy		printf("t3_os_ext_intr_handler\n");
1134167514Skmacy	/*
1135167514Skmacy	 * Schedule a task to handle external interrupts as they may be slow
1136167514Skmacy	 * and we use a mutex to protect MDIO registers.  We disable PHY
1137167514Skmacy	 * interrupts in the meantime and let the task reenable them when
1138167514Skmacy	 * it's done.
1139167514Skmacy	 */
1140169978Skmacy	ADAPTER_LOCK(sc);
1141167514Skmacy	if (sc->slow_intr_mask) {
1142167514Skmacy		sc->slow_intr_mask &= ~F_T3DBG;
1143167514Skmacy		t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
1144167514Skmacy		taskqueue_enqueue(sc->tq, &sc->ext_intr_task);
1145167514Skmacy	}
1146169978Skmacy	ADAPTER_UNLOCK(sc);
1147167514Skmacy}
1148167514Skmacy
1149167514Skmacyvoid
1150167514Skmacyt3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[])
1151167514Skmacy{
1152167514Skmacy
1153167514Skmacy	/*
1154167514Skmacy	 * The ifnet might not be allocated before this gets called,
1155167514Skmacy	 * as this is called early on in attach by t3_prep_adapter
1156167514Skmacy	 * save the address off in the port structure
1157167514Skmacy	 */
1158167514Skmacy	if (cxgb_debug)
1159167514Skmacy		printf("set_hw_addr on idx %d addr %6D\n", port_idx, hw_addr, ":");
1160167514Skmacy	bcopy(hw_addr, adapter->port[port_idx].hw_addr, ETHER_ADDR_LEN);
1161167514Skmacy}
1162167514Skmacy
1163167514Skmacy/**
1164167514Skmacy *	link_start - enable a port
1165167514Skmacy *	@p: the port to enable
1166167514Skmacy *
1167167514Skmacy *	Performs the MAC and PHY actions needed to enable a port.
1168167514Skmacy */
1169167514Skmacystatic void
1170167514Skmacycxgb_link_start(struct port_info *p)
1171167514Skmacy{
1172167514Skmacy	struct ifnet *ifp;
1173167514Skmacy	struct t3_rx_mode rm;
1174167514Skmacy	struct cmac *mac = &p->mac;
1175167514Skmacy
1176167514Skmacy	ifp = p->ifp;
1177167514Skmacy
1178167514Skmacy	t3_init_rx_mode(&rm, p);
1179172096Skmacy	if (!mac->multiport)
1180171978Skmacy		t3_mac_reset(mac);
1181170654Skmacy	t3_mac_set_mtu(mac, ifp->if_mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN);
1182167514Skmacy	t3_mac_set_address(mac, 0, p->hw_addr);
1183167514Skmacy	t3_mac_set_rx_mode(mac, &rm);
1184167514Skmacy	t3_link_start(&p->phy, mac, &p->link_config);
1185167514Skmacy	t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
1186167514Skmacy}
1187167514Skmacy
1188167514Skmacy/**
1189167514Skmacy *	setup_rss - configure Receive Side Steering (per-queue connection demux)
1190167514Skmacy *	@adap: the adapter
1191167514Skmacy *
1192167514Skmacy *	Sets up RSS to distribute packets to multiple receive queues.  We
1193167514Skmacy *	configure the RSS CPU lookup table to distribute to the number of HW
1194167514Skmacy *	receive queues, and the response queue lookup table to narrow that
1195167514Skmacy *	down to the response queues actually configured for each port.
1196167514Skmacy *	We always configure the RSS mapping for two ports since the mapping
1197167514Skmacy *	table has plenty of entries.
1198167514Skmacy */
1199167514Skmacystatic void
1200167514Skmacysetup_rss(adapter_t *adap)
1201167514Skmacy{
1202167514Skmacy	int i;
1203171471Skmacy	u_int nq[2];
1204167514Skmacy	uint8_t cpus[SGE_QSETS + 1];
1205167514Skmacy	uint16_t rspq_map[RSS_TABLE_SIZE];
1206171471Skmacy
1207167514Skmacy	for (i = 0; i < SGE_QSETS; ++i)
1208167514Skmacy		cpus[i] = i;
1209167514Skmacy	cpus[SGE_QSETS] = 0xff;
1210167514Skmacy
1211171978Skmacy	nq[0] = nq[1] = 0;
1212171978Skmacy	for_each_port(adap, i) {
1213171978Skmacy		const struct port_info *pi = adap2pinfo(adap, i);
1214171978Skmacy
1215171978Skmacy		nq[pi->tx_chan] += pi->nqsets;
1216171978Skmacy	}
1217172096Skmacy	nq[0] = max(nq[0], 1U);
1218172096Skmacy	nq[1] = max(nq[1], 1U);
1219167514Skmacy	for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
1220172096Skmacy		rspq_map[i] = i % nq[0];
1221172096Skmacy		rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq[1]) + nq[0];
1222167514Skmacy	}
1223171471Skmacy	/* Calculate the reverse RSS map table */
1224171471Skmacy	for (i = 0; i < RSS_TABLE_SIZE; ++i)
1225171471Skmacy		if (adap->rrss_map[rspq_map[i]] == 0xff)
1226171471Skmacy			adap->rrss_map[rspq_map[i]] = i;
1227167514Skmacy
1228167514Skmacy	t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
1229171471Skmacy		      F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | F_OFDMAPEN |
1230172096Skmacy		      V_RRCPLCPUSIZE(6), cpus, rspq_map);
1231171471Skmacy
1232167514Skmacy}
1233167514Skmacy
1234169978Skmacy/*
1235169978Skmacy * Sends an mbuf to an offload queue driver
1236169978Skmacy * after dealing with any active network taps.
1237169978Skmacy */
1238169978Skmacystatic inline int
1239174626Skmacyoffload_tx(struct t3cdev *tdev, struct mbuf *m)
1240169978Skmacy{
1241169978Skmacy	int ret;
1242169978Skmacy
1243169978Skmacy	critical_enter();
1244169978Skmacy	ret = t3_offload_tx(tdev, m);
1245169978Skmacy	critical_exit();
1246170654Skmacy	return (ret);
1247169978Skmacy}
1248169978Skmacy
1249169978Skmacystatic int
1250169978Skmacywrite_smt_entry(struct adapter *adapter, int idx)
1251169978Skmacy{
1252169978Skmacy	struct port_info *pi = &adapter->port[idx];
1253169978Skmacy	struct cpl_smt_write_req *req;
1254169978Skmacy	struct mbuf *m;
1255169978Skmacy
1256169978Skmacy	if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
1257169978Skmacy		return (ENOMEM);
1258169978Skmacy
1259169978Skmacy	req = mtod(m, struct cpl_smt_write_req *);
1260169978Skmacy	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1261169978Skmacy	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
1262169978Skmacy	req->mtu_idx = NMTUS - 1;  /* should be 0 but there's a T3 bug */
1263169978Skmacy	req->iff = idx;
1264169978Skmacy	memset(req->src_mac1, 0, sizeof(req->src_mac1));
1265169978Skmacy	memcpy(req->src_mac0, pi->hw_addr, ETHER_ADDR_LEN);
1266169978Skmacy
1267169978Skmacy	m_set_priority(m, 1);
1268169978Skmacy
1269169978Skmacy	offload_tx(&adapter->tdev, m);
1270169978Skmacy
1271169978Skmacy	return (0);
1272169978Skmacy}
1273169978Skmacy
1274169978Skmacystatic int
1275169978Skmacyinit_smt(struct adapter *adapter)
1276169978Skmacy{
1277169978Skmacy	int i;
1278169978Skmacy
1279169978Skmacy	for_each_port(adapter, i)
1280169978Skmacy		write_smt_entry(adapter, i);
1281169978Skmacy	return 0;
1282169978Skmacy}
1283169978Skmacy
1284167514Skmacystatic void
1285169978Skmacyinit_port_mtus(adapter_t *adapter)
1286169978Skmacy{
1287169978Skmacy	unsigned int mtus = adapter->port[0].ifp->if_mtu;
1288169978Skmacy
1289169978Skmacy	if (adapter->port[1].ifp)
1290169978Skmacy		mtus |= adapter->port[1].ifp->if_mtu << 16;
1291169978Skmacy	t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
1292169978Skmacy}
1293169978Skmacy
1294169978Skmacystatic void
1295167514Skmacysend_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
1296167514Skmacy			      int hi, int port)
1297167514Skmacy{
1298167514Skmacy	struct mbuf *m;
1299167514Skmacy	struct mngt_pktsched_wr *req;
1300167514Skmacy
1301171471Skmacy	m = m_gethdr(M_DONTWAIT, MT_DATA);
1302167848Skmacy	if (m) {
1303169978Skmacy		req = mtod(m, struct mngt_pktsched_wr *);
1304167848Skmacy		req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
1305167848Skmacy		req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
1306167848Skmacy		req->sched = sched;
1307167848Skmacy		req->idx = qidx;
1308167848Skmacy		req->min = lo;
1309167848Skmacy		req->max = hi;
1310167848Skmacy		req->binding = port;
1311167848Skmacy		m->m_len = m->m_pkthdr.len = sizeof(*req);
1312167848Skmacy		t3_mgmt_tx(adap, m);
1313167848Skmacy	}
1314167514Skmacy}
1315167514Skmacy
1316167514Skmacystatic void
1317167514Skmacybind_qsets(adapter_t *sc)
1318167514Skmacy{
1319167514Skmacy	int i, j;
1320167514Skmacy
1321167514Skmacy	for (i = 0; i < (sc)->params.nports; ++i) {
1322167514Skmacy		const struct port_info *pi = adap2pinfo(sc, i);
1323167514Skmacy
1324172096Skmacy		for (j = 0; j < pi->nqsets; ++j) {
1325167514Skmacy			send_pktsched_cmd(sc, 1, pi->first_qset + j, -1,
1326172096Skmacy					  -1, pi->tx_chan);
1327172096Skmacy
1328172096Skmacy		}
1329167514Skmacy	}
1330167514Skmacy}
1331167514Skmacy
1332171471Skmacystatic void
1333171471Skmacyupdate_tpeeprom(struct adapter *adap)
1334171471Skmacy{
1335172109Skmacy#ifdef FIRMWARE_LATEST
1336171471Skmacy	const struct firmware *tpeeprom;
1337172109Skmacy#else
1338172109Skmacy	struct firmware *tpeeprom;
1339172109Skmacy#endif
1340172109Skmacy
1341171471Skmacy	char buf[64];
1342171471Skmacy	uint32_t version;
1343171471Skmacy	unsigned int major, minor;
1344171471Skmacy	int ret, len;
1345171471Skmacy	char rev;
1346171471Skmacy
1347171471Skmacy	t3_seeprom_read(adap, TP_SRAM_OFFSET, &version);
1348171471Skmacy
1349171471Skmacy	major = G_TP_VERSION_MAJOR(version);
1350171471Skmacy	minor = G_TP_VERSION_MINOR(version);
1351171471Skmacy	if (major == TP_VERSION_MAJOR  && minor == TP_VERSION_MINOR)
1352171471Skmacy		return;
1353171471Skmacy
1354171471Skmacy	rev = t3rev2char(adap);
1355171471Skmacy
1356171471Skmacy	snprintf(buf, sizeof(buf), TPEEPROM_NAME, rev,
1357171471Skmacy		 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1358171471Skmacy
1359171471Skmacy	tpeeprom = firmware_get(buf);
1360171471Skmacy	if (tpeeprom == NULL) {
1361171471Skmacy		device_printf(adap->dev, "could not load TP EEPROM: unable to load %s\n",
1362171471Skmacy			buf);
1363171471Skmacy		return;
1364171471Skmacy	}
1365171471Skmacy
1366171471Skmacy	len = tpeeprom->datasize - 4;
1367171471Skmacy
1368171471Skmacy	ret = t3_check_tpsram(adap, tpeeprom->data, tpeeprom->datasize);
1369171471Skmacy	if (ret)
1370171471Skmacy		goto release_tpeeprom;
1371171471Skmacy
1372171471Skmacy	if (len != TP_SRAM_LEN) {
1373171471Skmacy		device_printf(adap->dev, "%s length is wrong len=%d expected=%d\n", buf, len, TP_SRAM_LEN);
1374171471Skmacy		return;
1375171471Skmacy	}
1376171471Skmacy
1377171471Skmacy	ret = set_eeprom(&adap->port[0], tpeeprom->data, tpeeprom->datasize,
1378171471Skmacy	    TP_SRAM_OFFSET);
1379171471Skmacy
1380171471Skmacy	if (!ret) {
1381171471Skmacy		device_printf(adap->dev,
1382171471Skmacy			"Protocol SRAM image updated in EEPROM to %d.%d.%d\n",
1383171471Skmacy			 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1384171471Skmacy	} else
1385171471Skmacy		device_printf(adap->dev, "Protocol SRAM image update in EEPROM failed\n");
1386171471Skmacy
1387171471Skmacyrelease_tpeeprom:
1388171471Skmacy	firmware_put(tpeeprom, FIRMWARE_UNLOAD);
1389171471Skmacy
1390171471Skmacy	return;
1391171471Skmacy}
1392171471Skmacy
1393171471Skmacystatic int
1394171471Skmacyupdate_tpsram(struct adapter *adap)
1395171471Skmacy{
1396172109Skmacy#ifdef FIRMWARE_LATEST
1397171471Skmacy	const struct firmware *tpsram;
1398172109Skmacy#else
1399172109Skmacy	struct firmware *tpsram;
1400172109Skmacy#endif
1401171471Skmacy	char buf[64];
1402171471Skmacy	int ret;
1403171471Skmacy	char rev;
1404171471Skmacy
1405171471Skmacy	rev = t3rev2char(adap);
1406171471Skmacy	if (!rev)
1407171471Skmacy		return 0;
1408171471Skmacy
1409171471Skmacy	update_tpeeprom(adap);
1410171471Skmacy
1411171471Skmacy	snprintf(buf, sizeof(buf), TPSRAM_NAME, rev,
1412171471Skmacy		 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1413171471Skmacy
1414171471Skmacy	tpsram = firmware_get(buf);
1415171471Skmacy	if (tpsram == NULL){
1416171471Skmacy		device_printf(adap->dev, "could not load TP SRAM: unable to load %s\n",
1417171471Skmacy			buf);
1418171471Skmacy		return (EINVAL);
1419171471Skmacy	} else
1420171471Skmacy		device_printf(adap->dev, "updating TP SRAM with %s\n", buf);
1421171471Skmacy
1422171471Skmacy	ret = t3_check_tpsram(adap, tpsram->data, tpsram->datasize);
1423171471Skmacy	if (ret)
1424171471Skmacy		goto release_tpsram;
1425171471Skmacy
1426171471Skmacy	ret = t3_set_proto_sram(adap, tpsram->data);
1427171471Skmacy	if (ret)
1428171471Skmacy		device_printf(adap->dev, "loading protocol SRAM failed\n");
1429171471Skmacy
1430171471Skmacyrelease_tpsram:
1431171471Skmacy	firmware_put(tpsram, FIRMWARE_UNLOAD);
1432171471Skmacy
1433171471Skmacy	return ret;
1434171471Skmacy}
1435171471Skmacy
1436169978Skmacy/**
1437169978Skmacy *	cxgb_up - enable the adapter
1438169978Skmacy *	@adap: adapter being enabled
1439169978Skmacy *
1440169978Skmacy *	Called when the first port is enabled, this function performs the
1441169978Skmacy *	actions necessary to make an adapter operational, such as completing
1442169978Skmacy *	the initialization of HW modules, and enabling interrupts.
1443169978Skmacy *
1444169978Skmacy */
1445169978Skmacystatic int
1446169978Skmacycxgb_up(struct adapter *sc)
1447169978Skmacy{
1448169978Skmacy	int err = 0;
1449169978Skmacy
1450169978Skmacy	if ((sc->flags & FULL_INIT_DONE) == 0) {
1451169978Skmacy
1452169978Skmacy		if ((sc->flags & FW_UPTODATE) == 0)
1453171471Skmacy			if ((err = upgrade_fw(sc)))
1454171471Skmacy				goto out;
1455171471Skmacy		if ((sc->flags & TPS_UPTODATE) == 0)
1456171471Skmacy			if ((err = update_tpsram(sc)))
1457171471Skmacy				goto out;
1458169978Skmacy		err = t3_init_hw(sc, 0);
1459169978Skmacy		if (err)
1460169978Skmacy			goto out;
1461169978Skmacy
1462169978Skmacy		t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
1463169978Skmacy
1464169978Skmacy		err = setup_sge_qsets(sc);
1465169978Skmacy		if (err)
1466169978Skmacy			goto out;
1467169978Skmacy
1468169978Skmacy		setup_rss(sc);
1469169978Skmacy		sc->flags |= FULL_INIT_DONE;
1470169978Skmacy	}
1471169978Skmacy
1472169978Skmacy	t3_intr_clear(sc);
1473169978Skmacy
1474169978Skmacy	/* If it's MSI or INTx, allocate a single interrupt for everything */
1475169978Skmacy	if ((sc->flags & USING_MSIX) == 0) {
1476169978Skmacy		if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
1477169978Skmacy		   &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
1478171978Skmacy			device_printf(sc->dev, "Cannot allocate interrupt rid=%d\n",
1479171978Skmacy			    sc->irq_rid);
1480169978Skmacy			err = EINVAL;
1481169978Skmacy			goto out;
1482169978Skmacy		}
1483169978Skmacy		device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res);
1484169978Skmacy
1485169978Skmacy		if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET,
1486169978Skmacy#ifdef INTR_FILTERS
1487169978Skmacy			NULL,
1488169978Skmacy#endif
1489169978Skmacy			sc->cxgb_intr, sc, &sc->intr_tag)) {
1490169978Skmacy			device_printf(sc->dev, "Cannot set up interrupt\n");
1491169978Skmacy			err = EINVAL;
1492169978Skmacy			goto irq_err;
1493169978Skmacy		}
1494169978Skmacy	} else {
1495169978Skmacy		cxgb_setup_msix(sc, sc->msi_count);
1496169978Skmacy	}
1497169978Skmacy
1498169978Skmacy	t3_sge_start(sc);
1499169978Skmacy	t3_intr_enable(sc);
1500169978Skmacy
1501172096Skmacy	if (!(sc->flags & QUEUES_BOUND)) {
1502172096Skmacy		printf("bind qsets\n");
1503169978Skmacy		bind_qsets(sc);
1504171471Skmacy		sc->flags |= QUEUES_BOUND;
1505171471Skmacy	}
1506169978Skmacyout:
1507169978Skmacy	return (err);
1508169978Skmacyirq_err:
1509169978Skmacy	CH_ERR(sc, "request_irq failed, err %d\n", err);
1510169978Skmacy	goto out;
1511169978Skmacy}
1512169978Skmacy
1513169978Skmacy
1514169978Skmacy/*
1515169978Skmacy * Release resources when all the ports and offloading have been stopped.
1516169978Skmacy */
1517167514Skmacystatic void
1518170869Skmacycxgb_down_locked(struct adapter *sc)
1519169978Skmacy{
1520169978Skmacy	int i;
1521170654Skmacy
1522169978Skmacy	t3_sge_stop(sc);
1523169978Skmacy	t3_intr_disable(sc);
1524170654Skmacy
1525169978Skmacy	if (sc->intr_tag != NULL) {
1526169978Skmacy		bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag);
1527169978Skmacy		sc->intr_tag = NULL;
1528169978Skmacy	}
1529169978Skmacy	if (sc->irq_res != NULL) {
1530169978Skmacy		device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n",
1531169978Skmacy		    sc->irq_rid, sc->irq_res);
1532169978Skmacy		bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
1533169978Skmacy		    sc->irq_res);
1534169978Skmacy		sc->irq_res = NULL;
1535169978Skmacy	}
1536170654Skmacy
1537170654Skmacy	if (sc->flags & USING_MSIX)
1538170654Skmacy		cxgb_teardown_msix(sc);
1539170869Skmacy	ADAPTER_UNLOCK(sc);
1540169978Skmacy
1541170869Skmacy	callout_drain(&sc->cxgb_tick_ch);
1542169978Skmacy	callout_drain(&sc->sge_timer_ch);
1543170869Skmacy
1544171978Skmacy	if (sc->tq != NULL) {
1545170654Skmacy		taskqueue_drain(sc->tq, &sc->slow_intr_task);
1546171978Skmacy		for (i = 0; i < sc->params.nports; i++)
1547171978Skmacy			taskqueue_drain(sc->tq, &sc->port[i].timer_reclaim_task);
1548171978Skmacy	}
1549171978Skmacy#ifdef notyet
1550171978Skmacy
1551170654Skmacy		if (sc->port[i].tq != NULL)
1552171978Skmacy#endif
1553170654Skmacy
1554169978Skmacy}
1555169978Skmacy
1556169978Skmacystatic int
1557169978Skmacyoffload_open(struct port_info *pi)
1558169978Skmacy{
1559169978Skmacy	struct adapter *adapter = pi->adapter;
1560174626Skmacy	struct t3cdev *tdev = TOEDEV(pi->ifp);
1561169978Skmacy	int adap_up = adapter->open_device_map & PORT_MASK;
1562169978Skmacy	int err = 0;
1563169978Skmacy
1564169978Skmacy	if (atomic_cmpset_int(&adapter->open_device_map,
1565169978Skmacy		(adapter->open_device_map & ~OFFLOAD_DEVMAP_BIT),
1566169978Skmacy		(adapter->open_device_map | OFFLOAD_DEVMAP_BIT)) == 0)
1567169978Skmacy		return (0);
1568169978Skmacy
1569169978Skmacy	ADAPTER_LOCK(pi->adapter);
1570169978Skmacy	if (!adap_up)
1571169978Skmacy		err = cxgb_up(adapter);
1572169978Skmacy	ADAPTER_UNLOCK(pi->adapter);
1573171471Skmacy	if (err)
1574169978Skmacy		return (err);
1575169978Skmacy
1576169978Skmacy	t3_tp_set_offload_mode(adapter, 1);
1577169978Skmacy	tdev->lldev = adapter->port[0].ifp;
1578169978Skmacy	err = cxgb_offload_activate(adapter);
1579169978Skmacy	if (err)
1580169978Skmacy		goto out;
1581169978Skmacy
1582169978Skmacy	init_port_mtus(adapter);
1583169978Skmacy	t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
1584169978Skmacy		     adapter->params.b_wnd,
1585169978Skmacy		     adapter->params.rev == 0 ?
1586169978Skmacy		       adapter->port[0].ifp->if_mtu : 0xffff);
1587169978Skmacy	init_smt(adapter);
1588169978Skmacy
1589169978Skmacy	/* Call back all registered clients */
1590169978Skmacy	cxgb_add_clients(tdev);
1591169978Skmacy
1592169978Skmacyout:
1593169978Skmacy	/* restore them in case the offload module has changed them */
1594169978Skmacy	if (err) {
1595169978Skmacy		t3_tp_set_offload_mode(adapter, 0);
1596169978Skmacy		clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT);
1597169978Skmacy		cxgb_set_dummy_ops(tdev);
1598169978Skmacy	}
1599169978Skmacy	return (err);
1600169978Skmacy}
1601170789Skmacy#ifdef notyet
1602169978Skmacystatic int
1603174626Skmacyoffload_close(struct t3cev *tdev)
1604169978Skmacy{
1605169978Skmacy	struct adapter *adapter = tdev2adap(tdev);
1606169978Skmacy
1607169978Skmacy	if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT))
1608170654Skmacy		return (0);
1609169978Skmacy
1610169978Skmacy	/* Call back all registered clients */
1611169978Skmacy	cxgb_remove_clients(tdev);
1612169978Skmacy	tdev->lldev = NULL;
1613169978Skmacy	cxgb_set_dummy_ops(tdev);
1614169978Skmacy	t3_tp_set_offload_mode(adapter, 0);
1615169978Skmacy	clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT);
1616169978Skmacy
1617169978Skmacy	if (!adapter->open_device_map)
1618169978Skmacy		cxgb_down(adapter);
1619169978Skmacy
1620169978Skmacy	cxgb_offload_deactivate(adapter);
1621170654Skmacy	return (0);
1622169978Skmacy}
1623170789Skmacy#endif
1624169978Skmacy
1625169978Skmacystatic void
1626167514Skmacycxgb_init(void *arg)
1627167514Skmacy{
1628167514Skmacy	struct port_info *p = arg;
1629167514Skmacy
1630167514Skmacy	PORT_LOCK(p);
1631167514Skmacy	cxgb_init_locked(p);
1632167514Skmacy	PORT_UNLOCK(p);
1633167514Skmacy}
1634167514Skmacy
1635167514Skmacystatic void
1636167514Skmacycxgb_init_locked(struct port_info *p)
1637167514Skmacy{
1638167514Skmacy	struct ifnet *ifp;
1639167514Skmacy	adapter_t *sc = p->adapter;
1640169978Skmacy	int err;
1641167514Skmacy
1642170869Skmacy	PORT_LOCK_ASSERT_OWNED(p);
1643167514Skmacy	ifp = p->ifp;
1644167514Skmacy
1645167514Skmacy	ADAPTER_LOCK(p->adapter);
1646171471Skmacy	if ((sc->open_device_map == 0) && (err = cxgb_up(sc))) {
1647169978Skmacy		ADAPTER_UNLOCK(p->adapter);
1648169978Skmacy		cxgb_stop_locked(p);
1649169978Skmacy		return;
1650169978Skmacy	}
1651170869Skmacy	if (p->adapter->open_device_map == 0) {
1652167514Skmacy		t3_intr_clear(sc);
1653170869Skmacy		t3_sge_init_adapter(sc);
1654170869Skmacy	}
1655171803Skmacy	setbit(&p->adapter->open_device_map, p->port_id);
1656170654Skmacy	ADAPTER_UNLOCK(p->adapter);
1657169978Skmacy
1658169978Skmacy	if (is_offload(sc) && !ofld_disable) {
1659169978Skmacy		err = offload_open(p);
1660169978Skmacy		if (err)
1661169978Skmacy			log(LOG_WARNING,
1662169978Skmacy			    "Could not initialize offload capabilities\n");
1663169978Skmacy	}
1664169978Skmacy	cxgb_link_start(p);
1665171803Skmacy	t3_link_changed(sc, p->port_id);
1666170654Skmacy	ifp->if_baudrate = p->link_config.speed * 1000000;
1667171978Skmacy
1668172096Skmacy	device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id);
1669171803Skmacy	t3_port_intr_enable(sc, p->port_id);
1670167760Skmacy
1671167514Skmacy	callout_reset(&sc->cxgb_tick_ch, sc->params.stats_update_period * hz,
1672167514Skmacy	    cxgb_tick, sc);
1673170869Skmacy
1674167514Skmacy	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1675167514Skmacy	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1676167514Skmacy}
1677167514Skmacy
1678167514Skmacystatic void
1679167514Skmacycxgb_set_rxmode(struct port_info *p)
1680167514Skmacy{
1681167514Skmacy	struct t3_rx_mode rm;
1682167514Skmacy	struct cmac *mac = &p->mac;
1683167760Skmacy
1684170869Skmacy	PORT_LOCK_ASSERT_OWNED(p);
1685170654Skmacy
1686167514Skmacy	t3_init_rx_mode(&rm, p);
1687167514Skmacy	t3_mac_set_rx_mode(mac, &rm);
1688167514Skmacy}
1689167514Skmacy
1690167514Skmacystatic void
1691167734Skmacycxgb_stop_locked(struct port_info *p)
1692167514Skmacy{
1693167514Skmacy	struct ifnet *ifp;
1694167514Skmacy
1695170869Skmacy	PORT_LOCK_ASSERT_OWNED(p);
1696170869Skmacy	ADAPTER_LOCK_ASSERT_NOTOWNED(p->adapter);
1697170654Skmacy
1698167514Skmacy	ifp = p->ifp;
1699167514Skmacy
1700171803Skmacy	t3_port_intr_disable(p->adapter, p->port_id);
1701169978Skmacy	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1702169978Skmacy	p->phy.ops->power_down(&p->phy, 1);
1703169978Skmacy	t3_mac_disable(&p->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
1704169978Skmacy
1705167514Skmacy	ADAPTER_LOCK(p->adapter);
1706171803Skmacy	clrbit(&p->adapter->open_device_map, p->port_id);
1707170869Skmacy
1708170869Skmacy
1709170869Skmacy	if (p->adapter->open_device_map == 0) {
1710170869Skmacy		cxgb_down_locked(p->adapter);
1711170869Skmacy	} else
1712170869Skmacy		ADAPTER_UNLOCK(p->adapter);
1713170869Skmacy
1714167514Skmacy}
1715167514Skmacy
1716167514Skmacystatic int
1717170654Skmacycxgb_set_mtu(struct port_info *p, int mtu)
1718170654Skmacy{
1719170654Skmacy	struct ifnet *ifp = p->ifp;
1720170654Skmacy	int error = 0;
1721170654Skmacy
1722170654Skmacy	if ((mtu < ETHERMIN) || (mtu > ETHER_MAX_LEN_JUMBO))
1723170654Skmacy		error = EINVAL;
1724170654Skmacy	else if (ifp->if_mtu != mtu) {
1725170654Skmacy		PORT_LOCK(p);
1726170654Skmacy		ifp->if_mtu = mtu;
1727170654Skmacy		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1728170654Skmacy			callout_stop(&p->adapter->cxgb_tick_ch);
1729170654Skmacy			cxgb_stop_locked(p);
1730170654Skmacy			cxgb_init_locked(p);
1731170654Skmacy		}
1732170654Skmacy		PORT_UNLOCK(p);
1733170654Skmacy	}
1734170654Skmacy	return (error);
1735170654Skmacy}
1736170654Skmacy
1737170654Skmacystatic int
1738167514Skmacycxgb_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data)
1739167514Skmacy{
1740167514Skmacy	struct port_info *p = ifp->if_softc;
1741167514Skmacy	struct ifaddr *ifa = (struct ifaddr *)data;
1742167514Skmacy	struct ifreq *ifr = (struct ifreq *)data;
1743167514Skmacy	int flags, error = 0;
1744167514Skmacy	uint32_t mask;
1745167514Skmacy
1746168737Skmacy	/*
1747168737Skmacy	 * XXX need to check that we aren't in the middle of an unload
1748168737Skmacy	 */
1749167514Skmacy	switch (command) {
1750167514Skmacy	case SIOCSIFMTU:
1751170654Skmacy		error = cxgb_set_mtu(p, ifr->ifr_mtu);
1752167514Skmacy		break;
1753167514Skmacy	case SIOCSIFADDR:
1754167514Skmacy	case SIOCGIFADDR:
1755170654Skmacy		PORT_LOCK(p);
1756167514Skmacy		if (ifa->ifa_addr->sa_family == AF_INET) {
1757167514Skmacy			ifp->if_flags |= IFF_UP;
1758170654Skmacy			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
1759170654Skmacy				cxgb_init_locked(p);
1760167514Skmacy			arp_ifinit(ifp, ifa);
1761167514Skmacy		} else
1762167514Skmacy			error = ether_ioctl(ifp, command, data);
1763170654Skmacy		PORT_UNLOCK(p);
1764167514Skmacy		break;
1765167514Skmacy	case SIOCSIFFLAGS:
1766170869Skmacy		callout_drain(&p->adapter->cxgb_tick_ch);
1767170869Skmacy		PORT_LOCK(p);
1768167514Skmacy		if (ifp->if_flags & IFF_UP) {
1769167514Skmacy			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1770167514Skmacy				flags = p->if_flags;
1771167514Skmacy				if (((ifp->if_flags ^ flags) & IFF_PROMISC) ||
1772167514Skmacy				    ((ifp->if_flags ^ flags) & IFF_ALLMULTI))
1773167514Skmacy					cxgb_set_rxmode(p);
1774167514Skmacy			} else
1775167514Skmacy				cxgb_init_locked(p);
1776167760Skmacy			p->if_flags = ifp->if_flags;
1777170869Skmacy		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1778170869Skmacy			cxgb_stop_locked(p);
1779170869Skmacy
1780170869Skmacy		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1781170869Skmacy			adapter_t *sc = p->adapter;
1782170869Skmacy			callout_reset(&sc->cxgb_tick_ch,
1783170869Skmacy			    sc->params.stats_update_period * hz,
1784170869Skmacy			    cxgb_tick, sc);
1785167514Skmacy		}
1786170654Skmacy		PORT_UNLOCK(p);
1787167514Skmacy		break;
1788167514Skmacy	case SIOCSIFMEDIA:
1789167514Skmacy	case SIOCGIFMEDIA:
1790167514Skmacy		error = ifmedia_ioctl(ifp, ifr, &p->media, command);
1791167514Skmacy		break;
1792167514Skmacy	case SIOCSIFCAP:
1793167514Skmacy		PORT_LOCK(p);
1794167514Skmacy		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1795167514Skmacy		if (mask & IFCAP_TXCSUM) {
1796167514Skmacy			if (IFCAP_TXCSUM & ifp->if_capenable) {
1797167514Skmacy				ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4);
1798167514Skmacy				ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP
1799167514Skmacy				    | CSUM_TSO);
1800167514Skmacy			} else {
1801167514Skmacy				ifp->if_capenable |= IFCAP_TXCSUM;
1802167514Skmacy				ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP);
1803167514Skmacy			}
1804167514Skmacy		} else if (mask & IFCAP_RXCSUM) {
1805167514Skmacy			if (IFCAP_RXCSUM & ifp->if_capenable) {
1806167514Skmacy				ifp->if_capenable &= ~IFCAP_RXCSUM;
1807167514Skmacy			} else {
1808167514Skmacy				ifp->if_capenable |= IFCAP_RXCSUM;
1809167514Skmacy			}
1810167514Skmacy		}
1811167514Skmacy		if (mask & IFCAP_TSO4) {
1812167514Skmacy			if (IFCAP_TSO4 & ifp->if_capenable) {
1813167514Skmacy				ifp->if_capenable &= ~IFCAP_TSO4;
1814167514Skmacy				ifp->if_hwassist &= ~CSUM_TSO;
1815167514Skmacy			} else if (IFCAP_TXCSUM & ifp->if_capenable) {
1816167514Skmacy				ifp->if_capenable |= IFCAP_TSO4;
1817167514Skmacy				ifp->if_hwassist |= CSUM_TSO;
1818167514Skmacy			} else {
1819167514Skmacy				if (cxgb_debug)
1820167514Skmacy					printf("cxgb requires tx checksum offload"
1821167514Skmacy					    " be enabled to use TSO\n");
1822167514Skmacy				error = EINVAL;
1823167514Skmacy			}
1824167514Skmacy		}
1825167514Skmacy		PORT_UNLOCK(p);
1826167514Skmacy		break;
1827167514Skmacy	default:
1828167514Skmacy		error = ether_ioctl(ifp, command, data);
1829167514Skmacy		break;
1830167514Skmacy	}
1831167514Skmacy	return (error);
1832167514Skmacy}
1833167514Skmacy
1834167514Skmacystatic int
1835167514Skmacycxgb_start_tx(struct ifnet *ifp, uint32_t txmax)
1836167514Skmacy{
1837167514Skmacy	struct sge_qset *qs;
1838167514Skmacy	struct sge_txq *txq;
1839167514Skmacy	struct port_info *p = ifp->if_softc;
1840172109Skmacy	struct mbuf *m = NULL;
1841172096Skmacy	int err, in_use_init, free;
1842170654Skmacy
1843167514Skmacy	if (!p->link_config.link_ok)
1844167514Skmacy		return (ENXIO);
1845167514Skmacy
1846167514Skmacy	if (IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1847167514Skmacy		return (ENOBUFS);
1848167514Skmacy
1849172096Skmacy	qs = &p->adapter->sge.qs[p->first_qset];
1850167514Skmacy	txq = &qs->txq[TXQ_ETH];
1851167514Skmacy	err = 0;
1852167514Skmacy
1853171335Skmacy	if (txq->flags & TXQ_TRANSMITTING)
1854171335Skmacy		return (EINPROGRESS);
1855171335Skmacy
1856167514Skmacy	mtx_lock(&txq->lock);
1857171335Skmacy	txq->flags |= TXQ_TRANSMITTING;
1858167514Skmacy	in_use_init = txq->in_use;
1859167514Skmacy	while ((txq->in_use - in_use_init < txmax) &&
1860167514Skmacy	    (txq->size > txq->in_use + TX_MAX_DESC)) {
1861172096Skmacy		free = 0;
1862167514Skmacy		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
1863167514Skmacy		if (m == NULL)
1864167514Skmacy			break;
1865168737Skmacy		/*
1866168737Skmacy		 * Convert chain to M_IOVEC
1867168737Skmacy		 */
1868168737Skmacy		KASSERT((m->m_flags & M_IOVEC) == 0, ("IOVEC set too early"));
1869172109Skmacy#ifdef notyet
1870168737Skmacy		m0 = m;
1871168749Skmacy		if (collapse_mbufs && m->m_pkthdr.len > MCLBYTES &&
1872168737Skmacy		    m_collapse(m, TX_MAX_SEGS, &m0) == EFBIG) {
1873168737Skmacy			if ((m0 = m_defrag(m, M_NOWAIT)) != NULL) {
1874168737Skmacy				m = m0;
1875168737Skmacy				m_collapse(m, TX_MAX_SEGS, &m0);
1876168737Skmacy			} else
1877171804Skmacy				break;
1878168737Skmacy		}
1879168737Skmacy		m = m0;
1880172109Skmacy#endif
1881172096Skmacy		if ((err = t3_encap(p, &m, &free)) != 0)
1882167514Skmacy			break;
1883169978Skmacy		BPF_MTAP(ifp, m);
1884172096Skmacy		if (free)
1885172096Skmacy			m_freem(m);
1886167514Skmacy	}
1887171335Skmacy	txq->flags &= ~TXQ_TRANSMITTING;
1888167514Skmacy	mtx_unlock(&txq->lock);
1889167514Skmacy
1890167514Skmacy	if (__predict_false(err)) {
1891167514Skmacy		if (err == ENOMEM) {
1892170083Skmacy			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1893167514Skmacy			IFQ_LOCK(&ifp->if_snd);
1894167514Skmacy			IFQ_DRV_PREPEND(&ifp->if_snd, m);
1895167514Skmacy			IFQ_UNLOCK(&ifp->if_snd);
1896167514Skmacy		}
1897167514Skmacy	}
1898170654Skmacy	if (err == 0 && m == NULL)
1899170654Skmacy		err = ENOBUFS;
1900170654Skmacy	else if ((err == 0) &&  (txq->size <= txq->in_use + TX_MAX_DESC) &&
1901170007Skmacy	    (ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
1902170007Skmacy		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1903170654Skmacy		err = ENOSPC;
1904170007Skmacy	}
1905167514Skmacy	return (err);
1906167514Skmacy}
1907167514Skmacy
1908167514Skmacystatic void
1909167514Skmacycxgb_start_proc(void *arg, int ncount)
1910167514Skmacy{
1911167514Skmacy	struct ifnet *ifp = arg;
1912167514Skmacy	struct port_info *pi = ifp->if_softc;
1913167514Skmacy	struct sge_qset *qs;
1914167514Skmacy	struct sge_txq *txq;
1915170654Skmacy	int error;
1916167514Skmacy
1917167514Skmacy	qs = &pi->adapter->sge.qs[pi->first_qset];
1918167514Skmacy	txq = &qs->txq[TXQ_ETH];
1919167514Skmacy
1920170654Skmacy	do {
1921171469Skmacy		if (desc_reclaimable(txq) > TX_CLEAN_MAX_DESC >> 2)
1922171469Skmacy			taskqueue_enqueue(pi->tq, &txq->qreclaim_task);
1923167525Skmacy
1924167538Skmacy		error = cxgb_start_tx(ifp, TX_START_MAX_DESC);
1925170654Skmacy	} while (error == 0);
1926167514Skmacy}
1927167514Skmacy
1928167514Skmacystatic void
1929167514Skmacycxgb_start(struct ifnet *ifp)
1930167514Skmacy{
1931167514Skmacy	struct port_info *pi = ifp->if_softc;
1932167514Skmacy	struct sge_qset *qs;
1933167514Skmacy	struct sge_txq *txq;
1934167514Skmacy	int err;
1935167514Skmacy
1936167514Skmacy	qs = &pi->adapter->sge.qs[pi->first_qset];
1937167514Skmacy	txq = &qs->txq[TXQ_ETH];
1938167514Skmacy
1939171469Skmacy	if (desc_reclaimable(txq) > TX_CLEAN_MAX_DESC >> 2)
1940171469Skmacy		taskqueue_enqueue(pi->tq,
1941171469Skmacy		    &txq->qreclaim_task);
1942167538Skmacy
1943167514Skmacy	err = cxgb_start_tx(ifp, TX_START_MAX_DESC);
1944167514Skmacy
1945167514Skmacy	if (err == 0)
1946167514Skmacy		taskqueue_enqueue(pi->tq, &pi->start_task);
1947167514Skmacy}
1948167514Skmacy
1949167514Skmacy
1950167514Skmacystatic int
1951167514Skmacycxgb_media_change(struct ifnet *ifp)
1952167514Skmacy{
1953167514Skmacy	if_printf(ifp, "media change not supported\n");
1954167514Skmacy	return (ENXIO);
1955167514Skmacy}
1956167514Skmacy
1957167514Skmacystatic void
1958167514Skmacycxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
1959167514Skmacy{
1960167514Skmacy	struct port_info *p = ifp->if_softc;
1961167514Skmacy
1962167514Skmacy	ifmr->ifm_status = IFM_AVALID;
1963167514Skmacy	ifmr->ifm_active = IFM_ETHER;
1964167514Skmacy
1965167514Skmacy	if (!p->link_config.link_ok)
1966167514Skmacy		return;
1967167514Skmacy
1968167514Skmacy	ifmr->ifm_status |= IFM_ACTIVE;
1969167514Skmacy
1970170654Skmacy	switch (p->link_config.speed) {
1971170654Skmacy	case 10:
1972170654Skmacy		ifmr->ifm_active |= IFM_10_T;
1973170654Skmacy		break;
1974170654Skmacy	case 100:
1975170654Skmacy		ifmr->ifm_active |= IFM_100_TX;
1976170654Skmacy			break;
1977170654Skmacy	case 1000:
1978170654Skmacy		ifmr->ifm_active |= IFM_1000_T;
1979170654Skmacy		break;
1980170654Skmacy	}
1981170654Skmacy
1982167514Skmacy	if (p->link_config.duplex)
1983167514Skmacy		ifmr->ifm_active |= IFM_FDX;
1984167514Skmacy	else
1985167514Skmacy		ifmr->ifm_active |= IFM_HDX;
1986167514Skmacy}
1987167514Skmacy
1988167514Skmacystatic void
1989167514Skmacycxgb_async_intr(void *data)
1990167514Skmacy{
1991167760Skmacy	adapter_t *sc = data;
1992167760Skmacy
1993167514Skmacy	if (cxgb_debug)
1994167760Skmacy		device_printf(sc->dev, "cxgb_async_intr\n");
1995170869Skmacy	/*
1996170869Skmacy	 * May need to sleep - defer to taskqueue
1997170869Skmacy	 */
1998170869Skmacy	taskqueue_enqueue(sc->tq, &sc->slow_intr_task);
1999167514Skmacy}
2000167514Skmacy
2001167514Skmacystatic void
2002167514Skmacycxgb_ext_intr_handler(void *arg, int count)
2003167514Skmacy{
2004167514Skmacy	adapter_t *sc = (adapter_t *)arg;
2005167514Skmacy
2006167514Skmacy	if (cxgb_debug)
2007167514Skmacy		printf("cxgb_ext_intr_handler\n");
2008167514Skmacy
2009167514Skmacy	t3_phy_intr_handler(sc);
2010167514Skmacy
2011167514Skmacy	/* Now reenable external interrupts */
2012169978Skmacy	ADAPTER_LOCK(sc);
2013167514Skmacy	if (sc->slow_intr_mask) {
2014167514Skmacy		sc->slow_intr_mask |= F_T3DBG;
2015167514Skmacy		t3_write_reg(sc, A_PL_INT_CAUSE0, F_T3DBG);
2016167514Skmacy		t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
2017167514Skmacy	}
2018169978Skmacy	ADAPTER_UNLOCK(sc);
2019167514Skmacy}
2020167514Skmacy
2021167514Skmacystatic void
2022167746Skmacycheck_link_status(adapter_t *sc)
2023167514Skmacy{
2024167746Skmacy	int i;
2025167514Skmacy
2026167746Skmacy	for (i = 0; i < (sc)->params.nports; ++i) {
2027167746Skmacy		struct port_info *p = &sc->port[i];
2028167514Skmacy
2029170654Skmacy		if (!(p->port_type->caps & SUPPORTED_IRQ))
2030167746Skmacy			t3_link_changed(sc, i);
2031170654Skmacy		p->ifp->if_baudrate = p->link_config.speed * 1000000;
2032167746Skmacy	}
2033167514Skmacy}
2034167514Skmacy
2035167514Skmacystatic void
2036167746Skmacycheck_t3b2_mac(struct adapter *adapter)
2037167514Skmacy{
2038167514Skmacy	int i;
2039167514Skmacy
2040167746Skmacy	for_each_port(adapter, i) {
2041167746Skmacy		struct port_info *p = &adapter->port[i];
2042167746Skmacy		struct ifnet *ifp = p->ifp;
2043167746Skmacy		int status;
2044167514Skmacy
2045167746Skmacy		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
2046167746Skmacy			continue;
2047167746Skmacy
2048167746Skmacy		status = 0;
2049167746Skmacy		PORT_LOCK(p);
2050167746Skmacy		if ((ifp->if_drv_flags & IFF_DRV_RUNNING))
2051167746Skmacy			status = t3b2_mac_watchdog_task(&p->mac);
2052167746Skmacy		if (status == 1)
2053167746Skmacy			p->mac.stats.num_toggled++;
2054167746Skmacy		else if (status == 2) {
2055167746Skmacy			struct cmac *mac = &p->mac;
2056167746Skmacy
2057170654Skmacy			t3_mac_set_mtu(mac, ifp->if_mtu + ETHER_HDR_LEN
2058170654Skmacy			    + ETHER_VLAN_ENCAP_LEN);
2059167746Skmacy			t3_mac_set_address(mac, 0, p->hw_addr);
2060167746Skmacy			cxgb_set_rxmode(p);
2061167746Skmacy			t3_link_start(&p->phy, mac, &p->link_config);
2062167746Skmacy			t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
2063171803Skmacy			t3_port_intr_enable(adapter, p->port_id);
2064167746Skmacy			p->mac.stats.num_resets++;
2065167746Skmacy		}
2066167746Skmacy		PORT_UNLOCK(p);
2067167514Skmacy	}
2068167514Skmacy}
2069167514Skmacy
2070167746Skmacystatic void
2071167746Skmacycxgb_tick(void *arg)
2072167746Skmacy{
2073167746Skmacy	adapter_t *sc = (adapter_t *)arg;
2074170869Skmacy
2075170869Skmacy	taskqueue_enqueue(sc->tq, &sc->tick_task);
2076170869Skmacy
2077170869Skmacy	if (sc->open_device_map != 0)
2078170869Skmacy		callout_reset(&sc->cxgb_tick_ch, sc->params.stats_update_period * hz,
2079170869Skmacy		    cxgb_tick, sc);
2080170869Skmacy}
2081170869Skmacy
2082170869Skmacystatic void
2083170869Skmacycxgb_tick_handler(void *arg, int count)
2084170869Skmacy{
2085170869Skmacy	adapter_t *sc = (adapter_t *)arg;
2086167746Skmacy	const struct adapter_params *p = &sc->params;
2087167746Skmacy
2088170869Skmacy	ADAPTER_LOCK(sc);
2089167746Skmacy	if (p->linkpoll_period)
2090167746Skmacy		check_link_status(sc);
2091167746Skmacy
2092167746Skmacy	/*
2093167746Skmacy	 * adapter lock can currently only be acquire after the
2094167746Skmacy	 * port lock
2095167746Skmacy	 */
2096167746Skmacy	ADAPTER_UNLOCK(sc);
2097170654Skmacy
2098171471Skmacy	if (p->rev == T3_REV_B2 && p->nports < 4)
2099167746Skmacy		check_t3b2_mac(sc);
2100167746Skmacy}
2101167746Skmacy
2102171978Skmacystatic void
2103171978Skmacytouch_bars(device_t dev)
2104171978Skmacy{
2105171978Skmacy	/*
2106171978Skmacy	 * Don't enable yet
2107171978Skmacy	 */
2108171978Skmacy#if !defined(__LP64__) && 0
2109171978Skmacy	u32 v;
2110171978Skmacy
2111171978Skmacy	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &v);
2112171978Skmacy	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, v);
2113171978Skmacy	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3, &v);
2114171978Skmacy	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_3, v);
2115171978Skmacy	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &v);
2116171978Skmacy	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_5, v);
2117171978Skmacy#endif
2118171978Skmacy}
2119171978Skmacy
2120167514Skmacystatic int
2121171471Skmacyset_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset)
2122171471Skmacy{
2123171471Skmacy	uint8_t *buf;
2124171471Skmacy	int err = 0;
2125171471Skmacy	u32 aligned_offset, aligned_len, *p;
2126171471Skmacy	struct adapter *adapter = pi->adapter;
2127171471Skmacy
2128171471Skmacy
2129171471Skmacy	aligned_offset = offset & ~3;
2130171471Skmacy	aligned_len = (len + (offset & 3) + 3) & ~3;
2131171471Skmacy
2132171471Skmacy	if (aligned_offset != offset || aligned_len != len) {
2133171471Skmacy		buf = malloc(aligned_len, M_DEVBUF, M_WAITOK|M_ZERO);
2134171471Skmacy		if (!buf)
2135171471Skmacy			return (ENOMEM);
2136171471Skmacy		err = t3_seeprom_read(adapter, aligned_offset, (u32 *)buf);
2137171471Skmacy		if (!err && aligned_len > 4)
2138171471Skmacy			err = t3_seeprom_read(adapter,
2139171471Skmacy					      aligned_offset + aligned_len - 4,
2140171471Skmacy					      (u32 *)&buf[aligned_len - 4]);
2141171471Skmacy		if (err)
2142171471Skmacy			goto out;
2143171471Skmacy		memcpy(buf + (offset & 3), data, len);
2144171471Skmacy	} else
2145171471Skmacy		buf = (uint8_t *)(uintptr_t)data;
2146171471Skmacy
2147171471Skmacy	err = t3_seeprom_wp(adapter, 0);
2148171471Skmacy	if (err)
2149171471Skmacy		goto out;
2150171471Skmacy
2151171471Skmacy	for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) {
2152171471Skmacy		err = t3_seeprom_write(adapter, aligned_offset, *p);
2153171471Skmacy		aligned_offset += 4;
2154171471Skmacy	}
2155171471Skmacy
2156171471Skmacy	if (!err)
2157171471Skmacy		err = t3_seeprom_wp(adapter, 1);
2158171471Skmacyout:
2159171471Skmacy	if (buf != data)
2160171471Skmacy		free(buf, M_DEVBUF);
2161171471Skmacy	return err;
2162171471Skmacy}
2163171471Skmacy
2164171471Skmacy
2165171471Skmacystatic int
2166167514Skmacyin_range(int val, int lo, int hi)
2167167514Skmacy{
2168167514Skmacy	return val < 0 || (val <= hi && val >= lo);
2169167514Skmacy}
2170167514Skmacy
2171167514Skmacystatic int
2172170654Skmacycxgb_extension_open(struct cdev *dev, int flags, int fmp, d_thread_t *td)
2173170654Skmacy{
2174170654Skmacy       return (0);
2175170654Skmacy}
2176170654Skmacy
2177170654Skmacystatic int
2178170654Skmacycxgb_extension_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
2179170654Skmacy{
2180170654Skmacy       return (0);
2181170654Skmacy}
2182170654Skmacy
2183170654Skmacystatic int
2184167514Skmacycxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
2185167514Skmacy    int fflag, struct thread *td)
2186167514Skmacy{
2187167514Skmacy	int mmd, error = 0;
2188167514Skmacy	struct port_info *pi = dev->si_drv1;
2189167514Skmacy	adapter_t *sc = pi->adapter;
2190167514Skmacy
2191167514Skmacy#ifdef PRIV_SUPPORTED
2192167514Skmacy	if (priv_check(td, PRIV_DRIVER)) {
2193167514Skmacy		if (cxgb_debug)
2194167514Skmacy			printf("user does not have access to privileged ioctls\n");
2195167514Skmacy		return (EPERM);
2196167514Skmacy	}
2197167514Skmacy#else
2198167514Skmacy	if (suser(td)) {
2199167514Skmacy		if (cxgb_debug)
2200167514Skmacy			printf("user does not have access to privileged ioctls\n");
2201167514Skmacy		return (EPERM);
2202167514Skmacy	}
2203167514Skmacy#endif
2204167514Skmacy
2205167514Skmacy	switch (cmd) {
2206167514Skmacy	case SIOCGMIIREG: {
2207167514Skmacy		uint32_t val;
2208167514Skmacy		struct cphy *phy = &pi->phy;
2209167514Skmacy		struct mii_data *mid = (struct mii_data *)data;
2210167514Skmacy
2211167514Skmacy		if (!phy->mdio_read)
2212167514Skmacy			return (EOPNOTSUPP);
2213167514Skmacy		if (is_10G(sc)) {
2214167514Skmacy			mmd = mid->phy_id >> 8;
2215167514Skmacy			if (!mmd)
2216167514Skmacy				mmd = MDIO_DEV_PCS;
2217167514Skmacy			else if (mmd > MDIO_DEV_XGXS)
2218171471Skmacy				return (EINVAL);
2219167514Skmacy
2220167514Skmacy			error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd,
2221167514Skmacy					     mid->reg_num, &val);
2222167514Skmacy		} else
2223167514Skmacy		        error = phy->mdio_read(sc, mid->phy_id & 0x1f, 0,
2224167514Skmacy					     mid->reg_num & 0x1f, &val);
2225167514Skmacy		if (error == 0)
2226167514Skmacy			mid->val_out = val;
2227167514Skmacy		break;
2228167514Skmacy	}
2229167514Skmacy	case SIOCSMIIREG: {
2230167514Skmacy		struct cphy *phy = &pi->phy;
2231167514Skmacy		struct mii_data *mid = (struct mii_data *)data;
2232167514Skmacy
2233167514Skmacy		if (!phy->mdio_write)
2234167514Skmacy			return (EOPNOTSUPP);
2235167514Skmacy		if (is_10G(sc)) {
2236167514Skmacy			mmd = mid->phy_id >> 8;
2237167514Skmacy			if (!mmd)
2238167514Skmacy				mmd = MDIO_DEV_PCS;
2239167514Skmacy			else if (mmd > MDIO_DEV_XGXS)
2240167514Skmacy				return (EINVAL);
2241167514Skmacy
2242167514Skmacy			error = phy->mdio_write(sc, mid->phy_id & 0x1f,
2243167514Skmacy					      mmd, mid->reg_num, mid->val_in);
2244167514Skmacy		} else
2245167514Skmacy			error = phy->mdio_write(sc, mid->phy_id & 0x1f, 0,
2246167514Skmacy					      mid->reg_num & 0x1f,
2247167514Skmacy					      mid->val_in);
2248167514Skmacy		break;
2249167514Skmacy	}
2250167514Skmacy	case CHELSIO_SETREG: {
2251167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
2252167514Skmacy		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2253167514Skmacy			return (EFAULT);
2254167514Skmacy		t3_write_reg(sc, edata->addr, edata->val);
2255167514Skmacy		break;
2256167514Skmacy	}
2257167514Skmacy	case CHELSIO_GETREG: {
2258167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
2259167514Skmacy		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2260167514Skmacy			return (EFAULT);
2261167514Skmacy		edata->val = t3_read_reg(sc, edata->addr);
2262167514Skmacy		break;
2263167514Skmacy	}
2264167514Skmacy	case CHELSIO_GET_SGE_CONTEXT: {
2265167514Skmacy		struct ch_cntxt *ecntxt = (struct ch_cntxt *)data;
2266167514Skmacy		mtx_lock(&sc->sge.reg_lock);
2267167514Skmacy		switch (ecntxt->cntxt_type) {
2268167514Skmacy		case CNTXT_TYPE_EGRESS:
2269167514Skmacy			error = t3_sge_read_ecntxt(sc, ecntxt->cntxt_id,
2270167514Skmacy			    ecntxt->data);
2271167514Skmacy			break;
2272167514Skmacy		case CNTXT_TYPE_FL:
2273167514Skmacy			error = t3_sge_read_fl(sc, ecntxt->cntxt_id,
2274167514Skmacy			    ecntxt->data);
2275167514Skmacy			break;
2276167514Skmacy		case CNTXT_TYPE_RSP:
2277167514Skmacy			error = t3_sge_read_rspq(sc, ecntxt->cntxt_id,
2278167514Skmacy			    ecntxt->data);
2279167514Skmacy			break;
2280167514Skmacy		case CNTXT_TYPE_CQ:
2281167514Skmacy			error = t3_sge_read_cq(sc, ecntxt->cntxt_id,
2282167514Skmacy			    ecntxt->data);
2283167514Skmacy			break;
2284167514Skmacy		default:
2285167514Skmacy			error = EINVAL;
2286167514Skmacy			break;
2287167514Skmacy		}
2288167514Skmacy		mtx_unlock(&sc->sge.reg_lock);
2289167514Skmacy		break;
2290167514Skmacy	}
2291167514Skmacy	case CHELSIO_GET_SGE_DESC: {
2292167514Skmacy		struct ch_desc *edesc = (struct ch_desc *)data;
2293167514Skmacy		int ret;
2294167514Skmacy		if (edesc->queue_num >= SGE_QSETS * 6)
2295167514Skmacy			return (EINVAL);
2296167514Skmacy		ret = t3_get_desc(&sc->sge.qs[edesc->queue_num / 6],
2297167514Skmacy		    edesc->queue_num % 6, edesc->idx, edesc->data);
2298167514Skmacy		if (ret < 0)
2299167514Skmacy			return (EINVAL);
2300167514Skmacy		edesc->size = ret;
2301167514Skmacy		break;
2302167514Skmacy	}
2303167514Skmacy	case CHELSIO_SET_QSET_PARAMS: {
2304167514Skmacy		struct qset_params *q;
2305167514Skmacy		struct ch_qset_params *t = (struct ch_qset_params *)data;
2306167514Skmacy
2307167514Skmacy		if (t->qset_idx >= SGE_QSETS)
2308171471Skmacy			return (EINVAL);
2309167514Skmacy		if (!in_range(t->intr_lat, 0, M_NEWTIMER) ||
2310167514Skmacy		    !in_range(t->cong_thres, 0, 255) ||
2311167514Skmacy		    !in_range(t->txq_size[0], MIN_TXQ_ENTRIES,
2312167514Skmacy			      MAX_TXQ_ENTRIES) ||
2313167514Skmacy		    !in_range(t->txq_size[1], MIN_TXQ_ENTRIES,
2314167514Skmacy			      MAX_TXQ_ENTRIES) ||
2315167514Skmacy		    !in_range(t->txq_size[2], MIN_CTRL_TXQ_ENTRIES,
2316167514Skmacy			      MAX_CTRL_TXQ_ENTRIES) ||
2317167514Skmacy		    !in_range(t->fl_size[0], MIN_FL_ENTRIES, MAX_RX_BUFFERS) ||
2318167514Skmacy		    !in_range(t->fl_size[1], MIN_FL_ENTRIES,
2319167514Skmacy			      MAX_RX_JUMBO_BUFFERS) ||
2320167514Skmacy		    !in_range(t->rspq_size, MIN_RSPQ_ENTRIES, MAX_RSPQ_ENTRIES))
2321171471Skmacy			return (EINVAL);
2322167514Skmacy		if ((sc->flags & FULL_INIT_DONE) &&
2323167514Skmacy		    (t->rspq_size >= 0 || t->fl_size[0] >= 0 ||
2324167514Skmacy		     t->fl_size[1] >= 0 || t->txq_size[0] >= 0 ||
2325167514Skmacy		     t->txq_size[1] >= 0 || t->txq_size[2] >= 0 ||
2326167514Skmacy		     t->polling >= 0 || t->cong_thres >= 0))
2327171471Skmacy			return (EBUSY);
2328167514Skmacy
2329167514Skmacy		q = &sc->params.sge.qset[t->qset_idx];
2330167514Skmacy
2331167514Skmacy		if (t->rspq_size >= 0)
2332167514Skmacy			q->rspq_size = t->rspq_size;
2333167514Skmacy		if (t->fl_size[0] >= 0)
2334167514Skmacy			q->fl_size = t->fl_size[0];
2335167514Skmacy		if (t->fl_size[1] >= 0)
2336167514Skmacy			q->jumbo_size = t->fl_size[1];
2337167514Skmacy		if (t->txq_size[0] >= 0)
2338167514Skmacy			q->txq_size[0] = t->txq_size[0];
2339167514Skmacy		if (t->txq_size[1] >= 0)
2340167514Skmacy			q->txq_size[1] = t->txq_size[1];
2341167514Skmacy		if (t->txq_size[2] >= 0)
2342167514Skmacy			q->txq_size[2] = t->txq_size[2];
2343167514Skmacy		if (t->cong_thres >= 0)
2344167514Skmacy			q->cong_thres = t->cong_thres;
2345167514Skmacy		if (t->intr_lat >= 0) {
2346167514Skmacy			struct sge_qset *qs = &sc->sge.qs[t->qset_idx];
2347167514Skmacy
2348167514Skmacy			q->coalesce_nsecs = t->intr_lat*1000;
2349167514Skmacy			t3_update_qset_coalesce(qs, q);
2350167514Skmacy		}
2351167514Skmacy		break;
2352167514Skmacy	}
2353167514Skmacy	case CHELSIO_GET_QSET_PARAMS: {
2354167514Skmacy		struct qset_params *q;
2355167514Skmacy		struct ch_qset_params *t = (struct ch_qset_params *)data;
2356167514Skmacy
2357167514Skmacy		if (t->qset_idx >= SGE_QSETS)
2358167514Skmacy			return (EINVAL);
2359167514Skmacy
2360167514Skmacy		q = &(sc)->params.sge.qset[t->qset_idx];
2361167514Skmacy		t->rspq_size   = q->rspq_size;
2362167514Skmacy		t->txq_size[0] = q->txq_size[0];
2363167514Skmacy		t->txq_size[1] = q->txq_size[1];
2364167514Skmacy		t->txq_size[2] = q->txq_size[2];
2365167514Skmacy		t->fl_size[0]  = q->fl_size;
2366167514Skmacy		t->fl_size[1]  = q->jumbo_size;
2367167514Skmacy		t->polling     = q->polling;
2368167514Skmacy		t->intr_lat    = q->coalesce_nsecs / 1000;
2369167514Skmacy		t->cong_thres  = q->cong_thres;
2370167514Skmacy		break;
2371167514Skmacy	}
2372167514Skmacy	case CHELSIO_SET_QSET_NUM: {
2373167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
2374171803Skmacy		unsigned int port_idx = pi->port_id;
2375167514Skmacy
2376167514Skmacy		if (sc->flags & FULL_INIT_DONE)
2377167514Skmacy			return (EBUSY);
2378167514Skmacy		if (edata->val < 1 ||
2379167514Skmacy		    (edata->val > 1 && !(sc->flags & USING_MSIX)))
2380167514Skmacy			return (EINVAL);
2381167514Skmacy		if (edata->val + sc->port[!port_idx].nqsets > SGE_QSETS)
2382167514Skmacy			return (EINVAL);
2383167514Skmacy		sc->port[port_idx].nqsets = edata->val;
2384169978Skmacy		sc->port[0].first_qset = 0;
2385167514Skmacy		/*
2386169978Skmacy		 * XXX hardcode ourselves to 2 ports just like LEEENUX
2387167514Skmacy		 */
2388167514Skmacy		sc->port[1].first_qset = sc->port[0].nqsets;
2389167514Skmacy		break;
2390167514Skmacy	}
2391167514Skmacy	case CHELSIO_GET_QSET_NUM: {
2392167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
2393167514Skmacy		edata->val = pi->nqsets;
2394167514Skmacy		break;
2395167514Skmacy	}
2396169978Skmacy#ifdef notyet
2397167514Skmacy	case CHELSIO_LOAD_FW:
2398167514Skmacy	case CHELSIO_GET_PM:
2399167514Skmacy	case CHELSIO_SET_PM:
2400167514Skmacy		return (EOPNOTSUPP);
2401167514Skmacy		break;
2402167514Skmacy#endif
2403169978Skmacy	case CHELSIO_SETMTUTAB: {
2404169978Skmacy		struct ch_mtus *m = (struct ch_mtus *)data;
2405169978Skmacy		int i;
2406169978Skmacy
2407169978Skmacy		if (!is_offload(sc))
2408169978Skmacy			return (EOPNOTSUPP);
2409169978Skmacy		if (offload_running(sc))
2410169978Skmacy			return (EBUSY);
2411169978Skmacy		if (m->nmtus != NMTUS)
2412169978Skmacy			return (EINVAL);
2413169978Skmacy		if (m->mtus[0] < 81)         /* accommodate SACK */
2414169978Skmacy			return (EINVAL);
2415169978Skmacy
2416169978Skmacy		/*
2417169978Skmacy		 * MTUs must be in ascending order
2418169978Skmacy		 */
2419169978Skmacy		for (i = 1; i < NMTUS; ++i)
2420169978Skmacy			if (m->mtus[i] < m->mtus[i - 1])
2421169978Skmacy				return (EINVAL);
2422169978Skmacy
2423169978Skmacy		memcpy(sc->params.mtus, m->mtus,
2424169978Skmacy		       sizeof(sc->params.mtus));
2425169978Skmacy		break;
2426169978Skmacy	}
2427169978Skmacy	case CHELSIO_GETMTUTAB: {
2428169978Skmacy		struct ch_mtus *m = (struct ch_mtus *)data;
2429169978Skmacy
2430169978Skmacy		if (!is_offload(sc))
2431169978Skmacy			return (EOPNOTSUPP);
2432169978Skmacy
2433169978Skmacy		memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus));
2434169978Skmacy		m->nmtus = NMTUS;
2435169978Skmacy		break;
2436171471Skmacy	}
2437169978Skmacy	case CHELSIO_DEVUP:
2438169978Skmacy		if (!is_offload(sc))
2439169978Skmacy			return (EOPNOTSUPP);
2440169978Skmacy		return offload_open(pi);
2441169978Skmacy		break;
2442167514Skmacy	case CHELSIO_GET_MEM: {
2443167514Skmacy		struct ch_mem_range *t = (struct ch_mem_range *)data;
2444167514Skmacy		struct mc7 *mem;
2445167514Skmacy		uint8_t *useraddr;
2446167514Skmacy		u64 buf[32];
2447167514Skmacy
2448167514Skmacy		if (!is_offload(sc))
2449167514Skmacy			return (EOPNOTSUPP);
2450167514Skmacy		if (!(sc->flags & FULL_INIT_DONE))
2451167514Skmacy			return (EIO);         /* need the memory controllers */
2452167514Skmacy		if ((t->addr & 0x7) || (t->len & 0x7))
2453167514Skmacy			return (EINVAL);
2454167514Skmacy		if (t->mem_id == MEM_CM)
2455167514Skmacy			mem = &sc->cm;
2456167514Skmacy		else if (t->mem_id == MEM_PMRX)
2457167514Skmacy			mem = &sc->pmrx;
2458167514Skmacy		else if (t->mem_id == MEM_PMTX)
2459167514Skmacy			mem = &sc->pmtx;
2460167514Skmacy		else
2461167514Skmacy			return (EINVAL);
2462167514Skmacy
2463167514Skmacy		/*
2464167514Skmacy		 * Version scheme:
2465167514Skmacy		 * bits 0..9: chip version
2466167514Skmacy		 * bits 10..15: chip revision
2467167514Skmacy		 */
2468167514Skmacy		t->version = 3 | (sc->params.rev << 10);
2469167514Skmacy
2470167514Skmacy		/*
2471167514Skmacy		 * Read 256 bytes at a time as len can be large and we don't
2472167514Skmacy		 * want to use huge intermediate buffers.
2473167514Skmacy		 */
2474167514Skmacy		useraddr = (uint8_t *)(t + 1);   /* advance to start of buffer */
2475167514Skmacy		while (t->len) {
2476167514Skmacy			unsigned int chunk = min(t->len, sizeof(buf));
2477167514Skmacy
2478167514Skmacy			error = t3_mc7_bd_read(mem, t->addr / 8, chunk / 8, buf);
2479167514Skmacy			if (error)
2480167514Skmacy				return (-error);
2481167514Skmacy			if (copyout(buf, useraddr, chunk))
2482167514Skmacy				return (EFAULT);
2483167514Skmacy			useraddr += chunk;
2484167514Skmacy			t->addr += chunk;
2485167514Skmacy			t->len -= chunk;
2486167514Skmacy		}
2487167514Skmacy		break;
2488167514Skmacy	}
2489169978Skmacy	case CHELSIO_READ_TCAM_WORD: {
2490169978Skmacy		struct ch_tcam_word *t = (struct ch_tcam_word *)data;
2491169978Skmacy
2492169978Skmacy		if (!is_offload(sc))
2493169978Skmacy			return (EOPNOTSUPP);
2494171471Skmacy		if (!(sc->flags & FULL_INIT_DONE))
2495171471Skmacy			return (EIO);         /* need MC5 */
2496169978Skmacy		return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf);
2497169978Skmacy		break;
2498169978Skmacy	}
2499167514Skmacy	case CHELSIO_SET_TRACE_FILTER: {
2500167514Skmacy		struct ch_trace *t = (struct ch_trace *)data;
2501167514Skmacy		const struct trace_params *tp;
2502167514Skmacy
2503167514Skmacy		tp = (const struct trace_params *)&t->sip;
2504167514Skmacy		if (t->config_tx)
2505167514Skmacy			t3_config_trace_filter(sc, tp, 0, t->invert_match,
2506167514Skmacy					       t->trace_tx);
2507167514Skmacy		if (t->config_rx)
2508167514Skmacy			t3_config_trace_filter(sc, tp, 1, t->invert_match,
2509167514Skmacy					       t->trace_rx);
2510167514Skmacy		break;
2511167514Skmacy	}
2512167514Skmacy	case CHELSIO_SET_PKTSCHED: {
2513167514Skmacy		struct ch_pktsched_params *p = (struct ch_pktsched_params *)data;
2514167514Skmacy		if (sc->open_device_map == 0)
2515167514Skmacy			return (EAGAIN);
2516167514Skmacy		send_pktsched_cmd(sc, p->sched, p->idx, p->min, p->max,
2517167514Skmacy		    p->binding);
2518167514Skmacy		break;
2519167514Skmacy	}
2520167514Skmacy	case CHELSIO_IFCONF_GETREGS: {
2521167514Skmacy		struct ifconf_regs *regs = (struct ifconf_regs *)data;
2522167514Skmacy		int reglen = cxgb_get_regs_len();
2523167514Skmacy		uint8_t *buf = malloc(REGDUMP_SIZE, M_DEVBUF, M_NOWAIT);
2524167514Skmacy		if (buf == NULL) {
2525167514Skmacy			return (ENOMEM);
2526167514Skmacy		} if (regs->len > reglen)
2527167514Skmacy			regs->len = reglen;
2528167514Skmacy		else if (regs->len < reglen) {
2529167514Skmacy			error = E2BIG;
2530167514Skmacy			goto done;
2531167514Skmacy		}
2532167514Skmacy		cxgb_get_regs(sc, regs, buf);
2533167514Skmacy		error = copyout(buf, regs->data, reglen);
2534167514Skmacy
2535167514Skmacy		done:
2536167514Skmacy		free(buf, M_DEVBUF);
2537167514Skmacy
2538167514Skmacy		break;
2539167514Skmacy	}
2540169978Skmacy	case CHELSIO_SET_HW_SCHED: {
2541169978Skmacy		struct ch_hw_sched *t = (struct ch_hw_sched *)data;
2542169978Skmacy		unsigned int ticks_per_usec = core_ticks_per_usec(sc);
2543169978Skmacy
2544169978Skmacy		if ((sc->flags & FULL_INIT_DONE) == 0)
2545169978Skmacy			return (EAGAIN);       /* need TP to be initialized */
2546169978Skmacy		if (t->sched >= NTX_SCHED || !in_range(t->mode, 0, 1) ||
2547169978Skmacy		    !in_range(t->channel, 0, 1) ||
2548169978Skmacy		    !in_range(t->kbps, 0, 10000000) ||
2549169978Skmacy		    !in_range(t->class_ipg, 0, 10000 * 65535 / ticks_per_usec) ||
2550169978Skmacy		    !in_range(t->flow_ipg, 0,
2551169978Skmacy			      dack_ticks_to_usec(sc, 0x7ff)))
2552169978Skmacy			return (EINVAL);
2553169978Skmacy
2554169978Skmacy		if (t->kbps >= 0) {
2555169978Skmacy			error = t3_config_sched(sc, t->kbps, t->sched);
2556169978Skmacy			if (error < 0)
2557169978Skmacy				return (-error);
2558169978Skmacy		}
2559169978Skmacy		if (t->class_ipg >= 0)
2560169978Skmacy			t3_set_sched_ipg(sc, t->sched, t->class_ipg);
2561169978Skmacy		if (t->flow_ipg >= 0) {
2562169978Skmacy			t->flow_ipg *= 1000;     /* us -> ns */
2563169978Skmacy			t3_set_pace_tbl(sc, &t->flow_ipg, t->sched, 1);
2564169978Skmacy		}
2565169978Skmacy		if (t->mode >= 0) {
2566169978Skmacy			int bit = 1 << (S_TX_MOD_TIMER_MODE + t->sched);
2567169978Skmacy
2568169978Skmacy			t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2569169978Skmacy					 bit, t->mode ? bit : 0);
2570169978Skmacy		}
2571169978Skmacy		if (t->channel >= 0)
2572169978Skmacy			t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2573169978Skmacy					 1 << t->sched, t->channel << t->sched);
2574169978Skmacy		break;
2575169978Skmacy	}
2576167514Skmacy	default:
2577167514Skmacy		return (EOPNOTSUPP);
2578167514Skmacy		break;
2579167514Skmacy	}
2580167514Skmacy
2581167514Skmacy	return (error);
2582167514Skmacy}
2583167514Skmacy
2584167514Skmacystatic __inline void
2585167514Skmacyreg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
2586167514Skmacy    unsigned int end)
2587167514Skmacy{
2588167514Skmacy	uint32_t *p = (uint32_t *)buf + start;
2589167514Skmacy
2590167514Skmacy	for ( ; start <= end; start += sizeof(uint32_t))
2591167514Skmacy		*p++ = t3_read_reg(ap, start);
2592167514Skmacy}
2593167514Skmacy
2594167514Skmacy#define T3_REGMAP_SIZE (3 * 1024)
2595167514Skmacystatic int
2596167514Skmacycxgb_get_regs_len(void)
2597167514Skmacy{
2598167514Skmacy	return T3_REGMAP_SIZE;
2599167514Skmacy}
2600167514Skmacy#undef T3_REGMAP_SIZE
2601167514Skmacy
2602167514Skmacystatic void
2603167514Skmacycxgb_get_regs(adapter_t *sc, struct ifconf_regs *regs, uint8_t *buf)
2604167514Skmacy{
2605167514Skmacy
2606167514Skmacy	/*
2607167514Skmacy	 * Version scheme:
2608167514Skmacy	 * bits 0..9: chip version
2609167514Skmacy	 * bits 10..15: chip revision
2610167514Skmacy	 * bit 31: set for PCIe cards
2611167514Skmacy	 */
2612167514Skmacy	regs->version = 3 | (sc->params.rev << 10) | (is_pcie(sc) << 31);
2613167514Skmacy
2614167514Skmacy	/*
2615167514Skmacy	 * We skip the MAC statistics registers because they are clear-on-read.
2616167514Skmacy	 * Also reading multi-register stats would need to synchronize with the
2617167514Skmacy	 * periodic mac stats accumulation.  Hard to justify the complexity.
2618167514Skmacy	 */
2619167514Skmacy	memset(buf, 0, REGDUMP_SIZE);
2620167514Skmacy	reg_block_dump(sc, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
2621167514Skmacy	reg_block_dump(sc, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
2622167514Skmacy	reg_block_dump(sc, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
2623167514Skmacy	reg_block_dump(sc, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
2624167514Skmacy	reg_block_dump(sc, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
2625167514Skmacy	reg_block_dump(sc, buf, A_XGM_SERDES_STATUS0,
2626167514Skmacy		       XGM_REG(A_XGM_SERDES_STAT3, 1));
2627167514Skmacy	reg_block_dump(sc, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
2628167514Skmacy		       XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
2629167514Skmacy}
2630