cxgb_main.c revision 183062
1167514Skmacy/**************************************************************************
2167514Skmacy
3178302SkmacyCopyright (c) 2007-2008, Chelsio Inc.
4167514SkmacyAll rights reserved.
5167514Skmacy
6167514SkmacyRedistribution and use in source and binary forms, with or without
7167514Skmacymodification, are permitted provided that the following conditions are met:
8167514Skmacy
9167514Skmacy 1. Redistributions of source code must retain the above copyright notice,
10167514Skmacy    this list of conditions and the following disclaimer.
11167514Skmacy
12178302Skmacy 2. Neither the name of the Chelsio Corporation nor the names of its
13167514Skmacy    contributors may be used to endorse or promote products derived from
14167514Skmacy    this software without specific prior written permission.
15167514Skmacy
16167514SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17167514SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18167514SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19167514SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20167514SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21167514SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22167514SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23167514SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24167514SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25167514SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26167514SkmacyPOSSIBILITY OF SUCH DAMAGE.
27167514Skmacy
28167514Skmacy***************************************************************************/
29167514Skmacy
30167514Skmacy#include <sys/cdefs.h>
31167514Skmacy__FBSDID("$FreeBSD: head/sys/dev/cxgb/cxgb_main.c 183062 2008-09-16 02:03:28Z 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>
43176472Skmacy#include <sys/ktr.h>
44167514Skmacy#include <sys/rman.h>
45167514Skmacy#include <sys/ioccom.h>
46167514Skmacy#include <sys/mbuf.h>
47167514Skmacy#include <sys/linker.h>
48167514Skmacy#include <sys/firmware.h>
49167514Skmacy#include <sys/socket.h>
50167514Skmacy#include <sys/sockio.h>
51167514Skmacy#include <sys/smp.h>
52167514Skmacy#include <sys/sysctl.h>
53174708Skmacy#include <sys/syslog.h>
54167514Skmacy#include <sys/queue.h>
55167514Skmacy#include <sys/taskqueue.h>
56174708Skmacy#include <sys/proc.h>
57167514Skmacy
58167514Skmacy#include <net/bpf.h>
59167514Skmacy#include <net/ethernet.h>
60167514Skmacy#include <net/if.h>
61167514Skmacy#include <net/if_arp.h>
62167514Skmacy#include <net/if_dl.h>
63167514Skmacy#include <net/if_media.h>
64167514Skmacy#include <net/if_types.h>
65180583Skmacy#include <net/if_vlan_var.h>
66167514Skmacy
67167514Skmacy#include <netinet/in_systm.h>
68167514Skmacy#include <netinet/in.h>
69167514Skmacy#include <netinet/if_ether.h>
70167514Skmacy#include <netinet/ip.h>
71167514Skmacy#include <netinet/ip.h>
72167514Skmacy#include <netinet/tcp.h>
73167514Skmacy#include <netinet/udp.h>
74167514Skmacy
75167514Skmacy#include <dev/pci/pcireg.h>
76167514Skmacy#include <dev/pci/pcivar.h>
77167514Skmacy#include <dev/pci/pci_private.h>
78167514Skmacy
79170076Skmacy#ifdef CONFIG_DEFINED
80170076Skmacy#include <cxgb_include.h>
81170076Skmacy#else
82170076Skmacy#include <dev/cxgb/cxgb_include.h>
83170076Skmacy#endif
84167514Skmacy
85167514Skmacy#ifdef PRIV_SUPPORTED
86167514Skmacy#include <sys/priv.h>
87167514Skmacy#endif
88167514Skmacy
89174726Skmacy#ifdef IFNET_MULTIQUEUE
90174708Skmacy#include <machine/intr_machdep.h>
91174726Skmacy#endif
92174708Skmacy
93167514Skmacystatic int cxgb_setup_msix(adapter_t *, int);
94170654Skmacystatic void cxgb_teardown_msix(adapter_t *);
95167514Skmacystatic void cxgb_init(void *);
96167514Skmacystatic void cxgb_init_locked(struct port_info *);
97167734Skmacystatic void cxgb_stop_locked(struct port_info *);
98167514Skmacystatic void cxgb_set_rxmode(struct port_info *);
99167514Skmacystatic int cxgb_ioctl(struct ifnet *, unsigned long, caddr_t);
100167514Skmacystatic int cxgb_media_change(struct ifnet *);
101167514Skmacystatic void cxgb_media_status(struct ifnet *, struct ifmediareq *);
102167514Skmacystatic int setup_sge_qsets(adapter_t *);
103167514Skmacystatic void cxgb_async_intr(void *);
104167514Skmacystatic void cxgb_ext_intr_handler(void *, int);
105170869Skmacystatic void cxgb_tick_handler(void *, int);
106170869Skmacystatic void cxgb_down_locked(struct adapter *sc);
107167514Skmacystatic void cxgb_tick(void *);
108167514Skmacystatic void setup_rss(adapter_t *sc);
109167514Skmacy
110167514Skmacy/* Attachment glue for the PCI controller end of the device.  Each port of
111167514Skmacy * the device is attached separately, as defined later.
112167514Skmacy */
113167514Skmacystatic int cxgb_controller_probe(device_t);
114167514Skmacystatic int cxgb_controller_attach(device_t);
115167514Skmacystatic int cxgb_controller_detach(device_t);
116167514Skmacystatic void cxgb_free(struct adapter *);
117167514Skmacystatic __inline void reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
118167514Skmacy    unsigned int end);
119182679Skmacystatic void cxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf);
120167514Skmacystatic int cxgb_get_regs_len(void);
121169978Skmacystatic int offload_open(struct port_info *pi);
122171978Skmacystatic void touch_bars(device_t dev);
123174626Skmacystatic int offload_close(struct t3cdev *tdev);
124176472Skmacystatic void cxgb_link_start(struct port_info *p);
125167514Skmacy
126167514Skmacystatic device_method_t cxgb_controller_methods[] = {
127167514Skmacy	DEVMETHOD(device_probe,		cxgb_controller_probe),
128167514Skmacy	DEVMETHOD(device_attach,	cxgb_controller_attach),
129167514Skmacy	DEVMETHOD(device_detach,	cxgb_controller_detach),
130167514Skmacy
131167514Skmacy	/* bus interface */
132167514Skmacy	DEVMETHOD(bus_print_child,	bus_generic_print_child),
133167514Skmacy	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
134167514Skmacy
135167514Skmacy	{ 0, 0 }
136167514Skmacy};
137167514Skmacy
138167514Skmacystatic driver_t cxgb_controller_driver = {
139167514Skmacy	"cxgbc",
140167514Skmacy	cxgb_controller_methods,
141167514Skmacy	sizeof(struct adapter)
142167514Skmacy};
143167514Skmacy
144167514Skmacystatic devclass_t	cxgb_controller_devclass;
145167514SkmacyDRIVER_MODULE(cxgbc, pci, cxgb_controller_driver, cxgb_controller_devclass, 0, 0);
146167514Skmacy
147167514Skmacy/*
148167514Skmacy * Attachment glue for the ports.  Attachment is done directly to the
149167514Skmacy * controller device.
150167514Skmacy */
151167514Skmacystatic int cxgb_port_probe(device_t);
152167514Skmacystatic int cxgb_port_attach(device_t);
153167514Skmacystatic int cxgb_port_detach(device_t);
154167514Skmacy
155167514Skmacystatic device_method_t cxgb_port_methods[] = {
156167514Skmacy	DEVMETHOD(device_probe,		cxgb_port_probe),
157167514Skmacy	DEVMETHOD(device_attach,	cxgb_port_attach),
158167514Skmacy	DEVMETHOD(device_detach,	cxgb_port_detach),
159167514Skmacy	{ 0, 0 }
160167514Skmacy};
161167514Skmacy
162167514Skmacystatic driver_t cxgb_port_driver = {
163167514Skmacy	"cxgb",
164167514Skmacy	cxgb_port_methods,
165167514Skmacy	0
166167514Skmacy};
167167514Skmacy
168167514Skmacystatic d_ioctl_t cxgb_extension_ioctl;
169170654Skmacystatic d_open_t cxgb_extension_open;
170170654Skmacystatic d_close_t cxgb_extension_close;
171167514Skmacy
172170654Skmacystatic struct cdevsw cxgb_cdevsw = {
173170654Skmacy       .d_version =    D_VERSION,
174170654Skmacy       .d_flags =      0,
175170654Skmacy       .d_open =       cxgb_extension_open,
176170654Skmacy       .d_close =      cxgb_extension_close,
177170654Skmacy       .d_ioctl =      cxgb_extension_ioctl,
178170654Skmacy       .d_name =       "cxgb",
179170654Skmacy};
180170654Skmacy
181167514Skmacystatic devclass_t	cxgb_port_devclass;
182167514SkmacyDRIVER_MODULE(cxgb, cxgbc, cxgb_port_driver, cxgb_port_devclass, 0, 0);
183167514Skmacy
184167514Skmacy#define SGE_MSIX_COUNT (SGE_QSETS + 1)
185167514Skmacy
186167514Skmacy/*
187167514Skmacy * The driver uses the best interrupt scheme available on a platform in the
188167514Skmacy * order MSI-X, MSI, legacy pin interrupts.  This parameter determines which
189167514Skmacy * of these schemes the driver may consider as follows:
190167514Skmacy *
191167514Skmacy * msi = 2: choose from among all three options
192167514Skmacy * msi = 1 : only consider MSI and pin interrupts
193167514Skmacy * msi = 0: force pin interrupts
194167514Skmacy */
195167760Skmacystatic int msi_allowed = 2;
196170083Skmacy
197167514SkmacyTUNABLE_INT("hw.cxgb.msi_allowed", &msi_allowed);
198167514SkmacySYSCTL_NODE(_hw, OID_AUTO, cxgb, CTLFLAG_RD, 0, "CXGB driver parameters");
199167514SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, msi_allowed, CTLFLAG_RDTUN, &msi_allowed, 0,
200167514Skmacy    "MSI-X, MSI, INTx selector");
201169978Skmacy
202169053Skmacy/*
203169978Skmacy * The driver enables offload as a default.
204169978Skmacy * To disable it, use ofld_disable = 1.
205169053Skmacy */
206169978Skmacystatic int ofld_disable = 0;
207169978SkmacyTUNABLE_INT("hw.cxgb.ofld_disable", &ofld_disable);
208169978SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, ofld_disable, CTLFLAG_RDTUN, &ofld_disable, 0,
209169978Skmacy    "disable ULP offload");
210169978Skmacy
211169978Skmacy/*
212169978Skmacy * The driver uses an auto-queue algorithm by default.
213169978Skmacy * To disable it and force a single queue-set per port, use singleq = 1.
214169978Skmacy */
215174708Skmacystatic int singleq = 0;
216169978SkmacyTUNABLE_INT("hw.cxgb.singleq", &singleq);
217169978SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, singleq, CTLFLAG_RDTUN, &singleq, 0,
218169978Skmacy    "use a single queue-set per port");
219167514Skmacy
220175200Skmacy
221176572Skmacy/*
222176572Skmacy * The driver uses an auto-queue algorithm by default.
223176572Skmacy * To disable it and force a single queue-set per port, use singleq = 1.
224176572Skmacy */
225176572Skmacystatic int force_fw_update = 0;
226176572SkmacyTUNABLE_INT("hw.cxgb.force_fw_update", &force_fw_update);
227176572SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, force_fw_update, CTLFLAG_RDTUN, &force_fw_update, 0,
228176572Skmacy    "update firmware even if up to date");
229175200Skmacy
230183059Skmacyint cxgb_use_16k_clusters = 1;
231175200SkmacyTUNABLE_INT("hw.cxgb.use_16k_clusters", &cxgb_use_16k_clusters);
232175200SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, use_16k_clusters, CTLFLAG_RDTUN,
233175200Skmacy    &cxgb_use_16k_clusters, 0, "use 16kB clusters for the jumbo queue ");
234175200Skmacy
235167514Skmacyenum {
236167514Skmacy	MAX_TXQ_ENTRIES      = 16384,
237167514Skmacy	MAX_CTRL_TXQ_ENTRIES = 1024,
238167514Skmacy	MAX_RSPQ_ENTRIES     = 16384,
239167514Skmacy	MAX_RX_BUFFERS       = 16384,
240167514Skmacy	MAX_RX_JUMBO_BUFFERS = 16384,
241167514Skmacy	MIN_TXQ_ENTRIES      = 4,
242167514Skmacy	MIN_CTRL_TXQ_ENTRIES = 4,
243167514Skmacy	MIN_RSPQ_ENTRIES     = 32,
244172096Skmacy	MIN_FL_ENTRIES       = 32,
245172096Skmacy	MIN_FL_JUMBO_ENTRIES = 32
246167514Skmacy};
247167514Skmacy
248171471Skmacystruct filter_info {
249171471Skmacy	u32 sip;
250171471Skmacy	u32 sip_mask;
251171471Skmacy	u32 dip;
252171471Skmacy	u16 sport;
253171471Skmacy	u16 dport;
254171471Skmacy	u32 vlan:12;
255171471Skmacy	u32 vlan_prio:3;
256171471Skmacy	u32 mac_hit:1;
257171471Skmacy	u32 mac_idx:4;
258171471Skmacy	u32 mac_vld:1;
259171471Skmacy	u32 pkt_type:2;
260171471Skmacy	u32 report_filter_id:1;
261171471Skmacy	u32 pass:1;
262171471Skmacy	u32 rss:1;
263171471Skmacy	u32 qset:3;
264171471Skmacy	u32 locked:1;
265171471Skmacy	u32 valid:1;
266171471Skmacy};
267171471Skmacy
268171471Skmacyenum { FILTER_NO_VLAN_PRI = 7 };
269171471Skmacy
270182679Skmacy#define EEPROM_MAGIC 0x38E2F10C
271182679Skmacy
272167514Skmacy#define PORT_MASK ((1 << MAX_NPORTS) - 1)
273167514Skmacy
274167514Skmacy/* Table for probing the cards.  The desc field isn't actually used */
275167514Skmacystruct cxgb_ident {
276167514Skmacy	uint16_t	vendor;
277167514Skmacy	uint16_t	device;
278167514Skmacy	int		index;
279167514Skmacy	char		*desc;
280167514Skmacy} cxgb_identifiers[] = {
281167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0020, 0, "PE9000"},
282167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0021, 1, "T302E"},
283167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0022, 2, "T310E"},
284167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0023, 3, "T320X"},
285167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0024, 1, "T302X"},
286167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0025, 3, "T320E"},
287167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0026, 2, "T310X"},
288167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0030, 2, "T3B10"},
289167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0031, 3, "T3B20"},
290167514Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0032, 1, "T3B02"},
291170654Skmacy	{PCI_VENDOR_ID_CHELSIO, 0x0033, 4, "T3B04"},
292167514Skmacy	{0, 0, 0, NULL}
293167514Skmacy};
294167514Skmacy
295171471Skmacystatic int set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset);
296171471Skmacy
297176472Skmacy
298174708Skmacystatic __inline char
299171471Skmacyt3rev2char(struct adapter *adapter)
300171471Skmacy{
301171471Skmacy	char rev = 'z';
302171471Skmacy
303171471Skmacy	switch(adapter->params.rev) {
304171471Skmacy	case T3_REV_A:
305171471Skmacy		rev = 'a';
306171471Skmacy		break;
307171471Skmacy	case T3_REV_B:
308171471Skmacy	case T3_REV_B2:
309171471Skmacy		rev = 'b';
310171471Skmacy		break;
311171471Skmacy	case T3_REV_C:
312171471Skmacy		rev = 'c';
313171471Skmacy		break;
314171471Skmacy	}
315171471Skmacy	return rev;
316171471Skmacy}
317171471Skmacy
318167514Skmacystatic struct cxgb_ident *
319167514Skmacycxgb_get_ident(device_t dev)
320167514Skmacy{
321167514Skmacy	struct cxgb_ident *id;
322167514Skmacy
323167514Skmacy	for (id = cxgb_identifiers; id->desc != NULL; id++) {
324167514Skmacy		if ((id->vendor == pci_get_vendor(dev)) &&
325167514Skmacy		    (id->device == pci_get_device(dev))) {
326167514Skmacy			return (id);
327167514Skmacy		}
328167514Skmacy	}
329167514Skmacy	return (NULL);
330167514Skmacy}
331167514Skmacy
332167514Skmacystatic const struct adapter_info *
333167514Skmacycxgb_get_adapter_info(device_t dev)
334167514Skmacy{
335167514Skmacy	struct cxgb_ident *id;
336167514Skmacy	const struct adapter_info *ai;
337167514Skmacy
338167514Skmacy	id = cxgb_get_ident(dev);
339167514Skmacy	if (id == NULL)
340167514Skmacy		return (NULL);
341167514Skmacy
342167514Skmacy	ai = t3_get_adapter_info(id->index);
343167514Skmacy
344167514Skmacy	return (ai);
345167514Skmacy}
346167514Skmacy
347167514Skmacystatic int
348167514Skmacycxgb_controller_probe(device_t dev)
349167514Skmacy{
350167514Skmacy	const struct adapter_info *ai;
351167514Skmacy	char *ports, buf[80];
352170654Skmacy	int nports;
353182695Skmacy	struct adapter *sc = device_get_softc(dev);
354170654Skmacy
355167514Skmacy	ai = cxgb_get_adapter_info(dev);
356167514Skmacy	if (ai == NULL)
357167514Skmacy		return (ENXIO);
358167514Skmacy
359170654Skmacy	nports = ai->nports0 + ai->nports1;
360170654Skmacy	if (nports == 1)
361167514Skmacy		ports = "port";
362167514Skmacy	else
363167514Skmacy		ports = "ports";
364167514Skmacy
365182695Skmacy	snprintf(buf, sizeof(buf), "%s %sNIC, rev: %d nports: %d %s",
366182695Skmacy	    ai->desc, is_offload(sc) ? "R" : "",
367182695Skmacy	    sc->params.rev, nports, ports);
368167514Skmacy	device_set_desc_copy(dev, buf);
369167514Skmacy	return (BUS_PROBE_DEFAULT);
370167514Skmacy}
371167514Skmacy
372176572Skmacy#define FW_FNAME "cxgb_t3fw"
373176613Skmacy#define TPEEPROM_NAME "t3b_tp_eeprom"
374176613Skmacy#define TPSRAM_NAME "t3b_protocol_sram"
375171471Skmacy
376167514Skmacystatic int
377169978Skmacyupgrade_fw(adapter_t *sc)
378167514Skmacy{
379167514Skmacy#ifdef FIRMWARE_LATEST
380167514Skmacy	const struct firmware *fw;
381167514Skmacy#else
382167514Skmacy	struct firmware *fw;
383167514Skmacy#endif
384167514Skmacy	int status;
385167514Skmacy
386176572Skmacy	if ((fw = firmware_get(FW_FNAME)) == NULL)  {
387176572Skmacy		device_printf(sc->dev, "Could not find firmware image %s\n", FW_FNAME);
388169978Skmacy		return (ENOENT);
389171471Skmacy	} else
390176572Skmacy		device_printf(sc->dev, "updating firmware on card\n");
391167514Skmacy	status = t3_load_fw(sc, (const uint8_t *)fw->data, fw->datasize);
392167514Skmacy
393171471Skmacy	device_printf(sc->dev, "firmware update returned %s %d\n", (status == 0) ? "success" : "fail", status);
394171471Skmacy
395167514Skmacy	firmware_put(fw, FIRMWARE_UNLOAD);
396167514Skmacy
397167514Skmacy	return (status);
398167514Skmacy}
399167514Skmacy
400167514Skmacystatic int
401167514Skmacycxgb_controller_attach(device_t dev)
402167514Skmacy{
403167514Skmacy	device_t child;
404167514Skmacy	const struct adapter_info *ai;
405167514Skmacy	struct adapter *sc;
406172109Skmacy	int i, error = 0;
407167514Skmacy	uint32_t vers;
408167760Skmacy	int port_qsets = 1;
409171868Skmacy#ifdef MSI_SUPPORTED
410172109Skmacy	int msi_needed, reg;
411176472Skmacy#endif
412176472Skmacy	int must_load = 0;
413167514Skmacy	sc = device_get_softc(dev);
414167514Skmacy	sc->dev = dev;
415169978Skmacy	sc->msi_count = 0;
416172109Skmacy	ai = cxgb_get_adapter_info(dev);
417172109Skmacy
418172109Skmacy	/*
419172109Skmacy	 * XXX not really related but a recent addition
420172109Skmacy	 */
421172109Skmacy#ifdef MSI_SUPPORTED
422167840Skmacy	/* find the PCIe link width and set max read request to 4KB*/
423167840Skmacy	if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 0) {
424167840Skmacy		uint16_t lnk, pectl;
425167840Skmacy		lnk = pci_read_config(dev, reg + 0x12, 2);
426167840Skmacy		sc->link_width = (lnk >> 4) & 0x3f;
427167840Skmacy
428167840Skmacy		pectl = pci_read_config(dev, reg + 0x8, 2);
429167840Skmacy		pectl = (pectl & ~0x7000) | (5 << 12);
430167840Skmacy		pci_write_config(dev, reg + 0x8, pectl, 2);
431167840Skmacy	}
432171471Skmacy
433171471Skmacy	if (sc->link_width != 0 && sc->link_width <= 4 &&
434171471Skmacy	    (ai->nports0 + ai->nports1) <= 2) {
435167840Skmacy		device_printf(sc->dev,
436167862Skmacy		    "PCIe x%d Link, expect reduced performance\n",
437167840Skmacy		    sc->link_width);
438167840Skmacy	}
439172109Skmacy#endif
440171978Skmacy	touch_bars(dev);
441167514Skmacy	pci_enable_busmaster(dev);
442167514Skmacy	/*
443167514Skmacy	 * Allocate the registers and make them available to the driver.
444167514Skmacy	 * The registers that we care about for NIC mode are in BAR 0
445167514Skmacy	 */
446167514Skmacy	sc->regs_rid = PCIR_BAR(0);
447167514Skmacy	if ((sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
448167514Skmacy	    &sc->regs_rid, RF_ACTIVE)) == NULL) {
449176472Skmacy		device_printf(dev, "Cannot allocate BAR region 0\n");
450167514Skmacy		return (ENXIO);
451167514Skmacy	}
452176472Skmacy	sc->udbs_rid = PCIR_BAR(2);
453176472Skmacy	if ((sc->udbs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
454176472Skmacy           &sc->udbs_rid, RF_ACTIVE)) == NULL) {
455176472Skmacy		device_printf(dev, "Cannot allocate BAR region 1\n");
456176472Skmacy		error = ENXIO;
457176472Skmacy		goto out;
458176472Skmacy       }
459167514Skmacy
460170869Skmacy	snprintf(sc->lockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb controller lock %d",
461170869Skmacy	    device_get_unit(dev));
462170869Skmacy	ADAPTER_LOCK_INIT(sc, sc->lockbuf);
463170869Skmacy
464170869Skmacy	snprintf(sc->reglockbuf, ADAPTER_LOCK_NAME_LEN, "SGE reg lock %d",
465170869Skmacy	    device_get_unit(dev));
466170869Skmacy	snprintf(sc->mdiolockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb mdio lock %d",
467170869Skmacy	    device_get_unit(dev));
468170869Skmacy	snprintf(sc->elmerlockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb elmer lock %d",
469170869Skmacy	    device_get_unit(dev));
470167514Skmacy
471176472Skmacy	MTX_INIT(&sc->sge.reg_lock, sc->reglockbuf, NULL, MTX_SPIN);
472170869Skmacy	MTX_INIT(&sc->mdio_lock, sc->mdiolockbuf, NULL, MTX_DEF);
473170869Skmacy	MTX_INIT(&sc->elmer_lock, sc->elmerlockbuf, NULL, MTX_DEF);
474170869Skmacy
475167514Skmacy	sc->bt = rman_get_bustag(sc->regs_res);
476167514Skmacy	sc->bh = rman_get_bushandle(sc->regs_res);
477167514Skmacy	sc->mmio_len = rman_get_size(sc->regs_res);
478167769Skmacy
479167769Skmacy	if (t3_prep_adapter(sc, ai, 1) < 0) {
480170654Skmacy		printf("prep adapter failed\n");
481167769Skmacy		error = ENODEV;
482167769Skmacy		goto out;
483167769Skmacy	}
484177464Skmacy        /* Allocate the BAR for doing MSI-X.  If it succeeds, try to allocate
485167514Skmacy	 * enough messages for the queue sets.  If that fails, try falling
486167514Skmacy	 * back to MSI.  If that fails, then try falling back to the legacy
487167514Skmacy	 * interrupt pin model.
488167514Skmacy	 */
489167514Skmacy#ifdef MSI_SUPPORTED
490167760Skmacy
491167514Skmacy	sc->msix_regs_rid = 0x20;
492167514Skmacy	if ((msi_allowed >= 2) &&
493167514Skmacy	    (sc->msix_regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
494167514Skmacy	    &sc->msix_regs_rid, RF_ACTIVE)) != NULL) {
495167514Skmacy
496169978Skmacy		msi_needed = sc->msi_count = SGE_MSIX_COUNT;
497167760Skmacy
498169978Skmacy		if (((error = pci_alloc_msix(dev, &sc->msi_count)) != 0) ||
499169978Skmacy		    (sc->msi_count != msi_needed)) {
500169978Skmacy			device_printf(dev, "msix allocation failed - msi_count = %d"
501169978Skmacy			    " msi_needed=%d will try msi err=%d\n", sc->msi_count,
502169978Skmacy			    msi_needed, error);
503169978Skmacy			sc->msi_count = 0;
504167514Skmacy			pci_release_msi(dev);
505167514Skmacy			bus_release_resource(dev, SYS_RES_MEMORY,
506167514Skmacy			    sc->msix_regs_rid, sc->msix_regs_res);
507167514Skmacy			sc->msix_regs_res = NULL;
508167514Skmacy		} else {
509167514Skmacy			sc->flags |= USING_MSIX;
510170081Skmacy			sc->cxgb_intr = t3_intr_msix;
511167514Skmacy		}
512167514Skmacy	}
513167514Skmacy
514169978Skmacy	if ((msi_allowed >= 1) && (sc->msi_count == 0)) {
515169978Skmacy		sc->msi_count = 1;
516169978Skmacy		if (pci_alloc_msi(dev, &sc->msi_count)) {
517167760Skmacy			device_printf(dev, "alloc msi failed - will try INTx\n");
518169978Skmacy			sc->msi_count = 0;
519167514Skmacy			pci_release_msi(dev);
520167514Skmacy		} else {
521167514Skmacy			sc->flags |= USING_MSI;
522167514Skmacy			sc->irq_rid = 1;
523170081Skmacy			sc->cxgb_intr = t3_intr_msi;
524167514Skmacy		}
525167514Skmacy	}
526167514Skmacy#endif
527169978Skmacy	if (sc->msi_count == 0) {
528167760Skmacy		device_printf(dev, "using line interrupts\n");
529167514Skmacy		sc->irq_rid = 0;
530170081Skmacy		sc->cxgb_intr = t3b_intr;
531167514Skmacy	}
532167514Skmacy
533177464Skmacy	if ((sc->flags & USING_MSIX) && !singleq)
534177464Skmacy		port_qsets = min((SGE_QSETS/(sc)->params.nports), mp_ncpus);
535177464Skmacy
536167514Skmacy	/* Create a private taskqueue thread for handling driver events */
537167514Skmacy#ifdef TASKQUEUE_CURRENT
538167514Skmacy	sc->tq = taskqueue_create("cxgb_taskq", M_NOWAIT,
539167514Skmacy	    taskqueue_thread_enqueue, &sc->tq);
540167514Skmacy#else
541167514Skmacy	sc->tq = taskqueue_create_fast("cxgb_taskq", M_NOWAIT,
542167514Skmacy	    taskqueue_thread_enqueue, &sc->tq);
543167514Skmacy#endif
544167514Skmacy	if (sc->tq == NULL) {
545167514Skmacy		device_printf(dev, "failed to allocate controller task queue\n");
546167514Skmacy		goto out;
547167514Skmacy	}
548171804Skmacy
549167514Skmacy	taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq",
550167514Skmacy	    device_get_nameunit(dev));
551167514Skmacy	TASK_INIT(&sc->ext_intr_task, 0, cxgb_ext_intr_handler, sc);
552170869Skmacy	TASK_INIT(&sc->tick_task, 0, cxgb_tick_handler, sc);
553167514Skmacy
554167514Skmacy
555167514Skmacy	/* Create a periodic callout for checking adapter status */
556170869Skmacy	callout_init(&sc->cxgb_tick_ch, TRUE);
557167514Skmacy
558176572Skmacy	if ((t3_check_fw_version(sc, &must_load) != 0 && must_load) || force_fw_update) {
559167514Skmacy		/*
560167514Skmacy		 * Warn user that a firmware update will be attempted in init.
561167514Skmacy		 */
562169978Skmacy		device_printf(dev, "firmware needs to be updated to version %d.%d.%d\n",
563169978Skmacy		    FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
564167514Skmacy		sc->flags &= ~FW_UPTODATE;
565167514Skmacy	} else {
566167514Skmacy		sc->flags |= FW_UPTODATE;
567167514Skmacy	}
568171471Skmacy
569176472Skmacy	if (t3_check_tpsram_version(sc, &must_load) != 0 && must_load) {
570171471Skmacy		/*
571171471Skmacy		 * Warn user that a firmware update will be attempted in init.
572171471Skmacy		 */
573171471Skmacy		device_printf(dev, "SRAM needs to be updated to version %c-%d.%d.%d\n",
574171471Skmacy		    t3rev2char(sc), TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
575171471Skmacy		sc->flags &= ~TPS_UPTODATE;
576171471Skmacy	} else {
577171471Skmacy		sc->flags |= TPS_UPTODATE;
578171471Skmacy	}
579167514Skmacy
580167514Skmacy	/*
581167514Skmacy	 * Create a child device for each MAC.  The ethernet attachment
582167514Skmacy	 * will be done in these children.
583167760Skmacy	 */
584167760Skmacy	for (i = 0; i < (sc)->params.nports; i++) {
585171978Skmacy		struct port_info *pi;
586171978Skmacy
587167514Skmacy		if ((child = device_add_child(dev, "cxgb", -1)) == NULL) {
588167514Skmacy			device_printf(dev, "failed to add child port\n");
589167514Skmacy			error = EINVAL;
590167514Skmacy			goto out;
591167514Skmacy		}
592171978Skmacy		pi = &sc->port[i];
593171978Skmacy		pi->adapter = sc;
594171978Skmacy		pi->nqsets = port_qsets;
595171978Skmacy		pi->first_qset = i*port_qsets;
596171978Skmacy		pi->port_id = i;
597171978Skmacy		pi->tx_chan = i >= ai->nports0;
598171978Skmacy		pi->txpkt_intf = pi->tx_chan ? 2 * (i - ai->nports0) + 1 : 2 * i;
599171978Skmacy		sc->rxpkt_map[pi->txpkt_intf] = i;
600174708Skmacy		sc->port[i].tx_chan = i >= ai->nports0;
601171471Skmacy		sc->portdev[i] = child;
602171978Skmacy		device_set_softc(child, pi);
603167514Skmacy	}
604167514Skmacy	if ((error = bus_generic_attach(dev)) != 0)
605167514Skmacy		goto out;
606167514Skmacy
607167514Skmacy	/* initialize sge private state */
608170654Skmacy	t3_sge_init_adapter(sc);
609167514Skmacy
610167514Skmacy	t3_led_ready(sc);
611169978Skmacy
612169978Skmacy	cxgb_offload_init();
613169978Skmacy	if (is_offload(sc)) {
614169978Skmacy		setbit(&sc->registered_device_map, OFFLOAD_DEVMAP_BIT);
615169978Skmacy		cxgb_adapter_ofld(sc);
616169978Skmacy        }
617167514Skmacy	error = t3_get_fw_version(sc, &vers);
618167514Skmacy	if (error)
619167514Skmacy		goto out;
620167514Skmacy
621169978Skmacy	snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d.%d",
622169978Skmacy	    G_FW_VERSION_MAJOR(vers), G_FW_VERSION_MINOR(vers),
623169978Skmacy	    G_FW_VERSION_MICRO(vers));
624169978Skmacy
625176472Skmacy	device_printf(sc->dev, "Firmware Version %s\n", &sc->fw_version[0]);
626181652Skmacy	callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc);
627174708Skmacy	t3_add_attach_sysctls(sc);
628167514Skmacyout:
629167514Skmacy	if (error)
630167514Skmacy		cxgb_free(sc);
631167514Skmacy
632167514Skmacy	return (error);
633167514Skmacy}
634167514Skmacy
635167514Skmacystatic int
636167514Skmacycxgb_controller_detach(device_t dev)
637167514Skmacy{
638167514Skmacy	struct adapter *sc;
639167514Skmacy
640167514Skmacy	sc = device_get_softc(dev);
641167514Skmacy
642167514Skmacy	cxgb_free(sc);
643167514Skmacy
644167514Skmacy	return (0);
645167514Skmacy}
646167514Skmacy
647167514Skmacystatic void
648167514Skmacycxgb_free(struct adapter *sc)
649167514Skmacy{
650167514Skmacy	int i;
651167514Skmacy
652176472Skmacy	ADAPTER_LOCK(sc);
653176472Skmacy	sc->flags |= CXGB_SHUTDOWN;
654176472Skmacy	ADAPTER_UNLOCK(sc);
655174708Skmacy	cxgb_pcpu_shutdown_threads(sc);
656170869Skmacy	ADAPTER_LOCK(sc);
657176472Skmacy
658174708Skmacy/*
659174708Skmacy * drops the lock
660174708Skmacy */
661170869Skmacy	cxgb_down_locked(sc);
662169978Skmacy
663169978Skmacy#ifdef MSI_SUPPORTED
664169978Skmacy	if (sc->flags & (USING_MSI | USING_MSIX)) {
665169978Skmacy		device_printf(sc->dev, "releasing msi message(s)\n");
666169978Skmacy		pci_release_msi(sc->dev);
667169978Skmacy	} else {
668169978Skmacy		device_printf(sc->dev, "no msi message to release\n");
669169978Skmacy	}
670169978Skmacy#endif
671169978Skmacy	if (sc->msix_regs_res != NULL) {
672169978Skmacy		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid,
673169978Skmacy		    sc->msix_regs_res);
674169978Skmacy	}
675176472Skmacy
676171978Skmacy	t3_sge_deinit_sw(sc);
677171978Skmacy	/*
678171978Skmacy	 * Wait for last callout
679171978Skmacy	 */
680171978Skmacy
681174708Skmacy	DELAY(hz*100);
682170869Skmacy
683167760Skmacy	for (i = 0; i < (sc)->params.nports; ++i) {
684167760Skmacy		if (sc->portdev[i] != NULL)
685167760Skmacy			device_delete_child(sc->dev, sc->portdev[i]);
686167760Skmacy	}
687167760Skmacy
688167514Skmacy	bus_generic_detach(sc->dev);
689176472Skmacy	if (sc->tq != NULL) {
690171978Skmacy		taskqueue_free(sc->tq);
691176472Skmacy		sc->tq = NULL;
692176472Skmacy	}
693176472Skmacy
694169978Skmacy	if (is_offload(sc)) {
695169978Skmacy		cxgb_adapter_unofld(sc);
696169978Skmacy		if (isset(&sc->open_device_map,	OFFLOAD_DEVMAP_BIT))
697169978Skmacy			offload_close(&sc->tdev);
698174708Skmacy		else
699174708Skmacy			printf("cxgb_free: DEVMAP_BIT not set\n");
700174708Skmacy	} else
701174708Skmacy		printf("not offloading set\n");
702183059Skmacy#ifdef notyet
703176472Skmacy	if (sc->flags & CXGB_OFLD_INIT)
704176472Skmacy		cxgb_offload_deactivate(sc);
705178302Skmacy#endif
706171471Skmacy	free(sc->filters, M_DEVBUF);
707167514Skmacy	t3_sge_free(sc);
708170869Skmacy
709170869Skmacy	cxgb_offload_exit();
710176472Skmacy
711176472Skmacy	if (sc->udbs_res != NULL)
712176472Skmacy		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->udbs_rid,
713176472Skmacy		    sc->udbs_res);
714176472Skmacy
715167514Skmacy	if (sc->regs_res != NULL)
716167514Skmacy		bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->regs_rid,
717167514Skmacy		    sc->regs_res);
718167514Skmacy
719170869Skmacy	MTX_DESTROY(&sc->mdio_lock);
720170869Skmacy	MTX_DESTROY(&sc->sge.reg_lock);
721170869Skmacy	MTX_DESTROY(&sc->elmer_lock);
722170869Skmacy	ADAPTER_LOCK_DEINIT(sc);
723167514Skmacy}
724167514Skmacy
725167514Skmacy/**
726167514Skmacy *	setup_sge_qsets - configure SGE Tx/Rx/response queues
727167514Skmacy *	@sc: the controller softc
728167514Skmacy *
729167514Skmacy *	Determines how many sets of SGE queues to use and initializes them.
730167514Skmacy *	We support multiple queue sets per port if we have MSI-X, otherwise
731167514Skmacy *	just one queue set per port.
732167514Skmacy */
733167514Skmacystatic int
734167514Skmacysetup_sge_qsets(adapter_t *sc)
735167514Skmacy{
736172096Skmacy	int i, j, err, irq_idx = 0, qset_idx = 0;
737169978Skmacy	u_int ntxq = SGE_TXQ_PER_SET;
738167514Skmacy
739167514Skmacy	if ((err = t3_sge_alloc(sc)) != 0) {
740167760Skmacy		device_printf(sc->dev, "t3_sge_alloc returned %d\n", err);
741167514Skmacy		return (err);
742167514Skmacy	}
743167514Skmacy
744167514Skmacy	if (sc->params.rev > 0 && !(sc->flags & USING_MSI))
745167514Skmacy		irq_idx = -1;
746167514Skmacy
747172096Skmacy	for (i = 0; i < (sc)->params.nports; i++) {
748167514Skmacy		struct port_info *pi = &sc->port[i];
749167514Skmacy
750171978Skmacy		for (j = 0; j < pi->nqsets; j++, qset_idx++) {
751167760Skmacy			err = t3_sge_alloc_qset(sc, qset_idx, (sc)->params.nports,
752167514Skmacy			    (sc->flags & USING_MSIX) ? qset_idx + 1 : irq_idx,
753167514Skmacy			    &sc->params.sge.qset[qset_idx], ntxq, pi);
754167514Skmacy			if (err) {
755167514Skmacy				t3_free_sge_resources(sc);
756171978Skmacy				device_printf(sc->dev, "t3_sge_alloc_qset failed with %d\n",
757171978Skmacy				    err);
758167514Skmacy				return (err);
759167514Skmacy			}
760167514Skmacy		}
761167514Skmacy	}
762167514Skmacy
763167514Skmacy	return (0);
764167514Skmacy}
765167514Skmacy
766170654Skmacystatic void
767170654Skmacycxgb_teardown_msix(adapter_t *sc)
768170654Skmacy{
769170654Skmacy	int i, nqsets;
770170654Skmacy
771170654Skmacy	for (nqsets = i = 0; i < (sc)->params.nports; i++)
772170654Skmacy		nqsets += sc->port[i].nqsets;
773170654Skmacy
774170654Skmacy	for (i = 0; i < nqsets; i++) {
775170654Skmacy		if (sc->msix_intr_tag[i] != NULL) {
776170654Skmacy			bus_teardown_intr(sc->dev, sc->msix_irq_res[i],
777170654Skmacy			    sc->msix_intr_tag[i]);
778170654Skmacy			sc->msix_intr_tag[i] = NULL;
779170654Skmacy		}
780170654Skmacy		if (sc->msix_irq_res[i] != NULL) {
781170654Skmacy			bus_release_resource(sc->dev, SYS_RES_IRQ,
782170654Skmacy			    sc->msix_irq_rid[i], sc->msix_irq_res[i]);
783170654Skmacy			sc->msix_irq_res[i] = NULL;
784170654Skmacy		}
785170654Skmacy	}
786170654Skmacy}
787170654Skmacy
788167514Skmacystatic int
789167514Skmacycxgb_setup_msix(adapter_t *sc, int msix_count)
790167514Skmacy{
791167514Skmacy	int i, j, k, nqsets, rid;
792167514Skmacy
793167514Skmacy	/* The first message indicates link changes and error conditions */
794167514Skmacy	sc->irq_rid = 1;
795167514Skmacy	if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
796167514Skmacy	   &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
797167514Skmacy		device_printf(sc->dev, "Cannot allocate msix interrupt\n");
798167514Skmacy		return (EINVAL);
799167514Skmacy	}
800167760Skmacy
801167514Skmacy	if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET,
802167514Skmacy#ifdef INTR_FILTERS
803171978Skmacy		NULL,
804167514Skmacy#endif
805167514Skmacy		cxgb_async_intr, sc, &sc->intr_tag)) {
806167514Skmacy		device_printf(sc->dev, "Cannot set up interrupt\n");
807167514Skmacy		return (EINVAL);
808167514Skmacy	}
809170654Skmacy	for (i = k = 0; i < (sc)->params.nports; i++) {
810167514Skmacy		nqsets = sc->port[i].nqsets;
811170654Skmacy		for (j = 0; j < nqsets; j++, k++) {
812167514Skmacy			struct sge_qset *qs = &sc->sge.qs[k];
813171804Skmacy
814167514Skmacy			rid = k + 2;
815167514Skmacy			if (cxgb_debug)
816167514Skmacy				printf("rid=%d ", rid);
817167514Skmacy			if ((sc->msix_irq_res[k] = bus_alloc_resource_any(
818167514Skmacy			    sc->dev, SYS_RES_IRQ, &rid,
819167514Skmacy			    RF_SHAREABLE | RF_ACTIVE)) == NULL) {
820167514Skmacy				device_printf(sc->dev, "Cannot allocate "
821167514Skmacy				    "interrupt for message %d\n", rid);
822167514Skmacy				return (EINVAL);
823167514Skmacy			}
824167514Skmacy			sc->msix_irq_rid[k] = rid;
825170654Skmacy			if (bus_setup_intr(sc->dev, sc->msix_irq_res[k],
826174708Skmacy				INTR_MPSAFE|INTR_TYPE_NET,
827167514Skmacy#ifdef INTR_FILTERS
828171978Skmacy				NULL,
829167514Skmacy#endif
830167514Skmacy				t3_intr_msix, qs, &sc->msix_intr_tag[k])) {
831167514Skmacy				device_printf(sc->dev, "Cannot set up "
832167514Skmacy				    "interrupt for message %d\n", rid);
833167514Skmacy				return (EINVAL);
834167514Skmacy			}
835174708Skmacy#ifdef IFNET_MULTIQUEUE
836174708Skmacy			if (singleq == 0) {
837174708Skmacy				int vector = rman_get_start(sc->msix_irq_res[k]);
838174708Skmacy				if (bootverbose)
839174708Skmacy					device_printf(sc->dev, "binding vector=%d to cpu=%d\n", vector, k % mp_ncpus);
840174708Skmacy				intr_bind(vector, k % mp_ncpus);
841174708Skmacy			}
842174708Skmacy#endif
843167514Skmacy		}
844167514Skmacy	}
845167760Skmacy
846167514Skmacy	return (0);
847167514Skmacy}
848167514Skmacy
849167514Skmacystatic int
850167514Skmacycxgb_port_probe(device_t dev)
851167514Skmacy{
852167514Skmacy	struct port_info *p;
853167514Skmacy	char buf[80];
854176472Skmacy	const char *desc;
855176472Skmacy
856167514Skmacy	p = device_get_softc(dev);
857176472Skmacy	desc = p->phy.desc;
858176472Skmacy	snprintf(buf, sizeof(buf), "Port %d %s", p->port_id, desc);
859167514Skmacy	device_set_desc_copy(dev, buf);
860167514Skmacy	return (0);
861167514Skmacy}
862167514Skmacy
863167514Skmacy
864167514Skmacystatic int
865167514Skmacycxgb_makedev(struct port_info *pi)
866167514Skmacy{
867167514Skmacy
868170654Skmacy	pi->port_cdev = make_dev(&cxgb_cdevsw, pi->ifp->if_dunit,
869170654Skmacy	    UID_ROOT, GID_WHEEL, 0600, if_name(pi->ifp));
870167514Skmacy
871167514Skmacy	if (pi->port_cdev == NULL)
872167514Skmacy		return (ENOMEM);
873167514Skmacy
874167514Skmacy	pi->port_cdev->si_drv1 = (void *)pi;
875167514Skmacy
876167514Skmacy	return (0);
877167514Skmacy}
878167514Skmacy
879167514Skmacy
880167514Skmacy#ifdef TSO_SUPPORTED
881181616Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO)
882167514Skmacy/* Don't enable TSO6 yet */
883181616Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO4 | IFCAP_JUMBO_MTU | IFCAP_LRO)
884167514Skmacy#else
885167514Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU)
886167514Skmacy/* Don't enable TSO6 yet */
887167514Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM |  IFCAP_JUMBO_MTU)
888167514Skmacy#define IFCAP_TSO4 0x0
889171868Skmacy#define IFCAP_TSO6 0x0
890167514Skmacy#define CSUM_TSO   0x0
891167514Skmacy#endif
892167514Skmacy
893167514Skmacy
894167514Skmacystatic int
895167514Skmacycxgb_port_attach(device_t dev)
896167514Skmacy{
897167514Skmacy	struct port_info *p;
898167514Skmacy	struct ifnet *ifp;
899170654Skmacy	int err, media_flags;
900176472Skmacy	struct adapter *sc;
901167514Skmacy
902176472Skmacy
903167514Skmacy	p = device_get_softc(dev);
904176472Skmacy	sc = p->adapter;
905170869Skmacy	snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d",
906171803Skmacy	    device_get_unit(device_get_parent(dev)), p->port_id);
907170869Skmacy	PORT_LOCK_INIT(p, p->lockbuf);
908167514Skmacy
909167514Skmacy	/* Allocate an ifnet object and set it up */
910167514Skmacy	ifp = p->ifp = if_alloc(IFT_ETHER);
911167514Skmacy	if (ifp == NULL) {
912167514Skmacy		device_printf(dev, "Cannot allocate ifnet\n");
913167514Skmacy		return (ENOMEM);
914167514Skmacy	}
915167514Skmacy
916167514Skmacy	/*
917167514Skmacy	 * Note that there is currently no watchdog timer.
918167514Skmacy	 */
919167514Skmacy	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
920167514Skmacy	ifp->if_init = cxgb_init;
921167514Skmacy	ifp->if_softc = p;
922167514Skmacy	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
923167514Skmacy	ifp->if_ioctl = cxgb_ioctl;
924167514Skmacy	ifp->if_start = cxgb_start;
925174708Skmacy
926176472Skmacy#if 0
927174708Skmacy#ifdef IFNET_MULTIQUEUE
928174708Skmacy	ifp->if_flags |= IFF_MULTIQ;
929174708Skmacy	ifp->if_mq_start = cxgb_pcpu_start;
930174708Skmacy#endif
931176472Skmacy#endif
932167514Skmacy	ifp->if_timer = 0;	/* Disable ifnet watchdog */
933167514Skmacy	ifp->if_watchdog = NULL;
934167514Skmacy
935175312Skmacy	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
936167514Skmacy	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
937167514Skmacy	IFQ_SET_READY(&ifp->if_snd);
938167514Skmacy
939167514Skmacy	ifp->if_hwassist = ifp->if_capabilities = ifp->if_capenable = 0;
940167514Skmacy	ifp->if_capabilities |= CXGB_CAP;
941167514Skmacy	ifp->if_capenable |= CXGB_CAP_ENABLE;
942167514Skmacy	ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO);
943171471Skmacy	/*
944171471Skmacy	 * disable TSO on 4-port - it isn't supported by the firmware yet
945171471Skmacy	 */
946171471Skmacy	if (p->adapter->params.nports > 2) {
947171471Skmacy		ifp->if_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6);
948171471Skmacy		ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TSO6);
949171471Skmacy		ifp->if_hwassist &= ~CSUM_TSO;
950171471Skmacy	}
951171471Skmacy
952167514Skmacy	ether_ifattach(ifp, p->hw_addr);
953171471Skmacy	/*
954171471Skmacy	 * Only default to jumbo frames on 10GigE
955171471Skmacy	 */
956171471Skmacy	if (p->adapter->params.nports <= 2)
957180583Skmacy		ifp->if_mtu = ETHERMTU_JUMBO;
958167514Skmacy	if ((err = cxgb_makedev(p)) != 0) {
959167514Skmacy		printf("makedev failed %d\n", err);
960167514Skmacy		return (err);
961167514Skmacy	}
962167514Skmacy	ifmedia_init(&p->media, IFM_IMASK, cxgb_media_change,
963167514Skmacy	    cxgb_media_status);
964176472Skmacy
965176472Skmacy	if (!strcmp(p->phy.desc,	"10GBASE-CX4")) {
966170654Skmacy		media_flags = IFM_ETHER | IFM_10G_CX4 | IFM_FDX;
967176472Skmacy	} else if (!strcmp(p->phy.desc, "10GBASE-SR")) {
968170654Skmacy		media_flags = IFM_ETHER | IFM_10G_SR | IFM_FDX;
969177340Skmacy	} else if (!strcmp(p->phy.desc, "10GBASE-R")) {
970170654Skmacy		media_flags = IFM_ETHER | IFM_10G_LR | IFM_FDX;
971176472Skmacy	} else if (!strcmp(p->phy.desc, "10/100/1000BASE-T")) {
972170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_10_T, 0, NULL);
973170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_10_T | IFM_FDX,
974170654Skmacy			    0, NULL);
975170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX,
976170654Skmacy			    0, NULL);
977170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX | IFM_FDX,
978170654Skmacy			    0, NULL);
979170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_1000_T | IFM_FDX,
980170654Skmacy			    0, NULL);
981170654Skmacy		media_flags = 0;
982170654Skmacy	} else {
983176472Skmacy	        printf("unsupported media type %s\n", p->phy.desc);
984167514Skmacy		return (ENXIO);
985167514Skmacy	}
986170654Skmacy	if (media_flags) {
987170654Skmacy		ifmedia_add(&p->media, media_flags, 0, NULL);
988170654Skmacy		ifmedia_set(&p->media, media_flags);
989170654Skmacy	} else {
990170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL);
991170654Skmacy		ifmedia_set(&p->media, IFM_ETHER | IFM_AUTO);
992170654Skmacy	}
993167514Skmacy
994177340Skmacy	/* Get the latest mac address, User can use a LAA */
995177340Skmacy	bcopy(IF_LLADDR(p->ifp), p->hw_addr, ETHER_ADDR_LEN);
996170654Skmacy	t3_sge_init_port(p);
997177415Skmacy#if defined(LINK_ATTACH)
998176472Skmacy	cxgb_link_start(p);
999176472Skmacy	t3_link_changed(sc, p->port_id);
1000177415Skmacy#endif
1001167514Skmacy	return (0);
1002167514Skmacy}
1003167514Skmacy
1004167514Skmacystatic int
1005167514Skmacycxgb_port_detach(device_t dev)
1006167514Skmacy{
1007167514Skmacy	struct port_info *p;
1008167514Skmacy
1009167514Skmacy	p = device_get_softc(dev);
1010169978Skmacy
1011169978Skmacy	PORT_LOCK(p);
1012170654Skmacy	if (p->ifp->if_drv_flags & IFF_DRV_RUNNING)
1013170654Skmacy		cxgb_stop_locked(p);
1014169978Skmacy	PORT_UNLOCK(p);
1015169978Skmacy
1016171978Skmacy	ether_ifdetach(p->ifp);
1017174708Skmacy	printf("waiting for callout to stop ...");
1018174708Skmacy	DELAY(1000000);
1019174708Skmacy	printf("done\n");
1020171978Skmacy	/*
1021171978Skmacy	 * the lock may be acquired in ifdetach
1022171978Skmacy	 */
1023170869Skmacy	PORT_LOCK_DEINIT(p);
1024167514Skmacy	if_free(p->ifp);
1025167514Skmacy
1026170654Skmacy	if (p->port_cdev != NULL)
1027170654Skmacy		destroy_dev(p->port_cdev);
1028170654Skmacy
1029167514Skmacy	return (0);
1030167514Skmacy}
1031167514Skmacy
1032167514Skmacyvoid
1033167514Skmacyt3_fatal_err(struct adapter *sc)
1034167514Skmacy{
1035167514Skmacy	u_int fw_status[4];
1036183062Skmacy
1037172096Skmacy	if (sc->flags & FULL_INIT_DONE) {
1038172096Skmacy		t3_sge_stop(sc);
1039172096Skmacy		t3_write_reg(sc, A_XGM_TX_CTRL, 0);
1040172096Skmacy		t3_write_reg(sc, A_XGM_RX_CTRL, 0);
1041172096Skmacy		t3_write_reg(sc, XGM_REG(A_XGM_TX_CTRL, 1), 0);
1042172096Skmacy		t3_write_reg(sc, XGM_REG(A_XGM_RX_CTRL, 1), 0);
1043172096Skmacy		t3_intr_disable(sc);
1044172096Skmacy	}
1045167514Skmacy	device_printf(sc->dev,"encountered fatal error, operation suspended\n");
1046167514Skmacy	if (!t3_cim_ctl_blk_read(sc, 0xa0, 4, fw_status))
1047167514Skmacy		device_printf(sc->dev, "FW_ status: 0x%x, 0x%x, 0x%x, 0x%x\n",
1048167514Skmacy		    fw_status[0], fw_status[1], fw_status[2], fw_status[3]);
1049167514Skmacy}
1050167514Skmacy
1051167514Skmacyint
1052167514Skmacyt3_os_find_pci_capability(adapter_t *sc, int cap)
1053167514Skmacy{
1054167514Skmacy	device_t dev;
1055167514Skmacy	struct pci_devinfo *dinfo;
1056167514Skmacy	pcicfgregs *cfg;
1057167514Skmacy	uint32_t status;
1058167514Skmacy	uint8_t ptr;
1059167514Skmacy
1060167514Skmacy	dev = sc->dev;
1061167514Skmacy	dinfo = device_get_ivars(dev);
1062167514Skmacy	cfg = &dinfo->cfg;
1063167514Skmacy
1064167514Skmacy	status = pci_read_config(dev, PCIR_STATUS, 2);
1065167514Skmacy	if (!(status & PCIM_STATUS_CAPPRESENT))
1066167514Skmacy		return (0);
1067167514Skmacy
1068167514Skmacy	switch (cfg->hdrtype & PCIM_HDRTYPE) {
1069167514Skmacy	case 0:
1070167514Skmacy	case 1:
1071167514Skmacy		ptr = PCIR_CAP_PTR;
1072167514Skmacy		break;
1073167514Skmacy	case 2:
1074167514Skmacy		ptr = PCIR_CAP_PTR_2;
1075167514Skmacy		break;
1076167514Skmacy	default:
1077167514Skmacy		return (0);
1078167514Skmacy		break;
1079167514Skmacy	}
1080167514Skmacy	ptr = pci_read_config(dev, ptr, 1);
1081167514Skmacy
1082167514Skmacy	while (ptr != 0) {
1083167514Skmacy		if (pci_read_config(dev, ptr + PCICAP_ID, 1) == cap)
1084167514Skmacy			return (ptr);
1085167514Skmacy		ptr = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1);
1086167514Skmacy	}
1087167514Skmacy
1088167514Skmacy	return (0);
1089167514Skmacy}
1090167514Skmacy
1091167514Skmacyint
1092167514Skmacyt3_os_pci_save_state(struct adapter *sc)
1093167514Skmacy{
1094167514Skmacy	device_t dev;
1095167514Skmacy	struct pci_devinfo *dinfo;
1096167514Skmacy
1097167514Skmacy	dev = sc->dev;
1098167514Skmacy	dinfo = device_get_ivars(dev);
1099167514Skmacy
1100167514Skmacy	pci_cfg_save(dev, dinfo, 0);
1101167514Skmacy	return (0);
1102167514Skmacy}
1103167514Skmacy
1104167514Skmacyint
1105167514Skmacyt3_os_pci_restore_state(struct adapter *sc)
1106167514Skmacy{
1107167514Skmacy	device_t dev;
1108167514Skmacy	struct pci_devinfo *dinfo;
1109167514Skmacy
1110167514Skmacy	dev = sc->dev;
1111167514Skmacy	dinfo = device_get_ivars(dev);
1112167514Skmacy
1113167514Skmacy	pci_cfg_restore(dev, dinfo);
1114167514Skmacy	return (0);
1115167514Skmacy}
1116167514Skmacy
1117167514Skmacy/**
1118167514Skmacy *	t3_os_link_changed - handle link status changes
1119167514Skmacy *	@adapter: the adapter associated with the link change
1120167514Skmacy *	@port_id: the port index whose limk status has changed
1121177340Skmacy *	@link_status: the new status of the link
1122167514Skmacy *	@speed: the new speed setting
1123167514Skmacy *	@duplex: the new duplex setting
1124167514Skmacy *	@fc: the new flow-control setting
1125167514Skmacy *
1126167514Skmacy *	This is the OS-dependent handler for link status changes.  The OS
1127167514Skmacy *	neutral handler takes care of most of the processing for these events,
1128167514Skmacy *	then calls this handler for any OS-specific processing.
1129167514Skmacy */
1130167514Skmacyvoid
1131167514Skmacyt3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed,
1132167514Skmacy     int duplex, int fc)
1133167514Skmacy{
1134167514Skmacy	struct port_info *pi = &adapter->port[port_id];
1135169978Skmacy	struct cmac *mac = &adapter->port[port_id].mac;
1136167514Skmacy
1137169978Skmacy	if (link_status) {
1138177340Skmacy		DELAY(10);
1139177340Skmacy		t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
1140177340Skmacy			/* Clear errors created by MAC enable */
1141177340Skmacy			t3_set_reg_field(adapter,
1142177340Skmacy					 A_XGM_STAT_CTRL + pi->mac.offset,
1143177340Skmacy					 F_CLRSTATS, 1);
1144167514Skmacy		if_link_state_change(pi->ifp, LINK_STATE_UP);
1145177340Skmacy
1146169978Skmacy	} else {
1147169978Skmacy		pi->phy.ops->power_down(&pi->phy, 1);
1148169978Skmacy		t3_mac_disable(mac, MAC_DIRECTION_RX);
1149169978Skmacy		t3_link_start(&pi->phy, mac, &pi->link_config);
1150177340Skmacy		t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
1151176472Skmacy		if_link_state_change(pi->ifp, LINK_STATE_DOWN);
1152169978Skmacy	}
1153167514Skmacy}
1154167514Skmacy
1155181614Skmacy/**
1156181614Skmacy *	t3_os_phymod_changed - handle PHY module changes
1157181614Skmacy *	@phy: the PHY reporting the module change
1158181614Skmacy *	@mod_type: new module type
1159181614Skmacy *
1160181614Skmacy *	This is the OS-dependent handler for PHY module changes.  It is
1161181614Skmacy *	invoked when a PHY module is removed or inserted for any OS-specific
1162181614Skmacy *	processing.
1163181614Skmacy */
1164181614Skmacyvoid t3_os_phymod_changed(struct adapter *adap, int port_id)
1165181614Skmacy{
1166181614Skmacy	static const char *mod_str[] = {
1167181614Skmacy		NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown"
1168181614Skmacy	};
1169181614Skmacy
1170181614Skmacy	struct port_info *pi = &adap->port[port_id];
1171181614Skmacy
1172181614Skmacy	if (pi->phy.modtype == phy_modtype_none)
1173181614Skmacy		device_printf(adap->dev, "PHY module unplugged\n");
1174181614Skmacy	else {
1175181614Skmacy		KASSERT(pi->phy.modtype < ARRAY_SIZE(mod_str),
1176181614Skmacy		    ("invalid PHY module type %d", pi->phy.modtype));
1177181614Skmacy		device_printf(adap->dev, "%s PHY module inserted\n",
1178181614Skmacy		    mod_str[pi->phy.modtype]);
1179181614Skmacy	}
1180181614Skmacy}
1181181614Skmacy
1182167514Skmacy/*
1183167514Skmacy * Interrupt-context handler for external (PHY) interrupts.
1184167514Skmacy */
1185167514Skmacyvoid
1186167514Skmacyt3_os_ext_intr_handler(adapter_t *sc)
1187167514Skmacy{
1188167514Skmacy	if (cxgb_debug)
1189167514Skmacy		printf("t3_os_ext_intr_handler\n");
1190167514Skmacy	/*
1191167514Skmacy	 * Schedule a task to handle external interrupts as they may be slow
1192167514Skmacy	 * and we use a mutex to protect MDIO registers.  We disable PHY
1193167514Skmacy	 * interrupts in the meantime and let the task reenable them when
1194167514Skmacy	 * it's done.
1195167514Skmacy	 */
1196169978Skmacy	ADAPTER_LOCK(sc);
1197167514Skmacy	if (sc->slow_intr_mask) {
1198167514Skmacy		sc->slow_intr_mask &= ~F_T3DBG;
1199167514Skmacy		t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
1200167514Skmacy		taskqueue_enqueue(sc->tq, &sc->ext_intr_task);
1201167514Skmacy	}
1202169978Skmacy	ADAPTER_UNLOCK(sc);
1203167514Skmacy}
1204167514Skmacy
1205167514Skmacyvoid
1206167514Skmacyt3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[])
1207167514Skmacy{
1208167514Skmacy
1209167514Skmacy	/*
1210167514Skmacy	 * The ifnet might not be allocated before this gets called,
1211167514Skmacy	 * as this is called early on in attach by t3_prep_adapter
1212167514Skmacy	 * save the address off in the port structure
1213167514Skmacy	 */
1214167514Skmacy	if (cxgb_debug)
1215167514Skmacy		printf("set_hw_addr on idx %d addr %6D\n", port_idx, hw_addr, ":");
1216167514Skmacy	bcopy(hw_addr, adapter->port[port_idx].hw_addr, ETHER_ADDR_LEN);
1217167514Skmacy}
1218167514Skmacy
1219167514Skmacy/**
1220167514Skmacy *	link_start - enable a port
1221167514Skmacy *	@p: the port to enable
1222167514Skmacy *
1223167514Skmacy *	Performs the MAC and PHY actions needed to enable a port.
1224167514Skmacy */
1225167514Skmacystatic void
1226167514Skmacycxgb_link_start(struct port_info *p)
1227167514Skmacy{
1228167514Skmacy	struct ifnet *ifp;
1229167514Skmacy	struct t3_rx_mode rm;
1230167514Skmacy	struct cmac *mac = &p->mac;
1231180583Skmacy	int mtu, hwtagging;
1232167514Skmacy
1233167514Skmacy	ifp = p->ifp;
1234167514Skmacy
1235180583Skmacy	bcopy(IF_LLADDR(ifp), p->hw_addr, ETHER_ADDR_LEN);
1236180583Skmacy
1237180583Skmacy	mtu = ifp->if_mtu;
1238180583Skmacy	if (ifp->if_capenable & IFCAP_VLAN_MTU)
1239180583Skmacy		mtu += ETHER_VLAN_ENCAP_LEN;
1240180583Skmacy
1241180583Skmacy	hwtagging = (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0;
1242180583Skmacy
1243167514Skmacy	t3_init_rx_mode(&rm, p);
1244172096Skmacy	if (!mac->multiport)
1245171978Skmacy		t3_mac_reset(mac);
1246180583Skmacy	t3_mac_set_mtu(mac, mtu);
1247180583Skmacy	t3_set_vlan_accel(p->adapter, 1 << p->tx_chan, hwtagging);
1248167514Skmacy	t3_mac_set_address(mac, 0, p->hw_addr);
1249167514Skmacy	t3_mac_set_rx_mode(mac, &rm);
1250167514Skmacy	t3_link_start(&p->phy, mac, &p->link_config);
1251167514Skmacy	t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
1252167514Skmacy}
1253167514Skmacy
1254176472Skmacy
1255176472Skmacystatic int
1256176472Skmacyawait_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
1257176472Skmacy			      unsigned long n)
1258176472Skmacy{
1259176472Skmacy	int attempts = 5;
1260176472Skmacy
1261176472Skmacy	while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
1262176472Skmacy		if (!--attempts)
1263176472Skmacy			return (ETIMEDOUT);
1264176472Skmacy		t3_os_sleep(10);
1265176472Skmacy	}
1266176472Skmacy	return 0;
1267176472Skmacy}
1268176472Skmacy
1269176472Skmacystatic int
1270176472Skmacyinit_tp_parity(struct adapter *adap)
1271176472Skmacy{
1272176472Skmacy	int i;
1273176472Skmacy	struct mbuf *m;
1274176472Skmacy	struct cpl_set_tcb_field *greq;
1275176472Skmacy	unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts;
1276176472Skmacy
1277176472Skmacy	t3_tp_set_offload_mode(adap, 1);
1278176472Skmacy
1279176472Skmacy	for (i = 0; i < 16; i++) {
1280176472Skmacy		struct cpl_smt_write_req *req;
1281176472Skmacy
1282176472Skmacy		m = m_gethdr(M_WAITOK, MT_DATA);
1283176472Skmacy		req = mtod(m, struct cpl_smt_write_req *);
1284176472Skmacy		m->m_len = m->m_pkthdr.len = sizeof(*req);
1285176472Skmacy		memset(req, 0, sizeof(*req));
1286176472Skmacy		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1287176472Skmacy		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
1288176472Skmacy		req->iff = i;
1289176472Skmacy		t3_mgmt_tx(adap, m);
1290176472Skmacy	}
1291176472Skmacy
1292176472Skmacy	for (i = 0; i < 2048; i++) {
1293176472Skmacy		struct cpl_l2t_write_req *req;
1294176472Skmacy
1295176472Skmacy		m = m_gethdr(M_WAITOK, MT_DATA);
1296176472Skmacy		req = mtod(m, struct cpl_l2t_write_req *);
1297176472Skmacy		m->m_len = m->m_pkthdr.len = sizeof(*req);
1298176472Skmacy		memset(req, 0, sizeof(*req));
1299176472Skmacy		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1300176472Skmacy		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
1301176472Skmacy		req->params = htonl(V_L2T_W_IDX(i));
1302176472Skmacy		t3_mgmt_tx(adap, m);
1303176472Skmacy	}
1304176472Skmacy
1305176472Skmacy	for (i = 0; i < 2048; i++) {
1306176472Skmacy		struct cpl_rte_write_req *req;
1307176472Skmacy
1308176472Skmacy		m = m_gethdr(M_WAITOK, MT_DATA);
1309176472Skmacy		req = mtod(m, struct cpl_rte_write_req *);
1310176472Skmacy		m->m_len = m->m_pkthdr.len = sizeof(*req);
1311176472Skmacy		memset(req, 0, sizeof(*req));
1312176472Skmacy		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1313176472Skmacy		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
1314176472Skmacy		req->l2t_idx = htonl(V_L2T_W_IDX(i));
1315176472Skmacy		t3_mgmt_tx(adap, m);
1316176472Skmacy	}
1317176472Skmacy
1318176472Skmacy	m = m_gethdr(M_WAITOK, MT_DATA);
1319176472Skmacy	greq = mtod(m, struct cpl_set_tcb_field *);
1320176472Skmacy	m->m_len = m->m_pkthdr.len = sizeof(*greq);
1321176472Skmacy	memset(greq, 0, sizeof(*greq));
1322176472Skmacy	greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1323176472Skmacy	OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0));
1324176472Skmacy	greq->mask = htobe64(1);
1325176472Skmacy	t3_mgmt_tx(adap, m);
1326176472Skmacy
1327176472Skmacy	i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
1328176472Skmacy	t3_tp_set_offload_mode(adap, 0);
1329176472Skmacy	return (i);
1330176472Skmacy}
1331176472Skmacy
1332167514Skmacy/**
1333167514Skmacy *	setup_rss - configure Receive Side Steering (per-queue connection demux)
1334167514Skmacy *	@adap: the adapter
1335167514Skmacy *
1336167514Skmacy *	Sets up RSS to distribute packets to multiple receive queues.  We
1337167514Skmacy *	configure the RSS CPU lookup table to distribute to the number of HW
1338167514Skmacy *	receive queues, and the response queue lookup table to narrow that
1339167514Skmacy *	down to the response queues actually configured for each port.
1340167514Skmacy *	We always configure the RSS mapping for two ports since the mapping
1341167514Skmacy *	table has plenty of entries.
1342167514Skmacy */
1343167514Skmacystatic void
1344167514Skmacysetup_rss(adapter_t *adap)
1345167514Skmacy{
1346167514Skmacy	int i;
1347171471Skmacy	u_int nq[2];
1348167514Skmacy	uint8_t cpus[SGE_QSETS + 1];
1349167514Skmacy	uint16_t rspq_map[RSS_TABLE_SIZE];
1350171471Skmacy
1351167514Skmacy	for (i = 0; i < SGE_QSETS; ++i)
1352167514Skmacy		cpus[i] = i;
1353167514Skmacy	cpus[SGE_QSETS] = 0xff;
1354167514Skmacy
1355171978Skmacy	nq[0] = nq[1] = 0;
1356171978Skmacy	for_each_port(adap, i) {
1357171978Skmacy		const struct port_info *pi = adap2pinfo(adap, i);
1358171978Skmacy
1359171978Skmacy		nq[pi->tx_chan] += pi->nqsets;
1360171978Skmacy	}
1361167514Skmacy	for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
1362176472Skmacy		rspq_map[i] = nq[0] ? i % nq[0] : 0;
1363176472Skmacy		rspq_map[i + RSS_TABLE_SIZE / 2] = nq[1] ? i % nq[1] + nq[0] : 0;
1364167514Skmacy	}
1365171471Skmacy	/* Calculate the reverse RSS map table */
1366171471Skmacy	for (i = 0; i < RSS_TABLE_SIZE; ++i)
1367171471Skmacy		if (adap->rrss_map[rspq_map[i]] == 0xff)
1368171471Skmacy			adap->rrss_map[rspq_map[i]] = i;
1369167514Skmacy
1370167514Skmacy	t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
1371171471Skmacy		      F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | F_OFDMAPEN |
1372176472Skmacy	              F_RRCPLMAPEN | V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ,
1373176472Skmacy	              cpus, rspq_map);
1374171471Skmacy
1375167514Skmacy}
1376167514Skmacy
1377169978Skmacy/*
1378169978Skmacy * Sends an mbuf to an offload queue driver
1379169978Skmacy * after dealing with any active network taps.
1380169978Skmacy */
1381169978Skmacystatic inline int
1382174626Skmacyoffload_tx(struct t3cdev *tdev, struct mbuf *m)
1383169978Skmacy{
1384169978Skmacy	int ret;
1385169978Skmacy
1386169978Skmacy	ret = t3_offload_tx(tdev, m);
1387170654Skmacy	return (ret);
1388169978Skmacy}
1389169978Skmacy
1390169978Skmacystatic int
1391169978Skmacywrite_smt_entry(struct adapter *adapter, int idx)
1392169978Skmacy{
1393169978Skmacy	struct port_info *pi = &adapter->port[idx];
1394169978Skmacy	struct cpl_smt_write_req *req;
1395169978Skmacy	struct mbuf *m;
1396169978Skmacy
1397169978Skmacy	if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
1398169978Skmacy		return (ENOMEM);
1399169978Skmacy
1400169978Skmacy	req = mtod(m, struct cpl_smt_write_req *);
1401174708Skmacy	m->m_pkthdr.len = m->m_len = sizeof(struct cpl_smt_write_req);
1402174708Skmacy
1403169978Skmacy	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1404169978Skmacy	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
1405169978Skmacy	req->mtu_idx = NMTUS - 1;  /* should be 0 but there's a T3 bug */
1406169978Skmacy	req->iff = idx;
1407169978Skmacy	memset(req->src_mac1, 0, sizeof(req->src_mac1));
1408169978Skmacy	memcpy(req->src_mac0, pi->hw_addr, ETHER_ADDR_LEN);
1409169978Skmacy
1410169978Skmacy	m_set_priority(m, 1);
1411169978Skmacy
1412169978Skmacy	offload_tx(&adapter->tdev, m);
1413169978Skmacy
1414169978Skmacy	return (0);
1415169978Skmacy}
1416169978Skmacy
1417169978Skmacystatic int
1418169978Skmacyinit_smt(struct adapter *adapter)
1419169978Skmacy{
1420169978Skmacy	int i;
1421169978Skmacy
1422169978Skmacy	for_each_port(adapter, i)
1423169978Skmacy		write_smt_entry(adapter, i);
1424169978Skmacy	return 0;
1425169978Skmacy}
1426169978Skmacy
1427167514Skmacystatic void
1428169978Skmacyinit_port_mtus(adapter_t *adapter)
1429169978Skmacy{
1430169978Skmacy	unsigned int mtus = adapter->port[0].ifp->if_mtu;
1431169978Skmacy
1432169978Skmacy	if (adapter->port[1].ifp)
1433169978Skmacy		mtus |= adapter->port[1].ifp->if_mtu << 16;
1434169978Skmacy	t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
1435169978Skmacy}
1436169978Skmacy
1437169978Skmacystatic void
1438167514Skmacysend_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
1439167514Skmacy			      int hi, int port)
1440167514Skmacy{
1441167514Skmacy	struct mbuf *m;
1442167514Skmacy	struct mngt_pktsched_wr *req;
1443167514Skmacy
1444171471Skmacy	m = m_gethdr(M_DONTWAIT, MT_DATA);
1445167848Skmacy	if (m) {
1446169978Skmacy		req = mtod(m, struct mngt_pktsched_wr *);
1447167848Skmacy		req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
1448167848Skmacy		req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
1449167848Skmacy		req->sched = sched;
1450167848Skmacy		req->idx = qidx;
1451167848Skmacy		req->min = lo;
1452167848Skmacy		req->max = hi;
1453167848Skmacy		req->binding = port;
1454167848Skmacy		m->m_len = m->m_pkthdr.len = sizeof(*req);
1455167848Skmacy		t3_mgmt_tx(adap, m);
1456167848Skmacy	}
1457167514Skmacy}
1458167514Skmacy
1459167514Skmacystatic void
1460167514Skmacybind_qsets(adapter_t *sc)
1461167514Skmacy{
1462167514Skmacy	int i, j;
1463167514Skmacy
1464174708Skmacy	cxgb_pcpu_startup_threads(sc);
1465167514Skmacy	for (i = 0; i < (sc)->params.nports; ++i) {
1466167514Skmacy		const struct port_info *pi = adap2pinfo(sc, i);
1467167514Skmacy
1468172096Skmacy		for (j = 0; j < pi->nqsets; ++j) {
1469167514Skmacy			send_pktsched_cmd(sc, 1, pi->first_qset + j, -1,
1470172096Skmacy					  -1, pi->tx_chan);
1471172096Skmacy
1472172096Skmacy		}
1473167514Skmacy	}
1474167514Skmacy}
1475167514Skmacy
1476171471Skmacystatic void
1477171471Skmacyupdate_tpeeprom(struct adapter *adap)
1478171471Skmacy{
1479172109Skmacy#ifdef FIRMWARE_LATEST
1480171471Skmacy	const struct firmware *tpeeprom;
1481172109Skmacy#else
1482172109Skmacy	struct firmware *tpeeprom;
1483172109Skmacy#endif
1484172109Skmacy
1485171471Skmacy	uint32_t version;
1486171471Skmacy	unsigned int major, minor;
1487171471Skmacy	int ret, len;
1488171471Skmacy	char rev;
1489171471Skmacy
1490171471Skmacy	t3_seeprom_read(adap, TP_SRAM_OFFSET, &version);
1491171471Skmacy
1492171471Skmacy	major = G_TP_VERSION_MAJOR(version);
1493171471Skmacy	minor = G_TP_VERSION_MINOR(version);
1494171471Skmacy	if (major == TP_VERSION_MAJOR  && minor == TP_VERSION_MINOR)
1495171471Skmacy		return;
1496171471Skmacy
1497171471Skmacy	rev = t3rev2char(adap);
1498171471Skmacy
1499176613Skmacy	tpeeprom = firmware_get(TPEEPROM_NAME);
1500171471Skmacy	if (tpeeprom == NULL) {
1501171471Skmacy		device_printf(adap->dev, "could not load TP EEPROM: unable to load %s\n",
1502176613Skmacy		    TPEEPROM_NAME);
1503171471Skmacy		return;
1504171471Skmacy	}
1505171471Skmacy
1506171471Skmacy	len = tpeeprom->datasize - 4;
1507171471Skmacy
1508171471Skmacy	ret = t3_check_tpsram(adap, tpeeprom->data, tpeeprom->datasize);
1509171471Skmacy	if (ret)
1510171471Skmacy		goto release_tpeeprom;
1511171471Skmacy
1512171471Skmacy	if (len != TP_SRAM_LEN) {
1513176613Skmacy		device_printf(adap->dev, "%s length is wrong len=%d expected=%d\n", TPEEPROM_NAME, len, TP_SRAM_LEN);
1514171471Skmacy		return;
1515171471Skmacy	}
1516171471Skmacy
1517171471Skmacy	ret = set_eeprom(&adap->port[0], tpeeprom->data, tpeeprom->datasize,
1518171471Skmacy	    TP_SRAM_OFFSET);
1519171471Skmacy
1520171471Skmacy	if (!ret) {
1521171471Skmacy		device_printf(adap->dev,
1522171471Skmacy			"Protocol SRAM image updated in EEPROM to %d.%d.%d\n",
1523171471Skmacy			 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1524171471Skmacy	} else
1525171471Skmacy		device_printf(adap->dev, "Protocol SRAM image update in EEPROM failed\n");
1526171471Skmacy
1527171471Skmacyrelease_tpeeprom:
1528171471Skmacy	firmware_put(tpeeprom, FIRMWARE_UNLOAD);
1529171471Skmacy
1530171471Skmacy	return;
1531171471Skmacy}
1532171471Skmacy
1533171471Skmacystatic int
1534171471Skmacyupdate_tpsram(struct adapter *adap)
1535171471Skmacy{
1536172109Skmacy#ifdef FIRMWARE_LATEST
1537171471Skmacy	const struct firmware *tpsram;
1538172109Skmacy#else
1539172109Skmacy	struct firmware *tpsram;
1540172109Skmacy#endif
1541171471Skmacy	int ret;
1542171471Skmacy	char rev;
1543171471Skmacy
1544171471Skmacy	rev = t3rev2char(adap);
1545171471Skmacy	if (!rev)
1546171471Skmacy		return 0;
1547171471Skmacy
1548171471Skmacy	update_tpeeprom(adap);
1549171471Skmacy
1550176613Skmacy	tpsram = firmware_get(TPSRAM_NAME);
1551171471Skmacy	if (tpsram == NULL){
1552176613Skmacy		device_printf(adap->dev, "could not load TP SRAM\n");
1553171471Skmacy		return (EINVAL);
1554171471Skmacy	} else
1555176613Skmacy		device_printf(adap->dev, "updating TP SRAM\n");
1556171471Skmacy
1557171471Skmacy	ret = t3_check_tpsram(adap, tpsram->data, tpsram->datasize);
1558171471Skmacy	if (ret)
1559171471Skmacy		goto release_tpsram;
1560171471Skmacy
1561171471Skmacy	ret = t3_set_proto_sram(adap, tpsram->data);
1562171471Skmacy	if (ret)
1563171471Skmacy		device_printf(adap->dev, "loading protocol SRAM failed\n");
1564171471Skmacy
1565171471Skmacyrelease_tpsram:
1566171471Skmacy	firmware_put(tpsram, FIRMWARE_UNLOAD);
1567171471Skmacy
1568171471Skmacy	return ret;
1569171471Skmacy}
1570171471Skmacy
1571169978Skmacy/**
1572169978Skmacy *	cxgb_up - enable the adapter
1573169978Skmacy *	@adap: adapter being enabled
1574169978Skmacy *
1575169978Skmacy *	Called when the first port is enabled, this function performs the
1576169978Skmacy *	actions necessary to make an adapter operational, such as completing
1577169978Skmacy *	the initialization of HW modules, and enabling interrupts.
1578169978Skmacy *
1579169978Skmacy */
1580169978Skmacystatic int
1581169978Skmacycxgb_up(struct adapter *sc)
1582169978Skmacy{
1583169978Skmacy	int err = 0;
1584169978Skmacy
1585169978Skmacy	if ((sc->flags & FULL_INIT_DONE) == 0) {
1586169978Skmacy
1587169978Skmacy		if ((sc->flags & FW_UPTODATE) == 0)
1588171471Skmacy			if ((err = upgrade_fw(sc)))
1589171471Skmacy				goto out;
1590171471Skmacy		if ((sc->flags & TPS_UPTODATE) == 0)
1591171471Skmacy			if ((err = update_tpsram(sc)))
1592171471Skmacy				goto out;
1593169978Skmacy		err = t3_init_hw(sc, 0);
1594169978Skmacy		if (err)
1595169978Skmacy			goto out;
1596169978Skmacy
1597176472Skmacy		t3_set_reg_field(sc, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT);
1598169978Skmacy		t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
1599169978Skmacy
1600169978Skmacy		err = setup_sge_qsets(sc);
1601169978Skmacy		if (err)
1602169978Skmacy			goto out;
1603169978Skmacy
1604169978Skmacy		setup_rss(sc);
1605174708Skmacy		t3_add_configured_sysctls(sc);
1606169978Skmacy		sc->flags |= FULL_INIT_DONE;
1607169978Skmacy	}
1608169978Skmacy
1609169978Skmacy	t3_intr_clear(sc);
1610169978Skmacy
1611169978Skmacy	/* If it's MSI or INTx, allocate a single interrupt for everything */
1612169978Skmacy	if ((sc->flags & USING_MSIX) == 0) {
1613169978Skmacy		if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
1614169978Skmacy		   &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
1615171978Skmacy			device_printf(sc->dev, "Cannot allocate interrupt rid=%d\n",
1616171978Skmacy			    sc->irq_rid);
1617169978Skmacy			err = EINVAL;
1618169978Skmacy			goto out;
1619169978Skmacy		}
1620169978Skmacy		device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res);
1621169978Skmacy
1622169978Skmacy		if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET,
1623169978Skmacy#ifdef INTR_FILTERS
1624169978Skmacy			NULL,
1625169978Skmacy#endif
1626169978Skmacy			sc->cxgb_intr, sc, &sc->intr_tag)) {
1627169978Skmacy			device_printf(sc->dev, "Cannot set up interrupt\n");
1628169978Skmacy			err = EINVAL;
1629169978Skmacy			goto irq_err;
1630169978Skmacy		}
1631169978Skmacy	} else {
1632169978Skmacy		cxgb_setup_msix(sc, sc->msi_count);
1633169978Skmacy	}
1634169978Skmacy
1635169978Skmacy	t3_sge_start(sc);
1636169978Skmacy	t3_intr_enable(sc);
1637169978Skmacy
1638176472Skmacy	if (sc->params.rev >= T3_REV_C && !(sc->flags & TP_PARITY_INIT) &&
1639176472Skmacy	    is_offload(sc) && init_tp_parity(sc) == 0)
1640176472Skmacy		sc->flags |= TP_PARITY_INIT;
1641176472Skmacy
1642176472Skmacy	if (sc->flags & TP_PARITY_INIT) {
1643176472Skmacy		t3_write_reg(sc, A_TP_INT_CAUSE,
1644176472Skmacy				F_CMCACHEPERR | F_ARPLUTPERR);
1645176472Skmacy		t3_write_reg(sc, A_TP_INT_ENABLE, 0x7fbfffff);
1646176472Skmacy	}
1647176472Skmacy
1648176472Skmacy
1649172096Skmacy	if (!(sc->flags & QUEUES_BOUND)) {
1650169978Skmacy		bind_qsets(sc);
1651171471Skmacy		sc->flags |= QUEUES_BOUND;
1652171471Skmacy	}
1653169978Skmacyout:
1654169978Skmacy	return (err);
1655169978Skmacyirq_err:
1656169978Skmacy	CH_ERR(sc, "request_irq failed, err %d\n", err);
1657169978Skmacy	goto out;
1658169978Skmacy}
1659169978Skmacy
1660169978Skmacy
1661169978Skmacy/*
1662169978Skmacy * Release resources when all the ports and offloading have been stopped.
1663169978Skmacy */
1664167514Skmacystatic void
1665170869Skmacycxgb_down_locked(struct adapter *sc)
1666169978Skmacy{
1667170654Skmacy
1668169978Skmacy	t3_sge_stop(sc);
1669169978Skmacy	t3_intr_disable(sc);
1670170654Skmacy
1671169978Skmacy	if (sc->intr_tag != NULL) {
1672169978Skmacy		bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag);
1673169978Skmacy		sc->intr_tag = NULL;
1674169978Skmacy	}
1675169978Skmacy	if (sc->irq_res != NULL) {
1676169978Skmacy		device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n",
1677169978Skmacy		    sc->irq_rid, sc->irq_res);
1678169978Skmacy		bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
1679169978Skmacy		    sc->irq_res);
1680169978Skmacy		sc->irq_res = NULL;
1681169978Skmacy	}
1682170654Skmacy
1683176472Skmacy	if (sc->flags & USING_MSIX)
1684170654Skmacy		cxgb_teardown_msix(sc);
1685176472Skmacy
1686174708Skmacy	callout_stop(&sc->cxgb_tick_ch);
1687174708Skmacy	callout_stop(&sc->sge_timer_ch);
1688170869Skmacy	callout_drain(&sc->cxgb_tick_ch);
1689169978Skmacy	callout_drain(&sc->sge_timer_ch);
1690170869Skmacy
1691171978Skmacy	if (sc->tq != NULL) {
1692176472Skmacy		printf("draining slow intr\n");
1693176472Skmacy
1694170654Skmacy		taskqueue_drain(sc->tq, &sc->slow_intr_task);
1695176472Skmacy			printf("draining ext intr\n");
1696176472Skmacy		taskqueue_drain(sc->tq, &sc->ext_intr_task);
1697176472Skmacy		printf("draining tick task\n");
1698176472Skmacy		taskqueue_drain(sc->tq, &sc->tick_task);
1699171978Skmacy	}
1700176472Skmacy	ADAPTER_UNLOCK(sc);
1701169978Skmacy}
1702169978Skmacy
1703169978Skmacystatic int
1704169978Skmacyoffload_open(struct port_info *pi)
1705169978Skmacy{
1706169978Skmacy	struct adapter *adapter = pi->adapter;
1707174708Skmacy	struct t3cdev *tdev = &adapter->tdev;
1708183059Skmacy
1709169978Skmacy	int adap_up = adapter->open_device_map & PORT_MASK;
1710169978Skmacy	int err = 0;
1711169978Skmacy
1712169978Skmacy	if (atomic_cmpset_int(&adapter->open_device_map,
1713174708Skmacy		(adapter->open_device_map & ~(1<<OFFLOAD_DEVMAP_BIT)),
1714174708Skmacy		(adapter->open_device_map | (1<<OFFLOAD_DEVMAP_BIT))) == 0)
1715169978Skmacy		return (0);
1716169978Skmacy
1717174708Skmacy	if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT))
1718183059Skmacy		printf("offload_open: DEVMAP_BIT did not get set 0x%x\n",
1719183059Skmacy		    adapter->open_device_map);
1720169978Skmacy	ADAPTER_LOCK(pi->adapter);
1721169978Skmacy	if (!adap_up)
1722169978Skmacy		err = cxgb_up(adapter);
1723169978Skmacy	ADAPTER_UNLOCK(pi->adapter);
1724171471Skmacy	if (err)
1725169978Skmacy		return (err);
1726169978Skmacy
1727169978Skmacy	t3_tp_set_offload_mode(adapter, 1);
1728174708Skmacy	tdev->lldev = pi->ifp;
1729169978Skmacy
1730169978Skmacy	init_port_mtus(adapter);
1731169978Skmacy	t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
1732169978Skmacy		     adapter->params.b_wnd,
1733169978Skmacy		     adapter->params.rev == 0 ?
1734169978Skmacy		       adapter->port[0].ifp->if_mtu : 0xffff);
1735169978Skmacy	init_smt(adapter);
1736178767Skmacy	/* Call back all registered clients */
1737178767Skmacy	cxgb_add_clients(tdev);
1738178767Skmacy
1739169978Skmacy	/* restore them in case the offload module has changed them */
1740169978Skmacy	if (err) {
1741169978Skmacy		t3_tp_set_offload_mode(adapter, 0);
1742169978Skmacy		clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT);
1743169978Skmacy		cxgb_set_dummy_ops(tdev);
1744169978Skmacy	}
1745169978Skmacy	return (err);
1746169978Skmacy}
1747174708Skmacy
1748169978Skmacystatic int
1749174708Skmacyoffload_close(struct t3cdev *tdev)
1750169978Skmacy{
1751169978Skmacy	struct adapter *adapter = tdev2adap(tdev);
1752169978Skmacy
1753176472Skmacy	if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT))
1754170654Skmacy		return (0);
1755178767Skmacy
1756178767Skmacy	/* Call back all registered clients */
1757178767Skmacy	cxgb_remove_clients(tdev);
1758178767Skmacy
1759169978Skmacy	tdev->lldev = NULL;
1760169978Skmacy	cxgb_set_dummy_ops(tdev);
1761169978Skmacy	t3_tp_set_offload_mode(adapter, 0);
1762169978Skmacy	clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT);
1763169978Skmacy
1764174708Skmacy	ADAPTER_LOCK(adapter);
1765169978Skmacy	if (!adapter->open_device_map)
1766174708Skmacy		cxgb_down_locked(adapter);
1767174708Skmacy	else
1768174708Skmacy		ADAPTER_UNLOCK(adapter);
1769170654Skmacy	return (0);
1770169978Skmacy}
1771169978Skmacy
1772174708Skmacy
1773169978Skmacystatic void
1774167514Skmacycxgb_init(void *arg)
1775167514Skmacy{
1776167514Skmacy	struct port_info *p = arg;
1777167514Skmacy
1778167514Skmacy	PORT_LOCK(p);
1779167514Skmacy	cxgb_init_locked(p);
1780167514Skmacy	PORT_UNLOCK(p);
1781167514Skmacy}
1782167514Skmacy
1783167514Skmacystatic void
1784167514Skmacycxgb_init_locked(struct port_info *p)
1785167514Skmacy{
1786167514Skmacy	struct ifnet *ifp;
1787167514Skmacy	adapter_t *sc = p->adapter;
1788169978Skmacy	int err;
1789167514Skmacy
1790170869Skmacy	PORT_LOCK_ASSERT_OWNED(p);
1791167514Skmacy	ifp = p->ifp;
1792167514Skmacy
1793167514Skmacy	ADAPTER_LOCK(p->adapter);
1794171471Skmacy	if ((sc->open_device_map == 0) && (err = cxgb_up(sc))) {
1795169978Skmacy		ADAPTER_UNLOCK(p->adapter);
1796169978Skmacy		cxgb_stop_locked(p);
1797169978Skmacy		return;
1798169978Skmacy	}
1799170869Skmacy	if (p->adapter->open_device_map == 0) {
1800167514Skmacy		t3_intr_clear(sc);
1801170869Skmacy	}
1802171803Skmacy	setbit(&p->adapter->open_device_map, p->port_id);
1803170654Skmacy	ADAPTER_UNLOCK(p->adapter);
1804169978Skmacy
1805169978Skmacy	if (is_offload(sc) && !ofld_disable) {
1806169978Skmacy		err = offload_open(p);
1807169978Skmacy		if (err)
1808169978Skmacy			log(LOG_WARNING,
1809169978Skmacy			    "Could not initialize offload capabilities\n");
1810169978Skmacy	}
1811177415Skmacy#if !defined(LINK_ATTACH)
1812177415Skmacy	cxgb_link_start(p);
1813177415Skmacy	t3_link_changed(sc, p->port_id);
1814177415Skmacy#endif
1815170654Skmacy	ifp->if_baudrate = p->link_config.speed * 1000000;
1816171978Skmacy
1817172096Skmacy	device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id);
1818171803Skmacy	t3_port_intr_enable(sc, p->port_id);
1819167760Skmacy
1820175224Skmacy	t3_sge_reset_adapter(sc);
1821170869Skmacy
1822167514Skmacy	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1823167514Skmacy	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1824167514Skmacy}
1825167514Skmacy
1826167514Skmacystatic void
1827167514Skmacycxgb_set_rxmode(struct port_info *p)
1828167514Skmacy{
1829167514Skmacy	struct t3_rx_mode rm;
1830167514Skmacy	struct cmac *mac = &p->mac;
1831167760Skmacy
1832167514Skmacy	t3_init_rx_mode(&rm, p);
1833176472Skmacy	mtx_lock(&p->adapter->mdio_lock);
1834167514Skmacy	t3_mac_set_rx_mode(mac, &rm);
1835176472Skmacy	mtx_unlock(&p->adapter->mdio_lock);
1836167514Skmacy}
1837167514Skmacy
1838167514Skmacystatic void
1839177340Skmacycxgb_stop_locked(struct port_info *pi)
1840167514Skmacy{
1841167514Skmacy	struct ifnet *ifp;
1842167514Skmacy
1843177340Skmacy	PORT_LOCK_ASSERT_OWNED(pi);
1844177340Skmacy	ADAPTER_LOCK_ASSERT_NOTOWNED(pi->adapter);
1845170654Skmacy
1846177340Skmacy	ifp = pi->ifp;
1847177340Skmacy	t3_port_intr_disable(pi->adapter, pi->port_id);
1848169978Skmacy	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1849169978Skmacy
1850177340Skmacy	/* disable pause frames */
1851177340Skmacy	t3_set_reg_field(pi->adapter, A_XGM_TX_CFG + pi->mac.offset,
1852177340Skmacy			 F_TXPAUSEEN, 0);
1853170869Skmacy
1854177340Skmacy	/* Reset RX FIFO HWM */
1855177340Skmacy        t3_set_reg_field(pi->adapter, A_XGM_RXFIFO_CFG +  pi->mac.offset,
1856177340Skmacy			 V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM), 0);
1857177340Skmacy
1858177340Skmacy
1859177340Skmacy	ADAPTER_LOCK(pi->adapter);
1860177340Skmacy	clrbit(&pi->adapter->open_device_map, pi->port_id);
1861177340Skmacy
1862177340Skmacy	if (pi->adapter->open_device_map == 0) {
1863177340Skmacy		cxgb_down_locked(pi->adapter);
1864170869Skmacy	} else
1865177340Skmacy		ADAPTER_UNLOCK(pi->adapter);
1866170869Skmacy
1867177415Skmacy#if !defined(LINK_ATTACH)
1868177340Skmacy	DELAY(100);
1869177340Skmacy
1870177340Skmacy	/* Wait for TXFIFO empty */
1871177340Skmacy	t3_wait_op_done(pi->adapter, A_XGM_TXFIFO_CFG + pi->mac.offset,
1872177340Skmacy			F_TXFIFO_EMPTY, 1, 20, 5);
1873177340Skmacy
1874177340Skmacy	DELAY(100);
1875177340Skmacy	t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
1876177340Skmacy
1877177340Skmacy	pi->phy.ops->power_down(&pi->phy, 1);
1878177415Skmacy#endif
1879177340Skmacy
1880167514Skmacy}
1881167514Skmacy
1882167514Skmacystatic int
1883170654Skmacycxgb_set_mtu(struct port_info *p, int mtu)
1884170654Skmacy{
1885170654Skmacy	struct ifnet *ifp = p->ifp;
1886170654Skmacy	int error = 0;
1887170654Skmacy
1888180583Skmacy	if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO))
1889170654Skmacy		error = EINVAL;
1890170654Skmacy	else if (ifp->if_mtu != mtu) {
1891170654Skmacy		PORT_LOCK(p);
1892170654Skmacy		ifp->if_mtu = mtu;
1893170654Skmacy		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1894170654Skmacy			cxgb_stop_locked(p);
1895170654Skmacy			cxgb_init_locked(p);
1896170654Skmacy		}
1897170654Skmacy		PORT_UNLOCK(p);
1898170654Skmacy	}
1899170654Skmacy	return (error);
1900170654Skmacy}
1901170654Skmacy
1902181616Skmacy/*
1903181616Skmacy * Mark lro enabled or disabled in all qsets for this port
1904181616Skmacy */
1905170654Skmacystatic int
1906181616Skmacycxgb_set_lro(struct port_info *p, int enabled)
1907181616Skmacy{
1908181616Skmacy	int i;
1909181616Skmacy	struct adapter *adp = p->adapter;
1910181616Skmacy	struct sge_qset *q;
1911181616Skmacy
1912181616Skmacy	PORT_LOCK_ASSERT_OWNED(p);
1913181616Skmacy	for (i = 0; i < p->nqsets; i++) {
1914181616Skmacy		q = &adp->sge.qs[p->first_qset + i];
1915181616Skmacy		q->lro.enabled = (enabled != 0);
1916181616Skmacy	}
1917181616Skmacy	return (0);
1918181616Skmacy}
1919181616Skmacy
1920181616Skmacystatic int
1921167514Skmacycxgb_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data)
1922167514Skmacy{
1923167514Skmacy	struct port_info *p = ifp->if_softc;
1924167514Skmacy	struct ifaddr *ifa = (struct ifaddr *)data;
1925167514Skmacy	struct ifreq *ifr = (struct ifreq *)data;
1926180583Skmacy	int flags, error = 0, reinit = 0;
1927167514Skmacy	uint32_t mask;
1928167514Skmacy
1929168737Skmacy	/*
1930168737Skmacy	 * XXX need to check that we aren't in the middle of an unload
1931168737Skmacy	 */
1932167514Skmacy	switch (command) {
1933167514Skmacy	case SIOCSIFMTU:
1934170654Skmacy		error = cxgb_set_mtu(p, ifr->ifr_mtu);
1935167514Skmacy		break;
1936167514Skmacy	case SIOCSIFADDR:
1937167514Skmacy		if (ifa->ifa_addr->sa_family == AF_INET) {
1938167514Skmacy			ifp->if_flags |= IFF_UP;
1939176472Skmacy			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1940176472Skmacy				PORT_LOCK(p);
1941170654Skmacy				cxgb_init_locked(p);
1942176472Skmacy				PORT_UNLOCK(p);
1943176472Skmacy			}
1944167514Skmacy			arp_ifinit(ifp, ifa);
1945167514Skmacy		} else
1946167514Skmacy			error = ether_ioctl(ifp, command, data);
1947167514Skmacy		break;
1948167514Skmacy	case SIOCSIFFLAGS:
1949170869Skmacy		PORT_LOCK(p);
1950167514Skmacy		if (ifp->if_flags & IFF_UP) {
1951167514Skmacy			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1952167514Skmacy				flags = p->if_flags;
1953167514Skmacy				if (((ifp->if_flags ^ flags) & IFF_PROMISC) ||
1954167514Skmacy				    ((ifp->if_flags ^ flags) & IFF_ALLMULTI))
1955167514Skmacy					cxgb_set_rxmode(p);
1956167514Skmacy			} else
1957167514Skmacy				cxgb_init_locked(p);
1958167760Skmacy			p->if_flags = ifp->if_flags;
1959170869Skmacy		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1960170869Skmacy			cxgb_stop_locked(p);
1961170869Skmacy
1962176472Skmacy		PORT_UNLOCK(p);
1963176472Skmacy		break;
1964176472Skmacy	case SIOCADDMULTI:
1965176472Skmacy	case SIOCDELMULTI:
1966170869Skmacy		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1967176472Skmacy			cxgb_set_rxmode(p);
1968167514Skmacy		}
1969167514Skmacy		break;
1970167514Skmacy	case SIOCSIFMEDIA:
1971167514Skmacy	case SIOCGIFMEDIA:
1972167514Skmacy		error = ifmedia_ioctl(ifp, ifr, &p->media, command);
1973167514Skmacy		break;
1974167514Skmacy	case SIOCSIFCAP:
1975167514Skmacy		PORT_LOCK(p);
1976167514Skmacy		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1977167514Skmacy		if (mask & IFCAP_TXCSUM) {
1978167514Skmacy			if (IFCAP_TXCSUM & ifp->if_capenable) {
1979167514Skmacy				ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4);
1980167514Skmacy				ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP
1981180583Skmacy				    | CSUM_IP | CSUM_TSO);
1982167514Skmacy			} else {
1983167514Skmacy				ifp->if_capenable |= IFCAP_TXCSUM;
1984180583Skmacy				ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP
1985180583Skmacy				    | CSUM_IP);
1986167514Skmacy			}
1987167514Skmacy		}
1988180583Skmacy		if (mask & IFCAP_RXCSUM) {
1989180583Skmacy			ifp->if_capenable ^= IFCAP_RXCSUM;
1990180583Skmacy		}
1991167514Skmacy		if (mask & IFCAP_TSO4) {
1992167514Skmacy			if (IFCAP_TSO4 & ifp->if_capenable) {
1993167514Skmacy				ifp->if_capenable &= ~IFCAP_TSO4;
1994167514Skmacy				ifp->if_hwassist &= ~CSUM_TSO;
1995167514Skmacy			} else if (IFCAP_TXCSUM & ifp->if_capenable) {
1996167514Skmacy				ifp->if_capenable |= IFCAP_TSO4;
1997167514Skmacy				ifp->if_hwassist |= CSUM_TSO;
1998167514Skmacy			} else {
1999167514Skmacy				if (cxgb_debug)
2000167514Skmacy					printf("cxgb requires tx checksum offload"
2001167514Skmacy					    " be enabled to use TSO\n");
2002167514Skmacy				error = EINVAL;
2003167514Skmacy			}
2004167514Skmacy		}
2005181616Skmacy		if (mask & IFCAP_LRO) {
2006181616Skmacy			ifp->if_capenable ^= IFCAP_LRO;
2007181616Skmacy
2008181616Skmacy			/* Safe to do this even if cxgb_up not called yet */
2009181616Skmacy			cxgb_set_lro(p, ifp->if_capenable & IFCAP_LRO);
2010181616Skmacy		}
2011180583Skmacy		if (mask & IFCAP_VLAN_HWTAGGING) {
2012180583Skmacy			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
2013180583Skmacy			reinit = ifp->if_drv_flags & IFF_DRV_RUNNING;
2014180583Skmacy		}
2015180583Skmacy		if (mask & IFCAP_VLAN_MTU) {
2016180583Skmacy			ifp->if_capenable ^= IFCAP_VLAN_MTU;
2017180583Skmacy			reinit = ifp->if_drv_flags & IFF_DRV_RUNNING;
2018180583Skmacy		}
2019180583Skmacy		if (mask & IFCAP_VLAN_HWCSUM) {
2020180583Skmacy			ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
2021180583Skmacy		}
2022180583Skmacy		if (reinit) {
2023180583Skmacy			cxgb_stop_locked(p);
2024180583Skmacy			cxgb_init_locked(p);
2025180583Skmacy		}
2026167514Skmacy		PORT_UNLOCK(p);
2027180583Skmacy
2028180583Skmacy#ifdef VLAN_CAPABILITIES
2029180583Skmacy		VLAN_CAPABILITIES(ifp);
2030180583Skmacy#endif
2031167514Skmacy		break;
2032167514Skmacy	default:
2033167514Skmacy		error = ether_ioctl(ifp, command, data);
2034167514Skmacy		break;
2035167514Skmacy	}
2036167514Skmacy	return (error);
2037167514Skmacy}
2038167514Skmacy
2039174708Skmacystatic int
2040167514Skmacycxgb_media_change(struct ifnet *ifp)
2041167514Skmacy{
2042167514Skmacy	if_printf(ifp, "media change not supported\n");
2043167514Skmacy	return (ENXIO);
2044167514Skmacy}
2045167514Skmacy
2046167514Skmacystatic void
2047167514Skmacycxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
2048167514Skmacy{
2049167514Skmacy	struct port_info *p = ifp->if_softc;
2050167514Skmacy
2051167514Skmacy	ifmr->ifm_status = IFM_AVALID;
2052167514Skmacy	ifmr->ifm_active = IFM_ETHER;
2053167514Skmacy
2054167514Skmacy	if (!p->link_config.link_ok)
2055167514Skmacy		return;
2056167514Skmacy
2057167514Skmacy	ifmr->ifm_status |= IFM_ACTIVE;
2058167514Skmacy
2059170654Skmacy	switch (p->link_config.speed) {
2060170654Skmacy	case 10:
2061170654Skmacy		ifmr->ifm_active |= IFM_10_T;
2062170654Skmacy		break;
2063170654Skmacy	case 100:
2064170654Skmacy		ifmr->ifm_active |= IFM_100_TX;
2065170654Skmacy			break;
2066170654Skmacy	case 1000:
2067170654Skmacy		ifmr->ifm_active |= IFM_1000_T;
2068170654Skmacy		break;
2069170654Skmacy	}
2070170654Skmacy
2071167514Skmacy	if (p->link_config.duplex)
2072167514Skmacy		ifmr->ifm_active |= IFM_FDX;
2073167514Skmacy	else
2074167514Skmacy		ifmr->ifm_active |= IFM_HDX;
2075167514Skmacy}
2076167514Skmacy
2077167514Skmacystatic void
2078167514Skmacycxgb_async_intr(void *data)
2079167514Skmacy{
2080167760Skmacy	adapter_t *sc = data;
2081167760Skmacy
2082167514Skmacy	if (cxgb_debug)
2083167760Skmacy		device_printf(sc->dev, "cxgb_async_intr\n");
2084170869Skmacy	/*
2085170869Skmacy	 * May need to sleep - defer to taskqueue
2086170869Skmacy	 */
2087170869Skmacy	taskqueue_enqueue(sc->tq, &sc->slow_intr_task);
2088167514Skmacy}
2089167514Skmacy
2090167514Skmacystatic void
2091167514Skmacycxgb_ext_intr_handler(void *arg, int count)
2092167514Skmacy{
2093167514Skmacy	adapter_t *sc = (adapter_t *)arg;
2094167514Skmacy
2095167514Skmacy	if (cxgb_debug)
2096167514Skmacy		printf("cxgb_ext_intr_handler\n");
2097167514Skmacy
2098167514Skmacy	t3_phy_intr_handler(sc);
2099167514Skmacy
2100167514Skmacy	/* Now reenable external interrupts */
2101169978Skmacy	ADAPTER_LOCK(sc);
2102167514Skmacy	if (sc->slow_intr_mask) {
2103167514Skmacy		sc->slow_intr_mask |= F_T3DBG;
2104167514Skmacy		t3_write_reg(sc, A_PL_INT_CAUSE0, F_T3DBG);
2105167514Skmacy		t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
2106167514Skmacy	}
2107169978Skmacy	ADAPTER_UNLOCK(sc);
2108167514Skmacy}
2109167514Skmacy
2110167514Skmacystatic void
2111167746Skmacycheck_link_status(adapter_t *sc)
2112167514Skmacy{
2113167746Skmacy	int i;
2114167514Skmacy
2115167746Skmacy	for (i = 0; i < (sc)->params.nports; ++i) {
2116167746Skmacy		struct port_info *p = &sc->port[i];
2117167514Skmacy
2118176472Skmacy		if (!(p->phy.caps & SUPPORTED_IRQ))
2119167746Skmacy			t3_link_changed(sc, i);
2120170654Skmacy		p->ifp->if_baudrate = p->link_config.speed * 1000000;
2121167746Skmacy	}
2122167514Skmacy}
2123167514Skmacy
2124167514Skmacystatic void
2125167746Skmacycheck_t3b2_mac(struct adapter *adapter)
2126167514Skmacy{
2127167514Skmacy	int i;
2128167514Skmacy
2129176472Skmacy	if(adapter->flags & CXGB_SHUTDOWN)
2130176472Skmacy		return;
2131176472Skmacy
2132167746Skmacy	for_each_port(adapter, i) {
2133167746Skmacy		struct port_info *p = &adapter->port[i];
2134167746Skmacy		struct ifnet *ifp = p->ifp;
2135167746Skmacy		int status;
2136176472Skmacy
2137176472Skmacy		if(adapter->flags & CXGB_SHUTDOWN)
2138176472Skmacy			return;
2139176472Skmacy
2140167746Skmacy		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
2141167746Skmacy			continue;
2142167746Skmacy
2143167746Skmacy		status = 0;
2144167746Skmacy		PORT_LOCK(p);
2145167746Skmacy		if ((ifp->if_drv_flags & IFF_DRV_RUNNING))
2146167746Skmacy			status = t3b2_mac_watchdog_task(&p->mac);
2147167746Skmacy		if (status == 1)
2148167746Skmacy			p->mac.stats.num_toggled++;
2149167746Skmacy		else if (status == 2) {
2150167746Skmacy			struct cmac *mac = &p->mac;
2151180583Skmacy			int mtu = ifp->if_mtu;
2152167746Skmacy
2153180583Skmacy			if (ifp->if_capenable & IFCAP_VLAN_MTU)
2154180583Skmacy				mtu += ETHER_VLAN_ENCAP_LEN;
2155180583Skmacy			t3_mac_set_mtu(mac, mtu);
2156167746Skmacy			t3_mac_set_address(mac, 0, p->hw_addr);
2157167746Skmacy			cxgb_set_rxmode(p);
2158167746Skmacy			t3_link_start(&p->phy, mac, &p->link_config);
2159167746Skmacy			t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
2160171803Skmacy			t3_port_intr_enable(adapter, p->port_id);
2161167746Skmacy			p->mac.stats.num_resets++;
2162167746Skmacy		}
2163167746Skmacy		PORT_UNLOCK(p);
2164167514Skmacy	}
2165167514Skmacy}
2166167514Skmacy
2167167746Skmacystatic void
2168167746Skmacycxgb_tick(void *arg)
2169167746Skmacy{
2170167746Skmacy	adapter_t *sc = (adapter_t *)arg;
2171170869Skmacy
2172176472Skmacy	if(sc->flags & CXGB_SHUTDOWN)
2173176472Skmacy		return;
2174174708Skmacy
2175170869Skmacy	taskqueue_enqueue(sc->tq, &sc->tick_task);
2176181652Skmacy	callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc);
2177170869Skmacy}
2178170869Skmacy
2179170869Skmacystatic void
2180170869Skmacycxgb_tick_handler(void *arg, int count)
2181170869Skmacy{
2182170869Skmacy	adapter_t *sc = (adapter_t *)arg;
2183167746Skmacy	const struct adapter_params *p = &sc->params;
2184181652Skmacy	int i;
2185167746Skmacy
2186176472Skmacy	if(sc->flags & CXGB_SHUTDOWN)
2187176472Skmacy		return;
2188176472Skmacy
2189170869Skmacy	ADAPTER_LOCK(sc);
2190167746Skmacy	if (p->linkpoll_period)
2191167746Skmacy		check_link_status(sc);
2192167746Skmacy
2193181652Skmacy	sc->check_task_cnt++;
2194181652Skmacy
2195167746Skmacy	/*
2196176472Skmacy	 * adapter lock can currently only be acquired after the
2197167746Skmacy	 * port lock
2198167746Skmacy	 */
2199167746Skmacy	ADAPTER_UNLOCK(sc);
2200170654Skmacy
2201176472Skmacy	if (p->rev == T3_REV_B2 && p->nports < 4 && sc->open_device_map)
2202167746Skmacy		check_t3b2_mac(sc);
2203181652Skmacy
2204181652Skmacy	/* Update MAC stats if it's time to do so */
2205181652Skmacy	if (!p->linkpoll_period ||
2206181652Skmacy	    (sc->check_task_cnt * p->linkpoll_period) / 10 >=
2207181652Skmacy	    p->stats_update_period) {
2208181652Skmacy		for_each_port(sc, i) {
2209181652Skmacy			struct port_info *port = &sc->port[i];
2210181652Skmacy			PORT_LOCK(port);
2211181652Skmacy			t3_mac_update_stats(&port->mac);
2212181652Skmacy			PORT_UNLOCK(port);
2213181652Skmacy		}
2214181652Skmacy		sc->check_task_cnt = 0;
2215181652Skmacy	}
2216167746Skmacy}
2217167746Skmacy
2218171978Skmacystatic void
2219171978Skmacytouch_bars(device_t dev)
2220171978Skmacy{
2221171978Skmacy	/*
2222171978Skmacy	 * Don't enable yet
2223171978Skmacy	 */
2224171978Skmacy#if !defined(__LP64__) && 0
2225171978Skmacy	u32 v;
2226171978Skmacy
2227171978Skmacy	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &v);
2228171978Skmacy	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, v);
2229171978Skmacy	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3, &v);
2230171978Skmacy	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_3, v);
2231171978Skmacy	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &v);
2232171978Skmacy	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_5, v);
2233171978Skmacy#endif
2234171978Skmacy}
2235171978Skmacy
2236167514Skmacystatic int
2237171471Skmacyset_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset)
2238171471Skmacy{
2239171471Skmacy	uint8_t *buf;
2240171471Skmacy	int err = 0;
2241171471Skmacy	u32 aligned_offset, aligned_len, *p;
2242171471Skmacy	struct adapter *adapter = pi->adapter;
2243171471Skmacy
2244171471Skmacy
2245171471Skmacy	aligned_offset = offset & ~3;
2246171471Skmacy	aligned_len = (len + (offset & 3) + 3) & ~3;
2247171471Skmacy
2248171471Skmacy	if (aligned_offset != offset || aligned_len != len) {
2249171471Skmacy		buf = malloc(aligned_len, M_DEVBUF, M_WAITOK|M_ZERO);
2250171471Skmacy		if (!buf)
2251171471Skmacy			return (ENOMEM);
2252171471Skmacy		err = t3_seeprom_read(adapter, aligned_offset, (u32 *)buf);
2253171471Skmacy		if (!err && aligned_len > 4)
2254171471Skmacy			err = t3_seeprom_read(adapter,
2255171471Skmacy					      aligned_offset + aligned_len - 4,
2256171471Skmacy					      (u32 *)&buf[aligned_len - 4]);
2257171471Skmacy		if (err)
2258171471Skmacy			goto out;
2259171471Skmacy		memcpy(buf + (offset & 3), data, len);
2260171471Skmacy	} else
2261171471Skmacy		buf = (uint8_t *)(uintptr_t)data;
2262171471Skmacy
2263171471Skmacy	err = t3_seeprom_wp(adapter, 0);
2264171471Skmacy	if (err)
2265171471Skmacy		goto out;
2266171471Skmacy
2267171471Skmacy	for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) {
2268171471Skmacy		err = t3_seeprom_write(adapter, aligned_offset, *p);
2269171471Skmacy		aligned_offset += 4;
2270171471Skmacy	}
2271171471Skmacy
2272171471Skmacy	if (!err)
2273171471Skmacy		err = t3_seeprom_wp(adapter, 1);
2274171471Skmacyout:
2275171471Skmacy	if (buf != data)
2276171471Skmacy		free(buf, M_DEVBUF);
2277171471Skmacy	return err;
2278171471Skmacy}
2279171471Skmacy
2280171471Skmacy
2281171471Skmacystatic int
2282167514Skmacyin_range(int val, int lo, int hi)
2283167514Skmacy{
2284167514Skmacy	return val < 0 || (val <= hi && val >= lo);
2285167514Skmacy}
2286167514Skmacy
2287167514Skmacystatic int
2288170654Skmacycxgb_extension_open(struct cdev *dev, int flags, int fmp, d_thread_t *td)
2289170654Skmacy{
2290170654Skmacy       return (0);
2291170654Skmacy}
2292170654Skmacy
2293170654Skmacystatic int
2294170654Skmacycxgb_extension_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
2295170654Skmacy{
2296170654Skmacy       return (0);
2297170654Skmacy}
2298170654Skmacy
2299170654Skmacystatic int
2300167514Skmacycxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
2301167514Skmacy    int fflag, struct thread *td)
2302167514Skmacy{
2303167514Skmacy	int mmd, error = 0;
2304167514Skmacy	struct port_info *pi = dev->si_drv1;
2305167514Skmacy	adapter_t *sc = pi->adapter;
2306167514Skmacy
2307167514Skmacy#ifdef PRIV_SUPPORTED
2308167514Skmacy	if (priv_check(td, PRIV_DRIVER)) {
2309167514Skmacy		if (cxgb_debug)
2310167514Skmacy			printf("user does not have access to privileged ioctls\n");
2311167514Skmacy		return (EPERM);
2312167514Skmacy	}
2313167514Skmacy#else
2314167514Skmacy	if (suser(td)) {
2315167514Skmacy		if (cxgb_debug)
2316167514Skmacy			printf("user does not have access to privileged ioctls\n");
2317167514Skmacy		return (EPERM);
2318167514Skmacy	}
2319167514Skmacy#endif
2320167514Skmacy
2321167514Skmacy	switch (cmd) {
2322182679Skmacy	case CHELSIO_GET_MIIREG: {
2323167514Skmacy		uint32_t val;
2324167514Skmacy		struct cphy *phy = &pi->phy;
2325182679Skmacy		struct ch_mii_data *mid = (struct ch_mii_data *)data;
2326167514Skmacy
2327167514Skmacy		if (!phy->mdio_read)
2328167514Skmacy			return (EOPNOTSUPP);
2329167514Skmacy		if (is_10G(sc)) {
2330167514Skmacy			mmd = mid->phy_id >> 8;
2331167514Skmacy			if (!mmd)
2332167514Skmacy				mmd = MDIO_DEV_PCS;
2333167514Skmacy			else if (mmd > MDIO_DEV_XGXS)
2334171471Skmacy				return (EINVAL);
2335167514Skmacy
2336167514Skmacy			error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd,
2337167514Skmacy					     mid->reg_num, &val);
2338167514Skmacy		} else
2339167514Skmacy		        error = phy->mdio_read(sc, mid->phy_id & 0x1f, 0,
2340167514Skmacy					     mid->reg_num & 0x1f, &val);
2341167514Skmacy		if (error == 0)
2342167514Skmacy			mid->val_out = val;
2343167514Skmacy		break;
2344167514Skmacy	}
2345182679Skmacy	case CHELSIO_SET_MIIREG: {
2346167514Skmacy		struct cphy *phy = &pi->phy;
2347182679Skmacy		struct ch_mii_data *mid = (struct ch_mii_data *)data;
2348167514Skmacy
2349167514Skmacy		if (!phy->mdio_write)
2350167514Skmacy			return (EOPNOTSUPP);
2351167514Skmacy		if (is_10G(sc)) {
2352167514Skmacy			mmd = mid->phy_id >> 8;
2353167514Skmacy			if (!mmd)
2354167514Skmacy				mmd = MDIO_DEV_PCS;
2355167514Skmacy			else if (mmd > MDIO_DEV_XGXS)
2356167514Skmacy				return (EINVAL);
2357167514Skmacy
2358167514Skmacy			error = phy->mdio_write(sc, mid->phy_id & 0x1f,
2359167514Skmacy					      mmd, mid->reg_num, mid->val_in);
2360167514Skmacy		} else
2361167514Skmacy			error = phy->mdio_write(sc, mid->phy_id & 0x1f, 0,
2362167514Skmacy					      mid->reg_num & 0x1f,
2363167514Skmacy					      mid->val_in);
2364167514Skmacy		break;
2365167514Skmacy	}
2366167514Skmacy	case CHELSIO_SETREG: {
2367167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
2368167514Skmacy		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2369167514Skmacy			return (EFAULT);
2370167514Skmacy		t3_write_reg(sc, edata->addr, edata->val);
2371167514Skmacy		break;
2372167514Skmacy	}
2373167514Skmacy	case CHELSIO_GETREG: {
2374167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
2375167514Skmacy		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2376167514Skmacy			return (EFAULT);
2377167514Skmacy		edata->val = t3_read_reg(sc, edata->addr);
2378167514Skmacy		break;
2379167514Skmacy	}
2380167514Skmacy	case CHELSIO_GET_SGE_CONTEXT: {
2381167514Skmacy		struct ch_cntxt *ecntxt = (struct ch_cntxt *)data;
2382176472Skmacy		mtx_lock_spin(&sc->sge.reg_lock);
2383167514Skmacy		switch (ecntxt->cntxt_type) {
2384167514Skmacy		case CNTXT_TYPE_EGRESS:
2385182679Skmacy			error = -t3_sge_read_ecntxt(sc, ecntxt->cntxt_id,
2386167514Skmacy			    ecntxt->data);
2387167514Skmacy			break;
2388167514Skmacy		case CNTXT_TYPE_FL:
2389182679Skmacy			error = -t3_sge_read_fl(sc, ecntxt->cntxt_id,
2390167514Skmacy			    ecntxt->data);
2391167514Skmacy			break;
2392167514Skmacy		case CNTXT_TYPE_RSP:
2393182679Skmacy			error = -t3_sge_read_rspq(sc, ecntxt->cntxt_id,
2394167514Skmacy			    ecntxt->data);
2395167514Skmacy			break;
2396167514Skmacy		case CNTXT_TYPE_CQ:
2397182679Skmacy			error = -t3_sge_read_cq(sc, ecntxt->cntxt_id,
2398167514Skmacy			    ecntxt->data);
2399167514Skmacy			break;
2400167514Skmacy		default:
2401167514Skmacy			error = EINVAL;
2402167514Skmacy			break;
2403167514Skmacy		}
2404176472Skmacy		mtx_unlock_spin(&sc->sge.reg_lock);
2405167514Skmacy		break;
2406167514Skmacy	}
2407167514Skmacy	case CHELSIO_GET_SGE_DESC: {
2408167514Skmacy		struct ch_desc *edesc = (struct ch_desc *)data;
2409167514Skmacy		int ret;
2410167514Skmacy		if (edesc->queue_num >= SGE_QSETS * 6)
2411167514Skmacy			return (EINVAL);
2412167514Skmacy		ret = t3_get_desc(&sc->sge.qs[edesc->queue_num / 6],
2413167514Skmacy		    edesc->queue_num % 6, edesc->idx, edesc->data);
2414167514Skmacy		if (ret < 0)
2415167514Skmacy			return (EINVAL);
2416167514Skmacy		edesc->size = ret;
2417167514Skmacy		break;
2418167514Skmacy	}
2419182679Skmacy	case CHELSIO_GET_QSET_PARAMS: {
2420167514Skmacy		struct qset_params *q;
2421167514Skmacy		struct ch_qset_params *t = (struct ch_qset_params *)data;
2422182679Skmacy		int q1 = pi->first_qset;
2423182679Skmacy		int nqsets = pi->nqsets;
2424176472Skmacy		int i;
2425176472Skmacy
2426182679Skmacy		if (t->qset_idx >= nqsets)
2427182679Skmacy			return EINVAL;
2428167514Skmacy
2429182679Skmacy		i = q1 + t->qset_idx;
2430182679Skmacy		q = &sc->params.sge.qset[i];
2431167514Skmacy		t->rspq_size   = q->rspq_size;
2432167514Skmacy		t->txq_size[0] = q->txq_size[0];
2433167514Skmacy		t->txq_size[1] = q->txq_size[1];
2434167514Skmacy		t->txq_size[2] = q->txq_size[2];
2435167514Skmacy		t->fl_size[0]  = q->fl_size;
2436167514Skmacy		t->fl_size[1]  = q->jumbo_size;
2437167514Skmacy		t->polling     = q->polling;
2438182679Skmacy		t->lro         = q->lro;
2439180583Skmacy		t->intr_lat    = q->coalesce_usecs;
2440167514Skmacy		t->cong_thres  = q->cong_thres;
2441182679Skmacy		t->qnum        = i;
2442182679Skmacy
2443182679Skmacy		if (sc->flags & USING_MSIX)
2444182679Skmacy			t->vector = rman_get_start(sc->msix_irq_res[i]);
2445182679Skmacy		else
2446182679Skmacy			t->vector = rman_get_start(sc->irq_res);
2447182679Skmacy
2448167514Skmacy		break;
2449167514Skmacy	}
2450182679Skmacy	case CHELSIO_GET_QSET_NUM: {
2451167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
2452182679Skmacy		edata->val = pi->nqsets;
2453182679Skmacy		break;
2454182679Skmacy	}
2455182679Skmacy	case CHELSIO_LOAD_FW: {
2456182679Skmacy		uint8_t *fw_data;
2457182679Skmacy		uint32_t vers;
2458182679Skmacy		struct ch_mem_range *t = (struct ch_mem_range *)data;
2459182679Skmacy
2460167514Skmacy		/*
2461182679Skmacy		 * You're allowed to load a firmware only before FULL_INIT_DONE
2462182679Skmacy		 *
2463182679Skmacy		 * FW_UPTODATE is also set so the rest of the initialization
2464182679Skmacy		 * will not overwrite what was loaded here.  This gives you the
2465182679Skmacy		 * flexibility to load any firmware (and maybe shoot yourself in
2466182679Skmacy		 * the foot).
2467167514Skmacy		 */
2468182679Skmacy
2469182679Skmacy		ADAPTER_LOCK(sc);
2470182679Skmacy		if (sc->open_device_map || sc->flags & FULL_INIT_DONE) {
2471182679Skmacy			ADAPTER_UNLOCK(sc);
2472182679Skmacy			return (EBUSY);
2473182679Skmacy		}
2474182679Skmacy
2475182679Skmacy		fw_data = malloc(t->len, M_DEVBUF, M_NOWAIT);
2476182679Skmacy		if (!fw_data)
2477182679Skmacy			error = ENOMEM;
2478182679Skmacy		else
2479182679Skmacy			error = copyin(t->buf, fw_data, t->len);
2480182679Skmacy
2481182679Skmacy		if (!error)
2482182679Skmacy			error = -t3_load_fw(sc, fw_data, t->len);
2483182679Skmacy
2484182679Skmacy		if (t3_get_fw_version(sc, &vers) == 0) {
2485182679Skmacy			snprintf(&sc->fw_version[0], sizeof(sc->fw_version),
2486182679Skmacy			    "%d.%d.%d", G_FW_VERSION_MAJOR(vers),
2487182679Skmacy			    G_FW_VERSION_MINOR(vers), G_FW_VERSION_MICRO(vers));
2488182679Skmacy		}
2489182679Skmacy
2490182679Skmacy		if (!error)
2491182679Skmacy			sc->flags |= FW_UPTODATE;
2492182679Skmacy
2493182679Skmacy		free(fw_data, M_DEVBUF);
2494182679Skmacy		ADAPTER_UNLOCK(sc);
2495167514Skmacy		break;
2496167514Skmacy	}
2497182679Skmacy	case CHELSIO_LOAD_BOOT: {
2498182679Skmacy		uint8_t *boot_data;
2499182679Skmacy		struct ch_mem_range *t = (struct ch_mem_range *)data;
2500182679Skmacy
2501182679Skmacy		boot_data = malloc(t->len, M_DEVBUF, M_NOWAIT);
2502182679Skmacy		if (!boot_data)
2503182679Skmacy			return ENOMEM;
2504182679Skmacy
2505182679Skmacy		error = copyin(t->buf, boot_data, t->len);
2506182679Skmacy		if (!error)
2507182679Skmacy			error = -t3_load_boot(sc, boot_data, t->len);
2508182679Skmacy
2509182679Skmacy		free(boot_data, M_DEVBUF);
2510167514Skmacy		break;
2511167514Skmacy	}
2512182679Skmacy	case CHELSIO_GET_PM: {
2513182679Skmacy		struct ch_pm *m = (struct ch_pm *)data;
2514182679Skmacy		struct tp_params *p = &sc->params.tp;
2515182679Skmacy
2516182679Skmacy		if (!is_offload(sc))
2517182679Skmacy			return (EOPNOTSUPP);
2518182679Skmacy
2519182679Skmacy		m->tx_pg_sz = p->tx_pg_size;
2520182679Skmacy		m->tx_num_pg = p->tx_num_pgs;
2521182679Skmacy		m->rx_pg_sz  = p->rx_pg_size;
2522182679Skmacy		m->rx_num_pg = p->rx_num_pgs;
2523182679Skmacy		m->pm_total  = p->pmtx_size + p->chan_rx_size * p->nchan;
2524182679Skmacy
2525167514Skmacy		break;
2526182679Skmacy	}
2527182679Skmacy	case CHELSIO_SET_PM: {
2528182679Skmacy		struct ch_pm *m = (struct ch_pm *)data;
2529182679Skmacy		struct tp_params *p = &sc->params.tp;
2530182679Skmacy
2531182679Skmacy		if (!is_offload(sc))
2532182679Skmacy			return (EOPNOTSUPP);
2533182679Skmacy		if (sc->flags & FULL_INIT_DONE)
2534182679Skmacy			return (EBUSY);
2535182679Skmacy
2536182679Skmacy		if (!m->rx_pg_sz || (m->rx_pg_sz & (m->rx_pg_sz - 1)) ||
2537182679Skmacy		    !m->tx_pg_sz || (m->tx_pg_sz & (m->tx_pg_sz - 1)))
2538182679Skmacy			return (EINVAL);	/* not power of 2 */
2539182679Skmacy		if (!(m->rx_pg_sz & 0x14000))
2540182679Skmacy			return (EINVAL);	/* not 16KB or 64KB */
2541182679Skmacy		if (!(m->tx_pg_sz & 0x1554000))
2542182679Skmacy			return (EINVAL);
2543182679Skmacy		if (m->tx_num_pg == -1)
2544182679Skmacy			m->tx_num_pg = p->tx_num_pgs;
2545182679Skmacy		if (m->rx_num_pg == -1)
2546182679Skmacy			m->rx_num_pg = p->rx_num_pgs;
2547182679Skmacy		if (m->tx_num_pg % 24 || m->rx_num_pg % 24)
2548182679Skmacy			return (EINVAL);
2549182679Skmacy		if (m->rx_num_pg * m->rx_pg_sz > p->chan_rx_size ||
2550182679Skmacy		    m->tx_num_pg * m->tx_pg_sz > p->chan_tx_size)
2551182679Skmacy			return (EINVAL);
2552182679Skmacy
2553182679Skmacy		p->rx_pg_size = m->rx_pg_sz;
2554182679Skmacy		p->tx_pg_size = m->tx_pg_sz;
2555182679Skmacy		p->rx_num_pgs = m->rx_num_pg;
2556182679Skmacy		p->tx_num_pgs = m->tx_num_pg;
2557182679Skmacy		break;
2558182679Skmacy	}
2559169978Skmacy	case CHELSIO_SETMTUTAB: {
2560169978Skmacy		struct ch_mtus *m = (struct ch_mtus *)data;
2561169978Skmacy		int i;
2562169978Skmacy
2563169978Skmacy		if (!is_offload(sc))
2564169978Skmacy			return (EOPNOTSUPP);
2565169978Skmacy		if (offload_running(sc))
2566169978Skmacy			return (EBUSY);
2567169978Skmacy		if (m->nmtus != NMTUS)
2568169978Skmacy			return (EINVAL);
2569169978Skmacy		if (m->mtus[0] < 81)         /* accommodate SACK */
2570169978Skmacy			return (EINVAL);
2571169978Skmacy
2572169978Skmacy		/*
2573169978Skmacy		 * MTUs must be in ascending order
2574169978Skmacy		 */
2575169978Skmacy		for (i = 1; i < NMTUS; ++i)
2576169978Skmacy			if (m->mtus[i] < m->mtus[i - 1])
2577169978Skmacy				return (EINVAL);
2578169978Skmacy
2579182679Skmacy		memcpy(sc->params.mtus, m->mtus, sizeof(sc->params.mtus));
2580169978Skmacy		break;
2581169978Skmacy	}
2582169978Skmacy	case CHELSIO_GETMTUTAB: {
2583169978Skmacy		struct ch_mtus *m = (struct ch_mtus *)data;
2584169978Skmacy
2585169978Skmacy		if (!is_offload(sc))
2586169978Skmacy			return (EOPNOTSUPP);
2587169978Skmacy
2588169978Skmacy		memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus));
2589169978Skmacy		m->nmtus = NMTUS;
2590169978Skmacy		break;
2591171471Skmacy	}
2592167514Skmacy	case CHELSIO_GET_MEM: {
2593167514Skmacy		struct ch_mem_range *t = (struct ch_mem_range *)data;
2594167514Skmacy		struct mc7 *mem;
2595167514Skmacy		uint8_t *useraddr;
2596167514Skmacy		u64 buf[32];
2597182679Skmacy
2598182679Skmacy		/*
2599182679Skmacy		 * Use these to avoid modifying len/addr in the the return
2600182679Skmacy		 * struct
2601182679Skmacy		 */
2602182679Skmacy		uint32_t len = t->len, addr = t->addr;
2603182679Skmacy
2604167514Skmacy		if (!is_offload(sc))
2605167514Skmacy			return (EOPNOTSUPP);
2606167514Skmacy		if (!(sc->flags & FULL_INIT_DONE))
2607167514Skmacy			return (EIO);         /* need the memory controllers */
2608182679Skmacy		if ((addr & 0x7) || (len & 0x7))
2609167514Skmacy			return (EINVAL);
2610167514Skmacy		if (t->mem_id == MEM_CM)
2611167514Skmacy			mem = &sc->cm;
2612167514Skmacy		else if (t->mem_id == MEM_PMRX)
2613167514Skmacy			mem = &sc->pmrx;
2614167514Skmacy		else if (t->mem_id == MEM_PMTX)
2615167514Skmacy			mem = &sc->pmtx;
2616167514Skmacy		else
2617167514Skmacy			return (EINVAL);
2618167514Skmacy
2619167514Skmacy		/*
2620167514Skmacy		 * Version scheme:
2621167514Skmacy		 * bits 0..9: chip version
2622167514Skmacy		 * bits 10..15: chip revision
2623167514Skmacy		 */
2624167514Skmacy		t->version = 3 | (sc->params.rev << 10);
2625167514Skmacy
2626167514Skmacy		/*
2627167514Skmacy		 * Read 256 bytes at a time as len can be large and we don't
2628167514Skmacy		 * want to use huge intermediate buffers.
2629167514Skmacy		 */
2630174708Skmacy		useraddr = (uint8_t *)t->buf;
2631182679Skmacy		while (len) {
2632182679Skmacy			unsigned int chunk = min(len, sizeof(buf));
2633167514Skmacy
2634182679Skmacy			error = t3_mc7_bd_read(mem, addr / 8, chunk / 8, buf);
2635167514Skmacy			if (error)
2636167514Skmacy				return (-error);
2637167514Skmacy			if (copyout(buf, useraddr, chunk))
2638167514Skmacy				return (EFAULT);
2639167514Skmacy			useraddr += chunk;
2640182679Skmacy			addr += chunk;
2641182679Skmacy			len -= chunk;
2642167514Skmacy		}
2643167514Skmacy		break;
2644167514Skmacy	}
2645169978Skmacy	case CHELSIO_READ_TCAM_WORD: {
2646169978Skmacy		struct ch_tcam_word *t = (struct ch_tcam_word *)data;
2647169978Skmacy
2648169978Skmacy		if (!is_offload(sc))
2649169978Skmacy			return (EOPNOTSUPP);
2650171471Skmacy		if (!(sc->flags & FULL_INIT_DONE))
2651171471Skmacy			return (EIO);         /* need MC5 */
2652169978Skmacy		return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf);
2653169978Skmacy		break;
2654169978Skmacy	}
2655167514Skmacy	case CHELSIO_SET_TRACE_FILTER: {
2656167514Skmacy		struct ch_trace *t = (struct ch_trace *)data;
2657167514Skmacy		const struct trace_params *tp;
2658167514Skmacy
2659167514Skmacy		tp = (const struct trace_params *)&t->sip;
2660167514Skmacy		if (t->config_tx)
2661167514Skmacy			t3_config_trace_filter(sc, tp, 0, t->invert_match,
2662167514Skmacy					       t->trace_tx);
2663167514Skmacy		if (t->config_rx)
2664167514Skmacy			t3_config_trace_filter(sc, tp, 1, t->invert_match,
2665167514Skmacy					       t->trace_rx);
2666167514Skmacy		break;
2667167514Skmacy	}
2668167514Skmacy	case CHELSIO_SET_PKTSCHED: {
2669167514Skmacy		struct ch_pktsched_params *p = (struct ch_pktsched_params *)data;
2670167514Skmacy		if (sc->open_device_map == 0)
2671167514Skmacy			return (EAGAIN);
2672167514Skmacy		send_pktsched_cmd(sc, p->sched, p->idx, p->min, p->max,
2673167514Skmacy		    p->binding);
2674167514Skmacy		break;
2675167514Skmacy	}
2676167514Skmacy	case CHELSIO_IFCONF_GETREGS: {
2677182679Skmacy		struct ch_ifconf_regs *regs = (struct ch_ifconf_regs *)data;
2678167514Skmacy		int reglen = cxgb_get_regs_len();
2679182679Skmacy		uint8_t *buf = malloc(reglen, M_DEVBUF, M_NOWAIT);
2680167514Skmacy		if (buf == NULL) {
2681167514Skmacy			return (ENOMEM);
2682182679Skmacy		}
2683182679Skmacy		if (regs->len > reglen)
2684167514Skmacy			regs->len = reglen;
2685182679Skmacy		else if (regs->len < reglen)
2686167514Skmacy			error = E2BIG;
2687182679Skmacy
2688182679Skmacy		if (!error) {
2689182679Skmacy			cxgb_get_regs(sc, regs, buf);
2690182679Skmacy			error = copyout(buf, regs->data, reglen);
2691167514Skmacy		}
2692167514Skmacy		free(buf, M_DEVBUF);
2693167514Skmacy
2694167514Skmacy		break;
2695167514Skmacy	}
2696169978Skmacy	case CHELSIO_SET_HW_SCHED: {
2697169978Skmacy		struct ch_hw_sched *t = (struct ch_hw_sched *)data;
2698169978Skmacy		unsigned int ticks_per_usec = core_ticks_per_usec(sc);
2699169978Skmacy
2700169978Skmacy		if ((sc->flags & FULL_INIT_DONE) == 0)
2701169978Skmacy			return (EAGAIN);       /* need TP to be initialized */
2702169978Skmacy		if (t->sched >= NTX_SCHED || !in_range(t->mode, 0, 1) ||
2703169978Skmacy		    !in_range(t->channel, 0, 1) ||
2704169978Skmacy		    !in_range(t->kbps, 0, 10000000) ||
2705169978Skmacy		    !in_range(t->class_ipg, 0, 10000 * 65535 / ticks_per_usec) ||
2706169978Skmacy		    !in_range(t->flow_ipg, 0,
2707169978Skmacy			      dack_ticks_to_usec(sc, 0x7ff)))
2708169978Skmacy			return (EINVAL);
2709169978Skmacy
2710169978Skmacy		if (t->kbps >= 0) {
2711169978Skmacy			error = t3_config_sched(sc, t->kbps, t->sched);
2712169978Skmacy			if (error < 0)
2713169978Skmacy				return (-error);
2714169978Skmacy		}
2715169978Skmacy		if (t->class_ipg >= 0)
2716169978Skmacy			t3_set_sched_ipg(sc, t->sched, t->class_ipg);
2717169978Skmacy		if (t->flow_ipg >= 0) {
2718169978Skmacy			t->flow_ipg *= 1000;     /* us -> ns */
2719169978Skmacy			t3_set_pace_tbl(sc, &t->flow_ipg, t->sched, 1);
2720169978Skmacy		}
2721169978Skmacy		if (t->mode >= 0) {
2722169978Skmacy			int bit = 1 << (S_TX_MOD_TIMER_MODE + t->sched);
2723169978Skmacy
2724169978Skmacy			t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2725169978Skmacy					 bit, t->mode ? bit : 0);
2726169978Skmacy		}
2727169978Skmacy		if (t->channel >= 0)
2728169978Skmacy			t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2729169978Skmacy					 1 << t->sched, t->channel << t->sched);
2730169978Skmacy		break;
2731182679Skmacy	}
2732182679Skmacy	case CHELSIO_GET_EEPROM: {
2733182679Skmacy		int i;
2734182679Skmacy		struct ch_eeprom *e = (struct ch_eeprom *)data;
2735182679Skmacy		uint8_t *buf = malloc(EEPROMSIZE, M_DEVBUF, M_NOWAIT);
2736182679Skmacy
2737182679Skmacy		if (buf == NULL) {
2738182679Skmacy			return (ENOMEM);
2739182679Skmacy		}
2740182679Skmacy		e->magic = EEPROM_MAGIC;
2741182679Skmacy		for (i = e->offset & ~3; !error && i < e->offset + e->len; i += 4)
2742182679Skmacy			error = -t3_seeprom_read(sc, i, (uint32_t *)&buf[i]);
2743182679Skmacy
2744182679Skmacy		if (!error)
2745182679Skmacy			error = copyout(buf + e->offset, e->data, e->len);
2746182679Skmacy
2747182679Skmacy		free(buf, M_DEVBUF);
2748182679Skmacy		break;
2749182679Skmacy	}
2750182679Skmacy	case CHELSIO_CLEAR_STATS: {
2751182679Skmacy		if (!(sc->flags & FULL_INIT_DONE))
2752182679Skmacy			return EAGAIN;
2753182679Skmacy
2754182679Skmacy		PORT_LOCK(pi);
2755182679Skmacy		t3_mac_update_stats(&pi->mac);
2756182679Skmacy		memset(&pi->mac.stats, 0, sizeof(pi->mac.stats));
2757182679Skmacy		PORT_UNLOCK(pi);
2758182679Skmacy		break;
2759182679Skmacy	}
2760167514Skmacy	default:
2761167514Skmacy		return (EOPNOTSUPP);
2762167514Skmacy		break;
2763167514Skmacy	}
2764167514Skmacy
2765167514Skmacy	return (error);
2766167514Skmacy}
2767167514Skmacy
2768167514Skmacystatic __inline void
2769167514Skmacyreg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
2770167514Skmacy    unsigned int end)
2771167514Skmacy{
2772182679Skmacy	uint32_t *p = (uint32_t *)(buf + start);
2773167514Skmacy
2774167514Skmacy	for ( ; start <= end; start += sizeof(uint32_t))
2775167514Skmacy		*p++ = t3_read_reg(ap, start);
2776167514Skmacy}
2777167514Skmacy
2778167514Skmacy#define T3_REGMAP_SIZE (3 * 1024)
2779167514Skmacystatic int
2780167514Skmacycxgb_get_regs_len(void)
2781167514Skmacy{
2782167514Skmacy	return T3_REGMAP_SIZE;
2783167514Skmacy}
2784167514Skmacy
2785167514Skmacystatic void
2786182679Skmacycxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf)
2787167514Skmacy{
2788167514Skmacy
2789167514Skmacy	/*
2790167514Skmacy	 * Version scheme:
2791167514Skmacy	 * bits 0..9: chip version
2792167514Skmacy	 * bits 10..15: chip revision
2793167514Skmacy	 * bit 31: set for PCIe cards
2794167514Skmacy	 */
2795167514Skmacy	regs->version = 3 | (sc->params.rev << 10) | (is_pcie(sc) << 31);
2796167514Skmacy
2797167514Skmacy	/*
2798167514Skmacy	 * We skip the MAC statistics registers because they are clear-on-read.
2799167514Skmacy	 * Also reading multi-register stats would need to synchronize with the
2800167514Skmacy	 * periodic mac stats accumulation.  Hard to justify the complexity.
2801167514Skmacy	 */
2802182679Skmacy	memset(buf, 0, cxgb_get_regs_len());
2803167514Skmacy	reg_block_dump(sc, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
2804167514Skmacy	reg_block_dump(sc, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
2805167514Skmacy	reg_block_dump(sc, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
2806167514Skmacy	reg_block_dump(sc, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
2807167514Skmacy	reg_block_dump(sc, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
2808167514Skmacy	reg_block_dump(sc, buf, A_XGM_SERDES_STATUS0,
2809167514Skmacy		       XGM_REG(A_XGM_SERDES_STAT3, 1));
2810167514Skmacy	reg_block_dump(sc, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
2811167514Skmacy		       XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
2812167514Skmacy}
2813176572Skmacy
2814176572Skmacy
2815176572SkmacyMODULE_DEPEND(if_cxgb, cxgb_t3fw, 1, 1, 1);
2816