cxgb_main.c revision 183289
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 183289 2008-09-23 02:22:24Z 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;
337183063Skmacy
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);
354183063Skmacy
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
879183289Skmacy#ifndef LRO_SUPPORTED
880183289Skmacy#ifdef IFCAP_LRO
881183289Skmacy#undef IFCAP_LRO
882183289Skmacy#endif
883183289Skmacy#define IFCAP_LRO 0x0
884183289Skmacy#endif
885167514Skmacy
886167514Skmacy#ifdef TSO_SUPPORTED
887181616Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO)
888167514Skmacy/* Don't enable TSO6 yet */
889181616Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO4 | IFCAP_JUMBO_MTU | IFCAP_LRO)
890167514Skmacy#else
891167514Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU)
892167514Skmacy/* Don't enable TSO6 yet */
893167514Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM |  IFCAP_JUMBO_MTU)
894167514Skmacy#define IFCAP_TSO4 0x0
895171868Skmacy#define IFCAP_TSO6 0x0
896167514Skmacy#define CSUM_TSO   0x0
897167514Skmacy#endif
898167514Skmacy
899167514Skmacy
900167514Skmacystatic int
901167514Skmacycxgb_port_attach(device_t dev)
902167514Skmacy{
903167514Skmacy	struct port_info *p;
904167514Skmacy	struct ifnet *ifp;
905170654Skmacy	int err, media_flags;
906176472Skmacy	struct adapter *sc;
907167514Skmacy
908176472Skmacy
909167514Skmacy	p = device_get_softc(dev);
910176472Skmacy	sc = p->adapter;
911170869Skmacy	snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d",
912171803Skmacy	    device_get_unit(device_get_parent(dev)), p->port_id);
913170869Skmacy	PORT_LOCK_INIT(p, p->lockbuf);
914167514Skmacy
915167514Skmacy	/* Allocate an ifnet object and set it up */
916167514Skmacy	ifp = p->ifp = if_alloc(IFT_ETHER);
917167514Skmacy	if (ifp == NULL) {
918167514Skmacy		device_printf(dev, "Cannot allocate ifnet\n");
919167514Skmacy		return (ENOMEM);
920167514Skmacy	}
921167514Skmacy
922167514Skmacy	/*
923167514Skmacy	 * Note that there is currently no watchdog timer.
924167514Skmacy	 */
925167514Skmacy	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
926167514Skmacy	ifp->if_init = cxgb_init;
927167514Skmacy	ifp->if_softc = p;
928167514Skmacy	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
929167514Skmacy	ifp->if_ioctl = cxgb_ioctl;
930167514Skmacy	ifp->if_start = cxgb_start;
931174708Skmacy
932176472Skmacy#if 0
933174708Skmacy#ifdef IFNET_MULTIQUEUE
934174708Skmacy	ifp->if_flags |= IFF_MULTIQ;
935174708Skmacy	ifp->if_mq_start = cxgb_pcpu_start;
936174708Skmacy#endif
937176472Skmacy#endif
938167514Skmacy	ifp->if_timer = 0;	/* Disable ifnet watchdog */
939167514Skmacy	ifp->if_watchdog = NULL;
940167514Skmacy
941175312Skmacy	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
942167514Skmacy	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
943167514Skmacy	IFQ_SET_READY(&ifp->if_snd);
944167514Skmacy
945167514Skmacy	ifp->if_hwassist = ifp->if_capabilities = ifp->if_capenable = 0;
946167514Skmacy	ifp->if_capabilities |= CXGB_CAP;
947167514Skmacy	ifp->if_capenable |= CXGB_CAP_ENABLE;
948167514Skmacy	ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO);
949171471Skmacy	/*
950171471Skmacy	 * disable TSO on 4-port - it isn't supported by the firmware yet
951171471Skmacy	 */
952171471Skmacy	if (p->adapter->params.nports > 2) {
953171471Skmacy		ifp->if_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6);
954171471Skmacy		ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TSO6);
955171471Skmacy		ifp->if_hwassist &= ~CSUM_TSO;
956171471Skmacy	}
957171471Skmacy
958167514Skmacy	ether_ifattach(ifp, p->hw_addr);
959171471Skmacy	/*
960171471Skmacy	 * Only default to jumbo frames on 10GigE
961171471Skmacy	 */
962171471Skmacy	if (p->adapter->params.nports <= 2)
963180583Skmacy		ifp->if_mtu = ETHERMTU_JUMBO;
964167514Skmacy	if ((err = cxgb_makedev(p)) != 0) {
965167514Skmacy		printf("makedev failed %d\n", err);
966167514Skmacy		return (err);
967167514Skmacy	}
968167514Skmacy	ifmedia_init(&p->media, IFM_IMASK, cxgb_media_change,
969167514Skmacy	    cxgb_media_status);
970176472Skmacy
971176472Skmacy	if (!strcmp(p->phy.desc,	"10GBASE-CX4")) {
972170654Skmacy		media_flags = IFM_ETHER | IFM_10G_CX4 | IFM_FDX;
973176472Skmacy	} else if (!strcmp(p->phy.desc, "10GBASE-SR")) {
974170654Skmacy		media_flags = IFM_ETHER | IFM_10G_SR | IFM_FDX;
975177340Skmacy	} else if (!strcmp(p->phy.desc, "10GBASE-R")) {
976170654Skmacy		media_flags = IFM_ETHER | IFM_10G_LR | IFM_FDX;
977176472Skmacy	} else if (!strcmp(p->phy.desc, "10/100/1000BASE-T")) {
978170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_10_T, 0, NULL);
979170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_10_T | IFM_FDX,
980170654Skmacy			    0, NULL);
981170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX,
982170654Skmacy			    0, NULL);
983170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX | IFM_FDX,
984170654Skmacy			    0, NULL);
985170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_1000_T | IFM_FDX,
986170654Skmacy			    0, NULL);
987170654Skmacy		media_flags = 0;
988170654Skmacy	} else {
989176472Skmacy	        printf("unsupported media type %s\n", p->phy.desc);
990167514Skmacy		return (ENXIO);
991167514Skmacy	}
992170654Skmacy	if (media_flags) {
993170654Skmacy		ifmedia_add(&p->media, media_flags, 0, NULL);
994170654Skmacy		ifmedia_set(&p->media, media_flags);
995170654Skmacy	} else {
996170654Skmacy		ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL);
997170654Skmacy		ifmedia_set(&p->media, IFM_ETHER | IFM_AUTO);
998170654Skmacy	}
999167514Skmacy
1000177340Skmacy	/* Get the latest mac address, User can use a LAA */
1001177340Skmacy	bcopy(IF_LLADDR(p->ifp), p->hw_addr, ETHER_ADDR_LEN);
1002170654Skmacy	t3_sge_init_port(p);
1003177415Skmacy#if defined(LINK_ATTACH)
1004176472Skmacy	cxgb_link_start(p);
1005176472Skmacy	t3_link_changed(sc, p->port_id);
1006177415Skmacy#endif
1007167514Skmacy	return (0);
1008167514Skmacy}
1009167514Skmacy
1010167514Skmacystatic int
1011167514Skmacycxgb_port_detach(device_t dev)
1012167514Skmacy{
1013167514Skmacy	struct port_info *p;
1014167514Skmacy
1015167514Skmacy	p = device_get_softc(dev);
1016169978Skmacy
1017169978Skmacy	PORT_LOCK(p);
1018170654Skmacy	if (p->ifp->if_drv_flags & IFF_DRV_RUNNING)
1019170654Skmacy		cxgb_stop_locked(p);
1020169978Skmacy	PORT_UNLOCK(p);
1021169978Skmacy
1022171978Skmacy	ether_ifdetach(p->ifp);
1023174708Skmacy	printf("waiting for callout to stop ...");
1024174708Skmacy	DELAY(1000000);
1025174708Skmacy	printf("done\n");
1026171978Skmacy	/*
1027171978Skmacy	 * the lock may be acquired in ifdetach
1028171978Skmacy	 */
1029170869Skmacy	PORT_LOCK_DEINIT(p);
1030167514Skmacy	if_free(p->ifp);
1031167514Skmacy
1032170654Skmacy	if (p->port_cdev != NULL)
1033170654Skmacy		destroy_dev(p->port_cdev);
1034170654Skmacy
1035167514Skmacy	return (0);
1036167514Skmacy}
1037167514Skmacy
1038167514Skmacyvoid
1039167514Skmacyt3_fatal_err(struct adapter *sc)
1040167514Skmacy{
1041167514Skmacy	u_int fw_status[4];
1042183062Skmacy
1043172096Skmacy	if (sc->flags & FULL_INIT_DONE) {
1044172096Skmacy		t3_sge_stop(sc);
1045172096Skmacy		t3_write_reg(sc, A_XGM_TX_CTRL, 0);
1046172096Skmacy		t3_write_reg(sc, A_XGM_RX_CTRL, 0);
1047172096Skmacy		t3_write_reg(sc, XGM_REG(A_XGM_TX_CTRL, 1), 0);
1048172096Skmacy		t3_write_reg(sc, XGM_REG(A_XGM_RX_CTRL, 1), 0);
1049172096Skmacy		t3_intr_disable(sc);
1050172096Skmacy	}
1051167514Skmacy	device_printf(sc->dev,"encountered fatal error, operation suspended\n");
1052167514Skmacy	if (!t3_cim_ctl_blk_read(sc, 0xa0, 4, fw_status))
1053167514Skmacy		device_printf(sc->dev, "FW_ status: 0x%x, 0x%x, 0x%x, 0x%x\n",
1054167514Skmacy		    fw_status[0], fw_status[1], fw_status[2], fw_status[3]);
1055167514Skmacy}
1056167514Skmacy
1057167514Skmacyint
1058167514Skmacyt3_os_find_pci_capability(adapter_t *sc, int cap)
1059167514Skmacy{
1060167514Skmacy	device_t dev;
1061167514Skmacy	struct pci_devinfo *dinfo;
1062167514Skmacy	pcicfgregs *cfg;
1063167514Skmacy	uint32_t status;
1064167514Skmacy	uint8_t ptr;
1065167514Skmacy
1066167514Skmacy	dev = sc->dev;
1067167514Skmacy	dinfo = device_get_ivars(dev);
1068167514Skmacy	cfg = &dinfo->cfg;
1069167514Skmacy
1070167514Skmacy	status = pci_read_config(dev, PCIR_STATUS, 2);
1071167514Skmacy	if (!(status & PCIM_STATUS_CAPPRESENT))
1072167514Skmacy		return (0);
1073167514Skmacy
1074167514Skmacy	switch (cfg->hdrtype & PCIM_HDRTYPE) {
1075167514Skmacy	case 0:
1076167514Skmacy	case 1:
1077167514Skmacy		ptr = PCIR_CAP_PTR;
1078167514Skmacy		break;
1079167514Skmacy	case 2:
1080167514Skmacy		ptr = PCIR_CAP_PTR_2;
1081167514Skmacy		break;
1082167514Skmacy	default:
1083167514Skmacy		return (0);
1084167514Skmacy		break;
1085167514Skmacy	}
1086167514Skmacy	ptr = pci_read_config(dev, ptr, 1);
1087167514Skmacy
1088167514Skmacy	while (ptr != 0) {
1089167514Skmacy		if (pci_read_config(dev, ptr + PCICAP_ID, 1) == cap)
1090167514Skmacy			return (ptr);
1091167514Skmacy		ptr = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1);
1092167514Skmacy	}
1093167514Skmacy
1094167514Skmacy	return (0);
1095167514Skmacy}
1096167514Skmacy
1097167514Skmacyint
1098167514Skmacyt3_os_pci_save_state(struct adapter *sc)
1099167514Skmacy{
1100167514Skmacy	device_t dev;
1101167514Skmacy	struct pci_devinfo *dinfo;
1102167514Skmacy
1103167514Skmacy	dev = sc->dev;
1104167514Skmacy	dinfo = device_get_ivars(dev);
1105167514Skmacy
1106167514Skmacy	pci_cfg_save(dev, dinfo, 0);
1107167514Skmacy	return (0);
1108167514Skmacy}
1109167514Skmacy
1110167514Skmacyint
1111167514Skmacyt3_os_pci_restore_state(struct adapter *sc)
1112167514Skmacy{
1113167514Skmacy	device_t dev;
1114167514Skmacy	struct pci_devinfo *dinfo;
1115167514Skmacy
1116167514Skmacy	dev = sc->dev;
1117167514Skmacy	dinfo = device_get_ivars(dev);
1118167514Skmacy
1119167514Skmacy	pci_cfg_restore(dev, dinfo);
1120167514Skmacy	return (0);
1121167514Skmacy}
1122167514Skmacy
1123167514Skmacy/**
1124167514Skmacy *	t3_os_link_changed - handle link status changes
1125167514Skmacy *	@adapter: the adapter associated with the link change
1126167514Skmacy *	@port_id: the port index whose limk status has changed
1127177340Skmacy *	@link_status: the new status of the link
1128167514Skmacy *	@speed: the new speed setting
1129167514Skmacy *	@duplex: the new duplex setting
1130167514Skmacy *	@fc: the new flow-control setting
1131167514Skmacy *
1132167514Skmacy *	This is the OS-dependent handler for link status changes.  The OS
1133167514Skmacy *	neutral handler takes care of most of the processing for these events,
1134167514Skmacy *	then calls this handler for any OS-specific processing.
1135167514Skmacy */
1136167514Skmacyvoid
1137167514Skmacyt3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed,
1138167514Skmacy     int duplex, int fc)
1139167514Skmacy{
1140167514Skmacy	struct port_info *pi = &adapter->port[port_id];
1141169978Skmacy	struct cmac *mac = &adapter->port[port_id].mac;
1142167514Skmacy
1143169978Skmacy	if (link_status) {
1144177340Skmacy		DELAY(10);
1145177340Skmacy		t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
1146177340Skmacy			/* Clear errors created by MAC enable */
1147177340Skmacy			t3_set_reg_field(adapter,
1148177340Skmacy					 A_XGM_STAT_CTRL + pi->mac.offset,
1149177340Skmacy					 F_CLRSTATS, 1);
1150167514Skmacy		if_link_state_change(pi->ifp, LINK_STATE_UP);
1151177340Skmacy
1152169978Skmacy	} else {
1153169978Skmacy		pi->phy.ops->power_down(&pi->phy, 1);
1154169978Skmacy		t3_mac_disable(mac, MAC_DIRECTION_RX);
1155169978Skmacy		t3_link_start(&pi->phy, mac, &pi->link_config);
1156177340Skmacy		t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
1157176472Skmacy		if_link_state_change(pi->ifp, LINK_STATE_DOWN);
1158169978Skmacy	}
1159167514Skmacy}
1160167514Skmacy
1161181614Skmacy/**
1162181614Skmacy *	t3_os_phymod_changed - handle PHY module changes
1163181614Skmacy *	@phy: the PHY reporting the module change
1164181614Skmacy *	@mod_type: new module type
1165181614Skmacy *
1166181614Skmacy *	This is the OS-dependent handler for PHY module changes.  It is
1167181614Skmacy *	invoked when a PHY module is removed or inserted for any OS-specific
1168181614Skmacy *	processing.
1169181614Skmacy */
1170181614Skmacyvoid t3_os_phymod_changed(struct adapter *adap, int port_id)
1171181614Skmacy{
1172181614Skmacy	static const char *mod_str[] = {
1173181614Skmacy		NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown"
1174181614Skmacy	};
1175181614Skmacy
1176181614Skmacy	struct port_info *pi = &adap->port[port_id];
1177181614Skmacy
1178181614Skmacy	if (pi->phy.modtype == phy_modtype_none)
1179181614Skmacy		device_printf(adap->dev, "PHY module unplugged\n");
1180181614Skmacy	else {
1181181614Skmacy		KASSERT(pi->phy.modtype < ARRAY_SIZE(mod_str),
1182181614Skmacy		    ("invalid PHY module type %d", pi->phy.modtype));
1183181614Skmacy		device_printf(adap->dev, "%s PHY module inserted\n",
1184181614Skmacy		    mod_str[pi->phy.modtype]);
1185181614Skmacy	}
1186181614Skmacy}
1187181614Skmacy
1188167514Skmacy/*
1189167514Skmacy * Interrupt-context handler for external (PHY) interrupts.
1190167514Skmacy */
1191167514Skmacyvoid
1192167514Skmacyt3_os_ext_intr_handler(adapter_t *sc)
1193167514Skmacy{
1194167514Skmacy	if (cxgb_debug)
1195167514Skmacy		printf("t3_os_ext_intr_handler\n");
1196167514Skmacy	/*
1197167514Skmacy	 * Schedule a task to handle external interrupts as they may be slow
1198167514Skmacy	 * and we use a mutex to protect MDIO registers.  We disable PHY
1199167514Skmacy	 * interrupts in the meantime and let the task reenable them when
1200167514Skmacy	 * it's done.
1201167514Skmacy	 */
1202169978Skmacy	ADAPTER_LOCK(sc);
1203167514Skmacy	if (sc->slow_intr_mask) {
1204167514Skmacy		sc->slow_intr_mask &= ~F_T3DBG;
1205167514Skmacy		t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
1206167514Skmacy		taskqueue_enqueue(sc->tq, &sc->ext_intr_task);
1207167514Skmacy	}
1208169978Skmacy	ADAPTER_UNLOCK(sc);
1209167514Skmacy}
1210167514Skmacy
1211167514Skmacyvoid
1212167514Skmacyt3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[])
1213167514Skmacy{
1214167514Skmacy
1215167514Skmacy	/*
1216167514Skmacy	 * The ifnet might not be allocated before this gets called,
1217167514Skmacy	 * as this is called early on in attach by t3_prep_adapter
1218167514Skmacy	 * save the address off in the port structure
1219167514Skmacy	 */
1220167514Skmacy	if (cxgb_debug)
1221167514Skmacy		printf("set_hw_addr on idx %d addr %6D\n", port_idx, hw_addr, ":");
1222167514Skmacy	bcopy(hw_addr, adapter->port[port_idx].hw_addr, ETHER_ADDR_LEN);
1223167514Skmacy}
1224167514Skmacy
1225167514Skmacy/**
1226167514Skmacy *	link_start - enable a port
1227167514Skmacy *	@p: the port to enable
1228167514Skmacy *
1229167514Skmacy *	Performs the MAC and PHY actions needed to enable a port.
1230167514Skmacy */
1231167514Skmacystatic void
1232167514Skmacycxgb_link_start(struct port_info *p)
1233167514Skmacy{
1234167514Skmacy	struct ifnet *ifp;
1235167514Skmacy	struct t3_rx_mode rm;
1236167514Skmacy	struct cmac *mac = &p->mac;
1237180583Skmacy	int mtu, hwtagging;
1238167514Skmacy
1239167514Skmacy	ifp = p->ifp;
1240167514Skmacy
1241180583Skmacy	bcopy(IF_LLADDR(ifp), p->hw_addr, ETHER_ADDR_LEN);
1242180583Skmacy
1243180583Skmacy	mtu = ifp->if_mtu;
1244180583Skmacy	if (ifp->if_capenable & IFCAP_VLAN_MTU)
1245180583Skmacy		mtu += ETHER_VLAN_ENCAP_LEN;
1246180583Skmacy
1247180583Skmacy	hwtagging = (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0;
1248180583Skmacy
1249167514Skmacy	t3_init_rx_mode(&rm, p);
1250172096Skmacy	if (!mac->multiport)
1251171978Skmacy		t3_mac_reset(mac);
1252180583Skmacy	t3_mac_set_mtu(mac, mtu);
1253180583Skmacy	t3_set_vlan_accel(p->adapter, 1 << p->tx_chan, hwtagging);
1254167514Skmacy	t3_mac_set_address(mac, 0, p->hw_addr);
1255167514Skmacy	t3_mac_set_rx_mode(mac, &rm);
1256167514Skmacy	t3_link_start(&p->phy, mac, &p->link_config);
1257167514Skmacy	t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
1258167514Skmacy}
1259167514Skmacy
1260176472Skmacy
1261176472Skmacystatic int
1262176472Skmacyawait_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
1263176472Skmacy			      unsigned long n)
1264176472Skmacy{
1265176472Skmacy	int attempts = 5;
1266176472Skmacy
1267176472Skmacy	while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
1268176472Skmacy		if (!--attempts)
1269176472Skmacy			return (ETIMEDOUT);
1270176472Skmacy		t3_os_sleep(10);
1271176472Skmacy	}
1272176472Skmacy	return 0;
1273176472Skmacy}
1274176472Skmacy
1275176472Skmacystatic int
1276176472Skmacyinit_tp_parity(struct adapter *adap)
1277176472Skmacy{
1278176472Skmacy	int i;
1279176472Skmacy	struct mbuf *m;
1280176472Skmacy	struct cpl_set_tcb_field *greq;
1281176472Skmacy	unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts;
1282176472Skmacy
1283176472Skmacy	t3_tp_set_offload_mode(adap, 1);
1284176472Skmacy
1285176472Skmacy	for (i = 0; i < 16; i++) {
1286176472Skmacy		struct cpl_smt_write_req *req;
1287176472Skmacy
1288176472Skmacy		m = m_gethdr(M_WAITOK, MT_DATA);
1289176472Skmacy		req = mtod(m, struct cpl_smt_write_req *);
1290176472Skmacy		m->m_len = m->m_pkthdr.len = sizeof(*req);
1291176472Skmacy		memset(req, 0, sizeof(*req));
1292176472Skmacy		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1293176472Skmacy		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
1294176472Skmacy		req->iff = i;
1295176472Skmacy		t3_mgmt_tx(adap, m);
1296176472Skmacy	}
1297176472Skmacy
1298176472Skmacy	for (i = 0; i < 2048; i++) {
1299176472Skmacy		struct cpl_l2t_write_req *req;
1300176472Skmacy
1301176472Skmacy		m = m_gethdr(M_WAITOK, MT_DATA);
1302176472Skmacy		req = mtod(m, struct cpl_l2t_write_req *);
1303176472Skmacy		m->m_len = m->m_pkthdr.len = sizeof(*req);
1304176472Skmacy		memset(req, 0, sizeof(*req));
1305176472Skmacy		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1306176472Skmacy		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
1307176472Skmacy		req->params = htonl(V_L2T_W_IDX(i));
1308176472Skmacy		t3_mgmt_tx(adap, m);
1309176472Skmacy	}
1310176472Skmacy
1311176472Skmacy	for (i = 0; i < 2048; i++) {
1312176472Skmacy		struct cpl_rte_write_req *req;
1313176472Skmacy
1314176472Skmacy		m = m_gethdr(M_WAITOK, MT_DATA);
1315176472Skmacy		req = mtod(m, struct cpl_rte_write_req *);
1316176472Skmacy		m->m_len = m->m_pkthdr.len = sizeof(*req);
1317176472Skmacy		memset(req, 0, sizeof(*req));
1318176472Skmacy		req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1319176472Skmacy		OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
1320176472Skmacy		req->l2t_idx = htonl(V_L2T_W_IDX(i));
1321176472Skmacy		t3_mgmt_tx(adap, m);
1322176472Skmacy	}
1323176472Skmacy
1324176472Skmacy	m = m_gethdr(M_WAITOK, MT_DATA);
1325176472Skmacy	greq = mtod(m, struct cpl_set_tcb_field *);
1326176472Skmacy	m->m_len = m->m_pkthdr.len = sizeof(*greq);
1327176472Skmacy	memset(greq, 0, sizeof(*greq));
1328176472Skmacy	greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1329176472Skmacy	OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0));
1330176472Skmacy	greq->mask = htobe64(1);
1331176472Skmacy	t3_mgmt_tx(adap, m);
1332176472Skmacy
1333176472Skmacy	i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
1334176472Skmacy	t3_tp_set_offload_mode(adap, 0);
1335176472Skmacy	return (i);
1336176472Skmacy}
1337176472Skmacy
1338167514Skmacy/**
1339167514Skmacy *	setup_rss - configure Receive Side Steering (per-queue connection demux)
1340167514Skmacy *	@adap: the adapter
1341167514Skmacy *
1342167514Skmacy *	Sets up RSS to distribute packets to multiple receive queues.  We
1343167514Skmacy *	configure the RSS CPU lookup table to distribute to the number of HW
1344167514Skmacy *	receive queues, and the response queue lookup table to narrow that
1345167514Skmacy *	down to the response queues actually configured for each port.
1346167514Skmacy *	We always configure the RSS mapping for two ports since the mapping
1347167514Skmacy *	table has plenty of entries.
1348167514Skmacy */
1349167514Skmacystatic void
1350167514Skmacysetup_rss(adapter_t *adap)
1351167514Skmacy{
1352167514Skmacy	int i;
1353171471Skmacy	u_int nq[2];
1354167514Skmacy	uint8_t cpus[SGE_QSETS + 1];
1355167514Skmacy	uint16_t rspq_map[RSS_TABLE_SIZE];
1356171471Skmacy
1357167514Skmacy	for (i = 0; i < SGE_QSETS; ++i)
1358167514Skmacy		cpus[i] = i;
1359167514Skmacy	cpus[SGE_QSETS] = 0xff;
1360167514Skmacy
1361171978Skmacy	nq[0] = nq[1] = 0;
1362171978Skmacy	for_each_port(adap, i) {
1363171978Skmacy		const struct port_info *pi = adap2pinfo(adap, i);
1364171978Skmacy
1365171978Skmacy		nq[pi->tx_chan] += pi->nqsets;
1366171978Skmacy	}
1367167514Skmacy	for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
1368176472Skmacy		rspq_map[i] = nq[0] ? i % nq[0] : 0;
1369176472Skmacy		rspq_map[i + RSS_TABLE_SIZE / 2] = nq[1] ? i % nq[1] + nq[0] : 0;
1370167514Skmacy	}
1371171471Skmacy	/* Calculate the reverse RSS map table */
1372171471Skmacy	for (i = 0; i < RSS_TABLE_SIZE; ++i)
1373171471Skmacy		if (adap->rrss_map[rspq_map[i]] == 0xff)
1374171471Skmacy			adap->rrss_map[rspq_map[i]] = i;
1375167514Skmacy
1376167514Skmacy	t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
1377171471Skmacy		      F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | F_OFDMAPEN |
1378176472Skmacy	              F_RRCPLMAPEN | V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ,
1379176472Skmacy	              cpus, rspq_map);
1380171471Skmacy
1381167514Skmacy}
1382167514Skmacy
1383169978Skmacy/*
1384169978Skmacy * Sends an mbuf to an offload queue driver
1385169978Skmacy * after dealing with any active network taps.
1386169978Skmacy */
1387169978Skmacystatic inline int
1388174626Skmacyoffload_tx(struct t3cdev *tdev, struct mbuf *m)
1389169978Skmacy{
1390169978Skmacy	int ret;
1391169978Skmacy
1392169978Skmacy	ret = t3_offload_tx(tdev, m);
1393170654Skmacy	return (ret);
1394169978Skmacy}
1395169978Skmacy
1396169978Skmacystatic int
1397169978Skmacywrite_smt_entry(struct adapter *adapter, int idx)
1398169978Skmacy{
1399169978Skmacy	struct port_info *pi = &adapter->port[idx];
1400169978Skmacy	struct cpl_smt_write_req *req;
1401169978Skmacy	struct mbuf *m;
1402169978Skmacy
1403169978Skmacy	if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
1404169978Skmacy		return (ENOMEM);
1405169978Skmacy
1406169978Skmacy	req = mtod(m, struct cpl_smt_write_req *);
1407174708Skmacy	m->m_pkthdr.len = m->m_len = sizeof(struct cpl_smt_write_req);
1408174708Skmacy
1409169978Skmacy	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
1410169978Skmacy	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
1411169978Skmacy	req->mtu_idx = NMTUS - 1;  /* should be 0 but there's a T3 bug */
1412169978Skmacy	req->iff = idx;
1413169978Skmacy	memset(req->src_mac1, 0, sizeof(req->src_mac1));
1414169978Skmacy	memcpy(req->src_mac0, pi->hw_addr, ETHER_ADDR_LEN);
1415169978Skmacy
1416169978Skmacy	m_set_priority(m, 1);
1417169978Skmacy
1418169978Skmacy	offload_tx(&adapter->tdev, m);
1419169978Skmacy
1420169978Skmacy	return (0);
1421169978Skmacy}
1422169978Skmacy
1423169978Skmacystatic int
1424169978Skmacyinit_smt(struct adapter *adapter)
1425169978Skmacy{
1426169978Skmacy	int i;
1427169978Skmacy
1428169978Skmacy	for_each_port(adapter, i)
1429169978Skmacy		write_smt_entry(adapter, i);
1430169978Skmacy	return 0;
1431169978Skmacy}
1432169978Skmacy
1433167514Skmacystatic void
1434169978Skmacyinit_port_mtus(adapter_t *adapter)
1435169978Skmacy{
1436169978Skmacy	unsigned int mtus = adapter->port[0].ifp->if_mtu;
1437169978Skmacy
1438169978Skmacy	if (adapter->port[1].ifp)
1439169978Skmacy		mtus |= adapter->port[1].ifp->if_mtu << 16;
1440169978Skmacy	t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
1441169978Skmacy}
1442169978Skmacy
1443169978Skmacystatic void
1444167514Skmacysend_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
1445167514Skmacy			      int hi, int port)
1446167514Skmacy{
1447167514Skmacy	struct mbuf *m;
1448167514Skmacy	struct mngt_pktsched_wr *req;
1449167514Skmacy
1450171471Skmacy	m = m_gethdr(M_DONTWAIT, MT_DATA);
1451167848Skmacy	if (m) {
1452169978Skmacy		req = mtod(m, struct mngt_pktsched_wr *);
1453167848Skmacy		req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
1454167848Skmacy		req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
1455167848Skmacy		req->sched = sched;
1456167848Skmacy		req->idx = qidx;
1457167848Skmacy		req->min = lo;
1458167848Skmacy		req->max = hi;
1459167848Skmacy		req->binding = port;
1460167848Skmacy		m->m_len = m->m_pkthdr.len = sizeof(*req);
1461167848Skmacy		t3_mgmt_tx(adap, m);
1462167848Skmacy	}
1463167514Skmacy}
1464167514Skmacy
1465167514Skmacystatic void
1466167514Skmacybind_qsets(adapter_t *sc)
1467167514Skmacy{
1468167514Skmacy	int i, j;
1469167514Skmacy
1470174708Skmacy	cxgb_pcpu_startup_threads(sc);
1471167514Skmacy	for (i = 0; i < (sc)->params.nports; ++i) {
1472167514Skmacy		const struct port_info *pi = adap2pinfo(sc, i);
1473167514Skmacy
1474172096Skmacy		for (j = 0; j < pi->nqsets; ++j) {
1475167514Skmacy			send_pktsched_cmd(sc, 1, pi->first_qset + j, -1,
1476172096Skmacy					  -1, pi->tx_chan);
1477172096Skmacy
1478172096Skmacy		}
1479167514Skmacy	}
1480167514Skmacy}
1481167514Skmacy
1482171471Skmacystatic void
1483171471Skmacyupdate_tpeeprom(struct adapter *adap)
1484171471Skmacy{
1485172109Skmacy#ifdef FIRMWARE_LATEST
1486171471Skmacy	const struct firmware *tpeeprom;
1487172109Skmacy#else
1488172109Skmacy	struct firmware *tpeeprom;
1489172109Skmacy#endif
1490172109Skmacy
1491171471Skmacy	uint32_t version;
1492171471Skmacy	unsigned int major, minor;
1493171471Skmacy	int ret, len;
1494171471Skmacy	char rev;
1495171471Skmacy
1496171471Skmacy	t3_seeprom_read(adap, TP_SRAM_OFFSET, &version);
1497171471Skmacy
1498171471Skmacy	major = G_TP_VERSION_MAJOR(version);
1499171471Skmacy	minor = G_TP_VERSION_MINOR(version);
1500171471Skmacy	if (major == TP_VERSION_MAJOR  && minor == TP_VERSION_MINOR)
1501171471Skmacy		return;
1502171471Skmacy
1503171471Skmacy	rev = t3rev2char(adap);
1504171471Skmacy
1505176613Skmacy	tpeeprom = firmware_get(TPEEPROM_NAME);
1506171471Skmacy	if (tpeeprom == NULL) {
1507171471Skmacy		device_printf(adap->dev, "could not load TP EEPROM: unable to load %s\n",
1508176613Skmacy		    TPEEPROM_NAME);
1509171471Skmacy		return;
1510171471Skmacy	}
1511171471Skmacy
1512171471Skmacy	len = tpeeprom->datasize - 4;
1513171471Skmacy
1514171471Skmacy	ret = t3_check_tpsram(adap, tpeeprom->data, tpeeprom->datasize);
1515171471Skmacy	if (ret)
1516171471Skmacy		goto release_tpeeprom;
1517171471Skmacy
1518171471Skmacy	if (len != TP_SRAM_LEN) {
1519176613Skmacy		device_printf(adap->dev, "%s length is wrong len=%d expected=%d\n", TPEEPROM_NAME, len, TP_SRAM_LEN);
1520171471Skmacy		return;
1521171471Skmacy	}
1522171471Skmacy
1523171471Skmacy	ret = set_eeprom(&adap->port[0], tpeeprom->data, tpeeprom->datasize,
1524171471Skmacy	    TP_SRAM_OFFSET);
1525171471Skmacy
1526171471Skmacy	if (!ret) {
1527171471Skmacy		device_printf(adap->dev,
1528171471Skmacy			"Protocol SRAM image updated in EEPROM to %d.%d.%d\n",
1529171471Skmacy			 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1530171471Skmacy	} else
1531171471Skmacy		device_printf(adap->dev, "Protocol SRAM image update in EEPROM failed\n");
1532171471Skmacy
1533171471Skmacyrelease_tpeeprom:
1534171471Skmacy	firmware_put(tpeeprom, FIRMWARE_UNLOAD);
1535171471Skmacy
1536171471Skmacy	return;
1537171471Skmacy}
1538171471Skmacy
1539171471Skmacystatic int
1540171471Skmacyupdate_tpsram(struct adapter *adap)
1541171471Skmacy{
1542172109Skmacy#ifdef FIRMWARE_LATEST
1543171471Skmacy	const struct firmware *tpsram;
1544172109Skmacy#else
1545172109Skmacy	struct firmware *tpsram;
1546172109Skmacy#endif
1547171471Skmacy	int ret;
1548171471Skmacy	char rev;
1549171471Skmacy
1550171471Skmacy	rev = t3rev2char(adap);
1551171471Skmacy	if (!rev)
1552171471Skmacy		return 0;
1553171471Skmacy
1554171471Skmacy	update_tpeeprom(adap);
1555171471Skmacy
1556176613Skmacy	tpsram = firmware_get(TPSRAM_NAME);
1557171471Skmacy	if (tpsram == NULL){
1558176613Skmacy		device_printf(adap->dev, "could not load TP SRAM\n");
1559171471Skmacy		return (EINVAL);
1560171471Skmacy	} else
1561176613Skmacy		device_printf(adap->dev, "updating TP SRAM\n");
1562171471Skmacy
1563171471Skmacy	ret = t3_check_tpsram(adap, tpsram->data, tpsram->datasize);
1564171471Skmacy	if (ret)
1565171471Skmacy		goto release_tpsram;
1566171471Skmacy
1567171471Skmacy	ret = t3_set_proto_sram(adap, tpsram->data);
1568171471Skmacy	if (ret)
1569171471Skmacy		device_printf(adap->dev, "loading protocol SRAM failed\n");
1570171471Skmacy
1571171471Skmacyrelease_tpsram:
1572171471Skmacy	firmware_put(tpsram, FIRMWARE_UNLOAD);
1573171471Skmacy
1574171471Skmacy	return ret;
1575171471Skmacy}
1576171471Skmacy
1577169978Skmacy/**
1578169978Skmacy *	cxgb_up - enable the adapter
1579169978Skmacy *	@adap: adapter being enabled
1580169978Skmacy *
1581169978Skmacy *	Called when the first port is enabled, this function performs the
1582169978Skmacy *	actions necessary to make an adapter operational, such as completing
1583169978Skmacy *	the initialization of HW modules, and enabling interrupts.
1584169978Skmacy *
1585169978Skmacy */
1586169978Skmacystatic int
1587169978Skmacycxgb_up(struct adapter *sc)
1588169978Skmacy{
1589169978Skmacy	int err = 0;
1590169978Skmacy
1591169978Skmacy	if ((sc->flags & FULL_INIT_DONE) == 0) {
1592169978Skmacy
1593169978Skmacy		if ((sc->flags & FW_UPTODATE) == 0)
1594171471Skmacy			if ((err = upgrade_fw(sc)))
1595171471Skmacy				goto out;
1596171471Skmacy		if ((sc->flags & TPS_UPTODATE) == 0)
1597171471Skmacy			if ((err = update_tpsram(sc)))
1598171471Skmacy				goto out;
1599169978Skmacy		err = t3_init_hw(sc, 0);
1600169978Skmacy		if (err)
1601169978Skmacy			goto out;
1602169978Skmacy
1603176472Skmacy		t3_set_reg_field(sc, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT);
1604169978Skmacy		t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
1605169978Skmacy
1606169978Skmacy		err = setup_sge_qsets(sc);
1607169978Skmacy		if (err)
1608169978Skmacy			goto out;
1609169978Skmacy
1610169978Skmacy		setup_rss(sc);
1611174708Skmacy		t3_add_configured_sysctls(sc);
1612169978Skmacy		sc->flags |= FULL_INIT_DONE;
1613169978Skmacy	}
1614169978Skmacy
1615169978Skmacy	t3_intr_clear(sc);
1616169978Skmacy
1617169978Skmacy	/* If it's MSI or INTx, allocate a single interrupt for everything */
1618169978Skmacy	if ((sc->flags & USING_MSIX) == 0) {
1619169978Skmacy		if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ,
1620169978Skmacy		   &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
1621171978Skmacy			device_printf(sc->dev, "Cannot allocate interrupt rid=%d\n",
1622171978Skmacy			    sc->irq_rid);
1623169978Skmacy			err = EINVAL;
1624169978Skmacy			goto out;
1625169978Skmacy		}
1626169978Skmacy		device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res);
1627169978Skmacy
1628169978Skmacy		if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET,
1629169978Skmacy#ifdef INTR_FILTERS
1630169978Skmacy			NULL,
1631169978Skmacy#endif
1632169978Skmacy			sc->cxgb_intr, sc, &sc->intr_tag)) {
1633169978Skmacy			device_printf(sc->dev, "Cannot set up interrupt\n");
1634169978Skmacy			err = EINVAL;
1635169978Skmacy			goto irq_err;
1636169978Skmacy		}
1637169978Skmacy	} else {
1638169978Skmacy		cxgb_setup_msix(sc, sc->msi_count);
1639169978Skmacy	}
1640169978Skmacy
1641169978Skmacy	t3_sge_start(sc);
1642169978Skmacy	t3_intr_enable(sc);
1643169978Skmacy
1644176472Skmacy	if (sc->params.rev >= T3_REV_C && !(sc->flags & TP_PARITY_INIT) &&
1645176472Skmacy	    is_offload(sc) && init_tp_parity(sc) == 0)
1646176472Skmacy		sc->flags |= TP_PARITY_INIT;
1647176472Skmacy
1648176472Skmacy	if (sc->flags & TP_PARITY_INIT) {
1649176472Skmacy		t3_write_reg(sc, A_TP_INT_CAUSE,
1650176472Skmacy				F_CMCACHEPERR | F_ARPLUTPERR);
1651176472Skmacy		t3_write_reg(sc, A_TP_INT_ENABLE, 0x7fbfffff);
1652176472Skmacy	}
1653176472Skmacy
1654176472Skmacy
1655172096Skmacy	if (!(sc->flags & QUEUES_BOUND)) {
1656169978Skmacy		bind_qsets(sc);
1657171471Skmacy		sc->flags |= QUEUES_BOUND;
1658171471Skmacy	}
1659169978Skmacyout:
1660169978Skmacy	return (err);
1661169978Skmacyirq_err:
1662169978Skmacy	CH_ERR(sc, "request_irq failed, err %d\n", err);
1663169978Skmacy	goto out;
1664169978Skmacy}
1665169978Skmacy
1666169978Skmacy
1667169978Skmacy/*
1668169978Skmacy * Release resources when all the ports and offloading have been stopped.
1669169978Skmacy */
1670167514Skmacystatic void
1671170869Skmacycxgb_down_locked(struct adapter *sc)
1672169978Skmacy{
1673170654Skmacy
1674169978Skmacy	t3_sge_stop(sc);
1675169978Skmacy	t3_intr_disable(sc);
1676170654Skmacy
1677169978Skmacy	if (sc->intr_tag != NULL) {
1678169978Skmacy		bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag);
1679169978Skmacy		sc->intr_tag = NULL;
1680169978Skmacy	}
1681169978Skmacy	if (sc->irq_res != NULL) {
1682169978Skmacy		device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n",
1683169978Skmacy		    sc->irq_rid, sc->irq_res);
1684169978Skmacy		bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
1685169978Skmacy		    sc->irq_res);
1686169978Skmacy		sc->irq_res = NULL;
1687169978Skmacy	}
1688170654Skmacy
1689176472Skmacy	if (sc->flags & USING_MSIX)
1690170654Skmacy		cxgb_teardown_msix(sc);
1691176472Skmacy
1692174708Skmacy	callout_stop(&sc->cxgb_tick_ch);
1693174708Skmacy	callout_stop(&sc->sge_timer_ch);
1694170869Skmacy	callout_drain(&sc->cxgb_tick_ch);
1695169978Skmacy	callout_drain(&sc->sge_timer_ch);
1696170869Skmacy
1697171978Skmacy	if (sc->tq != NULL) {
1698176472Skmacy		printf("draining slow intr\n");
1699176472Skmacy
1700170654Skmacy		taskqueue_drain(sc->tq, &sc->slow_intr_task);
1701176472Skmacy			printf("draining ext intr\n");
1702176472Skmacy		taskqueue_drain(sc->tq, &sc->ext_intr_task);
1703176472Skmacy		printf("draining tick task\n");
1704176472Skmacy		taskqueue_drain(sc->tq, &sc->tick_task);
1705171978Skmacy	}
1706176472Skmacy	ADAPTER_UNLOCK(sc);
1707169978Skmacy}
1708169978Skmacy
1709169978Skmacystatic int
1710169978Skmacyoffload_open(struct port_info *pi)
1711169978Skmacy{
1712169978Skmacy	struct adapter *adapter = pi->adapter;
1713174708Skmacy	struct t3cdev *tdev = &adapter->tdev;
1714183059Skmacy
1715169978Skmacy	int adap_up = adapter->open_device_map & PORT_MASK;
1716169978Skmacy	int err = 0;
1717169978Skmacy
1718169978Skmacy	if (atomic_cmpset_int(&adapter->open_device_map,
1719174708Skmacy		(adapter->open_device_map & ~(1<<OFFLOAD_DEVMAP_BIT)),
1720174708Skmacy		(adapter->open_device_map | (1<<OFFLOAD_DEVMAP_BIT))) == 0)
1721169978Skmacy		return (0);
1722169978Skmacy
1723174708Skmacy	if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT))
1724183059Skmacy		printf("offload_open: DEVMAP_BIT did not get set 0x%x\n",
1725183059Skmacy		    adapter->open_device_map);
1726169978Skmacy	ADAPTER_LOCK(pi->adapter);
1727169978Skmacy	if (!adap_up)
1728169978Skmacy		err = cxgb_up(adapter);
1729169978Skmacy	ADAPTER_UNLOCK(pi->adapter);
1730171471Skmacy	if (err)
1731169978Skmacy		return (err);
1732169978Skmacy
1733169978Skmacy	t3_tp_set_offload_mode(adapter, 1);
1734174708Skmacy	tdev->lldev = pi->ifp;
1735169978Skmacy
1736169978Skmacy	init_port_mtus(adapter);
1737169978Skmacy	t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
1738169978Skmacy		     adapter->params.b_wnd,
1739169978Skmacy		     adapter->params.rev == 0 ?
1740169978Skmacy		       adapter->port[0].ifp->if_mtu : 0xffff);
1741169978Skmacy	init_smt(adapter);
1742178767Skmacy	/* Call back all registered clients */
1743178767Skmacy	cxgb_add_clients(tdev);
1744178767Skmacy
1745169978Skmacy	/* restore them in case the offload module has changed them */
1746169978Skmacy	if (err) {
1747169978Skmacy		t3_tp_set_offload_mode(adapter, 0);
1748169978Skmacy		clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT);
1749169978Skmacy		cxgb_set_dummy_ops(tdev);
1750169978Skmacy	}
1751169978Skmacy	return (err);
1752169978Skmacy}
1753174708Skmacy
1754169978Skmacystatic int
1755174708Skmacyoffload_close(struct t3cdev *tdev)
1756169978Skmacy{
1757169978Skmacy	struct adapter *adapter = tdev2adap(tdev);
1758169978Skmacy
1759176472Skmacy	if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT))
1760170654Skmacy		return (0);
1761178767Skmacy
1762178767Skmacy	/* Call back all registered clients */
1763178767Skmacy	cxgb_remove_clients(tdev);
1764178767Skmacy
1765169978Skmacy	tdev->lldev = NULL;
1766169978Skmacy	cxgb_set_dummy_ops(tdev);
1767169978Skmacy	t3_tp_set_offload_mode(adapter, 0);
1768169978Skmacy	clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT);
1769169978Skmacy
1770174708Skmacy	ADAPTER_LOCK(adapter);
1771169978Skmacy	if (!adapter->open_device_map)
1772174708Skmacy		cxgb_down_locked(adapter);
1773174708Skmacy	else
1774174708Skmacy		ADAPTER_UNLOCK(adapter);
1775170654Skmacy	return (0);
1776169978Skmacy}
1777169978Skmacy
1778174708Skmacy
1779169978Skmacystatic void
1780167514Skmacycxgb_init(void *arg)
1781167514Skmacy{
1782167514Skmacy	struct port_info *p = arg;
1783167514Skmacy
1784167514Skmacy	PORT_LOCK(p);
1785167514Skmacy	cxgb_init_locked(p);
1786167514Skmacy	PORT_UNLOCK(p);
1787167514Skmacy}
1788167514Skmacy
1789167514Skmacystatic void
1790167514Skmacycxgb_init_locked(struct port_info *p)
1791167514Skmacy{
1792167514Skmacy	struct ifnet *ifp;
1793167514Skmacy	adapter_t *sc = p->adapter;
1794169978Skmacy	int err;
1795167514Skmacy
1796170869Skmacy	PORT_LOCK_ASSERT_OWNED(p);
1797167514Skmacy	ifp = p->ifp;
1798167514Skmacy
1799167514Skmacy	ADAPTER_LOCK(p->adapter);
1800171471Skmacy	if ((sc->open_device_map == 0) && (err = cxgb_up(sc))) {
1801169978Skmacy		ADAPTER_UNLOCK(p->adapter);
1802169978Skmacy		cxgb_stop_locked(p);
1803169978Skmacy		return;
1804169978Skmacy	}
1805170869Skmacy	if (p->adapter->open_device_map == 0) {
1806167514Skmacy		t3_intr_clear(sc);
1807170869Skmacy	}
1808171803Skmacy	setbit(&p->adapter->open_device_map, p->port_id);
1809170654Skmacy	ADAPTER_UNLOCK(p->adapter);
1810169978Skmacy
1811169978Skmacy	if (is_offload(sc) && !ofld_disable) {
1812169978Skmacy		err = offload_open(p);
1813169978Skmacy		if (err)
1814169978Skmacy			log(LOG_WARNING,
1815169978Skmacy			    "Could not initialize offload capabilities\n");
1816169978Skmacy	}
1817177415Skmacy#if !defined(LINK_ATTACH)
1818177415Skmacy	cxgb_link_start(p);
1819177415Skmacy	t3_link_changed(sc, p->port_id);
1820177415Skmacy#endif
1821170654Skmacy	ifp->if_baudrate = p->link_config.speed * 1000000;
1822171978Skmacy
1823172096Skmacy	device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id);
1824171803Skmacy	t3_port_intr_enable(sc, p->port_id);
1825167760Skmacy
1826175224Skmacy	t3_sge_reset_adapter(sc);
1827170869Skmacy
1828167514Skmacy	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1829167514Skmacy	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1830167514Skmacy}
1831167514Skmacy
1832167514Skmacystatic void
1833167514Skmacycxgb_set_rxmode(struct port_info *p)
1834167514Skmacy{
1835167514Skmacy	struct t3_rx_mode rm;
1836167514Skmacy	struct cmac *mac = &p->mac;
1837167760Skmacy
1838167514Skmacy	t3_init_rx_mode(&rm, p);
1839176472Skmacy	mtx_lock(&p->adapter->mdio_lock);
1840167514Skmacy	t3_mac_set_rx_mode(mac, &rm);
1841176472Skmacy	mtx_unlock(&p->adapter->mdio_lock);
1842167514Skmacy}
1843167514Skmacy
1844167514Skmacystatic void
1845177340Skmacycxgb_stop_locked(struct port_info *pi)
1846167514Skmacy{
1847167514Skmacy	struct ifnet *ifp;
1848167514Skmacy
1849177340Skmacy	PORT_LOCK_ASSERT_OWNED(pi);
1850177340Skmacy	ADAPTER_LOCK_ASSERT_NOTOWNED(pi->adapter);
1851170654Skmacy
1852177340Skmacy	ifp = pi->ifp;
1853177340Skmacy	t3_port_intr_disable(pi->adapter, pi->port_id);
1854169978Skmacy	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1855169978Skmacy
1856177340Skmacy	/* disable pause frames */
1857177340Skmacy	t3_set_reg_field(pi->adapter, A_XGM_TX_CFG + pi->mac.offset,
1858177340Skmacy			 F_TXPAUSEEN, 0);
1859170869Skmacy
1860177340Skmacy	/* Reset RX FIFO HWM */
1861177340Skmacy        t3_set_reg_field(pi->adapter, A_XGM_RXFIFO_CFG +  pi->mac.offset,
1862177340Skmacy			 V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM), 0);
1863177340Skmacy
1864177340Skmacy
1865177340Skmacy	ADAPTER_LOCK(pi->adapter);
1866177340Skmacy	clrbit(&pi->adapter->open_device_map, pi->port_id);
1867177340Skmacy
1868177340Skmacy	if (pi->adapter->open_device_map == 0) {
1869177340Skmacy		cxgb_down_locked(pi->adapter);
1870170869Skmacy	} else
1871177340Skmacy		ADAPTER_UNLOCK(pi->adapter);
1872170869Skmacy
1873177415Skmacy#if !defined(LINK_ATTACH)
1874177340Skmacy	DELAY(100);
1875177340Skmacy
1876177340Skmacy	/* Wait for TXFIFO empty */
1877177340Skmacy	t3_wait_op_done(pi->adapter, A_XGM_TXFIFO_CFG + pi->mac.offset,
1878177340Skmacy			F_TXFIFO_EMPTY, 1, 20, 5);
1879177340Skmacy
1880177340Skmacy	DELAY(100);
1881177340Skmacy	t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
1882177340Skmacy
1883177340Skmacy	pi->phy.ops->power_down(&pi->phy, 1);
1884177415Skmacy#endif
1885177340Skmacy
1886167514Skmacy}
1887167514Skmacy
1888167514Skmacystatic int
1889170654Skmacycxgb_set_mtu(struct port_info *p, int mtu)
1890170654Skmacy{
1891170654Skmacy	struct ifnet *ifp = p->ifp;
1892170654Skmacy	int error = 0;
1893170654Skmacy
1894180583Skmacy	if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO))
1895170654Skmacy		error = EINVAL;
1896170654Skmacy	else if (ifp->if_mtu != mtu) {
1897170654Skmacy		PORT_LOCK(p);
1898170654Skmacy		ifp->if_mtu = mtu;
1899170654Skmacy		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1900170654Skmacy			cxgb_stop_locked(p);
1901170654Skmacy			cxgb_init_locked(p);
1902170654Skmacy		}
1903170654Skmacy		PORT_UNLOCK(p);
1904170654Skmacy	}
1905170654Skmacy	return (error);
1906170654Skmacy}
1907170654Skmacy
1908183289Skmacy#ifdef LRO_SUPPORTED
1909181616Skmacy/*
1910181616Skmacy * Mark lro enabled or disabled in all qsets for this port
1911181616Skmacy */
1912170654Skmacystatic int
1913181616Skmacycxgb_set_lro(struct port_info *p, int enabled)
1914181616Skmacy{
1915181616Skmacy	int i;
1916181616Skmacy	struct adapter *adp = p->adapter;
1917181616Skmacy	struct sge_qset *q;
1918181616Skmacy
1919181616Skmacy	PORT_LOCK_ASSERT_OWNED(p);
1920181616Skmacy	for (i = 0; i < p->nqsets; i++) {
1921181616Skmacy		q = &adp->sge.qs[p->first_qset + i];
1922181616Skmacy		q->lro.enabled = (enabled != 0);
1923181616Skmacy	}
1924181616Skmacy	return (0);
1925181616Skmacy}
1926183289Skmacy#endif
1927181616Skmacy
1928181616Skmacystatic int
1929167514Skmacycxgb_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data)
1930167514Skmacy{
1931167514Skmacy	struct port_info *p = ifp->if_softc;
1932167514Skmacy	struct ifaddr *ifa = (struct ifaddr *)data;
1933167514Skmacy	struct ifreq *ifr = (struct ifreq *)data;
1934180583Skmacy	int flags, error = 0, reinit = 0;
1935167514Skmacy	uint32_t mask;
1936167514Skmacy
1937168737Skmacy	/*
1938168737Skmacy	 * XXX need to check that we aren't in the middle of an unload
1939168737Skmacy	 */
1940167514Skmacy	switch (command) {
1941167514Skmacy	case SIOCSIFMTU:
1942170654Skmacy		error = cxgb_set_mtu(p, ifr->ifr_mtu);
1943167514Skmacy		break;
1944167514Skmacy	case SIOCSIFADDR:
1945167514Skmacy		if (ifa->ifa_addr->sa_family == AF_INET) {
1946167514Skmacy			ifp->if_flags |= IFF_UP;
1947176472Skmacy			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
1948176472Skmacy				PORT_LOCK(p);
1949170654Skmacy				cxgb_init_locked(p);
1950176472Skmacy				PORT_UNLOCK(p);
1951176472Skmacy			}
1952167514Skmacy			arp_ifinit(ifp, ifa);
1953167514Skmacy		} else
1954167514Skmacy			error = ether_ioctl(ifp, command, data);
1955167514Skmacy		break;
1956167514Skmacy	case SIOCSIFFLAGS:
1957170869Skmacy		PORT_LOCK(p);
1958167514Skmacy		if (ifp->if_flags & IFF_UP) {
1959167514Skmacy			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1960167514Skmacy				flags = p->if_flags;
1961167514Skmacy				if (((ifp->if_flags ^ flags) & IFF_PROMISC) ||
1962167514Skmacy				    ((ifp->if_flags ^ flags) & IFF_ALLMULTI))
1963167514Skmacy					cxgb_set_rxmode(p);
1964167514Skmacy			} else
1965167514Skmacy				cxgb_init_locked(p);
1966167760Skmacy			p->if_flags = ifp->if_flags;
1967170869Skmacy		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1968170869Skmacy			cxgb_stop_locked(p);
1969170869Skmacy
1970176472Skmacy		PORT_UNLOCK(p);
1971176472Skmacy		break;
1972176472Skmacy	case SIOCADDMULTI:
1973176472Skmacy	case SIOCDELMULTI:
1974170869Skmacy		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1975176472Skmacy			cxgb_set_rxmode(p);
1976167514Skmacy		}
1977167514Skmacy		break;
1978167514Skmacy	case SIOCSIFMEDIA:
1979167514Skmacy	case SIOCGIFMEDIA:
1980167514Skmacy		error = ifmedia_ioctl(ifp, ifr, &p->media, command);
1981167514Skmacy		break;
1982167514Skmacy	case SIOCSIFCAP:
1983167514Skmacy		PORT_LOCK(p);
1984167514Skmacy		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1985167514Skmacy		if (mask & IFCAP_TXCSUM) {
1986167514Skmacy			if (IFCAP_TXCSUM & ifp->if_capenable) {
1987167514Skmacy				ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4);
1988167514Skmacy				ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP
1989180583Skmacy				    | CSUM_IP | CSUM_TSO);
1990167514Skmacy			} else {
1991167514Skmacy				ifp->if_capenable |= IFCAP_TXCSUM;
1992180583Skmacy				ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP
1993180583Skmacy				    | CSUM_IP);
1994167514Skmacy			}
1995167514Skmacy		}
1996180583Skmacy		if (mask & IFCAP_RXCSUM) {
1997180583Skmacy			ifp->if_capenable ^= IFCAP_RXCSUM;
1998180583Skmacy		}
1999167514Skmacy		if (mask & IFCAP_TSO4) {
2000167514Skmacy			if (IFCAP_TSO4 & ifp->if_capenable) {
2001167514Skmacy				ifp->if_capenable &= ~IFCAP_TSO4;
2002167514Skmacy				ifp->if_hwassist &= ~CSUM_TSO;
2003167514Skmacy			} else if (IFCAP_TXCSUM & ifp->if_capenable) {
2004167514Skmacy				ifp->if_capenable |= IFCAP_TSO4;
2005167514Skmacy				ifp->if_hwassist |= CSUM_TSO;
2006167514Skmacy			} else {
2007167514Skmacy				if (cxgb_debug)
2008167514Skmacy					printf("cxgb requires tx checksum offload"
2009167514Skmacy					    " be enabled to use TSO\n");
2010167514Skmacy				error = EINVAL;
2011167514Skmacy			}
2012167514Skmacy		}
2013183289Skmacy#ifdef LRO_SUPPORTED
2014181616Skmacy		if (mask & IFCAP_LRO) {
2015181616Skmacy			ifp->if_capenable ^= IFCAP_LRO;
2016181616Skmacy
2017181616Skmacy			/* Safe to do this even if cxgb_up not called yet */
2018181616Skmacy			cxgb_set_lro(p, ifp->if_capenable & IFCAP_LRO);
2019181616Skmacy		}
2020183289Skmacy#endif
2021180583Skmacy		if (mask & IFCAP_VLAN_HWTAGGING) {
2022180583Skmacy			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
2023180583Skmacy			reinit = ifp->if_drv_flags & IFF_DRV_RUNNING;
2024180583Skmacy		}
2025180583Skmacy		if (mask & IFCAP_VLAN_MTU) {
2026180583Skmacy			ifp->if_capenable ^= IFCAP_VLAN_MTU;
2027180583Skmacy			reinit = ifp->if_drv_flags & IFF_DRV_RUNNING;
2028180583Skmacy		}
2029180583Skmacy		if (mask & IFCAP_VLAN_HWCSUM) {
2030180583Skmacy			ifp->if_capenable ^= IFCAP_VLAN_HWCSUM;
2031180583Skmacy		}
2032180583Skmacy		if (reinit) {
2033180583Skmacy			cxgb_stop_locked(p);
2034180583Skmacy			cxgb_init_locked(p);
2035180583Skmacy		}
2036167514Skmacy		PORT_UNLOCK(p);
2037180583Skmacy
2038180583Skmacy#ifdef VLAN_CAPABILITIES
2039180583Skmacy		VLAN_CAPABILITIES(ifp);
2040180583Skmacy#endif
2041167514Skmacy		break;
2042167514Skmacy	default:
2043167514Skmacy		error = ether_ioctl(ifp, command, data);
2044167514Skmacy		break;
2045167514Skmacy	}
2046167514Skmacy	return (error);
2047167514Skmacy}
2048167514Skmacy
2049174708Skmacystatic int
2050167514Skmacycxgb_media_change(struct ifnet *ifp)
2051167514Skmacy{
2052167514Skmacy	if_printf(ifp, "media change not supported\n");
2053167514Skmacy	return (ENXIO);
2054167514Skmacy}
2055167514Skmacy
2056167514Skmacystatic void
2057167514Skmacycxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
2058167514Skmacy{
2059167514Skmacy	struct port_info *p = ifp->if_softc;
2060167514Skmacy
2061167514Skmacy	ifmr->ifm_status = IFM_AVALID;
2062167514Skmacy	ifmr->ifm_active = IFM_ETHER;
2063167514Skmacy
2064167514Skmacy	if (!p->link_config.link_ok)
2065167514Skmacy		return;
2066167514Skmacy
2067167514Skmacy	ifmr->ifm_status |= IFM_ACTIVE;
2068167514Skmacy
2069170654Skmacy	switch (p->link_config.speed) {
2070170654Skmacy	case 10:
2071170654Skmacy		ifmr->ifm_active |= IFM_10_T;
2072170654Skmacy		break;
2073170654Skmacy	case 100:
2074170654Skmacy		ifmr->ifm_active |= IFM_100_TX;
2075170654Skmacy			break;
2076170654Skmacy	case 1000:
2077170654Skmacy		ifmr->ifm_active |= IFM_1000_T;
2078170654Skmacy		break;
2079170654Skmacy	}
2080170654Skmacy
2081167514Skmacy	if (p->link_config.duplex)
2082167514Skmacy		ifmr->ifm_active |= IFM_FDX;
2083167514Skmacy	else
2084167514Skmacy		ifmr->ifm_active |= IFM_HDX;
2085167514Skmacy}
2086167514Skmacy
2087167514Skmacystatic void
2088167514Skmacycxgb_async_intr(void *data)
2089167514Skmacy{
2090167760Skmacy	adapter_t *sc = data;
2091167760Skmacy
2092167514Skmacy	if (cxgb_debug)
2093167760Skmacy		device_printf(sc->dev, "cxgb_async_intr\n");
2094170869Skmacy	/*
2095170869Skmacy	 * May need to sleep - defer to taskqueue
2096170869Skmacy	 */
2097170869Skmacy	taskqueue_enqueue(sc->tq, &sc->slow_intr_task);
2098167514Skmacy}
2099167514Skmacy
2100167514Skmacystatic void
2101167514Skmacycxgb_ext_intr_handler(void *arg, int count)
2102167514Skmacy{
2103167514Skmacy	adapter_t *sc = (adapter_t *)arg;
2104167514Skmacy
2105167514Skmacy	if (cxgb_debug)
2106167514Skmacy		printf("cxgb_ext_intr_handler\n");
2107167514Skmacy
2108167514Skmacy	t3_phy_intr_handler(sc);
2109167514Skmacy
2110167514Skmacy	/* Now reenable external interrupts */
2111169978Skmacy	ADAPTER_LOCK(sc);
2112167514Skmacy	if (sc->slow_intr_mask) {
2113167514Skmacy		sc->slow_intr_mask |= F_T3DBG;
2114167514Skmacy		t3_write_reg(sc, A_PL_INT_CAUSE0, F_T3DBG);
2115167514Skmacy		t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask);
2116167514Skmacy	}
2117169978Skmacy	ADAPTER_UNLOCK(sc);
2118167514Skmacy}
2119167514Skmacy
2120167514Skmacystatic void
2121167746Skmacycheck_link_status(adapter_t *sc)
2122167514Skmacy{
2123167746Skmacy	int i;
2124167514Skmacy
2125167746Skmacy	for (i = 0; i < (sc)->params.nports; ++i) {
2126167746Skmacy		struct port_info *p = &sc->port[i];
2127167514Skmacy
2128176472Skmacy		if (!(p->phy.caps & SUPPORTED_IRQ))
2129167746Skmacy			t3_link_changed(sc, i);
2130170654Skmacy		p->ifp->if_baudrate = p->link_config.speed * 1000000;
2131167746Skmacy	}
2132167514Skmacy}
2133167514Skmacy
2134167514Skmacystatic void
2135167746Skmacycheck_t3b2_mac(struct adapter *adapter)
2136167514Skmacy{
2137167514Skmacy	int i;
2138167514Skmacy
2139176472Skmacy	if(adapter->flags & CXGB_SHUTDOWN)
2140176472Skmacy		return;
2141176472Skmacy
2142167746Skmacy	for_each_port(adapter, i) {
2143167746Skmacy		struct port_info *p = &adapter->port[i];
2144167746Skmacy		struct ifnet *ifp = p->ifp;
2145167746Skmacy		int status;
2146176472Skmacy
2147176472Skmacy		if(adapter->flags & CXGB_SHUTDOWN)
2148176472Skmacy			return;
2149176472Skmacy
2150167746Skmacy		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
2151167746Skmacy			continue;
2152167746Skmacy
2153167746Skmacy		status = 0;
2154167746Skmacy		PORT_LOCK(p);
2155167746Skmacy		if ((ifp->if_drv_flags & IFF_DRV_RUNNING))
2156167746Skmacy			status = t3b2_mac_watchdog_task(&p->mac);
2157167746Skmacy		if (status == 1)
2158167746Skmacy			p->mac.stats.num_toggled++;
2159167746Skmacy		else if (status == 2) {
2160167746Skmacy			struct cmac *mac = &p->mac;
2161180583Skmacy			int mtu = ifp->if_mtu;
2162167746Skmacy
2163180583Skmacy			if (ifp->if_capenable & IFCAP_VLAN_MTU)
2164180583Skmacy				mtu += ETHER_VLAN_ENCAP_LEN;
2165180583Skmacy			t3_mac_set_mtu(mac, mtu);
2166167746Skmacy			t3_mac_set_address(mac, 0, p->hw_addr);
2167167746Skmacy			cxgb_set_rxmode(p);
2168167746Skmacy			t3_link_start(&p->phy, mac, &p->link_config);
2169167746Skmacy			t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
2170171803Skmacy			t3_port_intr_enable(adapter, p->port_id);
2171167746Skmacy			p->mac.stats.num_resets++;
2172167746Skmacy		}
2173167746Skmacy		PORT_UNLOCK(p);
2174167514Skmacy	}
2175167514Skmacy}
2176167514Skmacy
2177167746Skmacystatic void
2178167746Skmacycxgb_tick(void *arg)
2179167746Skmacy{
2180167746Skmacy	adapter_t *sc = (adapter_t *)arg;
2181170869Skmacy
2182176472Skmacy	if(sc->flags & CXGB_SHUTDOWN)
2183176472Skmacy		return;
2184174708Skmacy
2185170869Skmacy	taskqueue_enqueue(sc->tq, &sc->tick_task);
2186181652Skmacy	callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc);
2187170869Skmacy}
2188170869Skmacy
2189170869Skmacystatic void
2190170869Skmacycxgb_tick_handler(void *arg, int count)
2191170869Skmacy{
2192170869Skmacy	adapter_t *sc = (adapter_t *)arg;
2193167746Skmacy	const struct adapter_params *p = &sc->params;
2194181652Skmacy	int i;
2195167746Skmacy
2196176472Skmacy	if(sc->flags & CXGB_SHUTDOWN)
2197176472Skmacy		return;
2198176472Skmacy
2199170869Skmacy	ADAPTER_LOCK(sc);
2200167746Skmacy	if (p->linkpoll_period)
2201167746Skmacy		check_link_status(sc);
2202167746Skmacy
2203181652Skmacy	sc->check_task_cnt++;
2204181652Skmacy
2205167746Skmacy	/*
2206176472Skmacy	 * adapter lock can currently only be acquired after the
2207167746Skmacy	 * port lock
2208167746Skmacy	 */
2209167746Skmacy	ADAPTER_UNLOCK(sc);
2210170654Skmacy
2211176472Skmacy	if (p->rev == T3_REV_B2 && p->nports < 4 && sc->open_device_map)
2212167746Skmacy		check_t3b2_mac(sc);
2213181652Skmacy
2214181652Skmacy	/* Update MAC stats if it's time to do so */
2215181652Skmacy	if (!p->linkpoll_period ||
2216181652Skmacy	    (sc->check_task_cnt * p->linkpoll_period) / 10 >=
2217181652Skmacy	    p->stats_update_period) {
2218181652Skmacy		for_each_port(sc, i) {
2219181652Skmacy			struct port_info *port = &sc->port[i];
2220181652Skmacy			PORT_LOCK(port);
2221181652Skmacy			t3_mac_update_stats(&port->mac);
2222181652Skmacy			PORT_UNLOCK(port);
2223181652Skmacy		}
2224181652Skmacy		sc->check_task_cnt = 0;
2225181652Skmacy	}
2226167746Skmacy}
2227167746Skmacy
2228171978Skmacystatic void
2229171978Skmacytouch_bars(device_t dev)
2230171978Skmacy{
2231171978Skmacy	/*
2232171978Skmacy	 * Don't enable yet
2233171978Skmacy	 */
2234171978Skmacy#if !defined(__LP64__) && 0
2235171978Skmacy	u32 v;
2236171978Skmacy
2237171978Skmacy	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &v);
2238171978Skmacy	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, v);
2239171978Skmacy	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3, &v);
2240171978Skmacy	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_3, v);
2241171978Skmacy	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &v);
2242171978Skmacy	pci_write_config_dword(pdev, PCI_BASE_ADDRESS_5, v);
2243171978Skmacy#endif
2244171978Skmacy}
2245171978Skmacy
2246167514Skmacystatic int
2247171471Skmacyset_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset)
2248171471Skmacy{
2249171471Skmacy	uint8_t *buf;
2250171471Skmacy	int err = 0;
2251171471Skmacy	u32 aligned_offset, aligned_len, *p;
2252171471Skmacy	struct adapter *adapter = pi->adapter;
2253171471Skmacy
2254171471Skmacy
2255171471Skmacy	aligned_offset = offset & ~3;
2256171471Skmacy	aligned_len = (len + (offset & 3) + 3) & ~3;
2257171471Skmacy
2258171471Skmacy	if (aligned_offset != offset || aligned_len != len) {
2259171471Skmacy		buf = malloc(aligned_len, M_DEVBUF, M_WAITOK|M_ZERO);
2260171471Skmacy		if (!buf)
2261171471Skmacy			return (ENOMEM);
2262171471Skmacy		err = t3_seeprom_read(adapter, aligned_offset, (u32 *)buf);
2263171471Skmacy		if (!err && aligned_len > 4)
2264171471Skmacy			err = t3_seeprom_read(adapter,
2265171471Skmacy					      aligned_offset + aligned_len - 4,
2266171471Skmacy					      (u32 *)&buf[aligned_len - 4]);
2267171471Skmacy		if (err)
2268171471Skmacy			goto out;
2269171471Skmacy		memcpy(buf + (offset & 3), data, len);
2270171471Skmacy	} else
2271171471Skmacy		buf = (uint8_t *)(uintptr_t)data;
2272171471Skmacy
2273171471Skmacy	err = t3_seeprom_wp(adapter, 0);
2274171471Skmacy	if (err)
2275171471Skmacy		goto out;
2276171471Skmacy
2277171471Skmacy	for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) {
2278171471Skmacy		err = t3_seeprom_write(adapter, aligned_offset, *p);
2279171471Skmacy		aligned_offset += 4;
2280171471Skmacy	}
2281171471Skmacy
2282171471Skmacy	if (!err)
2283171471Skmacy		err = t3_seeprom_wp(adapter, 1);
2284171471Skmacyout:
2285171471Skmacy	if (buf != data)
2286171471Skmacy		free(buf, M_DEVBUF);
2287171471Skmacy	return err;
2288171471Skmacy}
2289171471Skmacy
2290171471Skmacy
2291171471Skmacystatic int
2292167514Skmacyin_range(int val, int lo, int hi)
2293167514Skmacy{
2294167514Skmacy	return val < 0 || (val <= hi && val >= lo);
2295167514Skmacy}
2296167514Skmacy
2297167514Skmacystatic int
2298170654Skmacycxgb_extension_open(struct cdev *dev, int flags, int fmp, d_thread_t *td)
2299170654Skmacy{
2300170654Skmacy       return (0);
2301170654Skmacy}
2302170654Skmacy
2303170654Skmacystatic int
2304170654Skmacycxgb_extension_close(struct cdev *dev, int flags, int fmt, d_thread_t *td)
2305170654Skmacy{
2306170654Skmacy       return (0);
2307170654Skmacy}
2308170654Skmacy
2309170654Skmacystatic int
2310167514Skmacycxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
2311167514Skmacy    int fflag, struct thread *td)
2312167514Skmacy{
2313167514Skmacy	int mmd, error = 0;
2314167514Skmacy	struct port_info *pi = dev->si_drv1;
2315167514Skmacy	adapter_t *sc = pi->adapter;
2316167514Skmacy
2317167514Skmacy#ifdef PRIV_SUPPORTED
2318167514Skmacy	if (priv_check(td, PRIV_DRIVER)) {
2319167514Skmacy		if (cxgb_debug)
2320167514Skmacy			printf("user does not have access to privileged ioctls\n");
2321167514Skmacy		return (EPERM);
2322167514Skmacy	}
2323167514Skmacy#else
2324167514Skmacy	if (suser(td)) {
2325167514Skmacy		if (cxgb_debug)
2326167514Skmacy			printf("user does not have access to privileged ioctls\n");
2327167514Skmacy		return (EPERM);
2328167514Skmacy	}
2329167514Skmacy#endif
2330167514Skmacy
2331167514Skmacy	switch (cmd) {
2332182679Skmacy	case CHELSIO_GET_MIIREG: {
2333167514Skmacy		uint32_t val;
2334167514Skmacy		struct cphy *phy = &pi->phy;
2335182679Skmacy		struct ch_mii_data *mid = (struct ch_mii_data *)data;
2336167514Skmacy
2337167514Skmacy		if (!phy->mdio_read)
2338167514Skmacy			return (EOPNOTSUPP);
2339167514Skmacy		if (is_10G(sc)) {
2340167514Skmacy			mmd = mid->phy_id >> 8;
2341167514Skmacy			if (!mmd)
2342167514Skmacy				mmd = MDIO_DEV_PCS;
2343167514Skmacy			else if (mmd > MDIO_DEV_XGXS)
2344171471Skmacy				return (EINVAL);
2345167514Skmacy
2346167514Skmacy			error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd,
2347167514Skmacy					     mid->reg_num, &val);
2348167514Skmacy		} else
2349167514Skmacy		        error = phy->mdio_read(sc, mid->phy_id & 0x1f, 0,
2350167514Skmacy					     mid->reg_num & 0x1f, &val);
2351167514Skmacy		if (error == 0)
2352167514Skmacy			mid->val_out = val;
2353167514Skmacy		break;
2354167514Skmacy	}
2355182679Skmacy	case CHELSIO_SET_MIIREG: {
2356167514Skmacy		struct cphy *phy = &pi->phy;
2357182679Skmacy		struct ch_mii_data *mid = (struct ch_mii_data *)data;
2358167514Skmacy
2359167514Skmacy		if (!phy->mdio_write)
2360167514Skmacy			return (EOPNOTSUPP);
2361167514Skmacy		if (is_10G(sc)) {
2362167514Skmacy			mmd = mid->phy_id >> 8;
2363167514Skmacy			if (!mmd)
2364167514Skmacy				mmd = MDIO_DEV_PCS;
2365167514Skmacy			else if (mmd > MDIO_DEV_XGXS)
2366167514Skmacy				return (EINVAL);
2367167514Skmacy
2368167514Skmacy			error = phy->mdio_write(sc, mid->phy_id & 0x1f,
2369167514Skmacy					      mmd, mid->reg_num, mid->val_in);
2370167514Skmacy		} else
2371167514Skmacy			error = phy->mdio_write(sc, mid->phy_id & 0x1f, 0,
2372167514Skmacy					      mid->reg_num & 0x1f,
2373167514Skmacy					      mid->val_in);
2374167514Skmacy		break;
2375167514Skmacy	}
2376167514Skmacy	case CHELSIO_SETREG: {
2377167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
2378167514Skmacy		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2379167514Skmacy			return (EFAULT);
2380167514Skmacy		t3_write_reg(sc, edata->addr, edata->val);
2381167514Skmacy		break;
2382167514Skmacy	}
2383167514Skmacy	case CHELSIO_GETREG: {
2384167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
2385167514Skmacy		if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2386167514Skmacy			return (EFAULT);
2387167514Skmacy		edata->val = t3_read_reg(sc, edata->addr);
2388167514Skmacy		break;
2389167514Skmacy	}
2390167514Skmacy	case CHELSIO_GET_SGE_CONTEXT: {
2391167514Skmacy		struct ch_cntxt *ecntxt = (struct ch_cntxt *)data;
2392176472Skmacy		mtx_lock_spin(&sc->sge.reg_lock);
2393167514Skmacy		switch (ecntxt->cntxt_type) {
2394167514Skmacy		case CNTXT_TYPE_EGRESS:
2395182679Skmacy			error = -t3_sge_read_ecntxt(sc, ecntxt->cntxt_id,
2396167514Skmacy			    ecntxt->data);
2397167514Skmacy			break;
2398167514Skmacy		case CNTXT_TYPE_FL:
2399182679Skmacy			error = -t3_sge_read_fl(sc, ecntxt->cntxt_id,
2400167514Skmacy			    ecntxt->data);
2401167514Skmacy			break;
2402167514Skmacy		case CNTXT_TYPE_RSP:
2403182679Skmacy			error = -t3_sge_read_rspq(sc, ecntxt->cntxt_id,
2404167514Skmacy			    ecntxt->data);
2405167514Skmacy			break;
2406167514Skmacy		case CNTXT_TYPE_CQ:
2407182679Skmacy			error = -t3_sge_read_cq(sc, ecntxt->cntxt_id,
2408167514Skmacy			    ecntxt->data);
2409167514Skmacy			break;
2410167514Skmacy		default:
2411167514Skmacy			error = EINVAL;
2412167514Skmacy			break;
2413167514Skmacy		}
2414176472Skmacy		mtx_unlock_spin(&sc->sge.reg_lock);
2415167514Skmacy		break;
2416167514Skmacy	}
2417167514Skmacy	case CHELSIO_GET_SGE_DESC: {
2418167514Skmacy		struct ch_desc *edesc = (struct ch_desc *)data;
2419167514Skmacy		int ret;
2420167514Skmacy		if (edesc->queue_num >= SGE_QSETS * 6)
2421167514Skmacy			return (EINVAL);
2422167514Skmacy		ret = t3_get_desc(&sc->sge.qs[edesc->queue_num / 6],
2423167514Skmacy		    edesc->queue_num % 6, edesc->idx, edesc->data);
2424167514Skmacy		if (ret < 0)
2425167514Skmacy			return (EINVAL);
2426167514Skmacy		edesc->size = ret;
2427167514Skmacy		break;
2428167514Skmacy	}
2429182679Skmacy	case CHELSIO_GET_QSET_PARAMS: {
2430167514Skmacy		struct qset_params *q;
2431167514Skmacy		struct ch_qset_params *t = (struct ch_qset_params *)data;
2432182679Skmacy		int q1 = pi->first_qset;
2433182679Skmacy		int nqsets = pi->nqsets;
2434176472Skmacy		int i;
2435176472Skmacy
2436182679Skmacy		if (t->qset_idx >= nqsets)
2437182679Skmacy			return EINVAL;
2438167514Skmacy
2439182679Skmacy		i = q1 + t->qset_idx;
2440182679Skmacy		q = &sc->params.sge.qset[i];
2441167514Skmacy		t->rspq_size   = q->rspq_size;
2442167514Skmacy		t->txq_size[0] = q->txq_size[0];
2443167514Skmacy		t->txq_size[1] = q->txq_size[1];
2444167514Skmacy		t->txq_size[2] = q->txq_size[2];
2445167514Skmacy		t->fl_size[0]  = q->fl_size;
2446167514Skmacy		t->fl_size[1]  = q->jumbo_size;
2447167514Skmacy		t->polling     = q->polling;
2448182679Skmacy		t->lro         = q->lro;
2449180583Skmacy		t->intr_lat    = q->coalesce_usecs;
2450167514Skmacy		t->cong_thres  = q->cong_thres;
2451182679Skmacy		t->qnum        = i;
2452182679Skmacy
2453182679Skmacy		if (sc->flags & USING_MSIX)
2454182679Skmacy			t->vector = rman_get_start(sc->msix_irq_res[i]);
2455182679Skmacy		else
2456182679Skmacy			t->vector = rman_get_start(sc->irq_res);
2457182679Skmacy
2458167514Skmacy		break;
2459167514Skmacy	}
2460182679Skmacy	case CHELSIO_GET_QSET_NUM: {
2461167514Skmacy		struct ch_reg *edata = (struct ch_reg *)data;
2462182679Skmacy		edata->val = pi->nqsets;
2463182679Skmacy		break;
2464182679Skmacy	}
2465182679Skmacy	case CHELSIO_LOAD_FW: {
2466182679Skmacy		uint8_t *fw_data;
2467182679Skmacy		uint32_t vers;
2468182679Skmacy		struct ch_mem_range *t = (struct ch_mem_range *)data;
2469182679Skmacy
2470167514Skmacy		/*
2471182679Skmacy		 * You're allowed to load a firmware only before FULL_INIT_DONE
2472182679Skmacy		 *
2473182679Skmacy		 * FW_UPTODATE is also set so the rest of the initialization
2474182679Skmacy		 * will not overwrite what was loaded here.  This gives you the
2475182679Skmacy		 * flexibility to load any firmware (and maybe shoot yourself in
2476182679Skmacy		 * the foot).
2477167514Skmacy		 */
2478182679Skmacy
2479182679Skmacy		ADAPTER_LOCK(sc);
2480182679Skmacy		if (sc->open_device_map || sc->flags & FULL_INIT_DONE) {
2481182679Skmacy			ADAPTER_UNLOCK(sc);
2482182679Skmacy			return (EBUSY);
2483182679Skmacy		}
2484182679Skmacy
2485182679Skmacy		fw_data = malloc(t->len, M_DEVBUF, M_NOWAIT);
2486182679Skmacy		if (!fw_data)
2487182679Skmacy			error = ENOMEM;
2488182679Skmacy		else
2489182679Skmacy			error = copyin(t->buf, fw_data, t->len);
2490182679Skmacy
2491182679Skmacy		if (!error)
2492182679Skmacy			error = -t3_load_fw(sc, fw_data, t->len);
2493182679Skmacy
2494182679Skmacy		if (t3_get_fw_version(sc, &vers) == 0) {
2495182679Skmacy			snprintf(&sc->fw_version[0], sizeof(sc->fw_version),
2496182679Skmacy			    "%d.%d.%d", G_FW_VERSION_MAJOR(vers),
2497182679Skmacy			    G_FW_VERSION_MINOR(vers), G_FW_VERSION_MICRO(vers));
2498182679Skmacy		}
2499182679Skmacy
2500182679Skmacy		if (!error)
2501182679Skmacy			sc->flags |= FW_UPTODATE;
2502182679Skmacy
2503182679Skmacy		free(fw_data, M_DEVBUF);
2504182679Skmacy		ADAPTER_UNLOCK(sc);
2505167514Skmacy		break;
2506167514Skmacy	}
2507182679Skmacy	case CHELSIO_LOAD_BOOT: {
2508182679Skmacy		uint8_t *boot_data;
2509182679Skmacy		struct ch_mem_range *t = (struct ch_mem_range *)data;
2510182679Skmacy
2511182679Skmacy		boot_data = malloc(t->len, M_DEVBUF, M_NOWAIT);
2512182679Skmacy		if (!boot_data)
2513182679Skmacy			return ENOMEM;
2514182679Skmacy
2515182679Skmacy		error = copyin(t->buf, boot_data, t->len);
2516182679Skmacy		if (!error)
2517182679Skmacy			error = -t3_load_boot(sc, boot_data, t->len);
2518182679Skmacy
2519182679Skmacy		free(boot_data, M_DEVBUF);
2520167514Skmacy		break;
2521167514Skmacy	}
2522182679Skmacy	case CHELSIO_GET_PM: {
2523182679Skmacy		struct ch_pm *m = (struct ch_pm *)data;
2524182679Skmacy		struct tp_params *p = &sc->params.tp;
2525182679Skmacy
2526182679Skmacy		if (!is_offload(sc))
2527182679Skmacy			return (EOPNOTSUPP);
2528182679Skmacy
2529182679Skmacy		m->tx_pg_sz = p->tx_pg_size;
2530182679Skmacy		m->tx_num_pg = p->tx_num_pgs;
2531182679Skmacy		m->rx_pg_sz  = p->rx_pg_size;
2532182679Skmacy		m->rx_num_pg = p->rx_num_pgs;
2533182679Skmacy		m->pm_total  = p->pmtx_size + p->chan_rx_size * p->nchan;
2534182679Skmacy
2535167514Skmacy		break;
2536182679Skmacy	}
2537182679Skmacy	case CHELSIO_SET_PM: {
2538182679Skmacy		struct ch_pm *m = (struct ch_pm *)data;
2539182679Skmacy		struct tp_params *p = &sc->params.tp;
2540182679Skmacy
2541182679Skmacy		if (!is_offload(sc))
2542182679Skmacy			return (EOPNOTSUPP);
2543182679Skmacy		if (sc->flags & FULL_INIT_DONE)
2544182679Skmacy			return (EBUSY);
2545182679Skmacy
2546182679Skmacy		if (!m->rx_pg_sz || (m->rx_pg_sz & (m->rx_pg_sz - 1)) ||
2547182679Skmacy		    !m->tx_pg_sz || (m->tx_pg_sz & (m->tx_pg_sz - 1)))
2548182679Skmacy			return (EINVAL);	/* not power of 2 */
2549182679Skmacy		if (!(m->rx_pg_sz & 0x14000))
2550182679Skmacy			return (EINVAL);	/* not 16KB or 64KB */
2551182679Skmacy		if (!(m->tx_pg_sz & 0x1554000))
2552182679Skmacy			return (EINVAL);
2553182679Skmacy		if (m->tx_num_pg == -1)
2554182679Skmacy			m->tx_num_pg = p->tx_num_pgs;
2555182679Skmacy		if (m->rx_num_pg == -1)
2556182679Skmacy			m->rx_num_pg = p->rx_num_pgs;
2557182679Skmacy		if (m->tx_num_pg % 24 || m->rx_num_pg % 24)
2558182679Skmacy			return (EINVAL);
2559182679Skmacy		if (m->rx_num_pg * m->rx_pg_sz > p->chan_rx_size ||
2560182679Skmacy		    m->tx_num_pg * m->tx_pg_sz > p->chan_tx_size)
2561182679Skmacy			return (EINVAL);
2562182679Skmacy
2563182679Skmacy		p->rx_pg_size = m->rx_pg_sz;
2564182679Skmacy		p->tx_pg_size = m->tx_pg_sz;
2565182679Skmacy		p->rx_num_pgs = m->rx_num_pg;
2566182679Skmacy		p->tx_num_pgs = m->tx_num_pg;
2567182679Skmacy		break;
2568182679Skmacy	}
2569169978Skmacy	case CHELSIO_SETMTUTAB: {
2570169978Skmacy		struct ch_mtus *m = (struct ch_mtus *)data;
2571169978Skmacy		int i;
2572169978Skmacy
2573169978Skmacy		if (!is_offload(sc))
2574169978Skmacy			return (EOPNOTSUPP);
2575169978Skmacy		if (offload_running(sc))
2576169978Skmacy			return (EBUSY);
2577169978Skmacy		if (m->nmtus != NMTUS)
2578169978Skmacy			return (EINVAL);
2579169978Skmacy		if (m->mtus[0] < 81)         /* accommodate SACK */
2580169978Skmacy			return (EINVAL);
2581169978Skmacy
2582169978Skmacy		/*
2583169978Skmacy		 * MTUs must be in ascending order
2584169978Skmacy		 */
2585169978Skmacy		for (i = 1; i < NMTUS; ++i)
2586169978Skmacy			if (m->mtus[i] < m->mtus[i - 1])
2587169978Skmacy				return (EINVAL);
2588169978Skmacy
2589182679Skmacy		memcpy(sc->params.mtus, m->mtus, sizeof(sc->params.mtus));
2590169978Skmacy		break;
2591169978Skmacy	}
2592169978Skmacy	case CHELSIO_GETMTUTAB: {
2593169978Skmacy		struct ch_mtus *m = (struct ch_mtus *)data;
2594169978Skmacy
2595169978Skmacy		if (!is_offload(sc))
2596169978Skmacy			return (EOPNOTSUPP);
2597169978Skmacy
2598169978Skmacy		memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus));
2599169978Skmacy		m->nmtus = NMTUS;
2600169978Skmacy		break;
2601171471Skmacy	}
2602167514Skmacy	case CHELSIO_GET_MEM: {
2603167514Skmacy		struct ch_mem_range *t = (struct ch_mem_range *)data;
2604167514Skmacy		struct mc7 *mem;
2605167514Skmacy		uint8_t *useraddr;
2606167514Skmacy		u64 buf[32];
2607182679Skmacy
2608182679Skmacy		/*
2609182679Skmacy		 * Use these to avoid modifying len/addr in the the return
2610182679Skmacy		 * struct
2611182679Skmacy		 */
2612182679Skmacy		uint32_t len = t->len, addr = t->addr;
2613182679Skmacy
2614167514Skmacy		if (!is_offload(sc))
2615167514Skmacy			return (EOPNOTSUPP);
2616167514Skmacy		if (!(sc->flags & FULL_INIT_DONE))
2617167514Skmacy			return (EIO);         /* need the memory controllers */
2618182679Skmacy		if ((addr & 0x7) || (len & 0x7))
2619167514Skmacy			return (EINVAL);
2620167514Skmacy		if (t->mem_id == MEM_CM)
2621167514Skmacy			mem = &sc->cm;
2622167514Skmacy		else if (t->mem_id == MEM_PMRX)
2623167514Skmacy			mem = &sc->pmrx;
2624167514Skmacy		else if (t->mem_id == MEM_PMTX)
2625167514Skmacy			mem = &sc->pmtx;
2626167514Skmacy		else
2627167514Skmacy			return (EINVAL);
2628167514Skmacy
2629167514Skmacy		/*
2630167514Skmacy		 * Version scheme:
2631167514Skmacy		 * bits 0..9: chip version
2632167514Skmacy		 * bits 10..15: chip revision
2633167514Skmacy		 */
2634167514Skmacy		t->version = 3 | (sc->params.rev << 10);
2635167514Skmacy
2636167514Skmacy		/*
2637167514Skmacy		 * Read 256 bytes at a time as len can be large and we don't
2638167514Skmacy		 * want to use huge intermediate buffers.
2639167514Skmacy		 */
2640174708Skmacy		useraddr = (uint8_t *)t->buf;
2641182679Skmacy		while (len) {
2642182679Skmacy			unsigned int chunk = min(len, sizeof(buf));
2643167514Skmacy
2644182679Skmacy			error = t3_mc7_bd_read(mem, addr / 8, chunk / 8, buf);
2645167514Skmacy			if (error)
2646167514Skmacy				return (-error);
2647167514Skmacy			if (copyout(buf, useraddr, chunk))
2648167514Skmacy				return (EFAULT);
2649167514Skmacy			useraddr += chunk;
2650182679Skmacy			addr += chunk;
2651182679Skmacy			len -= chunk;
2652167514Skmacy		}
2653167514Skmacy		break;
2654167514Skmacy	}
2655169978Skmacy	case CHELSIO_READ_TCAM_WORD: {
2656169978Skmacy		struct ch_tcam_word *t = (struct ch_tcam_word *)data;
2657169978Skmacy
2658169978Skmacy		if (!is_offload(sc))
2659169978Skmacy			return (EOPNOTSUPP);
2660171471Skmacy		if (!(sc->flags & FULL_INIT_DONE))
2661171471Skmacy			return (EIO);         /* need MC5 */
2662169978Skmacy		return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf);
2663169978Skmacy		break;
2664169978Skmacy	}
2665167514Skmacy	case CHELSIO_SET_TRACE_FILTER: {
2666167514Skmacy		struct ch_trace *t = (struct ch_trace *)data;
2667167514Skmacy		const struct trace_params *tp;
2668167514Skmacy
2669167514Skmacy		tp = (const struct trace_params *)&t->sip;
2670167514Skmacy		if (t->config_tx)
2671167514Skmacy			t3_config_trace_filter(sc, tp, 0, t->invert_match,
2672167514Skmacy					       t->trace_tx);
2673167514Skmacy		if (t->config_rx)
2674167514Skmacy			t3_config_trace_filter(sc, tp, 1, t->invert_match,
2675167514Skmacy					       t->trace_rx);
2676167514Skmacy		break;
2677167514Skmacy	}
2678167514Skmacy	case CHELSIO_SET_PKTSCHED: {
2679167514Skmacy		struct ch_pktsched_params *p = (struct ch_pktsched_params *)data;
2680167514Skmacy		if (sc->open_device_map == 0)
2681167514Skmacy			return (EAGAIN);
2682167514Skmacy		send_pktsched_cmd(sc, p->sched, p->idx, p->min, p->max,
2683167514Skmacy		    p->binding);
2684167514Skmacy		break;
2685167514Skmacy	}
2686167514Skmacy	case CHELSIO_IFCONF_GETREGS: {
2687182679Skmacy		struct ch_ifconf_regs *regs = (struct ch_ifconf_regs *)data;
2688167514Skmacy		int reglen = cxgb_get_regs_len();
2689182679Skmacy		uint8_t *buf = malloc(reglen, M_DEVBUF, M_NOWAIT);
2690167514Skmacy		if (buf == NULL) {
2691167514Skmacy			return (ENOMEM);
2692182679Skmacy		}
2693182679Skmacy		if (regs->len > reglen)
2694167514Skmacy			regs->len = reglen;
2695182679Skmacy		else if (regs->len < reglen)
2696167514Skmacy			error = E2BIG;
2697182679Skmacy
2698182679Skmacy		if (!error) {
2699182679Skmacy			cxgb_get_regs(sc, regs, buf);
2700182679Skmacy			error = copyout(buf, regs->data, reglen);
2701167514Skmacy		}
2702167514Skmacy		free(buf, M_DEVBUF);
2703167514Skmacy
2704167514Skmacy		break;
2705167514Skmacy	}
2706169978Skmacy	case CHELSIO_SET_HW_SCHED: {
2707169978Skmacy		struct ch_hw_sched *t = (struct ch_hw_sched *)data;
2708169978Skmacy		unsigned int ticks_per_usec = core_ticks_per_usec(sc);
2709169978Skmacy
2710169978Skmacy		if ((sc->flags & FULL_INIT_DONE) == 0)
2711169978Skmacy			return (EAGAIN);       /* need TP to be initialized */
2712169978Skmacy		if (t->sched >= NTX_SCHED || !in_range(t->mode, 0, 1) ||
2713169978Skmacy		    !in_range(t->channel, 0, 1) ||
2714169978Skmacy		    !in_range(t->kbps, 0, 10000000) ||
2715169978Skmacy		    !in_range(t->class_ipg, 0, 10000 * 65535 / ticks_per_usec) ||
2716169978Skmacy		    !in_range(t->flow_ipg, 0,
2717169978Skmacy			      dack_ticks_to_usec(sc, 0x7ff)))
2718169978Skmacy			return (EINVAL);
2719169978Skmacy
2720169978Skmacy		if (t->kbps >= 0) {
2721169978Skmacy			error = t3_config_sched(sc, t->kbps, t->sched);
2722169978Skmacy			if (error < 0)
2723169978Skmacy				return (-error);
2724169978Skmacy		}
2725169978Skmacy		if (t->class_ipg >= 0)
2726169978Skmacy			t3_set_sched_ipg(sc, t->sched, t->class_ipg);
2727169978Skmacy		if (t->flow_ipg >= 0) {
2728169978Skmacy			t->flow_ipg *= 1000;     /* us -> ns */
2729169978Skmacy			t3_set_pace_tbl(sc, &t->flow_ipg, t->sched, 1);
2730169978Skmacy		}
2731169978Skmacy		if (t->mode >= 0) {
2732169978Skmacy			int bit = 1 << (S_TX_MOD_TIMER_MODE + t->sched);
2733169978Skmacy
2734169978Skmacy			t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2735169978Skmacy					 bit, t->mode ? bit : 0);
2736169978Skmacy		}
2737169978Skmacy		if (t->channel >= 0)
2738169978Skmacy			t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2739169978Skmacy					 1 << t->sched, t->channel << t->sched);
2740169978Skmacy		break;
2741182679Skmacy	}
2742182679Skmacy	case CHELSIO_GET_EEPROM: {
2743182679Skmacy		int i;
2744182679Skmacy		struct ch_eeprom *e = (struct ch_eeprom *)data;
2745182679Skmacy		uint8_t *buf = malloc(EEPROMSIZE, M_DEVBUF, M_NOWAIT);
2746182679Skmacy
2747182679Skmacy		if (buf == NULL) {
2748182679Skmacy			return (ENOMEM);
2749182679Skmacy		}
2750182679Skmacy		e->magic = EEPROM_MAGIC;
2751182679Skmacy		for (i = e->offset & ~3; !error && i < e->offset + e->len; i += 4)
2752182679Skmacy			error = -t3_seeprom_read(sc, i, (uint32_t *)&buf[i]);
2753182679Skmacy
2754182679Skmacy		if (!error)
2755182679Skmacy			error = copyout(buf + e->offset, e->data, e->len);
2756182679Skmacy
2757182679Skmacy		free(buf, M_DEVBUF);
2758182679Skmacy		break;
2759182679Skmacy	}
2760182679Skmacy	case CHELSIO_CLEAR_STATS: {
2761182679Skmacy		if (!(sc->flags & FULL_INIT_DONE))
2762182679Skmacy			return EAGAIN;
2763182679Skmacy
2764182679Skmacy		PORT_LOCK(pi);
2765182679Skmacy		t3_mac_update_stats(&pi->mac);
2766182679Skmacy		memset(&pi->mac.stats, 0, sizeof(pi->mac.stats));
2767182679Skmacy		PORT_UNLOCK(pi);
2768182679Skmacy		break;
2769182679Skmacy	}
2770167514Skmacy	default:
2771167514Skmacy		return (EOPNOTSUPP);
2772167514Skmacy		break;
2773167514Skmacy	}
2774167514Skmacy
2775167514Skmacy	return (error);
2776167514Skmacy}
2777167514Skmacy
2778167514Skmacystatic __inline void
2779167514Skmacyreg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
2780167514Skmacy    unsigned int end)
2781167514Skmacy{
2782182679Skmacy	uint32_t *p = (uint32_t *)(buf + start);
2783167514Skmacy
2784167514Skmacy	for ( ; start <= end; start += sizeof(uint32_t))
2785167514Skmacy		*p++ = t3_read_reg(ap, start);
2786167514Skmacy}
2787167514Skmacy
2788167514Skmacy#define T3_REGMAP_SIZE (3 * 1024)
2789167514Skmacystatic int
2790167514Skmacycxgb_get_regs_len(void)
2791167514Skmacy{
2792167514Skmacy	return T3_REGMAP_SIZE;
2793167514Skmacy}
2794167514Skmacy
2795167514Skmacystatic void
2796182679Skmacycxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf)
2797167514Skmacy{
2798167514Skmacy
2799167514Skmacy	/*
2800167514Skmacy	 * Version scheme:
2801167514Skmacy	 * bits 0..9: chip version
2802167514Skmacy	 * bits 10..15: chip revision
2803167514Skmacy	 * bit 31: set for PCIe cards
2804167514Skmacy	 */
2805167514Skmacy	regs->version = 3 | (sc->params.rev << 10) | (is_pcie(sc) << 31);
2806167514Skmacy
2807167514Skmacy	/*
2808167514Skmacy	 * We skip the MAC statistics registers because they are clear-on-read.
2809167514Skmacy	 * Also reading multi-register stats would need to synchronize with the
2810167514Skmacy	 * periodic mac stats accumulation.  Hard to justify the complexity.
2811167514Skmacy	 */
2812182679Skmacy	memset(buf, 0, cxgb_get_regs_len());
2813167514Skmacy	reg_block_dump(sc, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
2814167514Skmacy	reg_block_dump(sc, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
2815167514Skmacy	reg_block_dump(sc, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
2816167514Skmacy	reg_block_dump(sc, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
2817167514Skmacy	reg_block_dump(sc, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
2818167514Skmacy	reg_block_dump(sc, buf, A_XGM_SERDES_STATUS0,
2819167514Skmacy		       XGM_REG(A_XGM_SERDES_STAT3, 1));
2820167514Skmacy	reg_block_dump(sc, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
2821167514Skmacy		       XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
2822167514Skmacy}
2823176572Skmacy
2824176572Skmacy
2825176572SkmacyMODULE_DEPEND(if_cxgb, cxgb_t3fw, 1, 1, 1);
2826