1b6d90eb7SKip Macy /**************************************************************************
24d846d26SWarner Losh SPDX-License-Identifier: BSD-2-Clause
3b6d90eb7SKip Macy
4f2d8ff04SGeorge V. Neville-Neil Copyright (c) 2007-2009, Chelsio Inc.
5b6d90eb7SKip Macy All rights reserved.
6b6d90eb7SKip Macy
7b6d90eb7SKip Macy Redistribution and use in source and binary forms, with or without
8b6d90eb7SKip Macy modification, are permitted provided that the following conditions are met:
9b6d90eb7SKip Macy
10b6d90eb7SKip Macy 1. Redistributions of source code must retain the above copyright notice,
11b6d90eb7SKip Macy this list of conditions and the following disclaimer.
12b6d90eb7SKip Macy
13d722cab4SKip Macy 2. Neither the name of the Chelsio Corporation nor the names of its
14b6d90eb7SKip Macy contributors may be used to endorse or promote products derived from
15b6d90eb7SKip Macy this software without specific prior written permission.
16b6d90eb7SKip Macy
17b6d90eb7SKip Macy THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18b6d90eb7SKip Macy AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19b6d90eb7SKip Macy IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20b6d90eb7SKip Macy ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21b6d90eb7SKip Macy LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22b6d90eb7SKip Macy CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23b6d90eb7SKip Macy SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24b6d90eb7SKip Macy INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25b6d90eb7SKip Macy CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26b6d90eb7SKip Macy ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27b6d90eb7SKip Macy POSSIBILITY OF SUCH DAMAGE.
28b6d90eb7SKip Macy
29b6d90eb7SKip Macy ***************************************************************************/
30b6d90eb7SKip Macy
31b6d90eb7SKip Macy #include <sys/cdefs.h>
3209fe6320SNavdeep Parhar #include "opt_inet.h"
3309fe6320SNavdeep Parhar
34b6d90eb7SKip Macy #include <sys/param.h>
35b6d90eb7SKip Macy #include <sys/systm.h>
36b6d90eb7SKip Macy #include <sys/kernel.h>
37b6d90eb7SKip Macy #include <sys/bus.h>
38b6d90eb7SKip Macy #include <sys/module.h>
39b6d90eb7SKip Macy #include <sys/conf.h>
40b6d90eb7SKip Macy #include <machine/bus.h>
41b6d90eb7SKip Macy #include <machine/resource.h>
428e10660fSKip Macy #include <sys/ktr.h>
43b6d90eb7SKip Macy #include <sys/rman.h>
44b6d90eb7SKip Macy #include <sys/ioccom.h>
45b6d90eb7SKip Macy #include <sys/mbuf.h>
46b6d90eb7SKip Macy #include <sys/linker.h>
47b6d90eb7SKip Macy #include <sys/firmware.h>
48b6d90eb7SKip Macy #include <sys/socket.h>
49b6d90eb7SKip Macy #include <sys/sockio.h>
50b6d90eb7SKip Macy #include <sys/smp.h>
51b6d90eb7SKip Macy #include <sys/sysctl.h>
528090c9f5SKip Macy #include <sys/syslog.h>
53b6d90eb7SKip Macy #include <sys/queue.h>
54b6d90eb7SKip Macy #include <sys/taskqueue.h>
558090c9f5SKip Macy #include <sys/proc.h>
56b6d90eb7SKip Macy
57b6d90eb7SKip Macy #include <net/bpf.h>
587790c8c1SConrad Meyer #include <net/debugnet.h>
59b6d90eb7SKip Macy #include <net/ethernet.h>
60b6d90eb7SKip Macy #include <net/if.h>
6176039bc8SGleb Smirnoff #include <net/if_var.h>
62b6d90eb7SKip Macy #include <net/if_arp.h>
63b6d90eb7SKip Macy #include <net/if_dl.h>
64b6d90eb7SKip Macy #include <net/if_media.h>
65b6d90eb7SKip Macy #include <net/if_types.h>
664af83c8cSKip Macy #include <net/if_vlan_var.h>
67b6d90eb7SKip Macy
68b6d90eb7SKip Macy #include <netinet/in_systm.h>
69b6d90eb7SKip Macy #include <netinet/in.h>
70b6d90eb7SKip Macy #include <netinet/if_ether.h>
71b6d90eb7SKip Macy #include <netinet/ip.h>
72b6d90eb7SKip Macy #include <netinet/ip.h>
73b6d90eb7SKip Macy #include <netinet/tcp.h>
74b6d90eb7SKip Macy #include <netinet/udp.h>
75b6d90eb7SKip Macy
76b6d90eb7SKip Macy #include <dev/pci/pcireg.h>
77b6d90eb7SKip Macy #include <dev/pci/pcivar.h>
78b6d90eb7SKip Macy
7910faa568SKip Macy #include <cxgb_include.h>
80b6d90eb7SKip Macy
81b6d90eb7SKip Macy #ifdef PRIV_SUPPORTED
82b6d90eb7SKip Macy #include <sys/priv.h>
83b6d90eb7SKip Macy #endif
84b6d90eb7SKip Macy
85e3503bc9SGeorge V. Neville-Neil static int cxgb_setup_interrupts(adapter_t *);
86e3503bc9SGeorge V. Neville-Neil static void cxgb_teardown_interrupts(adapter_t *);
87b6d90eb7SKip Macy static void cxgb_init(void *);
88b302b77cSNavdeep Parhar static int cxgb_init_locked(struct port_info *);
89b302b77cSNavdeep Parhar static int cxgb_uninit_locked(struct port_info *);
903f345a5dSKip Macy static int cxgb_uninit_synchronized(struct port_info *);
91954712e8SJustin Hibbits static int cxgb_ioctl(if_t, unsigned long, caddr_t);
92954712e8SJustin Hibbits static int cxgb_media_change(if_t);
93837f41b0SGeorge V. Neville-Neil static int cxgb_ifm_type(int);
942975f787SNavdeep Parhar static void cxgb_build_medialist(struct port_info *);
95954712e8SJustin Hibbits static void cxgb_media_status(if_t, struct ifmediareq *);
96954712e8SJustin Hibbits static uint64_t cxgb_get_counter(if_t, ift_counter);
97b6d90eb7SKip Macy static int setup_sge_qsets(adapter_t *);
98b6d90eb7SKip Macy static void cxgb_async_intr(void *);
99bb38cd2fSKip Macy static void cxgb_tick_handler(void *, int);
100b6d90eb7SKip Macy static void cxgb_tick(void *);
101bd1a9fbaSNavdeep Parhar static void link_check_callout(void *);
102bd1a9fbaSNavdeep Parhar static void check_link_status(void *, int);
103b6d90eb7SKip Macy static void setup_rss(adapter_t *sc);
104d6da8362SNavdeep Parhar static int alloc_filters(struct adapter *);
105d6da8362SNavdeep Parhar static int setup_hw_filters(struct adapter *);
106d6da8362SNavdeep Parhar static int set_filter(struct adapter *, int, const struct filter_info *);
107d6da8362SNavdeep Parhar static inline void mk_set_tcb_field(struct cpl_set_tcb_field *, unsigned int,
108d6da8362SNavdeep Parhar unsigned int, u64, u64);
109d6da8362SNavdeep Parhar static inline void set_tcb_field_ulp(struct cpl_set_tcb_field *, unsigned int,
110d6da8362SNavdeep Parhar unsigned int, u64, u64);
11109fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
11209fe6320SNavdeep Parhar static int cpl_not_handled(struct sge_qset *, struct rsp_desc *, struct mbuf *);
11309fe6320SNavdeep Parhar #endif
114b6d90eb7SKip Macy
115b6d90eb7SKip Macy /* Attachment glue for the PCI controller end of the device. Each port of
116b6d90eb7SKip Macy * the device is attached separately, as defined later.
117b6d90eb7SKip Macy */
118b6d90eb7SKip Macy static int cxgb_controller_probe(device_t);
119b6d90eb7SKip Macy static int cxgb_controller_attach(device_t);
120b6d90eb7SKip Macy static int cxgb_controller_detach(device_t);
121b6d90eb7SKip Macy static void cxgb_free(struct adapter *);
122b6d90eb7SKip Macy static __inline void reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
123b6d90eb7SKip Macy unsigned int end);
1241ffd6e58SKip Macy static void cxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf);
125b6d90eb7SKip Macy static int cxgb_get_regs_len(void);
1267ac2e6c3SKip Macy static void touch_bars(device_t dev);
127c01f2b83SNavdeep Parhar static void cxgb_update_mac_settings(struct port_info *p);
12809fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
12909fe6320SNavdeep Parhar static int toe_capability(struct port_info *, int);
13009fe6320SNavdeep Parhar #endif
131b6d90eb7SKip Macy
1320dc34160SWarner Losh /* Table for probing the cards. The desc field isn't actually used */
1330dc34160SWarner Losh struct cxgb_ident {
1340dc34160SWarner Losh uint16_t vendor;
1350dc34160SWarner Losh uint16_t device;
1360dc34160SWarner Losh int index;
1370dc34160SWarner Losh char *desc;
1380dc34160SWarner Losh } cxgb_identifiers[] = {
1390dc34160SWarner Losh {PCI_VENDOR_ID_CHELSIO, 0x0020, 0, "PE9000"},
1400dc34160SWarner Losh {PCI_VENDOR_ID_CHELSIO, 0x0021, 1, "T302E"},
1410dc34160SWarner Losh {PCI_VENDOR_ID_CHELSIO, 0x0022, 2, "T310E"},
1420dc34160SWarner Losh {PCI_VENDOR_ID_CHELSIO, 0x0023, 3, "T320X"},
1430dc34160SWarner Losh {PCI_VENDOR_ID_CHELSIO, 0x0024, 1, "T302X"},
1440dc34160SWarner Losh {PCI_VENDOR_ID_CHELSIO, 0x0025, 3, "T320E"},
1450dc34160SWarner Losh {PCI_VENDOR_ID_CHELSIO, 0x0026, 2, "T310X"},
1460dc34160SWarner Losh {PCI_VENDOR_ID_CHELSIO, 0x0030, 2, "T3B10"},
1470dc34160SWarner Losh {PCI_VENDOR_ID_CHELSIO, 0x0031, 3, "T3B20"},
1480dc34160SWarner Losh {PCI_VENDOR_ID_CHELSIO, 0x0032, 1, "T3B02"},
1490dc34160SWarner Losh {PCI_VENDOR_ID_CHELSIO, 0x0033, 4, "T3B04"},
1500dc34160SWarner Losh {PCI_VENDOR_ID_CHELSIO, 0x0035, 6, "T3C10"},
1510dc34160SWarner Losh {PCI_VENDOR_ID_CHELSIO, 0x0036, 3, "S320E-CR"},
1520dc34160SWarner Losh {PCI_VENDOR_ID_CHELSIO, 0x0037, 7, "N320E-G2"},
1530dc34160SWarner Losh {0, 0, 0, NULL}
1540dc34160SWarner Losh };
1550dc34160SWarner Losh
156b6d90eb7SKip Macy static device_method_t cxgb_controller_methods[] = {
157b6d90eb7SKip Macy DEVMETHOD(device_probe, cxgb_controller_probe),
158b6d90eb7SKip Macy DEVMETHOD(device_attach, cxgb_controller_attach),
159b6d90eb7SKip Macy DEVMETHOD(device_detach, cxgb_controller_detach),
160b6d90eb7SKip Macy
1614b7ec270SMarius Strobl DEVMETHOD_END
162b6d90eb7SKip Macy };
163b6d90eb7SKip Macy
164b6d90eb7SKip Macy static driver_t cxgb_controller_driver = {
165b6d90eb7SKip Macy "cxgbc",
166b6d90eb7SKip Macy cxgb_controller_methods,
167b6d90eb7SKip Macy sizeof(struct adapter)
168b6d90eb7SKip Macy };
169b6d90eb7SKip Macy
17009fe6320SNavdeep Parhar static int cxgbc_mod_event(module_t, int, void *);
171c54f3323SJohn Baldwin
172c54f3323SJohn Baldwin DRIVER_MODULE(cxgbc, pci, cxgb_controller_driver, cxgbc_mod_event, NULL);
1730dc34160SWarner Losh MODULE_PNP_INFO("U16:vendor;U16:device", pci, cxgbc, cxgb_identifiers,
1740dc34160SWarner Losh nitems(cxgb_identifiers) - 1);
17509fe6320SNavdeep Parhar MODULE_VERSION(cxgbc, 1);
1765ada8664SKonstantin Belousov MODULE_DEPEND(cxgbc, firmware, 1, 1, 1);
177b6d90eb7SKip Macy
178b6d90eb7SKip Macy /*
179b6d90eb7SKip Macy * Attachment glue for the ports. Attachment is done directly to the
180b6d90eb7SKip Macy * controller device.
181b6d90eb7SKip Macy */
182b6d90eb7SKip Macy static int cxgb_port_probe(device_t);
183b6d90eb7SKip Macy static int cxgb_port_attach(device_t);
184b6d90eb7SKip Macy static int cxgb_port_detach(device_t);
185b6d90eb7SKip Macy
186b6d90eb7SKip Macy static device_method_t cxgb_port_methods[] = {
187b6d90eb7SKip Macy DEVMETHOD(device_probe, cxgb_port_probe),
188b6d90eb7SKip Macy DEVMETHOD(device_attach, cxgb_port_attach),
189b6d90eb7SKip Macy DEVMETHOD(device_detach, cxgb_port_detach),
190b6d90eb7SKip Macy { 0, 0 }
191b6d90eb7SKip Macy };
192b6d90eb7SKip Macy
193b6d90eb7SKip Macy static driver_t cxgb_port_driver = {
194b6d90eb7SKip Macy "cxgb",
195b6d90eb7SKip Macy cxgb_port_methods,
196b6d90eb7SKip Macy 0
197b6d90eb7SKip Macy };
198b6d90eb7SKip Macy
199b6d90eb7SKip Macy static d_ioctl_t cxgb_extension_ioctl;
200ef72318fSKip Macy static d_open_t cxgb_extension_open;
201ef72318fSKip Macy static d_close_t cxgb_extension_close;
202ef72318fSKip Macy
203ef72318fSKip Macy static struct cdevsw cxgb_cdevsw = {
204ef72318fSKip Macy .d_version = D_VERSION,
205ef72318fSKip Macy .d_flags = 0,
206ef72318fSKip Macy .d_open = cxgb_extension_open,
207ef72318fSKip Macy .d_close = cxgb_extension_close,
208ef72318fSKip Macy .d_ioctl = cxgb_extension_ioctl,
209ef72318fSKip Macy .d_name = "cxgb",
210ef72318fSKip Macy };
211b6d90eb7SKip Macy
212c54f3323SJohn Baldwin DRIVER_MODULE(cxgb, cxgbc, cxgb_port_driver, 0, 0);
21309fe6320SNavdeep Parhar MODULE_VERSION(cxgb, 1);
21409fe6320SNavdeep Parhar
2157790c8c1SConrad Meyer DEBUGNET_DEFINE(cxgb);
216eb07d67eSMark Johnston
21709fe6320SNavdeep Parhar static struct mtx t3_list_lock;
21809fe6320SNavdeep Parhar static SLIST_HEAD(, adapter) t3_list;
21909fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
22009fe6320SNavdeep Parhar static struct mtx t3_uld_list_lock;
22109fe6320SNavdeep Parhar static SLIST_HEAD(, uld_info) t3_uld_list;
22209fe6320SNavdeep Parhar #endif
223b6d90eb7SKip Macy
224b6d90eb7SKip Macy /*
225b6d90eb7SKip Macy * The driver uses the best interrupt scheme available on a platform in the
226b6d90eb7SKip Macy * order MSI-X, MSI, legacy pin interrupts. This parameter determines which
227b6d90eb7SKip Macy * of these schemes the driver may consider as follows:
228b6d90eb7SKip Macy *
229b6d90eb7SKip Macy * msi = 2: choose from among all three options
230b6d90eb7SKip Macy * msi = 1 : only consider MSI and pin interrupts
231b6d90eb7SKip Macy * msi = 0: force pin interrupts
232b6d90eb7SKip Macy */
233693d746cSKip Macy static int msi_allowed = 2;
234cebf6b9fSKip Macy
2357029da5cSPawel Biernacki SYSCTL_NODE(_hw, OID_AUTO, cxgb, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
2367029da5cSPawel Biernacki "CXGB driver parameters");
237deceab87SMatthew D Fleming SYSCTL_INT(_hw_cxgb, OID_AUTO, msi_allowed, CTLFLAG_RDTUN, &msi_allowed, 0,
238b6d90eb7SKip Macy "MSI-X, MSI, INTx selector");
239d722cab4SKip Macy
24064c43db5SKip Macy /*
241d722cab4SKip Macy * The driver uses an auto-queue algorithm by default.
242a02573bcSKip Macy * To disable it and force a single queue-set per port, use multiq = 0
24364c43db5SKip Macy */
244a02573bcSKip Macy static int multiq = 1;
245deceab87SMatthew D Fleming SYSCTL_INT(_hw_cxgb, OID_AUTO, multiq, CTLFLAG_RDTUN, &multiq, 0,
246a02573bcSKip Macy "use min(ncpus/ports, 8) queue-sets per port");
247f001b63dSKip Macy
248404825a7SKip Macy /*
249a02573bcSKip Macy * By default the driver will not update the firmware unless
250a02573bcSKip Macy * it was compiled against a newer version
251a02573bcSKip Macy *
252404825a7SKip Macy */
253404825a7SKip Macy static int force_fw_update = 0;
254deceab87SMatthew D Fleming SYSCTL_INT(_hw_cxgb, OID_AUTO, force_fw_update, CTLFLAG_RDTUN, &force_fw_update, 0,
255404825a7SKip Macy "update firmware even if up to date");
256f001b63dSKip Macy
25797ae3bc3SNavdeep Parhar int cxgb_use_16k_clusters = -1;
25897ae3bc3SNavdeep Parhar SYSCTL_INT(_hw_cxgb, OID_AUTO, use_16k_clusters, CTLFLAG_RDTUN,
259f001b63dSKip Macy &cxgb_use_16k_clusters, 0, "use 16kB clusters for the jumbo queue ");
260f001b63dSKip Macy
2613a2c6562SNavdeep Parhar static int nfilters = -1;
2623a2c6562SNavdeep Parhar SYSCTL_INT(_hw_cxgb, OID_AUTO, nfilters, CTLFLAG_RDTUN,
2633a2c6562SNavdeep Parhar &nfilters, 0, "max number of entries in the filter table");
26402c7d9a6SGeorge V. Neville-Neil
265b6d90eb7SKip Macy enum {
266b6d90eb7SKip Macy MAX_TXQ_ENTRIES = 16384,
267b6d90eb7SKip Macy MAX_CTRL_TXQ_ENTRIES = 1024,
268b6d90eb7SKip Macy MAX_RSPQ_ENTRIES = 16384,
269b6d90eb7SKip Macy MAX_RX_BUFFERS = 16384,
270b6d90eb7SKip Macy MAX_RX_JUMBO_BUFFERS = 16384,
271b6d90eb7SKip Macy MIN_TXQ_ENTRIES = 4,
272b6d90eb7SKip Macy MIN_CTRL_TXQ_ENTRIES = 4,
273b6d90eb7SKip Macy MIN_RSPQ_ENTRIES = 32,
2745c5df3daSKip Macy MIN_FL_ENTRIES = 32,
2755c5df3daSKip Macy MIN_FL_JUMBO_ENTRIES = 32
276b6d90eb7SKip Macy };
277b6d90eb7SKip Macy
278ac3a6d9cSKip Macy struct filter_info {
279ac3a6d9cSKip Macy u32 sip;
280ac3a6d9cSKip Macy u32 sip_mask;
281ac3a6d9cSKip Macy u32 dip;
282ac3a6d9cSKip Macy u16 sport;
283ac3a6d9cSKip Macy u16 dport;
284ac3a6d9cSKip Macy u32 vlan:12;
285ac3a6d9cSKip Macy u32 vlan_prio:3;
286ac3a6d9cSKip Macy u32 mac_hit:1;
287ac3a6d9cSKip Macy u32 mac_idx:4;
288ac3a6d9cSKip Macy u32 mac_vld:1;
289ac3a6d9cSKip Macy u32 pkt_type:2;
290ac3a6d9cSKip Macy u32 report_filter_id:1;
291ac3a6d9cSKip Macy u32 pass:1;
292ac3a6d9cSKip Macy u32 rss:1;
293ac3a6d9cSKip Macy u32 qset:3;
294ac3a6d9cSKip Macy u32 locked:1;
295ac3a6d9cSKip Macy u32 valid:1;
296ac3a6d9cSKip Macy };
297ac3a6d9cSKip Macy
298ac3a6d9cSKip Macy enum { FILTER_NO_VLAN_PRI = 7 };
299ac3a6d9cSKip Macy
3001ffd6e58SKip Macy #define EEPROM_MAGIC 0x38E2F10C
3011ffd6e58SKip Macy
302b6d90eb7SKip Macy #define PORT_MASK ((1 << MAX_NPORTS) - 1)
303b6d90eb7SKip Macy
304b6d90eb7SKip Macy
305ac3a6d9cSKip Macy static int set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset);
306ac3a6d9cSKip Macy
3078e10660fSKip Macy
3088090c9f5SKip Macy static __inline char
t3rev2char(struct adapter * adapter)309ac3a6d9cSKip Macy t3rev2char(struct adapter *adapter)
310ac3a6d9cSKip Macy {
311ac3a6d9cSKip Macy char rev = 'z';
312ac3a6d9cSKip Macy
313ac3a6d9cSKip Macy switch(adapter->params.rev) {
314ac3a6d9cSKip Macy case T3_REV_A:
315ac3a6d9cSKip Macy rev = 'a';
316ac3a6d9cSKip Macy break;
317ac3a6d9cSKip Macy case T3_REV_B:
318ac3a6d9cSKip Macy case T3_REV_B2:
319ac3a6d9cSKip Macy rev = 'b';
320ac3a6d9cSKip Macy break;
321ac3a6d9cSKip Macy case T3_REV_C:
322ac3a6d9cSKip Macy rev = 'c';
323ac3a6d9cSKip Macy break;
324ac3a6d9cSKip Macy }
325ac3a6d9cSKip Macy return rev;
326ac3a6d9cSKip Macy }
327ac3a6d9cSKip Macy
328b6d90eb7SKip Macy static struct cxgb_ident *
cxgb_get_ident(device_t dev)329b6d90eb7SKip Macy cxgb_get_ident(device_t dev)
330b6d90eb7SKip Macy {
331b6d90eb7SKip Macy struct cxgb_ident *id;
332b6d90eb7SKip Macy
333b6d90eb7SKip Macy for (id = cxgb_identifiers; id->desc != NULL; id++) {
334b6d90eb7SKip Macy if ((id->vendor == pci_get_vendor(dev)) &&
335b6d90eb7SKip Macy (id->device == pci_get_device(dev))) {
336b6d90eb7SKip Macy return (id);
337b6d90eb7SKip Macy }
338b6d90eb7SKip Macy }
339b6d90eb7SKip Macy return (NULL);
340b6d90eb7SKip Macy }
341b6d90eb7SKip Macy
342b6d90eb7SKip Macy static const struct adapter_info *
cxgb_get_adapter_info(device_t dev)343b6d90eb7SKip Macy cxgb_get_adapter_info(device_t dev)
344b6d90eb7SKip Macy {
345b6d90eb7SKip Macy struct cxgb_ident *id;
346b6d90eb7SKip Macy const struct adapter_info *ai;
347b6d90eb7SKip Macy
348b6d90eb7SKip Macy id = cxgb_get_ident(dev);
349b6d90eb7SKip Macy if (id == NULL)
350b6d90eb7SKip Macy return (NULL);
351b6d90eb7SKip Macy
352b6d90eb7SKip Macy ai = t3_get_adapter_info(id->index);
353b6d90eb7SKip Macy
354b6d90eb7SKip Macy return (ai);
355b6d90eb7SKip Macy }
356b6d90eb7SKip Macy
357b6d90eb7SKip Macy static int
cxgb_controller_probe(device_t dev)358b6d90eb7SKip Macy cxgb_controller_probe(device_t dev)
359b6d90eb7SKip Macy {
360b6d90eb7SKip Macy const struct adapter_info *ai;
361796bcf18SMark Johnston const char *ports;
362ef72318fSKip Macy int nports;
363b6d90eb7SKip Macy
364b6d90eb7SKip Macy ai = cxgb_get_adapter_info(dev);
365b6d90eb7SKip Macy if (ai == NULL)
366b6d90eb7SKip Macy return (ENXIO);
367b6d90eb7SKip Macy
368ef72318fSKip Macy nports = ai->nports0 + ai->nports1;
369ef72318fSKip Macy if (nports == 1)
370b6d90eb7SKip Macy ports = "port";
371b6d90eb7SKip Macy else
372b6d90eb7SKip Macy ports = "ports";
373b6d90eb7SKip Macy
374796bcf18SMark Johnston device_set_descf(dev, "%s, %d %s", ai->desc, nports, ports);
375b6d90eb7SKip Macy return (BUS_PROBE_DEFAULT);
376b6d90eb7SKip Macy }
377b6d90eb7SKip Macy
378404825a7SKip Macy #define FW_FNAME "cxgb_t3fw"
3790c1ff9c6SGeorge V. Neville-Neil #define TPEEPROM_NAME "cxgb_t3%c_tp_eeprom"
3800c1ff9c6SGeorge V. Neville-Neil #define TPSRAM_NAME "cxgb_t3%c_protocol_sram"
381ac3a6d9cSKip Macy
382b6d90eb7SKip Macy static int
upgrade_fw(adapter_t * sc)383d722cab4SKip Macy upgrade_fw(adapter_t *sc)
384b6d90eb7SKip Macy {
385b6d90eb7SKip Macy const struct firmware *fw;
386b6d90eb7SKip Macy int status;
387a9da6d23SNavdeep Parhar u32 vers;
388b6d90eb7SKip Macy
389404825a7SKip Macy if ((fw = firmware_get(FW_FNAME)) == NULL) {
390404825a7SKip Macy device_printf(sc->dev, "Could not find firmware image %s\n", FW_FNAME);
391d722cab4SKip Macy return (ENOENT);
392ac3a6d9cSKip Macy } else
393a9da6d23SNavdeep Parhar device_printf(sc->dev, "installing firmware on card\n");
394b6d90eb7SKip Macy status = t3_load_fw(sc, (const uint8_t *)fw->data, fw->datasize);
395b6d90eb7SKip Macy
396a9da6d23SNavdeep Parhar if (status != 0) {
397a9da6d23SNavdeep Parhar device_printf(sc->dev, "failed to install firmware: %d\n",
398a9da6d23SNavdeep Parhar status);
399a9da6d23SNavdeep Parhar } else {
400a9da6d23SNavdeep Parhar t3_get_fw_version(sc, &vers);
401a9da6d23SNavdeep Parhar snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d.%d",
402a9da6d23SNavdeep Parhar G_FW_VERSION_MAJOR(vers), G_FW_VERSION_MINOR(vers),
403a9da6d23SNavdeep Parhar G_FW_VERSION_MICRO(vers));
404a9da6d23SNavdeep Parhar }
405ac3a6d9cSKip Macy
406b6d90eb7SKip Macy firmware_put(fw, FIRMWARE_UNLOAD);
407b6d90eb7SKip Macy
408b6d90eb7SKip Macy return (status);
409b6d90eb7SKip Macy }
410b6d90eb7SKip Macy
4113cf138bbSGeorge V. Neville-Neil /*
4123cf138bbSGeorge V. Neville-Neil * The cxgb_controller_attach function is responsible for the initial
4133cf138bbSGeorge V. Neville-Neil * bringup of the device. Its responsibilities include:
4143cf138bbSGeorge V. Neville-Neil *
4153cf138bbSGeorge V. Neville-Neil * 1. Determine if the device supports MSI or MSI-X.
4163cf138bbSGeorge V. Neville-Neil * 2. Allocate bus resources so that we can access the Base Address Register
4173cf138bbSGeorge V. Neville-Neil * 3. Create and initialize mutexes for the controller and its control
4183cf138bbSGeorge V. Neville-Neil * logic such as SGE and MDIO.
4193cf138bbSGeorge V. Neville-Neil * 4. Call hardware specific setup routine for the adapter as a whole.
4203cf138bbSGeorge V. Neville-Neil * 5. Allocate the BAR for doing MSI-X.
4213cf138bbSGeorge V. Neville-Neil * 6. Setup the line interrupt iff MSI-X is not supported.
4223cf138bbSGeorge V. Neville-Neil * 7. Create the driver's taskq.
423c2009a4cSGeorge V. Neville-Neil * 8. Start one task queue service thread.
424c2009a4cSGeorge V. Neville-Neil * 9. Check if the firmware and SRAM are up-to-date. They will be
425c2009a4cSGeorge V. Neville-Neil * auto-updated later (before FULL_INIT_DONE), if required.
4263cf138bbSGeorge V. Neville-Neil * 10. Create a child device for each MAC (port)
4273cf138bbSGeorge V. Neville-Neil * 11. Initialize T3 private state.
4283cf138bbSGeorge V. Neville-Neil * 12. Trigger the LED
4293cf138bbSGeorge V. Neville-Neil * 13. Setup offload iff supported.
4303cf138bbSGeorge V. Neville-Neil * 14. Reset/restart the tick callout.
4313cf138bbSGeorge V. Neville-Neil * 15. Attach sysctls
4323cf138bbSGeorge V. Neville-Neil *
4333cf138bbSGeorge V. Neville-Neil * NOTE: Any modification or deviation from this list MUST be reflected in
4343cf138bbSGeorge V. Neville-Neil * the above comment. Failure to do so will result in problems on various
4353cf138bbSGeorge V. Neville-Neil * error conditions including link flapping.
4363cf138bbSGeorge V. Neville-Neil */
437b6d90eb7SKip Macy static int
cxgb_controller_attach(device_t dev)438b6d90eb7SKip Macy cxgb_controller_attach(device_t dev)
439b6d90eb7SKip Macy {
440b6d90eb7SKip Macy device_t child;
441b6d90eb7SKip Macy const struct adapter_info *ai;
442b6d90eb7SKip Macy struct adapter *sc;
4432de1fa86SKip Macy int i, error = 0;
444b6d90eb7SKip Macy uint32_t vers;
445693d746cSKip Macy int port_qsets = 1;
4462de1fa86SKip Macy int msi_needed, reg;
4475197f3abSGeorge V. Neville-Neil
448b6d90eb7SKip Macy sc = device_get_softc(dev);
449b6d90eb7SKip Macy sc->dev = dev;
450d722cab4SKip Macy sc->msi_count = 0;
4512de1fa86SKip Macy ai = cxgb_get_adapter_info(dev);
452b6d90eb7SKip Macy
45309fe6320SNavdeep Parhar snprintf(sc->lockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb controller lock %d",
45409fe6320SNavdeep Parhar device_get_unit(dev));
45509fe6320SNavdeep Parhar ADAPTER_LOCK_INIT(sc, sc->lockbuf);
45609fe6320SNavdeep Parhar
45709fe6320SNavdeep Parhar snprintf(sc->reglockbuf, ADAPTER_LOCK_NAME_LEN, "SGE reg lock %d",
45809fe6320SNavdeep Parhar device_get_unit(dev));
45909fe6320SNavdeep Parhar snprintf(sc->mdiolockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb mdio lock %d",
46009fe6320SNavdeep Parhar device_get_unit(dev));
46109fe6320SNavdeep Parhar snprintf(sc->elmerlockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb elmer lock %d",
46209fe6320SNavdeep Parhar device_get_unit(dev));
46309fe6320SNavdeep Parhar
46409fe6320SNavdeep Parhar MTX_INIT(&sc->sge.reg_lock, sc->reglockbuf, NULL, MTX_SPIN);
46509fe6320SNavdeep Parhar MTX_INIT(&sc->mdio_lock, sc->mdiolockbuf, NULL, MTX_DEF);
46609fe6320SNavdeep Parhar MTX_INIT(&sc->elmer_lock, sc->elmerlockbuf, NULL, MTX_DEF);
46709fe6320SNavdeep Parhar
46809fe6320SNavdeep Parhar mtx_lock(&t3_list_lock);
46909fe6320SNavdeep Parhar SLIST_INSERT_HEAD(&t3_list, sc, link);
47009fe6320SNavdeep Parhar mtx_unlock(&t3_list_lock);
47109fe6320SNavdeep Parhar
472fc01c613SKip Macy /* find the PCIe link width and set max read request to 4KB*/
4733b0a4aefSJohn Baldwin if (pci_find_cap(dev, PCIY_EXPRESS, ®) == 0) {
474b739a509SJohn Baldwin uint16_t lnk;
475fc01c613SKip Macy
476389c8bd5SGavin Atkinson lnk = pci_read_config(dev, reg + PCIER_LINK_STA, 2);
477389c8bd5SGavin Atkinson sc->link_width = (lnk & PCIEM_LINK_STA_WIDTH) >> 4;
478b739a509SJohn Baldwin if (sc->link_width < 8 &&
479b739a509SJohn Baldwin (ai->caps & SUPPORTED_10000baseT_Full)) {
480fc01c613SKip Macy device_printf(sc->dev,
481ac6b4cf1SKip Macy "PCIe x%d Link, expect reduced performance\n",
482fc01c613SKip Macy sc->link_width);
483fc01c613SKip Macy }
484e83ec3e5SNavdeep Parhar
485b739a509SJohn Baldwin pci_set_max_read_req(dev, 4096);
486b739a509SJohn Baldwin }
487b739a509SJohn Baldwin
4887ac2e6c3SKip Macy touch_bars(dev);
489b6d90eb7SKip Macy pci_enable_busmaster(dev);
490b6d90eb7SKip Macy /*
491b6d90eb7SKip Macy * Allocate the registers and make them available to the driver.
492b6d90eb7SKip Macy * The registers that we care about for NIC mode are in BAR 0
493b6d90eb7SKip Macy */
494b6d90eb7SKip Macy sc->regs_rid = PCIR_BAR(0);
495b6d90eb7SKip Macy if ((sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
496b6d90eb7SKip Macy &sc->regs_rid, RF_ACTIVE)) == NULL) {
4978e10660fSKip Macy device_printf(dev, "Cannot allocate BAR region 0\n");
49809fe6320SNavdeep Parhar error = ENXIO;
49909fe6320SNavdeep Parhar goto out;
500b6d90eb7SKip Macy }
501b6d90eb7SKip Macy
502b6d90eb7SKip Macy sc->bt = rman_get_bustag(sc->regs_res);
503b6d90eb7SKip Macy sc->bh = rman_get_bushandle(sc->regs_res);
504b6d90eb7SKip Macy sc->mmio_len = rman_get_size(sc->regs_res);
505b6d90eb7SKip Macy
506c01f2b83SNavdeep Parhar for (i = 0; i < MAX_NPORTS; i++)
507c01f2b83SNavdeep Parhar sc->port[i].adapter = sc;
508c01f2b83SNavdeep Parhar
50924cdd067SKip Macy if (t3_prep_adapter(sc, ai, 1) < 0) {
510ef72318fSKip Macy printf("prep adapter failed\n");
51124cdd067SKip Macy error = ENODEV;
51224cdd067SKip Macy goto out;
51324cdd067SKip Macy }
514c3286cd2SNavdeep Parhar
515c3286cd2SNavdeep Parhar sc->udbs_rid = PCIR_BAR(2);
516c3286cd2SNavdeep Parhar sc->udbs_res = NULL;
517c3286cd2SNavdeep Parhar if (is_offload(sc) &&
518c3286cd2SNavdeep Parhar ((sc->udbs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
519c3286cd2SNavdeep Parhar &sc->udbs_rid, RF_ACTIVE)) == NULL)) {
520c3286cd2SNavdeep Parhar device_printf(dev, "Cannot allocate BAR region 1\n");
521c3286cd2SNavdeep Parhar error = ENXIO;
522c3286cd2SNavdeep Parhar goto out;
523c3286cd2SNavdeep Parhar }
524c3286cd2SNavdeep Parhar
525b6d90eb7SKip Macy /* Allocate the BAR for doing MSI-X. If it succeeds, try to allocate
526b6d90eb7SKip Macy * enough messages for the queue sets. If that fails, try falling
527b6d90eb7SKip Macy * back to MSI. If that fails, then try falling back to the legacy
528b6d90eb7SKip Macy * interrupt pin model.
529b6d90eb7SKip Macy */
530b6d90eb7SKip Macy sc->msix_regs_rid = 0x20;
531b6d90eb7SKip Macy if ((msi_allowed >= 2) &&
532b6d90eb7SKip Macy (sc->msix_regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
533b6d90eb7SKip Macy &sc->msix_regs_rid, RF_ACTIVE)) != NULL) {
534b6d90eb7SKip Macy
535e3503bc9SGeorge V. Neville-Neil if (multiq)
536e3503bc9SGeorge V. Neville-Neil port_qsets = min(SGE_QSETS/sc->params.nports, mp_ncpus);
537e3503bc9SGeorge V. Neville-Neil msi_needed = sc->msi_count = sc->params.nports * port_qsets + 1;
538693d746cSKip Macy
539e3503bc9SGeorge V. Neville-Neil if (pci_msix_count(dev) == 0 ||
540e3503bc9SGeorge V. Neville-Neil (error = pci_alloc_msix(dev, &sc->msi_count)) != 0 ||
541e3503bc9SGeorge V. Neville-Neil sc->msi_count != msi_needed) {
542e3503bc9SGeorge V. Neville-Neil device_printf(dev, "alloc msix failed - "
543e3503bc9SGeorge V. Neville-Neil "msi_count=%d, msi_needed=%d, err=%d; "
544e3503bc9SGeorge V. Neville-Neil "will try MSI\n", sc->msi_count,
545d722cab4SKip Macy msi_needed, error);
546d722cab4SKip Macy sc->msi_count = 0;
547e3503bc9SGeorge V. Neville-Neil port_qsets = 1;
548b6d90eb7SKip Macy pci_release_msi(dev);
549b6d90eb7SKip Macy bus_release_resource(dev, SYS_RES_MEMORY,
550b6d90eb7SKip Macy sc->msix_regs_rid, sc->msix_regs_res);
551b6d90eb7SKip Macy sc->msix_regs_res = NULL;
552b6d90eb7SKip Macy } else {
553b6d90eb7SKip Macy sc->flags |= USING_MSIX;
554e3503bc9SGeorge V. Neville-Neil sc->cxgb_intr = cxgb_async_intr;
555e3503bc9SGeorge V. Neville-Neil device_printf(dev,
556e3503bc9SGeorge V. Neville-Neil "using MSI-X interrupts (%u vectors)\n",
557e3503bc9SGeorge V. Neville-Neil sc->msi_count);
558b6d90eb7SKip Macy }
559b6d90eb7SKip Macy }
560b6d90eb7SKip Macy
561d722cab4SKip Macy if ((msi_allowed >= 1) && (sc->msi_count == 0)) {
562d722cab4SKip Macy sc->msi_count = 1;
563e3503bc9SGeorge V. Neville-Neil if ((error = pci_alloc_msi(dev, &sc->msi_count)) != 0) {
564e3503bc9SGeorge V. Neville-Neil device_printf(dev, "alloc msi failed - "
565e3503bc9SGeorge V. Neville-Neil "err=%d; will try INTx\n", error);
566d722cab4SKip Macy sc->msi_count = 0;
567e3503bc9SGeorge V. Neville-Neil port_qsets = 1;
568b6d90eb7SKip Macy pci_release_msi(dev);
569b6d90eb7SKip Macy } else {
570b6d90eb7SKip Macy sc->flags |= USING_MSI;
571f0a542f8SKip Macy sc->cxgb_intr = t3_intr_msi;
572e3503bc9SGeorge V. Neville-Neil device_printf(dev, "using MSI interrupts\n");
573b6d90eb7SKip Macy }
574b6d90eb7SKip Macy }
575d722cab4SKip Macy if (sc->msi_count == 0) {
576693d746cSKip Macy device_printf(dev, "using line interrupts\n");
577f0a542f8SKip Macy sc->cxgb_intr = t3b_intr;
578b6d90eb7SKip Macy }
579b6d90eb7SKip Macy
580b6d90eb7SKip Macy /* Create a private taskqueue thread for handling driver events */
581b6d90eb7SKip Macy sc->tq = taskqueue_create("cxgb_taskq", M_NOWAIT,
582b6d90eb7SKip Macy taskqueue_thread_enqueue, &sc->tq);
583b6d90eb7SKip Macy if (sc->tq == NULL) {
584b6d90eb7SKip Macy device_printf(dev, "failed to allocate controller task queue\n");
585b6d90eb7SKip Macy goto out;
586b6d90eb7SKip Macy }
587b6d90eb7SKip Macy
588b6d90eb7SKip Macy taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq",
589b6d90eb7SKip Macy device_get_nameunit(dev));
590bb38cd2fSKip Macy TASK_INIT(&sc->tick_task, 0, cxgb_tick_handler, sc);
591b6d90eb7SKip Macy
592b6d90eb7SKip Macy
593b6d90eb7SKip Macy /* Create a periodic callout for checking adapter status */
594fd90e2edSJung-uk Kim callout_init(&sc->cxgb_tick_ch, 1);
595b6d90eb7SKip Macy
596f2d8ff04SGeorge V. Neville-Neil if (t3_check_fw_version(sc) < 0 || force_fw_update) {
597b6d90eb7SKip Macy /*
598b6d90eb7SKip Macy * Warn user that a firmware update will be attempted in init.
599b6d90eb7SKip Macy */
600d722cab4SKip Macy device_printf(dev, "firmware needs to be updated to version %d.%d.%d\n",
601d722cab4SKip Macy FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
602b6d90eb7SKip Macy sc->flags &= ~FW_UPTODATE;
603b6d90eb7SKip Macy } else {
604b6d90eb7SKip Macy sc->flags |= FW_UPTODATE;
605b6d90eb7SKip Macy }
606b6d90eb7SKip Macy
607f2d8ff04SGeorge V. Neville-Neil if (t3_check_tpsram_version(sc) < 0) {
608ac3a6d9cSKip Macy /*
609ac3a6d9cSKip Macy * Warn user that a firmware update will be attempted in init.
610ac3a6d9cSKip Macy */
611ac3a6d9cSKip Macy device_printf(dev, "SRAM needs to be updated to version %c-%d.%d.%d\n",
612ac3a6d9cSKip Macy t3rev2char(sc), TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
613ac3a6d9cSKip Macy sc->flags &= ~TPS_UPTODATE;
614ac3a6d9cSKip Macy } else {
615ac3a6d9cSKip Macy sc->flags |= TPS_UPTODATE;
616ac3a6d9cSKip Macy }
617ac3a6d9cSKip Macy
618b6d90eb7SKip Macy /*
619b6d90eb7SKip Macy * Create a child device for each MAC. The ethernet attachment
620b6d90eb7SKip Macy * will be done in these children.
621b6d90eb7SKip Macy */
622693d746cSKip Macy for (i = 0; i < (sc)->params.nports; i++) {
6237ac2e6c3SKip Macy struct port_info *pi;
6247ac2e6c3SKip Macy
625b6d90eb7SKip Macy if ((child = device_add_child(dev, "cxgb", -1)) == NULL) {
626b6d90eb7SKip Macy device_printf(dev, "failed to add child port\n");
627b6d90eb7SKip Macy error = EINVAL;
628b6d90eb7SKip Macy goto out;
629b6d90eb7SKip Macy }
6307ac2e6c3SKip Macy pi = &sc->port[i];
6317ac2e6c3SKip Macy pi->adapter = sc;
6327ac2e6c3SKip Macy pi->nqsets = port_qsets;
6337ac2e6c3SKip Macy pi->first_qset = i*port_qsets;
6347ac2e6c3SKip Macy pi->port_id = i;
6357ac2e6c3SKip Macy pi->tx_chan = i >= ai->nports0;
6367ac2e6c3SKip Macy pi->txpkt_intf = pi->tx_chan ? 2 * (i - ai->nports0) + 1 : 2 * i;
6377ac2e6c3SKip Macy sc->rxpkt_map[pi->txpkt_intf] = i;
6388090c9f5SKip Macy sc->port[i].tx_chan = i >= ai->nports0;
639ac3a6d9cSKip Macy sc->portdev[i] = child;
6407ac2e6c3SKip Macy device_set_softc(child, pi);
641b6d90eb7SKip Macy }
64218250ec6SJohn Baldwin bus_attach_children(dev);
643b6d90eb7SKip Macy
644b6d90eb7SKip Macy /* initialize sge private state */
645ef72318fSKip Macy t3_sge_init_adapter(sc);
646b6d90eb7SKip Macy
647b6d90eb7SKip Macy t3_led_ready(sc);
648b6d90eb7SKip Macy
649b6d90eb7SKip Macy error = t3_get_fw_version(sc, &vers);
650b6d90eb7SKip Macy if (error)
651b6d90eb7SKip Macy goto out;
652b6d90eb7SKip Macy
653d722cab4SKip Macy snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d.%d",
654d722cab4SKip Macy G_FW_VERSION_MAJOR(vers), G_FW_VERSION_MINOR(vers),
655d722cab4SKip Macy G_FW_VERSION_MICRO(vers));
656b6d90eb7SKip Macy
657796bcf18SMark Johnston device_set_descf(dev, "%s %sNIC\t E/C: %s S/N: %s",
6587ead19d4SNavdeep Parhar ai->desc, is_offload(sc) ? "R" : "",
6595197f3abSGeorge V. Neville-Neil sc->params.vpd.ec, sc->params.vpd.sn);
6605197f3abSGeorge V. Neville-Neil
6610bbdea77SGeorge V. Neville-Neil snprintf(&sc->port_types[0], sizeof(sc->port_types), "%x%x%x%x",
6620bbdea77SGeorge V. Neville-Neil sc->params.vpd.port_type[0], sc->params.vpd.port_type[1],
6630bbdea77SGeorge V. Neville-Neil sc->params.vpd.port_type[2], sc->params.vpd.port_type[3]);
6640bbdea77SGeorge V. Neville-Neil
6658e10660fSKip Macy device_printf(sc->dev, "Firmware Version %s\n", &sc->fw_version[0]);
666bd1a9fbaSNavdeep Parhar callout_reset(&sc->cxgb_tick_ch, hz, cxgb_tick, sc);
6678090c9f5SKip Macy t3_add_attach_sysctls(sc);
66809fe6320SNavdeep Parhar
66909fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
67009fe6320SNavdeep Parhar for (i = 0; i < NUM_CPL_HANDLERS; i++)
67109fe6320SNavdeep Parhar sc->cpl_handler[i] = cpl_not_handled;
67209fe6320SNavdeep Parhar #endif
673ec9a9cf1SJohn Baldwin
674ec9a9cf1SJohn Baldwin t3_intr_clear(sc);
675ec9a9cf1SJohn Baldwin error = cxgb_setup_interrupts(sc);
676b6d90eb7SKip Macy out:
677b6d90eb7SKip Macy if (error)
678b6d90eb7SKip Macy cxgb_free(sc);
679b6d90eb7SKip Macy
680b6d90eb7SKip Macy return (error);
681b6d90eb7SKip Macy }
682b6d90eb7SKip Macy
6833cf138bbSGeorge V. Neville-Neil /*
684c2009a4cSGeorge V. Neville-Neil * The cxgb_controller_detach routine is called with the device is
6853cf138bbSGeorge V. Neville-Neil * unloaded from the system.
6863cf138bbSGeorge V. Neville-Neil */
6873cf138bbSGeorge V. Neville-Neil
688b6d90eb7SKip Macy static int
cxgb_controller_detach(device_t dev)689b6d90eb7SKip Macy cxgb_controller_detach(device_t dev)
690b6d90eb7SKip Macy {
691b6d90eb7SKip Macy struct adapter *sc;
692b6d90eb7SKip Macy
693b6d90eb7SKip Macy sc = device_get_softc(dev);
694b6d90eb7SKip Macy
695b6d90eb7SKip Macy cxgb_free(sc);
696b6d90eb7SKip Macy
697b6d90eb7SKip Macy return (0);
698b6d90eb7SKip Macy }
699b6d90eb7SKip Macy
7003cf138bbSGeorge V. Neville-Neil /*
7013cf138bbSGeorge V. Neville-Neil * The cxgb_free() is called by the cxgb_controller_detach() routine
7023cf138bbSGeorge V. Neville-Neil * to tear down the structures that were built up in
7033cf138bbSGeorge V. Neville-Neil * cxgb_controller_attach(), and should be the final piece of work
704c2009a4cSGeorge V. Neville-Neil * done when fully unloading the driver.
7053cf138bbSGeorge V. Neville-Neil *
7063cf138bbSGeorge V. Neville-Neil *
7073cf138bbSGeorge V. Neville-Neil * 1. Shutting down the threads started by the cxgb_controller_attach()
7083cf138bbSGeorge V. Neville-Neil * routine.
7093cf138bbSGeorge V. Neville-Neil * 2. Stopping the lower level device and all callouts (cxgb_down_locked()).
7103cf138bbSGeorge V. Neville-Neil * 3. Detaching all of the port devices created during the
7113cf138bbSGeorge V. Neville-Neil * cxgb_controller_attach() routine.
7123cf138bbSGeorge V. Neville-Neil * 4. Removing the device children created via cxgb_controller_attach().
713e3503bc9SGeorge V. Neville-Neil * 5. Releasing PCI resources associated with the device.
7143cf138bbSGeorge V. Neville-Neil * 6. Turning off the offload support, iff it was turned on.
7153cf138bbSGeorge V. Neville-Neil * 7. Destroying the mutexes created in cxgb_controller_attach().
7163cf138bbSGeorge V. Neville-Neil *
7173cf138bbSGeorge V. Neville-Neil */
718b6d90eb7SKip Macy static void
cxgb_free(struct adapter * sc)719b6d90eb7SKip Macy cxgb_free(struct adapter *sc)
720b6d90eb7SKip Macy {
7217eeb16ceSNavdeep Parhar int i, nqsets = 0;
722b6d90eb7SKip Macy
7238e10660fSKip Macy ADAPTER_LOCK(sc);
7248e10660fSKip Macy sc->flags |= CXGB_SHUTDOWN;
7258e10660fSKip Macy ADAPTER_UNLOCK(sc);
7268e10660fSKip Macy
7273cf138bbSGeorge V. Neville-Neil /*
7283f345a5dSKip Macy * Make sure all child devices are gone.
7293cf138bbSGeorge V. Neville-Neil */
730e9d38570SJohn Baldwin bus_detach_children(sc->dev);
7313cf138bbSGeorge V. Neville-Neil for (i = 0; i < (sc)->params.nports; i++) {
732c2009a4cSGeorge V. Neville-Neil if (sc->portdev[i] &&
733c2009a4cSGeorge V. Neville-Neil device_delete_child(sc->dev, sc->portdev[i]) != 0)
7343cf138bbSGeorge V. Neville-Neil device_printf(sc->dev, "failed to delete child port\n");
7357eeb16ceSNavdeep Parhar nqsets += sc->port[i].nqsets;
7363cf138bbSGeorge V. Neville-Neil }
737d722cab4SKip Macy
7383f345a5dSKip Macy /*
7393f345a5dSKip Macy * At this point, it is as if cxgb_port_detach has run on all ports, and
7403f345a5dSKip Macy * cxgb_down has run on the adapter. All interrupts have been silenced,
7413f345a5dSKip Macy * all open devices have been closed.
7423f345a5dSKip Macy */
7433f345a5dSKip Macy KASSERT(sc->open_device_map == 0, ("%s: device(s) still open (%x)",
7443f345a5dSKip Macy __func__, sc->open_device_map));
7453f345a5dSKip Macy for (i = 0; i < sc->params.nports; i++) {
7463f345a5dSKip Macy KASSERT(sc->port[i].ifp == NULL, ("%s: port %i undead!",
7473f345a5dSKip Macy __func__, i));
7483f345a5dSKip Macy }
749e3503bc9SGeorge V. Neville-Neil
7503f345a5dSKip Macy /*
7513f345a5dSKip Macy * Finish off the adapter's callouts.
7523f345a5dSKip Macy */
7533f345a5dSKip Macy callout_drain(&sc->cxgb_tick_ch);
7543f345a5dSKip Macy callout_drain(&sc->sge_timer_ch);
7553f345a5dSKip Macy
7563f345a5dSKip Macy /*
7573f345a5dSKip Macy * Release resources grabbed under FULL_INIT_DONE by cxgb_up. The
7583f345a5dSKip Macy * sysctls are cleaned up by the kernel linker.
7593f345a5dSKip Macy */
7603f345a5dSKip Macy if (sc->flags & FULL_INIT_DONE) {
7617eeb16ceSNavdeep Parhar t3_free_sge_resources(sc, nqsets);
7623f345a5dSKip Macy sc->flags &= ~FULL_INIT_DONE;
7633f345a5dSKip Macy }
7643f345a5dSKip Macy
7653f345a5dSKip Macy /*
7663f345a5dSKip Macy * Release all interrupt resources.
7673f345a5dSKip Macy */
7683f345a5dSKip Macy cxgb_teardown_interrupts(sc);
769d722cab4SKip Macy if (sc->flags & (USING_MSI | USING_MSIX)) {
770d722cab4SKip Macy device_printf(sc->dev, "releasing msi message(s)\n");
771d722cab4SKip Macy pci_release_msi(sc->dev);
772d722cab4SKip Macy } else {
773d722cab4SKip Macy device_printf(sc->dev, "no msi message to release\n");
774d722cab4SKip Macy }
775e3503bc9SGeorge V. Neville-Neil
776d722cab4SKip Macy if (sc->msix_regs_res != NULL) {
777d722cab4SKip Macy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid,
778d722cab4SKip Macy sc->msix_regs_res);
779d722cab4SKip Macy }
780d722cab4SKip Macy
7813f345a5dSKip Macy /*
7823f345a5dSKip Macy * Free the adapter's taskqueue.
7833f345a5dSKip Macy */
7848e10660fSKip Macy if (sc->tq != NULL) {
7857ac2e6c3SKip Macy taskqueue_free(sc->tq);
7868e10660fSKip Macy sc->tq = NULL;
7878e10660fSKip Macy }
7888e10660fSKip Macy
789ac3a6d9cSKip Macy free(sc->filters, M_DEVBUF);
790b6d90eb7SKip Macy t3_sge_free(sc);
791b6d90eb7SKip Macy
7928e10660fSKip Macy if (sc->udbs_res != NULL)
7938e10660fSKip Macy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->udbs_rid,
7948e10660fSKip Macy sc->udbs_res);
7958e10660fSKip Macy
796b6d90eb7SKip Macy if (sc->regs_res != NULL)
797b6d90eb7SKip Macy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->regs_rid,
798b6d90eb7SKip Macy sc->regs_res);
799b6d90eb7SKip Macy
800bb38cd2fSKip Macy MTX_DESTROY(&sc->mdio_lock);
801bb38cd2fSKip Macy MTX_DESTROY(&sc->sge.reg_lock);
802bb38cd2fSKip Macy MTX_DESTROY(&sc->elmer_lock);
80309fe6320SNavdeep Parhar mtx_lock(&t3_list_lock);
80409fe6320SNavdeep Parhar SLIST_REMOVE(&t3_list, sc, adapter, link);
80509fe6320SNavdeep Parhar mtx_unlock(&t3_list_lock);
806bb38cd2fSKip Macy ADAPTER_LOCK_DEINIT(sc);
807b6d90eb7SKip Macy }
808b6d90eb7SKip Macy
809b6d90eb7SKip Macy /**
810b6d90eb7SKip Macy * setup_sge_qsets - configure SGE Tx/Rx/response queues
811b6d90eb7SKip Macy * @sc: the controller softc
812b6d90eb7SKip Macy *
813b6d90eb7SKip Macy * Determines how many sets of SGE queues to use and initializes them.
814b6d90eb7SKip Macy * We support multiple queue sets per port if we have MSI-X, otherwise
815b6d90eb7SKip Macy * just one queue set per port.
816b6d90eb7SKip Macy */
817b6d90eb7SKip Macy static int
setup_sge_qsets(adapter_t * sc)818b6d90eb7SKip Macy setup_sge_qsets(adapter_t *sc)
819b6d90eb7SKip Macy {
8205c5df3daSKip Macy int i, j, err, irq_idx = 0, qset_idx = 0;
821d722cab4SKip Macy u_int ntxq = SGE_TXQ_PER_SET;
822b6d90eb7SKip Macy
823b6d90eb7SKip Macy if ((err = t3_sge_alloc(sc)) != 0) {
824693d746cSKip Macy device_printf(sc->dev, "t3_sge_alloc returned %d\n", err);
825b6d90eb7SKip Macy return (err);
826b6d90eb7SKip Macy }
827b6d90eb7SKip Macy
828b6d90eb7SKip Macy if (sc->params.rev > 0 && !(sc->flags & USING_MSI))
829b6d90eb7SKip Macy irq_idx = -1;
830b6d90eb7SKip Macy
8315c5df3daSKip Macy for (i = 0; i < (sc)->params.nports; i++) {
832b6d90eb7SKip Macy struct port_info *pi = &sc->port[i];
833b6d90eb7SKip Macy
8347ac2e6c3SKip Macy for (j = 0; j < pi->nqsets; j++, qset_idx++) {
835693d746cSKip Macy err = t3_sge_alloc_qset(sc, qset_idx, (sc)->params.nports,
836b6d90eb7SKip Macy (sc->flags & USING_MSIX) ? qset_idx + 1 : irq_idx,
837b6d90eb7SKip Macy &sc->params.sge.qset[qset_idx], ntxq, pi);
838b6d90eb7SKip Macy if (err) {
8397eeb16ceSNavdeep Parhar t3_free_sge_resources(sc, qset_idx);
8407eeb16ceSNavdeep Parhar device_printf(sc->dev,
8417eeb16ceSNavdeep Parhar "t3_sge_alloc_qset failed with %d\n", err);
842b6d90eb7SKip Macy return (err);
843b6d90eb7SKip Macy }
844b6d90eb7SKip Macy }
845b6d90eb7SKip Macy }
846b6d90eb7SKip Macy
8473948ad29SConrad Meyer sc->nqsets = qset_idx;
8483948ad29SConrad Meyer
849b6d90eb7SKip Macy return (0);
850b6d90eb7SKip Macy }
851b6d90eb7SKip Macy
852ef72318fSKip Macy static void
cxgb_teardown_interrupts(adapter_t * sc)853e3503bc9SGeorge V. Neville-Neil cxgb_teardown_interrupts(adapter_t *sc)
854ef72318fSKip Macy {
855e3503bc9SGeorge V. Neville-Neil int i;
856ef72318fSKip Macy
857e3503bc9SGeorge V. Neville-Neil for (i = 0; i < SGE_QSETS; i++) {
858e3503bc9SGeorge V. Neville-Neil if (sc->msix_intr_tag[i] == NULL) {
859ef72318fSKip Macy
860e3503bc9SGeorge V. Neville-Neil /* Should have been setup fully or not at all */
861e3503bc9SGeorge V. Neville-Neil KASSERT(sc->msix_irq_res[i] == NULL &&
862e3503bc9SGeorge V. Neville-Neil sc->msix_irq_rid[i] == 0,
863e3503bc9SGeorge V. Neville-Neil ("%s: half-done interrupt (%d).", __func__, i));
864e3503bc9SGeorge V. Neville-Neil
865e3503bc9SGeorge V. Neville-Neil continue;
866e3503bc9SGeorge V. Neville-Neil }
867e3503bc9SGeorge V. Neville-Neil
868ef72318fSKip Macy bus_teardown_intr(sc->dev, sc->msix_irq_res[i],
869ef72318fSKip Macy sc->msix_intr_tag[i]);
870e3503bc9SGeorge V. Neville-Neil bus_release_resource(sc->dev, SYS_RES_IRQ, sc->msix_irq_rid[i],
871e3503bc9SGeorge V. Neville-Neil sc->msix_irq_res[i]);
872e3503bc9SGeorge V. Neville-Neil
873e3503bc9SGeorge V. Neville-Neil sc->msix_irq_res[i] = sc->msix_intr_tag[i] = NULL;
874e3503bc9SGeorge V. Neville-Neil sc->msix_irq_rid[i] = 0;
875ef72318fSKip Macy }
876e3503bc9SGeorge V. Neville-Neil
877e3503bc9SGeorge V. Neville-Neil if (sc->intr_tag) {
878e3503bc9SGeorge V. Neville-Neil KASSERT(sc->irq_res != NULL,
879e3503bc9SGeorge V. Neville-Neil ("%s: half-done interrupt.", __func__));
880e3503bc9SGeorge V. Neville-Neil
881e3503bc9SGeorge V. Neville-Neil bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag);
882e3503bc9SGeorge V. Neville-Neil bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
883e3503bc9SGeorge V. Neville-Neil sc->irq_res);
884e3503bc9SGeorge V. Neville-Neil
885e3503bc9SGeorge V. Neville-Neil sc->irq_res = sc->intr_tag = NULL;
886e3503bc9SGeorge V. Neville-Neil sc->irq_rid = 0;
887ef72318fSKip Macy }
888ef72318fSKip Macy }
889ef72318fSKip Macy
890b6d90eb7SKip Macy static int
cxgb_setup_interrupts(adapter_t * sc)891e3503bc9SGeorge V. Neville-Neil cxgb_setup_interrupts(adapter_t *sc)
892b6d90eb7SKip Macy {
893e3503bc9SGeorge V. Neville-Neil struct resource *res;
894e3503bc9SGeorge V. Neville-Neil void *tag;
895e3503bc9SGeorge V. Neville-Neil int i, rid, err, intr_flag = sc->flags & (USING_MSI | USING_MSIX);
896b6d90eb7SKip Macy
897e3503bc9SGeorge V. Neville-Neil sc->irq_rid = intr_flag ? 1 : 0;
898e3503bc9SGeorge V. Neville-Neil sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &sc->irq_rid,
899e3503bc9SGeorge V. Neville-Neil RF_SHAREABLE | RF_ACTIVE);
900e3503bc9SGeorge V. Neville-Neil if (sc->irq_res == NULL) {
901e3503bc9SGeorge V. Neville-Neil device_printf(sc->dev, "Cannot allocate interrupt (%x, %u)\n",
902e3503bc9SGeorge V. Neville-Neil intr_flag, sc->irq_rid);
903e3503bc9SGeorge V. Neville-Neil err = EINVAL;
904e3503bc9SGeorge V. Neville-Neil sc->irq_rid = 0;
905e3503bc9SGeorge V. Neville-Neil } else {
906e3503bc9SGeorge V. Neville-Neil err = bus_setup_intr(sc->dev, sc->irq_res,
907e83ec3e5SNavdeep Parhar INTR_MPSAFE | INTR_TYPE_NET, NULL,
908e3503bc9SGeorge V. Neville-Neil sc->cxgb_intr, sc, &sc->intr_tag);
909a02573bcSKip Macy
910e3503bc9SGeorge V. Neville-Neil if (err) {
911e3503bc9SGeorge V. Neville-Neil device_printf(sc->dev,
912e3503bc9SGeorge V. Neville-Neil "Cannot set up interrupt (%x, %u, %d)\n",
913e3503bc9SGeorge V. Neville-Neil intr_flag, sc->irq_rid, err);
914e3503bc9SGeorge V. Neville-Neil bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid,
915e3503bc9SGeorge V. Neville-Neil sc->irq_res);
916e3503bc9SGeorge V. Neville-Neil sc->irq_res = sc->intr_tag = NULL;
917e3503bc9SGeorge V. Neville-Neil sc->irq_rid = 0;
918b6d90eb7SKip Macy }
919b6d90eb7SKip Macy }
920693d746cSKip Macy
921e3503bc9SGeorge V. Neville-Neil /* That's all for INTx or MSI */
922e3503bc9SGeorge V. Neville-Neil if (!(intr_flag & USING_MSIX) || err)
923e3503bc9SGeorge V. Neville-Neil return (err);
924e3503bc9SGeorge V. Neville-Neil
925ec9a9cf1SJohn Baldwin bus_describe_intr(sc->dev, sc->irq_res, sc->intr_tag, "err");
926e3503bc9SGeorge V. Neville-Neil for (i = 0; i < sc->msi_count - 1; i++) {
927e3503bc9SGeorge V. Neville-Neil rid = i + 2;
928e3503bc9SGeorge V. Neville-Neil res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &rid,
929e3503bc9SGeorge V. Neville-Neil RF_SHAREABLE | RF_ACTIVE);
930e3503bc9SGeorge V. Neville-Neil if (res == NULL) {
931e3503bc9SGeorge V. Neville-Neil device_printf(sc->dev, "Cannot allocate interrupt "
932e3503bc9SGeorge V. Neville-Neil "for message %d\n", rid);
933e3503bc9SGeorge V. Neville-Neil err = EINVAL;
934e3503bc9SGeorge V. Neville-Neil break;
935b6d90eb7SKip Macy }
936b6d90eb7SKip Macy
937e3503bc9SGeorge V. Neville-Neil err = bus_setup_intr(sc->dev, res, INTR_MPSAFE | INTR_TYPE_NET,
938e83ec3e5SNavdeep Parhar NULL, t3_intr_msix, &sc->sge.qs[i], &tag);
939e3503bc9SGeorge V. Neville-Neil if (err) {
940e3503bc9SGeorge V. Neville-Neil device_printf(sc->dev, "Cannot set up interrupt "
941e3503bc9SGeorge V. Neville-Neil "for message %d (%d)\n", rid, err);
942e3503bc9SGeorge V. Neville-Neil bus_release_resource(sc->dev, SYS_RES_IRQ, rid, res);
943e3503bc9SGeorge V. Neville-Neil break;
944e3503bc9SGeorge V. Neville-Neil }
945e3503bc9SGeorge V. Neville-Neil
946e3503bc9SGeorge V. Neville-Neil sc->msix_irq_rid[i] = rid;
947e3503bc9SGeorge V. Neville-Neil sc->msix_irq_res[i] = res;
948e3503bc9SGeorge V. Neville-Neil sc->msix_intr_tag[i] = tag;
949ec9a9cf1SJohn Baldwin bus_describe_intr(sc->dev, res, tag, "qs%d", i);
950e3503bc9SGeorge V. Neville-Neil }
951e3503bc9SGeorge V. Neville-Neil
952e3503bc9SGeorge V. Neville-Neil if (err)
953e3503bc9SGeorge V. Neville-Neil cxgb_teardown_interrupts(sc);
954e3503bc9SGeorge V. Neville-Neil
955e3503bc9SGeorge V. Neville-Neil return (err);
956e3503bc9SGeorge V. Neville-Neil }
957e3503bc9SGeorge V. Neville-Neil
958e3503bc9SGeorge V. Neville-Neil
959b6d90eb7SKip Macy static int
cxgb_port_probe(device_t dev)960b6d90eb7SKip Macy cxgb_port_probe(device_t dev)
961b6d90eb7SKip Macy {
962b6d90eb7SKip Macy struct port_info *p;
9638e10660fSKip Macy const char *desc;
964b6d90eb7SKip Macy
965b6d90eb7SKip Macy p = device_get_softc(dev);
9668e10660fSKip Macy desc = p->phy.desc;
967796bcf18SMark Johnston device_set_descf(dev, "Port %d %s", p->port_id, desc);
968b6d90eb7SKip Macy return (0);
969b6d90eb7SKip Macy }
970b6d90eb7SKip Macy
971b6d90eb7SKip Macy
972b6d90eb7SKip Macy static int
cxgb_makedev(struct port_info * pi)973b6d90eb7SKip Macy cxgb_makedev(struct port_info *pi)
974b6d90eb7SKip Macy {
975b6d90eb7SKip Macy
976954712e8SJustin Hibbits pi->port_cdev = make_dev(&cxgb_cdevsw, if_getdunit(pi->ifp),
97706eace63SNavdeep Parhar UID_ROOT, GID_WHEEL, 0600, "%s", if_name(pi->ifp));
978b6d90eb7SKip Macy
979b6d90eb7SKip Macy if (pi->port_cdev == NULL)
980b6d90eb7SKip Macy return (ENOMEM);
981b6d90eb7SKip Macy
982b6d90eb7SKip Macy pi->port_cdev->si_drv1 = (void *)pi;
983b6d90eb7SKip Macy
984b6d90eb7SKip Macy return (0);
985b6d90eb7SKip Macy }
986b6d90eb7SKip Macy
987e83ec3e5SNavdeep Parhar #define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \
988f9c6e164SNavdeep Parhar IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \
9890a704909SNavdeep Parhar IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6)
9903e7cc3caSNavdeep Parhar #define CXGB_CAP_ENABLE CXGB_CAP
991b6d90eb7SKip Macy
992b6d90eb7SKip Macy static int
cxgb_port_attach(device_t dev)993b6d90eb7SKip Macy cxgb_port_attach(device_t dev)
994b6d90eb7SKip Macy {
995b6d90eb7SKip Macy struct port_info *p;
996954712e8SJustin Hibbits if_t ifp;
9972975f787SNavdeep Parhar int err;
9988e10660fSKip Macy struct adapter *sc;
9998e10660fSKip Macy
1000b6d90eb7SKip Macy p = device_get_softc(dev);
10018e10660fSKip Macy sc = p->adapter;
1002bb38cd2fSKip Macy snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d",
10036b68e276SKip Macy device_get_unit(device_get_parent(dev)), p->port_id);
1004bb38cd2fSKip Macy PORT_LOCK_INIT(p, p->lockbuf);
1005b6d90eb7SKip Macy
1006fd90e2edSJung-uk Kim callout_init(&p->link_check_ch, 1);
1007bd1a9fbaSNavdeep Parhar TASK_INIT(&p->link_check_task, 0, check_link_status, p);
1008bd1a9fbaSNavdeep Parhar
1009b6d90eb7SKip Macy /* Allocate an ifnet object and set it up */
1010b6d90eb7SKip Macy ifp = p->ifp = if_alloc(IFT_ETHER);
1011b6d90eb7SKip Macy if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1012954712e8SJustin Hibbits if_setinitfn(ifp, cxgb_init);
1013954712e8SJustin Hibbits if_setsoftc(ifp, p);
1014954712e8SJustin Hibbits if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
1015954712e8SJustin Hibbits if_setioctlfn(ifp, cxgb_ioctl);
1016954712e8SJustin Hibbits if_settransmitfn(ifp, cxgb_transmit);
1017954712e8SJustin Hibbits if_setqflushfn(ifp, cxgb_qflush);
1018954712e8SJustin Hibbits if_setgetcounterfn(ifp, cxgb_get_counter);
1019b6d90eb7SKip Macy
1020954712e8SJustin Hibbits if_setcapabilities(ifp, CXGB_CAP);
102109fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
102209fe6320SNavdeep Parhar if (is_offload(sc))
1023954712e8SJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_TOE4, 0);
102409fe6320SNavdeep Parhar #endif
1025954712e8SJustin Hibbits if_setcapenable(ifp, CXGB_CAP_ENABLE);
1026954712e8SJustin Hibbits if_sethwassist(ifp, CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO |
1027954712e8SJustin Hibbits CSUM_UDP_IPV6 | CSUM_TCP_IPV6);
1028954712e8SJustin Hibbits if_sethwtsomax(ifp, IP_MAXPACKET);
1029954712e8SJustin Hibbits if_sethwtsomaxsegcount(ifp, 36);
1030954712e8SJustin Hibbits if_sethwtsomaxsegsize(ifp, 65536);
1031e83ec3e5SNavdeep Parhar
1032ac3a6d9cSKip Macy /*
1033e83ec3e5SNavdeep Parhar * Disable TSO on 4-port - it isn't supported by the firmware.
1034ac3a6d9cSKip Macy */
1035e83ec3e5SNavdeep Parhar if (sc->params.nports > 2) {
1036954712e8SJustin Hibbits if_setcapabilitiesbit(ifp, 0, IFCAP_TSO | IFCAP_VLAN_HWTSO);
1037954712e8SJustin Hibbits if_setcapenablebit(ifp, 0, IFCAP_TSO | IFCAP_VLAN_HWTSO);
1038954712e8SJustin Hibbits if_sethwassistbits(ifp, 0, CSUM_TSO);
1039ac3a6d9cSKip Macy }
1040b6d90eb7SKip Macy
1041f2daf899SScottD /* Create a list of media supported by this port */
1042f2daf899SScottD ifmedia_init(&p->media, IFM_IMASK, cxgb_media_change,
1043f2daf899SScottD cxgb_media_status);
1044f2daf899SScottD cxgb_build_medialist(p);
1045f2daf899SScottD
1046b6d90eb7SKip Macy ether_ifattach(ifp, p->hw_addr);
10473cf138bbSGeorge V. Neville-Neil
10487790c8c1SConrad Meyer /* Attach driver debugnet methods. */
10497790c8c1SConrad Meyer DEBUGNET_SET(ifp, cxgb);
1050eb07d67eSMark Johnston
1051e83ec3e5SNavdeep Parhar #ifdef DEFAULT_JUMBO
1052e83ec3e5SNavdeep Parhar if (sc->params.nports <= 2)
1053954712e8SJustin Hibbits if_setmtu(ifp, ETHERMTU_JUMBO);
1054e83ec3e5SNavdeep Parhar #endif
1055b6d90eb7SKip Macy if ((err = cxgb_makedev(p)) != 0) {
1056b6d90eb7SKip Macy printf("makedev failed %d\n", err);
1057b6d90eb7SKip Macy return (err);
1058b6d90eb7SKip Macy }
10592975f787SNavdeep Parhar
1060ef72318fSKip Macy t3_sge_init_port(p);
1061f2d8ff04SGeorge V. Neville-Neil
10623cf138bbSGeorge V. Neville-Neil return (err);
1063b6d90eb7SKip Macy }
1064b6d90eb7SKip Macy
10653cf138bbSGeorge V. Neville-Neil /*
10663cf138bbSGeorge V. Neville-Neil * cxgb_port_detach() is called via the device_detach methods when
1067e9d38570SJohn Baldwin * cxgb_free() calls the bus_detach_children. It is responsible for
10683cf138bbSGeorge V. Neville-Neil * removing the device from the view of the kernel, i.e. from all
10693cf138bbSGeorge V. Neville-Neil * interfaces lists etc. This routine is only called when the driver is
10703cf138bbSGeorge V. Neville-Neil * being unloaded, not when the link goes down.
10713cf138bbSGeorge V. Neville-Neil */
1072b6d90eb7SKip Macy static int
cxgb_port_detach(device_t dev)1073b6d90eb7SKip Macy cxgb_port_detach(device_t dev)
1074b6d90eb7SKip Macy {
1075b6d90eb7SKip Macy struct port_info *p;
10763cf138bbSGeorge V. Neville-Neil struct adapter *sc;
10773f345a5dSKip Macy int i;
1078b6d90eb7SKip Macy
1079b6d90eb7SKip Macy p = device_get_softc(dev);
10803cf138bbSGeorge V. Neville-Neil sc = p->adapter;
10813cf138bbSGeorge V. Neville-Neil
1082b302b77cSNavdeep Parhar /* Tell cxgb_ioctl and if_init that the port is going away */
1083b302b77cSNavdeep Parhar ADAPTER_LOCK(sc);
1084b302b77cSNavdeep Parhar SET_DOOMED(p);
1085b302b77cSNavdeep Parhar wakeup(&sc->flags);
1086b302b77cSNavdeep Parhar while (IS_BUSY(sc))
1087b302b77cSNavdeep Parhar mtx_sleep(&sc->flags, &sc->lock, 0, "cxgbdtch", 0);
1088b302b77cSNavdeep Parhar SET_BUSY(sc);
1089b302b77cSNavdeep Parhar ADAPTER_UNLOCK(sc);
10903f345a5dSKip Macy
10913cf138bbSGeorge V. Neville-Neil if (p->port_cdev != NULL)
10923cf138bbSGeorge V. Neville-Neil destroy_dev(p->port_cdev);
10933cf138bbSGeorge V. Neville-Neil
10943f345a5dSKip Macy cxgb_uninit_synchronized(p);
10953cf138bbSGeorge V. Neville-Neil ether_ifdetach(p->ifp);
1096d722cab4SKip Macy
10973f345a5dSKip Macy for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) {
10983f345a5dSKip Macy struct sge_qset *qs = &sc->sge.qs[i];
10993f345a5dSKip Macy struct sge_txq *txq = &qs->txq[TXQ_ETH];
1100d722cab4SKip Macy
11013f345a5dSKip Macy callout_drain(&txq->txq_watchdog);
11023f345a5dSKip Macy callout_drain(&txq->txq_timer);
11033cf138bbSGeorge V. Neville-Neil }
11043cf138bbSGeorge V. Neville-Neil
11057ac2e6c3SKip Macy PORT_LOCK_DEINIT(p);
1106b6d90eb7SKip Macy if_free(p->ifp);
11073f345a5dSKip Macy p->ifp = NULL;
1108b6d90eb7SKip Macy
1109b302b77cSNavdeep Parhar ADAPTER_LOCK(sc);
1110b302b77cSNavdeep Parhar CLR_BUSY(sc);
1111b302b77cSNavdeep Parhar wakeup_one(&sc->flags);
1112b302b77cSNavdeep Parhar ADAPTER_UNLOCK(sc);
1113b6d90eb7SKip Macy return (0);
1114b6d90eb7SKip Macy }
1115b6d90eb7SKip Macy
1116b6d90eb7SKip Macy void
t3_fatal_err(struct adapter * sc)1117b6d90eb7SKip Macy t3_fatal_err(struct adapter *sc)
1118b6d90eb7SKip Macy {
1119b6d90eb7SKip Macy u_int fw_status[4];
1120b6d90eb7SKip Macy
11215c5df3daSKip Macy if (sc->flags & FULL_INIT_DONE) {
11225c5df3daSKip Macy t3_sge_stop(sc);
11235c5df3daSKip Macy t3_write_reg(sc, A_XGM_TX_CTRL, 0);
11245c5df3daSKip Macy t3_write_reg(sc, A_XGM_RX_CTRL, 0);
11255c5df3daSKip Macy t3_write_reg(sc, XGM_REG(A_XGM_TX_CTRL, 1), 0);
11265c5df3daSKip Macy t3_write_reg(sc, XGM_REG(A_XGM_RX_CTRL, 1), 0);
11275c5df3daSKip Macy t3_intr_disable(sc);
11285c5df3daSKip Macy }
1129b6d90eb7SKip Macy device_printf(sc->dev,"encountered fatal error, operation suspended\n");
1130b6d90eb7SKip Macy if (!t3_cim_ctl_blk_read(sc, 0xa0, 4, fw_status))
1131b6d90eb7SKip Macy device_printf(sc->dev, "FW_ status: 0x%x, 0x%x, 0x%x, 0x%x\n",
1132b6d90eb7SKip Macy fw_status[0], fw_status[1], fw_status[2], fw_status[3]);
1133b6d90eb7SKip Macy }
1134b6d90eb7SKip Macy
1135b6d90eb7SKip Macy int
t3_os_find_pci_capability(adapter_t * sc,int cap)1136b6d90eb7SKip Macy t3_os_find_pci_capability(adapter_t *sc, int cap)
1137b6d90eb7SKip Macy {
1138*762d3235SNavdeep Parhar int rc, reg = 0;
1139b6d90eb7SKip Macy
1140*762d3235SNavdeep Parhar rc = pci_find_cap(sc->dev, cap, ®);
1141*762d3235SNavdeep Parhar return (rc == 0 ? reg : 0);
1142b6d90eb7SKip Macy }
1143b6d90eb7SKip Macy
1144b6d90eb7SKip Macy int
t3_os_pci_save_state(struct adapter * sc)1145b6d90eb7SKip Macy t3_os_pci_save_state(struct adapter *sc)
1146b6d90eb7SKip Macy {
1147*762d3235SNavdeep Parhar pci_save_state(sc->dev);
1148b6d90eb7SKip Macy return (0);
1149b6d90eb7SKip Macy }
1150b6d90eb7SKip Macy
1151b6d90eb7SKip Macy int
t3_os_pci_restore_state(struct adapter * sc)1152b6d90eb7SKip Macy t3_os_pci_restore_state(struct adapter *sc)
1153b6d90eb7SKip Macy {
1154*762d3235SNavdeep Parhar pci_restore_state(sc->dev);
1155b6d90eb7SKip Macy return (0);
1156b6d90eb7SKip Macy }
1157b6d90eb7SKip Macy
1158b6d90eb7SKip Macy /**
1159b6d90eb7SKip Macy * t3_os_link_changed - handle link status changes
1160c01f2b83SNavdeep Parhar * @sc: the adapter associated with the link change
1161c01f2b83SNavdeep Parhar * @port_id: the port index whose link status has changed
116219905d6dSKip Macy * @link_status: the new status of the link
1163b6d90eb7SKip Macy * @speed: the new speed setting
1164b6d90eb7SKip Macy * @duplex: the new duplex setting
1165b6d90eb7SKip Macy * @fc: the new flow-control setting
1166b6d90eb7SKip Macy *
1167b6d90eb7SKip Macy * This is the OS-dependent handler for link status changes. The OS
1168b6d90eb7SKip Macy * neutral handler takes care of most of the processing for these events,
1169b6d90eb7SKip Macy * then calls this handler for any OS-specific processing.
1170b6d90eb7SKip Macy */
1171b6d90eb7SKip Macy void
t3_os_link_changed(adapter_t * adapter,int port_id,int link_status,int speed,int duplex,int fc,int mac_was_reset)1172b6d90eb7SKip Macy t3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed,
1173c01f2b83SNavdeep Parhar int duplex, int fc, int mac_was_reset)
1174b6d90eb7SKip Macy {
1175b6d90eb7SKip Macy struct port_info *pi = &adapter->port[port_id];
1176954712e8SJustin Hibbits if_t ifp = pi->ifp;
11773f345a5dSKip Macy
11783f345a5dSKip Macy /* no race with detach, so ifp should always be good */
11793f345a5dSKip Macy KASSERT(ifp, ("%s: if detached.", __func__));
1180b6d90eb7SKip Macy
1181c01f2b83SNavdeep Parhar /* Reapply mac settings if they were lost due to a reset */
1182c01f2b83SNavdeep Parhar if (mac_was_reset) {
1183c01f2b83SNavdeep Parhar PORT_LOCK(pi);
1184c01f2b83SNavdeep Parhar cxgb_update_mac_settings(pi);
1185c01f2b83SNavdeep Parhar PORT_UNLOCK(pi);
1186c01f2b83SNavdeep Parhar }
1187c01f2b83SNavdeep Parhar
1188d722cab4SKip Macy if (link_status) {
1189954712e8SJustin Hibbits if_setbaudrate(ifp, IF_Mbps(speed));
11903f345a5dSKip Macy if_link_state_change(ifp, LINK_STATE_UP);
11910bbdea77SGeorge V. Neville-Neil } else
11923f345a5dSKip Macy if_link_state_change(ifp, LINK_STATE_DOWN);
1193d722cab4SKip Macy }
1194b6d90eb7SKip Macy
11959b4de886SKip Macy /**
11969b4de886SKip Macy * t3_os_phymod_changed - handle PHY module changes
11979b4de886SKip Macy * @phy: the PHY reporting the module change
11989b4de886SKip Macy * @mod_type: new module type
11999b4de886SKip Macy *
12009b4de886SKip Macy * This is the OS-dependent handler for PHY module changes. It is
12019b4de886SKip Macy * invoked when a PHY module is removed or inserted for any OS-specific
12029b4de886SKip Macy * processing.
12039b4de886SKip Macy */
t3_os_phymod_changed(struct adapter * adap,int port_id)12049b4de886SKip Macy void t3_os_phymod_changed(struct adapter *adap, int port_id)
12059b4de886SKip Macy {
12069b4de886SKip Macy static const char *mod_str[] = {
1207cd5c70b2SNavdeep Parhar NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX-L", "unknown"
12089b4de886SKip Macy };
12099b4de886SKip Macy struct port_info *pi = &adap->port[port_id];
12102975f787SNavdeep Parhar int mod = pi->phy.modtype;
12119b4de886SKip Macy
12122975f787SNavdeep Parhar if (mod != pi->media.ifm_cur->ifm_data)
12132975f787SNavdeep Parhar cxgb_build_medialist(pi);
12142975f787SNavdeep Parhar
12152975f787SNavdeep Parhar if (mod == phy_modtype_none)
12162975f787SNavdeep Parhar if_printf(pi->ifp, "PHY module unplugged\n");
12179b4de886SKip Macy else {
12182975f787SNavdeep Parhar KASSERT(mod < ARRAY_SIZE(mod_str),
12192975f787SNavdeep Parhar ("invalid PHY module type %d", mod));
12202975f787SNavdeep Parhar if_printf(pi->ifp, "%s PHY module inserted\n", mod_str[mod]);
12219b4de886SKip Macy }
12229b4de886SKip Macy }
12239b4de886SKip Macy
1224b6d90eb7SKip Macy void
t3_os_set_hw_addr(adapter_t * adapter,int port_idx,u8 hw_addr[])1225b6d90eb7SKip Macy t3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[])
1226b6d90eb7SKip Macy {
1227b6d90eb7SKip Macy
1228b6d90eb7SKip Macy /*
1229b6d90eb7SKip Macy * The ifnet might not be allocated before this gets called,
1230b6d90eb7SKip Macy * as this is called early on in attach by t3_prep_adapter
1231b6d90eb7SKip Macy * save the address off in the port structure
1232b6d90eb7SKip Macy */
1233b6d90eb7SKip Macy if (cxgb_debug)
1234b6d90eb7SKip Macy printf("set_hw_addr on idx %d addr %6D\n", port_idx, hw_addr, ":");
1235b6d90eb7SKip Macy bcopy(hw_addr, adapter->port[port_idx].hw_addr, ETHER_ADDR_LEN);
1236b6d90eb7SKip Macy }
1237b6d90eb7SKip Macy
12383f345a5dSKip Macy /*
12393f345a5dSKip Macy * Programs the XGMAC based on the settings in the ifnet. These settings
12403f345a5dSKip Macy * include MTU, MAC address, mcast addresses, etc.
1241b6d90eb7SKip Macy */
1242b6d90eb7SKip Macy static void
cxgb_update_mac_settings(struct port_info * p)12433f345a5dSKip Macy cxgb_update_mac_settings(struct port_info *p)
1244b6d90eb7SKip Macy {
1245954712e8SJustin Hibbits if_t ifp = p->ifp;
1246b6d90eb7SKip Macy struct t3_rx_mode rm;
1247b6d90eb7SKip Macy struct cmac *mac = &p->mac;
12484af83c8cSKip Macy int mtu, hwtagging;
1249b6d90eb7SKip Macy
12503f345a5dSKip Macy PORT_LOCK_ASSERT_OWNED(p);
1251b6d90eb7SKip Macy
1252954712e8SJustin Hibbits bcopy(if_getlladdr(ifp), p->hw_addr, ETHER_ADDR_LEN);
12534af83c8cSKip Macy
1254954712e8SJustin Hibbits mtu = if_getmtu(ifp);
1255954712e8SJustin Hibbits if (if_getcapenable(ifp) & IFCAP_VLAN_MTU)
12564af83c8cSKip Macy mtu += ETHER_VLAN_ENCAP_LEN;
12574af83c8cSKip Macy
1258954712e8SJustin Hibbits hwtagging = (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) != 0;
12594af83c8cSKip Macy
12604af83c8cSKip Macy t3_mac_set_mtu(mac, mtu);
12614af83c8cSKip Macy t3_set_vlan_accel(p->adapter, 1 << p->tx_chan, hwtagging);
1262b6d90eb7SKip Macy t3_mac_set_address(mac, 0, p->hw_addr);
12633f345a5dSKip Macy t3_init_rx_mode(&rm, p);
1264b6d90eb7SKip Macy t3_mac_set_rx_mode(mac, &rm);
1265b6d90eb7SKip Macy }
1266b6d90eb7SKip Macy
12678e10660fSKip Macy
12688e10660fSKip Macy static int
await_mgmt_replies(struct adapter * adap,unsigned long init_cnt,unsigned long n)12698e10660fSKip Macy await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
12708e10660fSKip Macy unsigned long n)
12718e10660fSKip Macy {
12728e10660fSKip Macy int attempts = 5;
12738e10660fSKip Macy
12748e10660fSKip Macy while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
12758e10660fSKip Macy if (!--attempts)
12768e10660fSKip Macy return (ETIMEDOUT);
12778e10660fSKip Macy t3_os_sleep(10);
12788e10660fSKip Macy }
12798e10660fSKip Macy return 0;
12808e10660fSKip Macy }
12818e10660fSKip Macy
12828e10660fSKip Macy static int
init_tp_parity(struct adapter * adap)12838e10660fSKip Macy init_tp_parity(struct adapter *adap)
12848e10660fSKip Macy {
12858e10660fSKip Macy int i;
12868e10660fSKip Macy struct mbuf *m;
12878e10660fSKip Macy struct cpl_set_tcb_field *greq;
12888e10660fSKip Macy unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts;
12898e10660fSKip Macy
12908e10660fSKip Macy t3_tp_set_offload_mode(adap, 1);
12918e10660fSKip Macy
12928e10660fSKip Macy for (i = 0; i < 16; i++) {
12938e10660fSKip Macy struct cpl_smt_write_req *req;
12948e10660fSKip Macy
12958e10660fSKip Macy m = m_gethdr(M_WAITOK, MT_DATA);
12968e10660fSKip Macy req = mtod(m, struct cpl_smt_write_req *);
12978e10660fSKip Macy m->m_len = m->m_pkthdr.len = sizeof(*req);
12988e10660fSKip Macy memset(req, 0, sizeof(*req));
12993f345a5dSKip Macy req->wr.wrh_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
13008e10660fSKip Macy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
13018e10660fSKip Macy req->iff = i;
13028e10660fSKip Macy t3_mgmt_tx(adap, m);
13038e10660fSKip Macy }
13048e10660fSKip Macy
13058e10660fSKip Macy for (i = 0; i < 2048; i++) {
13068e10660fSKip Macy struct cpl_l2t_write_req *req;
13078e10660fSKip Macy
13088e10660fSKip Macy m = m_gethdr(M_WAITOK, MT_DATA);
13098e10660fSKip Macy req = mtod(m, struct cpl_l2t_write_req *);
13108e10660fSKip Macy m->m_len = m->m_pkthdr.len = sizeof(*req);
13118e10660fSKip Macy memset(req, 0, sizeof(*req));
13123f345a5dSKip Macy req->wr.wrh_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
13138e10660fSKip Macy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
13148e10660fSKip Macy req->params = htonl(V_L2T_W_IDX(i));
13158e10660fSKip Macy t3_mgmt_tx(adap, m);
13168e10660fSKip Macy }
13178e10660fSKip Macy
13188e10660fSKip Macy for (i = 0; i < 2048; i++) {
13198e10660fSKip Macy struct cpl_rte_write_req *req;
13208e10660fSKip Macy
13218e10660fSKip Macy m = m_gethdr(M_WAITOK, MT_DATA);
13228e10660fSKip Macy req = mtod(m, struct cpl_rte_write_req *);
13238e10660fSKip Macy m->m_len = m->m_pkthdr.len = sizeof(*req);
13248e10660fSKip Macy memset(req, 0, sizeof(*req));
13253f345a5dSKip Macy req->wr.wrh_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
13268e10660fSKip Macy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
13278e10660fSKip Macy req->l2t_idx = htonl(V_L2T_W_IDX(i));
13288e10660fSKip Macy t3_mgmt_tx(adap, m);
13298e10660fSKip Macy }
13308e10660fSKip Macy
13318e10660fSKip Macy m = m_gethdr(M_WAITOK, MT_DATA);
13328e10660fSKip Macy greq = mtod(m, struct cpl_set_tcb_field *);
13338e10660fSKip Macy m->m_len = m->m_pkthdr.len = sizeof(*greq);
13348e10660fSKip Macy memset(greq, 0, sizeof(*greq));
13353f345a5dSKip Macy greq->wr.wrh_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
13368e10660fSKip Macy OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0));
13378e10660fSKip Macy greq->mask = htobe64(1);
13388e10660fSKip Macy t3_mgmt_tx(adap, m);
13398e10660fSKip Macy
13408e10660fSKip Macy i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
13418e10660fSKip Macy t3_tp_set_offload_mode(adap, 0);
13428e10660fSKip Macy return (i);
13438e10660fSKip Macy }
13448e10660fSKip Macy
1345b6d90eb7SKip Macy /**
1346b6d90eb7SKip Macy * setup_rss - configure Receive Side Steering (per-queue connection demux)
1347b6d90eb7SKip Macy * @adap: the adapter
1348b6d90eb7SKip Macy *
1349b6d90eb7SKip Macy * Sets up RSS to distribute packets to multiple receive queues. We
1350b6d90eb7SKip Macy * configure the RSS CPU lookup table to distribute to the number of HW
1351b6d90eb7SKip Macy * receive queues, and the response queue lookup table to narrow that
1352b6d90eb7SKip Macy * down to the response queues actually configured for each port.
1353b6d90eb7SKip Macy * We always configure the RSS mapping for two ports since the mapping
1354b6d90eb7SKip Macy * table has plenty of entries.
1355b6d90eb7SKip Macy */
1356b6d90eb7SKip Macy static void
setup_rss(adapter_t * adap)1357b6d90eb7SKip Macy setup_rss(adapter_t *adap)
1358b6d90eb7SKip Macy {
1359b6d90eb7SKip Macy int i;
1360ac3a6d9cSKip Macy u_int nq[2];
1361b6d90eb7SKip Macy uint8_t cpus[SGE_QSETS + 1];
1362b6d90eb7SKip Macy uint16_t rspq_map[RSS_TABLE_SIZE];
13635c5df3daSKip Macy
1364b6d90eb7SKip Macy for (i = 0; i < SGE_QSETS; ++i)
1365b6d90eb7SKip Macy cpus[i] = i;
1366b6d90eb7SKip Macy cpus[SGE_QSETS] = 0xff;
1367b6d90eb7SKip Macy
13687ac2e6c3SKip Macy nq[0] = nq[1] = 0;
13697ac2e6c3SKip Macy for_each_port(adap, i) {
13707ac2e6c3SKip Macy const struct port_info *pi = adap2pinfo(adap, i);
13717ac2e6c3SKip Macy
13727ac2e6c3SKip Macy nq[pi->tx_chan] += pi->nqsets;
13737ac2e6c3SKip Macy }
1374b6d90eb7SKip Macy for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
13758e10660fSKip Macy rspq_map[i] = nq[0] ? i % nq[0] : 0;
13768e10660fSKip Macy rspq_map[i + RSS_TABLE_SIZE / 2] = nq[1] ? i % nq[1] + nq[0] : 0;
1377b6d90eb7SKip Macy }
13786b2eaa83SJohn Baldwin
1379ac3a6d9cSKip Macy /* Calculate the reverse RSS map table */
13806b2eaa83SJohn Baldwin for (i = 0; i < SGE_QSETS; ++i)
13816b2eaa83SJohn Baldwin adap->rrss_map[i] = 0xff;
1382ac3a6d9cSKip Macy for (i = 0; i < RSS_TABLE_SIZE; ++i)
1383ac3a6d9cSKip Macy if (adap->rrss_map[rspq_map[i]] == 0xff)
1384ac3a6d9cSKip Macy adap->rrss_map[rspq_map[i]] = i;
1385b6d90eb7SKip Macy
1386b6d90eb7SKip Macy t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
1387ac3a6d9cSKip Macy F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | F_OFDMAPEN |
13888e10660fSKip Macy F_RRCPLMAPEN | V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ,
13898e10660fSKip Macy cpus, rspq_map);
1390ac3a6d9cSKip Macy
1391b6d90eb7SKip Macy }
1392b6d90eb7SKip Macy static void
send_pktsched_cmd(struct adapter * adap,int sched,int qidx,int lo,int hi,int port)1393b6d90eb7SKip Macy send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
1394b6d90eb7SKip Macy int hi, int port)
1395b6d90eb7SKip Macy {
1396b6d90eb7SKip Macy struct mbuf *m;
1397b6d90eb7SKip Macy struct mngt_pktsched_wr *req;
1398b6d90eb7SKip Macy
1399c6499eccSGleb Smirnoff m = m_gethdr(M_NOWAIT, MT_DATA);
140020fe52b8SKip Macy if (m) {
1401d722cab4SKip Macy req = mtod(m, struct mngt_pktsched_wr *);
14023f345a5dSKip Macy req->wr.wrh_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
1403b6d90eb7SKip Macy req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
1404b6d90eb7SKip Macy req->sched = sched;
1405b6d90eb7SKip Macy req->idx = qidx;
1406b6d90eb7SKip Macy req->min = lo;
1407b6d90eb7SKip Macy req->max = hi;
1408b6d90eb7SKip Macy req->binding = port;
1409b6d90eb7SKip Macy m->m_len = m->m_pkthdr.len = sizeof(*req);
1410b6d90eb7SKip Macy t3_mgmt_tx(adap, m);
1411b6d90eb7SKip Macy }
141220fe52b8SKip Macy }
1413b6d90eb7SKip Macy
1414b6d90eb7SKip Macy static void
bind_qsets(adapter_t * sc)1415b6d90eb7SKip Macy bind_qsets(adapter_t *sc)
1416b6d90eb7SKip Macy {
1417b6d90eb7SKip Macy int i, j;
1418b6d90eb7SKip Macy
1419b6d90eb7SKip Macy for (i = 0; i < (sc)->params.nports; ++i) {
1420b6d90eb7SKip Macy const struct port_info *pi = adap2pinfo(sc, i);
1421b6d90eb7SKip Macy
14225c5df3daSKip Macy for (j = 0; j < pi->nqsets; ++j) {
1423b6d90eb7SKip Macy send_pktsched_cmd(sc, 1, pi->first_qset + j, -1,
14245c5df3daSKip Macy -1, pi->tx_chan);
14255c5df3daSKip Macy
14265c5df3daSKip Macy }
1427b6d90eb7SKip Macy }
1428b6d90eb7SKip Macy }
1429b6d90eb7SKip Macy
1430ac3a6d9cSKip Macy static void
update_tpeeprom(struct adapter * adap)1431ac3a6d9cSKip Macy update_tpeeprom(struct adapter *adap)
1432ac3a6d9cSKip Macy {
1433ac3a6d9cSKip Macy const struct firmware *tpeeprom;
14342de1fa86SKip Macy
1435ac3a6d9cSKip Macy uint32_t version;
1436ac3a6d9cSKip Macy unsigned int major, minor;
1437ac3a6d9cSKip Macy int ret, len;
1438f2d8ff04SGeorge V. Neville-Neil char rev, name[32];
1439ac3a6d9cSKip Macy
1440ac3a6d9cSKip Macy t3_seeprom_read(adap, TP_SRAM_OFFSET, &version);
1441ac3a6d9cSKip Macy
1442ac3a6d9cSKip Macy major = G_TP_VERSION_MAJOR(version);
1443ac3a6d9cSKip Macy minor = G_TP_VERSION_MINOR(version);
1444ac3a6d9cSKip Macy if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR)
1445ac3a6d9cSKip Macy return;
1446ac3a6d9cSKip Macy
1447ac3a6d9cSKip Macy rev = t3rev2char(adap);
1448f2d8ff04SGeorge V. Neville-Neil snprintf(name, sizeof(name), TPEEPROM_NAME, rev);
1449ac3a6d9cSKip Macy
1450f2d8ff04SGeorge V. Neville-Neil tpeeprom = firmware_get(name);
1451ac3a6d9cSKip Macy if (tpeeprom == NULL) {
14520c1ff9c6SGeorge V. Neville-Neil device_printf(adap->dev,
14530c1ff9c6SGeorge V. Neville-Neil "could not load TP EEPROM: unable to load %s\n",
14540c1ff9c6SGeorge V. Neville-Neil name);
1455ac3a6d9cSKip Macy return;
1456ac3a6d9cSKip Macy }
1457ac3a6d9cSKip Macy
1458ac3a6d9cSKip Macy len = tpeeprom->datasize - 4;
1459ac3a6d9cSKip Macy
1460ac3a6d9cSKip Macy ret = t3_check_tpsram(adap, tpeeprom->data, tpeeprom->datasize);
1461ac3a6d9cSKip Macy if (ret)
1462ac3a6d9cSKip Macy goto release_tpeeprom;
1463ac3a6d9cSKip Macy
1464ac3a6d9cSKip Macy if (len != TP_SRAM_LEN) {
14650c1ff9c6SGeorge V. Neville-Neil device_printf(adap->dev,
14660c1ff9c6SGeorge V. Neville-Neil "%s length is wrong len=%d expected=%d\n", name,
14670c1ff9c6SGeorge V. Neville-Neil len, TP_SRAM_LEN);
1468ac3a6d9cSKip Macy return;
1469ac3a6d9cSKip Macy }
1470ac3a6d9cSKip Macy
1471ac3a6d9cSKip Macy ret = set_eeprom(&adap->port[0], tpeeprom->data, tpeeprom->datasize,
1472ac3a6d9cSKip Macy TP_SRAM_OFFSET);
1473ac3a6d9cSKip Macy
1474ac3a6d9cSKip Macy if (!ret) {
1475ac3a6d9cSKip Macy device_printf(adap->dev,
1476ac3a6d9cSKip Macy "Protocol SRAM image updated in EEPROM to %d.%d.%d\n",
1477ac3a6d9cSKip Macy TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
1478ac3a6d9cSKip Macy } else
14790c1ff9c6SGeorge V. Neville-Neil device_printf(adap->dev,
14800c1ff9c6SGeorge V. Neville-Neil "Protocol SRAM image update in EEPROM failed\n");
1481ac3a6d9cSKip Macy
1482ac3a6d9cSKip Macy release_tpeeprom:
1483ac3a6d9cSKip Macy firmware_put(tpeeprom, FIRMWARE_UNLOAD);
1484ac3a6d9cSKip Macy
1485ac3a6d9cSKip Macy return;
1486ac3a6d9cSKip Macy }
1487ac3a6d9cSKip Macy
1488ac3a6d9cSKip Macy static int
update_tpsram(struct adapter * adap)1489ac3a6d9cSKip Macy update_tpsram(struct adapter *adap)
1490ac3a6d9cSKip Macy {
1491ac3a6d9cSKip Macy const struct firmware *tpsram;
1492ac3a6d9cSKip Macy int ret;
1493f2d8ff04SGeorge V. Neville-Neil char rev, name[32];
1494ac3a6d9cSKip Macy
1495ac3a6d9cSKip Macy rev = t3rev2char(adap);
1496f2d8ff04SGeorge V. Neville-Neil snprintf(name, sizeof(name), TPSRAM_NAME, rev);
1497ac3a6d9cSKip Macy
1498ac3a6d9cSKip Macy update_tpeeprom(adap);
1499ac3a6d9cSKip Macy
1500f2d8ff04SGeorge V. Neville-Neil tpsram = firmware_get(name);
1501ac3a6d9cSKip Macy if (tpsram == NULL){
150264a37133SKip Macy device_printf(adap->dev, "could not load TP SRAM\n");
1503ac3a6d9cSKip Macy return (EINVAL);
1504ac3a6d9cSKip Macy } else
150564a37133SKip Macy device_printf(adap->dev, "updating TP SRAM\n");
1506ac3a6d9cSKip Macy
1507ac3a6d9cSKip Macy ret = t3_check_tpsram(adap, tpsram->data, tpsram->datasize);
1508ac3a6d9cSKip Macy if (ret)
1509ac3a6d9cSKip Macy goto release_tpsram;
1510ac3a6d9cSKip Macy
1511ac3a6d9cSKip Macy ret = t3_set_proto_sram(adap, tpsram->data);
1512ac3a6d9cSKip Macy if (ret)
1513ac3a6d9cSKip Macy device_printf(adap->dev, "loading protocol SRAM failed\n");
1514ac3a6d9cSKip Macy
1515ac3a6d9cSKip Macy release_tpsram:
1516ac3a6d9cSKip Macy firmware_put(tpsram, FIRMWARE_UNLOAD);
1517ac3a6d9cSKip Macy
1518ac3a6d9cSKip Macy return ret;
1519ac3a6d9cSKip Macy }
1520ac3a6d9cSKip Macy
1521d722cab4SKip Macy /**
1522d722cab4SKip Macy * cxgb_up - enable the adapter
1523d722cab4SKip Macy * @adap: adapter being enabled
1524d722cab4SKip Macy *
1525d722cab4SKip Macy * Called when the first port is enabled, this function performs the
1526d722cab4SKip Macy * actions necessary to make an adapter operational, such as completing
1527d722cab4SKip Macy * the initialization of HW modules, and enabling interrupts.
1528d722cab4SKip Macy */
1529d722cab4SKip Macy static int
cxgb_up(struct adapter * sc)1530d722cab4SKip Macy cxgb_up(struct adapter *sc)
1531d722cab4SKip Macy {
1532d722cab4SKip Macy int err = 0;
15333a2c6562SNavdeep Parhar unsigned int mxf = t3_mc5_size(&sc->mc5) - MC5_MIN_TIDS;
1534d722cab4SKip Macy
15353f345a5dSKip Macy KASSERT(sc->open_device_map == 0, ("%s: device(s) already open (%x)",
15363f345a5dSKip Macy __func__, sc->open_device_map));
15373f345a5dSKip Macy
1538d722cab4SKip Macy if ((sc->flags & FULL_INIT_DONE) == 0) {
1539d722cab4SKip Macy
1540b302b77cSNavdeep Parhar ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1541b302b77cSNavdeep Parhar
1542d722cab4SKip Macy if ((sc->flags & FW_UPTODATE) == 0)
1543ac3a6d9cSKip Macy if ((err = upgrade_fw(sc)))
1544d722cab4SKip Macy goto out;
15453f345a5dSKip Macy
1546ac3a6d9cSKip Macy if ((sc->flags & TPS_UPTODATE) == 0)
1547ac3a6d9cSKip Macy if ((err = update_tpsram(sc)))
1548ac3a6d9cSKip Macy goto out;
15493f345a5dSKip Macy
15503a2c6562SNavdeep Parhar if (is_offload(sc) && nfilters != 0) {
1551d6da8362SNavdeep Parhar sc->params.mc5.nservers = 0;
15523a2c6562SNavdeep Parhar
15533a2c6562SNavdeep Parhar if (nfilters < 0)
15543a2c6562SNavdeep Parhar sc->params.mc5.nfilters = mxf;
15553a2c6562SNavdeep Parhar else
15563a2c6562SNavdeep Parhar sc->params.mc5.nfilters = min(nfilters, mxf);
1557d6da8362SNavdeep Parhar }
1558d6da8362SNavdeep Parhar
1559d722cab4SKip Macy err = t3_init_hw(sc, 0);
1560d722cab4SKip Macy if (err)
1561d722cab4SKip Macy goto out;
1562d722cab4SKip Macy
15638e10660fSKip Macy t3_set_reg_field(sc, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT);
1564d722cab4SKip Macy t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
1565d722cab4SKip Macy
1566d722cab4SKip Macy err = setup_sge_qsets(sc);
1567d722cab4SKip Macy if (err)
1568d722cab4SKip Macy goto out;
1569d722cab4SKip Macy
1570d6da8362SNavdeep Parhar alloc_filters(sc);
1571d722cab4SKip Macy setup_rss(sc);
1572e3503bc9SGeorge V. Neville-Neil
15738090c9f5SKip Macy t3_add_configured_sysctls(sc);
1574d722cab4SKip Macy sc->flags |= FULL_INIT_DONE;
1575d722cab4SKip Macy }
1576d722cab4SKip Macy
1577d722cab4SKip Macy t3_intr_clear(sc);
1578d722cab4SKip Macy t3_sge_start(sc);
1579d722cab4SKip Macy t3_intr_enable(sc);
1580d722cab4SKip Macy
15818e10660fSKip Macy if (sc->params.rev >= T3_REV_C && !(sc->flags & TP_PARITY_INIT) &&
15828e10660fSKip Macy is_offload(sc) && init_tp_parity(sc) == 0)
15838e10660fSKip Macy sc->flags |= TP_PARITY_INIT;
15848e10660fSKip Macy
15858e10660fSKip Macy if (sc->flags & TP_PARITY_INIT) {
15863f345a5dSKip Macy t3_write_reg(sc, A_TP_INT_CAUSE, F_CMCACHEPERR | F_ARPLUTPERR);
15878e10660fSKip Macy t3_write_reg(sc, A_TP_INT_ENABLE, 0x7fbfffff);
15888e10660fSKip Macy }
15898e10660fSKip Macy
15905c5df3daSKip Macy if (!(sc->flags & QUEUES_BOUND)) {
1591d722cab4SKip Macy bind_qsets(sc);
1592d6da8362SNavdeep Parhar setup_hw_filters(sc);
1593d722cab4SKip Macy sc->flags |= QUEUES_BOUND;
1594ac3a6d9cSKip Macy }
15953f345a5dSKip Macy
15963f345a5dSKip Macy t3_sge_reset_adapter(sc);
1597d722cab4SKip Macy out:
1598d722cab4SKip Macy return (err);
1599d722cab4SKip Macy }
1600d722cab4SKip Macy
1601d722cab4SKip Macy /*
16023f345a5dSKip Macy * Called when the last open device is closed. Does NOT undo all of cxgb_up's
16033f345a5dSKip Macy * work. Specifically, the resources grabbed under FULL_INIT_DONE are released
16043f345a5dSKip Macy * during controller_detach, not here.
1605d722cab4SKip Macy */
1606d722cab4SKip Macy static void
cxgb_down(struct adapter * sc)16073f345a5dSKip Macy cxgb_down(struct adapter *sc)
1608d722cab4SKip Macy {
1609d722cab4SKip Macy t3_sge_stop(sc);
1610d722cab4SKip Macy t3_intr_disable(sc);
1611d722cab4SKip Macy }
1612d722cab4SKip Macy
16133f345a5dSKip Macy /*
16143f345a5dSKip Macy * if_init for cxgb ports.
16153f345a5dSKip Macy */
1616b6d90eb7SKip Macy static void
cxgb_init(void * arg)1617b6d90eb7SKip Macy cxgb_init(void *arg)
1618b6d90eb7SKip Macy {
1619b6d90eb7SKip Macy struct port_info *p = arg;
1620b302b77cSNavdeep Parhar struct adapter *sc = p->adapter;
1621b6d90eb7SKip Macy
1622b302b77cSNavdeep Parhar ADAPTER_LOCK(sc);
1623b302b77cSNavdeep Parhar cxgb_init_locked(p); /* releases adapter lock */
1624b302b77cSNavdeep Parhar ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
16253f345a5dSKip Macy }
16263f345a5dSKip Macy
16273f345a5dSKip Macy static int
cxgb_init_locked(struct port_info * p)1628b302b77cSNavdeep Parhar cxgb_init_locked(struct port_info *p)
16293f345a5dSKip Macy {
16303f345a5dSKip Macy struct adapter *sc = p->adapter;
1631954712e8SJustin Hibbits if_t ifp = p->ifp;
16323f345a5dSKip Macy struct cmac *mac = &p->mac;
163361cb6c90SNavdeep Parhar int i, rc = 0, may_sleep = 0, gave_up_lock = 0;
1634b302b77cSNavdeep Parhar
1635b302b77cSNavdeep Parhar ADAPTER_LOCK_ASSERT_OWNED(sc);
1636b302b77cSNavdeep Parhar
1637b302b77cSNavdeep Parhar while (!IS_DOOMED(p) && IS_BUSY(sc)) {
163861cb6c90SNavdeep Parhar gave_up_lock = 1;
1639b302b77cSNavdeep Parhar if (mtx_sleep(&sc->flags, &sc->lock, PCATCH, "cxgbinit", 0)) {
1640b302b77cSNavdeep Parhar rc = EINTR;
1641b302b77cSNavdeep Parhar goto done;
1642b302b77cSNavdeep Parhar }
1643b302b77cSNavdeep Parhar }
1644b302b77cSNavdeep Parhar if (IS_DOOMED(p)) {
1645b302b77cSNavdeep Parhar rc = ENXIO;
1646b302b77cSNavdeep Parhar goto done;
1647b302b77cSNavdeep Parhar }
1648b302b77cSNavdeep Parhar KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__));
1649b302b77cSNavdeep Parhar
1650b302b77cSNavdeep Parhar /*
1651b302b77cSNavdeep Parhar * The code that runs during one-time adapter initialization can sleep
1652b302b77cSNavdeep Parhar * so it's important not to hold any locks across it.
1653b302b77cSNavdeep Parhar */
1654b302b77cSNavdeep Parhar may_sleep = sc->flags & FULL_INIT_DONE ? 0 : 1;
1655b302b77cSNavdeep Parhar
1656b302b77cSNavdeep Parhar if (may_sleep) {
1657b302b77cSNavdeep Parhar SET_BUSY(sc);
165861cb6c90SNavdeep Parhar gave_up_lock = 1;
1659b302b77cSNavdeep Parhar ADAPTER_UNLOCK(sc);
1660b302b77cSNavdeep Parhar }
16613f345a5dSKip Macy
166209fe6320SNavdeep Parhar if (sc->open_device_map == 0 && ((rc = cxgb_up(sc)) != 0))
1663b302b77cSNavdeep Parhar goto done;
16643f345a5dSKip Macy
16653f345a5dSKip Macy PORT_LOCK(p);
1666b302b77cSNavdeep Parhar if (isset(&sc->open_device_map, p->port_id) &&
1667954712e8SJustin Hibbits (if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
1668b302b77cSNavdeep Parhar PORT_UNLOCK(p);
1669b302b77cSNavdeep Parhar goto done;
1670b302b77cSNavdeep Parhar }
16710bbdea77SGeorge V. Neville-Neil t3_port_intr_enable(sc, p->port_id);
16723f345a5dSKip Macy if (!mac->multiport)
1673c01f2b83SNavdeep Parhar t3_mac_init(mac);
16743f345a5dSKip Macy cxgb_update_mac_settings(p);
16753f345a5dSKip Macy t3_link_start(&p->phy, mac, &p->link_config);
16763f345a5dSKip Macy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
1677954712e8SJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, IFF_DRV_OACTIVE);
16783f345a5dSKip Macy PORT_UNLOCK(p);
16793f345a5dSKip Macy
16803f345a5dSKip Macy for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) {
16813f345a5dSKip Macy struct sge_qset *qs = &sc->sge.qs[i];
16823f345a5dSKip Macy struct sge_txq *txq = &qs->txq[TXQ_ETH];
16833f345a5dSKip Macy
16843f345a5dSKip Macy callout_reset_on(&txq->txq_watchdog, hz, cxgb_tx_watchdog, qs,
16853f345a5dSKip Macy txq->txq_watchdog.c_cpu);
1686b6d90eb7SKip Macy }
1687b6d90eb7SKip Macy
16883f345a5dSKip Macy /* all ok */
16893f345a5dSKip Macy setbit(&sc->open_device_map, p->port_id);
1690bd1a9fbaSNavdeep Parhar callout_reset(&p->link_check_ch,
1691bd1a9fbaSNavdeep Parhar p->phy.caps & SUPPORTED_LINK_IRQ ? hz * 3 : hz / 4,
1692bd1a9fbaSNavdeep Parhar link_check_callout, p);
1693b6d90eb7SKip Macy
1694b302b77cSNavdeep Parhar done:
1695b302b77cSNavdeep Parhar if (may_sleep) {
1696b302b77cSNavdeep Parhar ADAPTER_LOCK(sc);
1697b302b77cSNavdeep Parhar KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__));
1698b302b77cSNavdeep Parhar CLR_BUSY(sc);
1699b302b77cSNavdeep Parhar }
170061cb6c90SNavdeep Parhar if (gave_up_lock)
170161cb6c90SNavdeep Parhar wakeup_one(&sc->flags);
1702b302b77cSNavdeep Parhar ADAPTER_UNLOCK(sc);
1703b302b77cSNavdeep Parhar return (rc);
1704b302b77cSNavdeep Parhar }
1705b302b77cSNavdeep Parhar
1706b302b77cSNavdeep Parhar static int
cxgb_uninit_locked(struct port_info * p)1707b302b77cSNavdeep Parhar cxgb_uninit_locked(struct port_info *p)
1708b302b77cSNavdeep Parhar {
1709b302b77cSNavdeep Parhar struct adapter *sc = p->adapter;
1710b302b77cSNavdeep Parhar int rc;
1711b302b77cSNavdeep Parhar
1712b302b77cSNavdeep Parhar ADAPTER_LOCK_ASSERT_OWNED(sc);
1713b302b77cSNavdeep Parhar
1714b302b77cSNavdeep Parhar while (!IS_DOOMED(p) && IS_BUSY(sc)) {
1715b302b77cSNavdeep Parhar if (mtx_sleep(&sc->flags, &sc->lock, PCATCH, "cxgbunin", 0)) {
1716b302b77cSNavdeep Parhar rc = EINTR;
1717b302b77cSNavdeep Parhar goto done;
1718b302b77cSNavdeep Parhar }
1719b302b77cSNavdeep Parhar }
1720b302b77cSNavdeep Parhar if (IS_DOOMED(p)) {
1721b302b77cSNavdeep Parhar rc = ENXIO;
1722b302b77cSNavdeep Parhar goto done;
1723b302b77cSNavdeep Parhar }
1724b302b77cSNavdeep Parhar KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__));
1725b302b77cSNavdeep Parhar SET_BUSY(sc);
1726b302b77cSNavdeep Parhar ADAPTER_UNLOCK(sc);
1727b302b77cSNavdeep Parhar
1728b302b77cSNavdeep Parhar rc = cxgb_uninit_synchronized(p);
1729b302b77cSNavdeep Parhar
1730b302b77cSNavdeep Parhar ADAPTER_LOCK(sc);
1731b302b77cSNavdeep Parhar KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__));
1732b302b77cSNavdeep Parhar CLR_BUSY(sc);
1733b302b77cSNavdeep Parhar wakeup_one(&sc->flags);
1734b302b77cSNavdeep Parhar done:
1735b302b77cSNavdeep Parhar ADAPTER_UNLOCK(sc);
1736b302b77cSNavdeep Parhar return (rc);
1737b6d90eb7SKip Macy }
1738b6d90eb7SKip Macy
17393f345a5dSKip Macy /*
17403f345a5dSKip Macy * Called on "ifconfig down", and from port_detach
17413f345a5dSKip Macy */
17423f345a5dSKip Macy static int
cxgb_uninit_synchronized(struct port_info * pi)17433f345a5dSKip Macy cxgb_uninit_synchronized(struct port_info *pi)
1744b6d90eb7SKip Macy {
17453f345a5dSKip Macy struct adapter *sc = pi->adapter;
1746954712e8SJustin Hibbits if_t ifp = pi->ifp;
1747b6d90eb7SKip Macy
17483f345a5dSKip Macy /*
1749b302b77cSNavdeep Parhar * taskqueue_drain may cause a deadlock if the adapter lock is held.
1750b302b77cSNavdeep Parhar */
1751b302b77cSNavdeep Parhar ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1752b302b77cSNavdeep Parhar
1753b302b77cSNavdeep Parhar /*
17543f345a5dSKip Macy * Clear this port's bit from the open device map, and then drain all
17553f345a5dSKip Macy * the tasks that can access/manipulate this port's port_info or ifp.
17566bccea7cSRebecca Cran * We disable this port's interrupts here and so the slow/ext
17573f345a5dSKip Macy * interrupt tasks won't be enqueued. The tick task will continue to
17583f345a5dSKip Macy * be enqueued every second but the runs after this drain will not see
17593f345a5dSKip Macy * this port in the open device map.
17603f345a5dSKip Macy *
17613f345a5dSKip Macy * A well behaved task must take open_device_map into account and ignore
17623f345a5dSKip Macy * ports that are not open.
17633f345a5dSKip Macy */
17643f345a5dSKip Macy clrbit(&sc->open_device_map, pi->port_id);
17653f345a5dSKip Macy t3_port_intr_disable(sc, pi->port_id);
17663f345a5dSKip Macy taskqueue_drain(sc->tq, &sc->slow_intr_task);
17673f345a5dSKip Macy taskqueue_drain(sc->tq, &sc->tick_task);
176877f07749SKip Macy
1769bd1a9fbaSNavdeep Parhar callout_drain(&pi->link_check_ch);
1770bd1a9fbaSNavdeep Parhar taskqueue_drain(sc->tq, &pi->link_check_task);
1771bd1a9fbaSNavdeep Parhar
17723f345a5dSKip Macy PORT_LOCK(pi);
1773954712e8SJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1774b6d90eb7SKip Macy
177519905d6dSKip Macy /* disable pause frames */
17763f345a5dSKip Macy t3_set_reg_field(sc, A_XGM_TX_CFG + pi->mac.offset, F_TXPAUSEEN, 0);
1777bb38cd2fSKip Macy
177819905d6dSKip Macy /* Reset RX FIFO HWM */
17793f345a5dSKip Macy t3_set_reg_field(sc, A_XGM_RXFIFO_CFG + pi->mac.offset,
178019905d6dSKip Macy V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM), 0);
178119905d6dSKip Macy
1782a9c23ef0SNavdeep Parhar DELAY(100 * 1000);
178319905d6dSKip Macy
178419905d6dSKip Macy /* Wait for TXFIFO empty */
17853f345a5dSKip Macy t3_wait_op_done(sc, A_XGM_TXFIFO_CFG + pi->mac.offset,
178619905d6dSKip Macy F_TXFIFO_EMPTY, 1, 20, 5);
178719905d6dSKip Macy
1788a9c23ef0SNavdeep Parhar DELAY(100 * 1000);
1789a9c23ef0SNavdeep Parhar t3_mac_disable(&pi->mac, MAC_DIRECTION_RX);
179019905d6dSKip Macy
179119905d6dSKip Macy pi->phy.ops->power_down(&pi->phy, 1);
1792bb38cd2fSKip Macy
17933f345a5dSKip Macy PORT_UNLOCK(pi);
1794b6d90eb7SKip Macy
17953f345a5dSKip Macy pi->link_config.link_ok = 0;
1796c01f2b83SNavdeep Parhar t3_os_link_changed(sc, pi->port_id, 0, 0, 0, 0, 0);
1797ef72318fSKip Macy
17983f345a5dSKip Macy if (sc->open_device_map == 0)
17993f345a5dSKip Macy cxgb_down(pi->adapter);
18003f345a5dSKip Macy
18013f345a5dSKip Macy return (0);
1802ef72318fSKip Macy }
1803ef72318fSKip Macy
180425292debSKip Macy /*
180525292debSKip Macy * Mark lro enabled or disabled in all qsets for this port
180625292debSKip Macy */
180725292debSKip Macy static int
cxgb_set_lro(struct port_info * p,int enabled)180825292debSKip Macy cxgb_set_lro(struct port_info *p, int enabled)
180925292debSKip Macy {
181025292debSKip Macy int i;
181125292debSKip Macy struct adapter *adp = p->adapter;
181225292debSKip Macy struct sge_qset *q;
181325292debSKip Macy
181425292debSKip Macy for (i = 0; i < p->nqsets; i++) {
181525292debSKip Macy q = &adp->sge.qs[p->first_qset + i];
181625292debSKip Macy q->lro.enabled = (enabled != 0);
181725292debSKip Macy }
181825292debSKip Macy return (0);
181925292debSKip Macy }
182025292debSKip Macy
1821ef72318fSKip Macy static int
cxgb_ioctl(if_t ifp,unsigned long command,caddr_t data)1822954712e8SJustin Hibbits cxgb_ioctl(if_t ifp, unsigned long command, caddr_t data)
1823b6d90eb7SKip Macy {
1824954712e8SJustin Hibbits struct port_info *p = if_getsoftc(ifp);
1825b302b77cSNavdeep Parhar struct adapter *sc = p->adapter;
1826b6d90eb7SKip Macy struct ifreq *ifr = (struct ifreq *)data;
1827b302b77cSNavdeep Parhar int flags, error = 0, mtu;
1828b6d90eb7SKip Macy uint32_t mask;
1829b6d90eb7SKip Macy
1830b6d90eb7SKip Macy switch (command) {
1831b6d90eb7SKip Macy case SIOCSIFMTU:
1832b302b77cSNavdeep Parhar ADAPTER_LOCK(sc);
1833b302b77cSNavdeep Parhar error = IS_DOOMED(p) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
1834b302b77cSNavdeep Parhar if (error) {
1835b302b77cSNavdeep Parhar fail:
1836b302b77cSNavdeep Parhar ADAPTER_UNLOCK(sc);
1837b302b77cSNavdeep Parhar return (error);
1838b302b77cSNavdeep Parhar }
1839b302b77cSNavdeep Parhar
18403f345a5dSKip Macy mtu = ifr->ifr_mtu;
18413f345a5dSKip Macy if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) {
18423f345a5dSKip Macy error = EINVAL;
18433f345a5dSKip Macy } else {
1844954712e8SJustin Hibbits if_setmtu(ifp, mtu);
18458e10660fSKip Macy PORT_LOCK(p);
18463f345a5dSKip Macy cxgb_update_mac_settings(p);
18474f6a96aeSKip Macy PORT_UNLOCK(p);
18488e10660fSKip Macy }
1849b302b77cSNavdeep Parhar ADAPTER_UNLOCK(sc);
1850b6d90eb7SKip Macy break;
1851b6d90eb7SKip Macy case SIOCSIFFLAGS:
1852b302b77cSNavdeep Parhar ADAPTER_LOCK(sc);
1853b302b77cSNavdeep Parhar if (IS_DOOMED(p)) {
1854b302b77cSNavdeep Parhar error = ENXIO;
1855b302b77cSNavdeep Parhar goto fail;
1856b302b77cSNavdeep Parhar }
1857954712e8SJustin Hibbits if (if_getflags(ifp) & IFF_UP) {
1858954712e8SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
1859b6d90eb7SKip Macy flags = p->if_flags;
1860954712e8SJustin Hibbits if (((if_getflags(ifp) ^ flags) & IFF_PROMISC) ||
1861954712e8SJustin Hibbits ((if_getflags(ifp) ^ flags) & IFF_ALLMULTI)) {
1862b302b77cSNavdeep Parhar if (IS_BUSY(sc)) {
1863b302b77cSNavdeep Parhar error = EBUSY;
1864b302b77cSNavdeep Parhar goto fail;
1865b302b77cSNavdeep Parhar }
18663f345a5dSKip Macy PORT_LOCK(p);
18673f345a5dSKip Macy cxgb_update_mac_settings(p);
18683f345a5dSKip Macy PORT_UNLOCK(p);
18693f345a5dSKip Macy }
1870b302b77cSNavdeep Parhar ADAPTER_UNLOCK(sc);
1871b6d90eb7SKip Macy } else
1872b302b77cSNavdeep Parhar error = cxgb_init_locked(p);
1873954712e8SJustin Hibbits p->if_flags = if_getflags(ifp);
1874954712e8SJustin Hibbits } else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
1875b302b77cSNavdeep Parhar error = cxgb_uninit_locked(p);
18763c0e59deSNavdeep Parhar else
18773c0e59deSNavdeep Parhar ADAPTER_UNLOCK(sc);
1878bb38cd2fSKip Macy
1879b302b77cSNavdeep Parhar ADAPTER_LOCK_ASSERT_NOTOWNED(sc);
1880b6d90eb7SKip Macy break;
18818e10660fSKip Macy case SIOCADDMULTI:
18828e10660fSKip Macy case SIOCDELMULTI:
1883b302b77cSNavdeep Parhar ADAPTER_LOCK(sc);
1884b302b77cSNavdeep Parhar error = IS_DOOMED(p) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
1885b302b77cSNavdeep Parhar if (error)
1886b302b77cSNavdeep Parhar goto fail;
1887b302b77cSNavdeep Parhar
1888954712e8SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
1889837f41b0SGeorge V. Neville-Neil PORT_LOCK(p);
18903f345a5dSKip Macy cxgb_update_mac_settings(p);
1891837f41b0SGeorge V. Neville-Neil PORT_UNLOCK(p);
18923f345a5dSKip Macy }
1893b302b77cSNavdeep Parhar ADAPTER_UNLOCK(sc);
18943f345a5dSKip Macy
1895b6d90eb7SKip Macy break;
1896b6d90eb7SKip Macy case SIOCSIFCAP:
1897b302b77cSNavdeep Parhar ADAPTER_LOCK(sc);
1898b302b77cSNavdeep Parhar error = IS_DOOMED(p) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0);
1899b302b77cSNavdeep Parhar if (error)
1900b302b77cSNavdeep Parhar goto fail;
1901b302b77cSNavdeep Parhar
1902954712e8SJustin Hibbits mask = ifr->ifr_reqcap ^ if_getcapenable(ifp);
1903b6d90eb7SKip Macy if (mask & IFCAP_TXCSUM) {
1904954712e8SJustin Hibbits if_togglecapenable(ifp, IFCAP_TXCSUM);
1905954712e8SJustin Hibbits if_togglehwassist(ifp, CSUM_TCP | CSUM_UDP | CSUM_IP);
1906f9c6e164SNavdeep Parhar
1907954712e8SJustin Hibbits if (IFCAP_TSO4 & if_getcapenable(ifp) &&
1908954712e8SJustin Hibbits !(IFCAP_TXCSUM & if_getcapenable(ifp))) {
1909cbb9ccf7SRyan Moeller mask &= ~IFCAP_TSO4;
1910954712e8SJustin Hibbits if_setcapenablebit(ifp, 0, IFCAP_TSO4);
1911f9c6e164SNavdeep Parhar if_printf(ifp,
19120a704909SNavdeep Parhar "tso4 disabled due to -txcsum.\n");
19130a704909SNavdeep Parhar }
19140a704909SNavdeep Parhar }
19150a704909SNavdeep Parhar if (mask & IFCAP_TXCSUM_IPV6) {
1916954712e8SJustin Hibbits if_togglecapenable(ifp, IFCAP_TXCSUM_IPV6);
1917954712e8SJustin Hibbits if_togglehwassist(ifp, CSUM_UDP_IPV6 | CSUM_TCP_IPV6);
19180a704909SNavdeep Parhar
1919954712e8SJustin Hibbits if (IFCAP_TSO6 & if_getcapenable(ifp) &&
1920954712e8SJustin Hibbits !(IFCAP_TXCSUM_IPV6 & if_getcapenable(ifp))) {
1921cbb9ccf7SRyan Moeller mask &= ~IFCAP_TSO6;
1922954712e8SJustin Hibbits if_setcapenablebit(ifp, 0, IFCAP_TSO6);
19230a704909SNavdeep Parhar if_printf(ifp,
19240a704909SNavdeep Parhar "tso6 disabled due to -txcsum6.\n");
1925f9c6e164SNavdeep Parhar }
1926f9c6e164SNavdeep Parhar }
1927f9c6e164SNavdeep Parhar if (mask & IFCAP_RXCSUM)
1928954712e8SJustin Hibbits if_togglecapenable(ifp, IFCAP_RXCSUM);
19290a704909SNavdeep Parhar if (mask & IFCAP_RXCSUM_IPV6)
1930954712e8SJustin Hibbits if_togglecapenable(ifp, IFCAP_RXCSUM_IPV6);
1931f9c6e164SNavdeep Parhar
19320a704909SNavdeep Parhar /*
19330a704909SNavdeep Parhar * Note that we leave CSUM_TSO alone (it is always set). The
19340a704909SNavdeep Parhar * kernel takes both IFCAP_TSOx and CSUM_TSO into account before
19350a704909SNavdeep Parhar * sending a TSO request our way, so it's sufficient to toggle
19360a704909SNavdeep Parhar * IFCAP_TSOx only.
19370a704909SNavdeep Parhar */
19380a704909SNavdeep Parhar if (mask & IFCAP_TSO4) {
1939954712e8SJustin Hibbits if (!(IFCAP_TSO4 & if_getcapenable(ifp)) &&
1940954712e8SJustin Hibbits !(IFCAP_TXCSUM & if_getcapenable(ifp))) {
19410a704909SNavdeep Parhar if_printf(ifp, "enable txcsum first.\n");
1942f9c6e164SNavdeep Parhar error = EAGAIN;
19430a704909SNavdeep Parhar goto fail;
1944f9c6e164SNavdeep Parhar }
1945954712e8SJustin Hibbits if_togglecapenable(ifp, IFCAP_TSO4);
19460a704909SNavdeep Parhar }
19470a704909SNavdeep Parhar if (mask & IFCAP_TSO6) {
1948954712e8SJustin Hibbits if (!(IFCAP_TSO6 & if_getcapenable(ifp)) &&
1949954712e8SJustin Hibbits !(IFCAP_TXCSUM_IPV6 & if_getcapenable(ifp))) {
19500a704909SNavdeep Parhar if_printf(ifp, "enable txcsum6 first.\n");
19510a704909SNavdeep Parhar error = EAGAIN;
19520a704909SNavdeep Parhar goto fail;
19530a704909SNavdeep Parhar }
1954954712e8SJustin Hibbits if_togglecapenable(ifp, IFCAP_TSO6);
1955b6d90eb7SKip Macy }
195625292debSKip Macy if (mask & IFCAP_LRO) {
1957954712e8SJustin Hibbits if_togglecapenable(ifp, IFCAP_LRO);
195825292debSKip Macy
195925292debSKip Macy /* Safe to do this even if cxgb_up not called yet */
1960954712e8SJustin Hibbits cxgb_set_lro(p, if_getcapenable(ifp) & IFCAP_LRO);
196125292debSKip Macy }
196209fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
196309fe6320SNavdeep Parhar if (mask & IFCAP_TOE4) {
1964954712e8SJustin Hibbits int enable = (if_getcapenable(ifp) ^ mask) & IFCAP_TOE4;
196509fe6320SNavdeep Parhar
196609fe6320SNavdeep Parhar error = toe_capability(p, enable);
196709fe6320SNavdeep Parhar if (error == 0)
1968954712e8SJustin Hibbits if_togglecapenable(ifp, mask);
196909fe6320SNavdeep Parhar }
197009fe6320SNavdeep Parhar #endif
19714af83c8cSKip Macy if (mask & IFCAP_VLAN_HWTAGGING) {
1972954712e8SJustin Hibbits if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING);
1973954712e8SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
19743f345a5dSKip Macy PORT_LOCK(p);
19753f345a5dSKip Macy cxgb_update_mac_settings(p);
19763f345a5dSKip Macy PORT_UNLOCK(p);
19773f345a5dSKip Macy }
19784af83c8cSKip Macy }
19794af83c8cSKip Macy if (mask & IFCAP_VLAN_MTU) {
1980954712e8SJustin Hibbits if_togglecapenable(ifp, IFCAP_VLAN_MTU);
1981954712e8SJustin Hibbits if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
19823f345a5dSKip Macy PORT_LOCK(p);
19833f345a5dSKip Macy cxgb_update_mac_settings(p);
19843f345a5dSKip Macy PORT_UNLOCK(p);
19853f345a5dSKip Macy }
19864af83c8cSKip Macy }
1987f9c6e164SNavdeep Parhar if (mask & IFCAP_VLAN_HWTSO)
1988954712e8SJustin Hibbits if_togglecapenable(ifp, IFCAP_VLAN_HWTSO);
1989b302b77cSNavdeep Parhar if (mask & IFCAP_VLAN_HWCSUM)
1990954712e8SJustin Hibbits if_togglecapenable(ifp, IFCAP_VLAN_HWCSUM);
19914af83c8cSKip Macy
19924af83c8cSKip Macy #ifdef VLAN_CAPABILITIES
19934af83c8cSKip Macy VLAN_CAPABILITIES(ifp);
19944af83c8cSKip Macy #endif
1995b302b77cSNavdeep Parhar ADAPTER_UNLOCK(sc);
1996b302b77cSNavdeep Parhar break;
1997b302b77cSNavdeep Parhar case SIOCSIFMEDIA:
1998b302b77cSNavdeep Parhar case SIOCGIFMEDIA:
1999b302b77cSNavdeep Parhar error = ifmedia_ioctl(ifp, ifr, &p->media, command);
2000b6d90eb7SKip Macy break;
2001b6d90eb7SKip Macy default:
20023f345a5dSKip Macy error = ether_ioctl(ifp, command, data);
20033f345a5dSKip Macy }
20043f345a5dSKip Macy
2005b6d90eb7SKip Macy return (error);
2006b6d90eb7SKip Macy }
2007b6d90eb7SKip Macy
2008b6d90eb7SKip Macy static int
cxgb_media_change(if_t ifp)2009954712e8SJustin Hibbits cxgb_media_change(if_t ifp)
2010b6d90eb7SKip Macy {
20112975f787SNavdeep Parhar return (EOPNOTSUPP);
2012b6d90eb7SKip Macy }
2013b6d90eb7SKip Macy
2014837f41b0SGeorge V. Neville-Neil /*
20152975f787SNavdeep Parhar * Translates phy->modtype to the correct Ethernet media subtype.
2016837f41b0SGeorge V. Neville-Neil */
2017837f41b0SGeorge V. Neville-Neil static int
cxgb_ifm_type(int mod)20182975f787SNavdeep Parhar cxgb_ifm_type(int mod)
2019837f41b0SGeorge V. Neville-Neil {
20202975f787SNavdeep Parhar switch (mod) {
2021837f41b0SGeorge V. Neville-Neil case phy_modtype_sr:
20222975f787SNavdeep Parhar return (IFM_10G_SR);
2023837f41b0SGeorge V. Neville-Neil case phy_modtype_lr:
20242975f787SNavdeep Parhar return (IFM_10G_LR);
2025837f41b0SGeorge V. Neville-Neil case phy_modtype_lrm:
20262975f787SNavdeep Parhar return (IFM_10G_LRM);
2027837f41b0SGeorge V. Neville-Neil case phy_modtype_twinax:
20282975f787SNavdeep Parhar return (IFM_10G_TWINAX);
2029837f41b0SGeorge V. Neville-Neil case phy_modtype_twinax_long:
20302975f787SNavdeep Parhar return (IFM_10G_TWINAX_LONG);
2031837f41b0SGeorge V. Neville-Neil case phy_modtype_none:
20322975f787SNavdeep Parhar return (IFM_NONE);
2033837f41b0SGeorge V. Neville-Neil case phy_modtype_unknown:
20342975f787SNavdeep Parhar return (IFM_UNKNOWN);
2035837f41b0SGeorge V. Neville-Neil }
2036837f41b0SGeorge V. Neville-Neil
20372975f787SNavdeep Parhar KASSERT(0, ("%s: modtype %d unknown", __func__, mod));
20382975f787SNavdeep Parhar return (IFM_UNKNOWN);
20392975f787SNavdeep Parhar }
20402975f787SNavdeep Parhar
20412975f787SNavdeep Parhar /*
20422975f787SNavdeep Parhar * Rebuilds the ifmedia list for this port, and sets the current media.
20432975f787SNavdeep Parhar */
20442975f787SNavdeep Parhar static void
cxgb_build_medialist(struct port_info * p)20452975f787SNavdeep Parhar cxgb_build_medialist(struct port_info *p)
20462975f787SNavdeep Parhar {
20472975f787SNavdeep Parhar struct cphy *phy = &p->phy;
20482975f787SNavdeep Parhar struct ifmedia *media = &p->media;
20492975f787SNavdeep Parhar int mod = phy->modtype;
20502975f787SNavdeep Parhar int m = IFM_ETHER | IFM_FDX;
20512975f787SNavdeep Parhar
20522975f787SNavdeep Parhar PORT_LOCK(p);
20532975f787SNavdeep Parhar
20542975f787SNavdeep Parhar ifmedia_removeall(media);
20552975f787SNavdeep Parhar if (phy->caps & SUPPORTED_TP && phy->caps & SUPPORTED_Autoneg) {
20562975f787SNavdeep Parhar /* Copper (RJ45) */
20572975f787SNavdeep Parhar
20582975f787SNavdeep Parhar if (phy->caps & SUPPORTED_10000baseT_Full)
20592975f787SNavdeep Parhar ifmedia_add(media, m | IFM_10G_T, mod, NULL);
20602975f787SNavdeep Parhar
20612975f787SNavdeep Parhar if (phy->caps & SUPPORTED_1000baseT_Full)
20622975f787SNavdeep Parhar ifmedia_add(media, m | IFM_1000_T, mod, NULL);
20632975f787SNavdeep Parhar
20642975f787SNavdeep Parhar if (phy->caps & SUPPORTED_100baseT_Full)
20652975f787SNavdeep Parhar ifmedia_add(media, m | IFM_100_TX, mod, NULL);
20662975f787SNavdeep Parhar
20672975f787SNavdeep Parhar if (phy->caps & SUPPORTED_10baseT_Full)
20682975f787SNavdeep Parhar ifmedia_add(media, m | IFM_10_T, mod, NULL);
20692975f787SNavdeep Parhar
20702975f787SNavdeep Parhar ifmedia_add(media, IFM_ETHER | IFM_AUTO, mod, NULL);
20712975f787SNavdeep Parhar ifmedia_set(media, IFM_ETHER | IFM_AUTO);
20722975f787SNavdeep Parhar
20732975f787SNavdeep Parhar } else if (phy->caps & SUPPORTED_TP) {
20742975f787SNavdeep Parhar /* Copper (CX4) */
20752975f787SNavdeep Parhar
20762975f787SNavdeep Parhar KASSERT(phy->caps & SUPPORTED_10000baseT_Full,
20772975f787SNavdeep Parhar ("%s: unexpected cap 0x%x", __func__, phy->caps));
20782975f787SNavdeep Parhar
20792975f787SNavdeep Parhar ifmedia_add(media, m | IFM_10G_CX4, mod, NULL);
20802975f787SNavdeep Parhar ifmedia_set(media, m | IFM_10G_CX4);
20812975f787SNavdeep Parhar
20822975f787SNavdeep Parhar } else if (phy->caps & SUPPORTED_FIBRE &&
20832975f787SNavdeep Parhar phy->caps & SUPPORTED_10000baseT_Full) {
20842975f787SNavdeep Parhar /* 10G optical (but includes SFP+ twinax) */
20852975f787SNavdeep Parhar
20862975f787SNavdeep Parhar m |= cxgb_ifm_type(mod);
20872975f787SNavdeep Parhar if (IFM_SUBTYPE(m) == IFM_NONE)
20882975f787SNavdeep Parhar m &= ~IFM_FDX;
20892975f787SNavdeep Parhar
20902975f787SNavdeep Parhar ifmedia_add(media, m, mod, NULL);
20912975f787SNavdeep Parhar ifmedia_set(media, m);
20922975f787SNavdeep Parhar
20932975f787SNavdeep Parhar } else if (phy->caps & SUPPORTED_FIBRE &&
20942975f787SNavdeep Parhar phy->caps & SUPPORTED_1000baseT_Full) {
20952975f787SNavdeep Parhar /* 1G optical */
20962975f787SNavdeep Parhar
20972975f787SNavdeep Parhar /* XXX: Lie and claim to be SX, could actually be any 1G-X */
20982975f787SNavdeep Parhar ifmedia_add(media, m | IFM_1000_SX, mod, NULL);
20992975f787SNavdeep Parhar ifmedia_set(media, m | IFM_1000_SX);
21002975f787SNavdeep Parhar
21012975f787SNavdeep Parhar } else {
21022975f787SNavdeep Parhar KASSERT(0, ("%s: don't know how to handle 0x%x.", __func__,
21032975f787SNavdeep Parhar phy->caps));
21042975f787SNavdeep Parhar }
21052975f787SNavdeep Parhar
21062975f787SNavdeep Parhar PORT_UNLOCK(p);
2107837f41b0SGeorge V. Neville-Neil }
2108837f41b0SGeorge V. Neville-Neil
2109b6d90eb7SKip Macy static void
cxgb_media_status(if_t ifp,struct ifmediareq * ifmr)2110954712e8SJustin Hibbits cxgb_media_status(if_t ifp, struct ifmediareq *ifmr)
2111b6d90eb7SKip Macy {
2112954712e8SJustin Hibbits struct port_info *p = if_getsoftc(ifp);
2113837f41b0SGeorge V. Neville-Neil struct ifmedia_entry *cur = p->media.ifm_cur;
21142975f787SNavdeep Parhar int speed = p->link_config.speed;
2115837f41b0SGeorge V. Neville-Neil
2116837f41b0SGeorge V. Neville-Neil if (cur->ifm_data != p->phy.modtype) {
21172975f787SNavdeep Parhar cxgb_build_medialist(p);
21182975f787SNavdeep Parhar cur = p->media.ifm_cur;
2119837f41b0SGeorge V. Neville-Neil }
2120b6d90eb7SKip Macy
2121b6d90eb7SKip Macy ifmr->ifm_status = IFM_AVALID;
2122b6d90eb7SKip Macy if (!p->link_config.link_ok)
2123b6d90eb7SKip Macy return;
2124b6d90eb7SKip Macy
2125b6d90eb7SKip Macy ifmr->ifm_status |= IFM_ACTIVE;
2126b6d90eb7SKip Macy
21272975f787SNavdeep Parhar /*
21282975f787SNavdeep Parhar * active and current will differ iff current media is autoselect. That
21292975f787SNavdeep Parhar * can happen only for copper RJ45.
21302975f787SNavdeep Parhar */
21312975f787SNavdeep Parhar if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO)
21322975f787SNavdeep Parhar return;
21332975f787SNavdeep Parhar KASSERT(p->phy.caps & SUPPORTED_TP && p->phy.caps & SUPPORTED_Autoneg,
21342975f787SNavdeep Parhar ("%s: unexpected PHY caps 0x%x", __func__, p->phy.caps));
2135ef72318fSKip Macy
21362975f787SNavdeep Parhar ifmr->ifm_active = IFM_ETHER | IFM_FDX;
21372975f787SNavdeep Parhar if (speed == SPEED_10000)
21382975f787SNavdeep Parhar ifmr->ifm_active |= IFM_10G_T;
21392975f787SNavdeep Parhar else if (speed == SPEED_1000)
21402975f787SNavdeep Parhar ifmr->ifm_active |= IFM_1000_T;
21412975f787SNavdeep Parhar else if (speed == SPEED_100)
21422975f787SNavdeep Parhar ifmr->ifm_active |= IFM_100_TX;
21432975f787SNavdeep Parhar else if (speed == SPEED_10)
21442975f787SNavdeep Parhar ifmr->ifm_active |= IFM_10_T;
2145b6d90eb7SKip Macy else
21462975f787SNavdeep Parhar KASSERT(0, ("%s: link up but speed unknown (%u)", __func__,
21472975f787SNavdeep Parhar speed));
2148b6d90eb7SKip Macy }
2149b6d90eb7SKip Macy
2150e26e6373SNavdeep Parhar static uint64_t
cxgb_get_counter(if_t ifp,ift_counter c)2151954712e8SJustin Hibbits cxgb_get_counter(if_t ifp, ift_counter c)
2152e26e6373SNavdeep Parhar {
2153954712e8SJustin Hibbits struct port_info *pi = if_getsoftc(ifp);
2154e26e6373SNavdeep Parhar struct adapter *sc = pi->adapter;
2155e26e6373SNavdeep Parhar struct cmac *mac = &pi->mac;
2156e26e6373SNavdeep Parhar struct mac_stats *mstats = &mac->stats;
2157e26e6373SNavdeep Parhar
2158e26e6373SNavdeep Parhar cxgb_refresh_stats(pi);
2159e26e6373SNavdeep Parhar
2160e26e6373SNavdeep Parhar switch (c) {
2161e26e6373SNavdeep Parhar case IFCOUNTER_IPACKETS:
2162e26e6373SNavdeep Parhar return (mstats->rx_frames);
2163e26e6373SNavdeep Parhar
2164e26e6373SNavdeep Parhar case IFCOUNTER_IERRORS:
2165e26e6373SNavdeep Parhar return (mstats->rx_jabber + mstats->rx_data_errs +
2166e26e6373SNavdeep Parhar mstats->rx_sequence_errs + mstats->rx_runt +
2167e26e6373SNavdeep Parhar mstats->rx_too_long + mstats->rx_mac_internal_errs +
2168e26e6373SNavdeep Parhar mstats->rx_short + mstats->rx_fcs_errs);
2169e26e6373SNavdeep Parhar
2170e26e6373SNavdeep Parhar case IFCOUNTER_OPACKETS:
2171e26e6373SNavdeep Parhar return (mstats->tx_frames);
2172e26e6373SNavdeep Parhar
2173e26e6373SNavdeep Parhar case IFCOUNTER_OERRORS:
2174e26e6373SNavdeep Parhar return (mstats->tx_excess_collisions + mstats->tx_underrun +
2175e26e6373SNavdeep Parhar mstats->tx_len_errs + mstats->tx_mac_internal_errs +
2176e26e6373SNavdeep Parhar mstats->tx_excess_deferral + mstats->tx_fcs_errs);
2177e26e6373SNavdeep Parhar
2178e26e6373SNavdeep Parhar case IFCOUNTER_COLLISIONS:
2179e26e6373SNavdeep Parhar return (mstats->tx_total_collisions);
2180e26e6373SNavdeep Parhar
2181e26e6373SNavdeep Parhar case IFCOUNTER_IBYTES:
2182e26e6373SNavdeep Parhar return (mstats->rx_octets);
2183e26e6373SNavdeep Parhar
2184e26e6373SNavdeep Parhar case IFCOUNTER_OBYTES:
2185e26e6373SNavdeep Parhar return (mstats->tx_octets);
2186e26e6373SNavdeep Parhar
2187e26e6373SNavdeep Parhar case IFCOUNTER_IMCASTS:
2188e26e6373SNavdeep Parhar return (mstats->rx_mcast_frames);
2189e26e6373SNavdeep Parhar
2190e26e6373SNavdeep Parhar case IFCOUNTER_OMCASTS:
2191e26e6373SNavdeep Parhar return (mstats->tx_mcast_frames);
2192e26e6373SNavdeep Parhar
2193e26e6373SNavdeep Parhar case IFCOUNTER_IQDROPS:
2194e26e6373SNavdeep Parhar return (mstats->rx_cong_drops);
2195e26e6373SNavdeep Parhar
2196e26e6373SNavdeep Parhar case IFCOUNTER_OQDROPS: {
2197e26e6373SNavdeep Parhar int i;
2198e26e6373SNavdeep Parhar uint64_t drops;
2199e26e6373SNavdeep Parhar
2200e26e6373SNavdeep Parhar drops = 0;
2201e26e6373SNavdeep Parhar if (sc->flags & FULL_INIT_DONE) {
2202e26e6373SNavdeep Parhar for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++)
2203e26e6373SNavdeep Parhar drops += sc->sge.qs[i].txq[TXQ_ETH].txq_mr->br_drops;
2204e26e6373SNavdeep Parhar }
2205e26e6373SNavdeep Parhar
2206e26e6373SNavdeep Parhar return (drops);
2207e26e6373SNavdeep Parhar
2208e26e6373SNavdeep Parhar }
2209e26e6373SNavdeep Parhar
2210e26e6373SNavdeep Parhar default:
2211e26e6373SNavdeep Parhar return (if_get_counter_default(ifp, c));
2212e26e6373SNavdeep Parhar }
2213e26e6373SNavdeep Parhar }
2214e26e6373SNavdeep Parhar
2215b6d90eb7SKip Macy static void
cxgb_async_intr(void * data)2216b6d90eb7SKip Macy cxgb_async_intr(void *data)
2217b6d90eb7SKip Macy {
2218693d746cSKip Macy adapter_t *sc = data;
2219693d746cSKip Macy
22202c32b502SNavdeep Parhar t3_write_reg(sc, A_PL_INT_ENABLE0, 0);
22212c32b502SNavdeep Parhar (void) t3_read_reg(sc, A_PL_INT_ENABLE0);
2222bb38cd2fSKip Macy taskqueue_enqueue(sc->tq, &sc->slow_intr_task);
2223b6d90eb7SKip Macy }
2224b6d90eb7SKip Macy
2225bd1a9fbaSNavdeep Parhar static void
link_check_callout(void * arg)2226bd1a9fbaSNavdeep Parhar link_check_callout(void *arg)
2227c01f2b83SNavdeep Parhar {
2228bd1a9fbaSNavdeep Parhar struct port_info *pi = arg;
2229bd1a9fbaSNavdeep Parhar struct adapter *sc = pi->adapter;
2230c01f2b83SNavdeep Parhar
2231bd1a9fbaSNavdeep Parhar if (!isset(&sc->open_device_map, pi->port_id))
2232bd1a9fbaSNavdeep Parhar return;
2233c01f2b83SNavdeep Parhar
2234bd1a9fbaSNavdeep Parhar taskqueue_enqueue(sc->tq, &pi->link_check_task);
2235c01f2b83SNavdeep Parhar }
2236c01f2b83SNavdeep Parhar
2237b6d90eb7SKip Macy static void
check_link_status(void * arg,int pending)2238bd1a9fbaSNavdeep Parhar check_link_status(void *arg, int pending)
2239b6d90eb7SKip Macy {
2240bd1a9fbaSNavdeep Parhar struct port_info *pi = arg;
2241bd1a9fbaSNavdeep Parhar struct adapter *sc = pi->adapter;
2242b6d90eb7SKip Macy
2243bd1a9fbaSNavdeep Parhar if (!isset(&sc->open_device_map, pi->port_id))
2244bd1a9fbaSNavdeep Parhar return;
2245b6d90eb7SKip Macy
2246bd1a9fbaSNavdeep Parhar t3_link_changed(sc, pi->port_id);
22473f345a5dSKip Macy
2248a5eb009bSNavdeep Parhar if (pi->link_fault || !(pi->phy.caps & SUPPORTED_LINK_IRQ) ||
2249a5eb009bSNavdeep Parhar pi->link_config.link_ok == 0)
2250bd1a9fbaSNavdeep Parhar callout_reset(&pi->link_check_ch, hz, link_check_callout, pi);
2251b6d90eb7SKip Macy }
2252bd1a9fbaSNavdeep Parhar
2253bd1a9fbaSNavdeep Parhar void
t3_os_link_intr(struct port_info * pi)2254bd1a9fbaSNavdeep Parhar t3_os_link_intr(struct port_info *pi)
2255bd1a9fbaSNavdeep Parhar {
2256bd1a9fbaSNavdeep Parhar /*
2257bd1a9fbaSNavdeep Parhar * Schedule a link check in the near future. If the link is flapping
2258bd1a9fbaSNavdeep Parhar * rapidly we'll keep resetting the callout and delaying the check until
2259bd1a9fbaSNavdeep Parhar * things stabilize a bit.
2260bd1a9fbaSNavdeep Parhar */
2261bd1a9fbaSNavdeep Parhar callout_reset(&pi->link_check_ch, hz / 4, link_check_callout, pi);
2262b6d90eb7SKip Macy }
2263b6d90eb7SKip Macy
2264577e9bbeSKip Macy static void
check_t3b2_mac(struct adapter * sc)22653f345a5dSKip Macy check_t3b2_mac(struct adapter *sc)
2266577e9bbeSKip Macy {
2267577e9bbeSKip Macy int i;
2268577e9bbeSKip Macy
22693f345a5dSKip Macy if (sc->flags & CXGB_SHUTDOWN)
22708e10660fSKip Macy return;
22718e10660fSKip Macy
22723f345a5dSKip Macy for_each_port(sc, i) {
22733f345a5dSKip Macy struct port_info *p = &sc->port[i];
2274577e9bbeSKip Macy int status;
22753f345a5dSKip Macy #ifdef INVARIANTS
2276954712e8SJustin Hibbits if_t ifp = p->ifp;
22773f345a5dSKip Macy #endif
2278577e9bbeSKip Macy
2279c01f2b83SNavdeep Parhar if (!isset(&sc->open_device_map, p->port_id) || p->link_fault ||
2280c01f2b83SNavdeep Parhar !p->link_config.link_ok)
2281577e9bbeSKip Macy continue;
2282577e9bbeSKip Macy
2283954712e8SJustin Hibbits KASSERT(if_getdrvflags(ifp) & IFF_DRV_RUNNING,
22843f345a5dSKip Macy ("%s: state mismatch (drv_flags %x, device_map %x)",
2285954712e8SJustin Hibbits __func__, if_getdrvflags(ifp), sc->open_device_map));
22863f345a5dSKip Macy
2287577e9bbeSKip Macy PORT_LOCK(p);
2288577e9bbeSKip Macy status = t3b2_mac_watchdog_task(&p->mac);
2289577e9bbeSKip Macy if (status == 1)
2290577e9bbeSKip Macy p->mac.stats.num_toggled++;
2291577e9bbeSKip Macy else if (status == 2) {
2292577e9bbeSKip Macy struct cmac *mac = &p->mac;
2293577e9bbeSKip Macy
22943f345a5dSKip Macy cxgb_update_mac_settings(p);
2295577e9bbeSKip Macy t3_link_start(&p->phy, mac, &p->link_config);
2296577e9bbeSKip Macy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
22973f345a5dSKip Macy t3_port_intr_enable(sc, p->port_id);
2298577e9bbeSKip Macy p->mac.stats.num_resets++;
2299577e9bbeSKip Macy }
2300577e9bbeSKip Macy PORT_UNLOCK(p);
2301577e9bbeSKip Macy }
2302577e9bbeSKip Macy }
2303577e9bbeSKip Macy
2304577e9bbeSKip Macy static void
cxgb_tick(void * arg)2305577e9bbeSKip Macy cxgb_tick(void *arg)
2306577e9bbeSKip Macy {
2307577e9bbeSKip Macy adapter_t *sc = (adapter_t *)arg;
23088090c9f5SKip Macy
23098e10660fSKip Macy if (sc->flags & CXGB_SHUTDOWN)
23108090c9f5SKip Macy return;
2311577e9bbeSKip Macy
2312bb38cd2fSKip Macy taskqueue_enqueue(sc->tq, &sc->tick_task);
2313bd1a9fbaSNavdeep Parhar callout_reset(&sc->cxgb_tick_ch, hz, cxgb_tick, sc);
2314bb38cd2fSKip Macy }
2315bb38cd2fSKip Macy
2316e26e6373SNavdeep Parhar void
cxgb_refresh_stats(struct port_info * pi)2317e26e6373SNavdeep Parhar cxgb_refresh_stats(struct port_info *pi)
2318e26e6373SNavdeep Parhar {
2319e26e6373SNavdeep Parhar struct timeval tv;
2320e26e6373SNavdeep Parhar const struct timeval interval = {0, 250000}; /* 250ms */
2321e26e6373SNavdeep Parhar
2322e26e6373SNavdeep Parhar getmicrotime(&tv);
2323e26e6373SNavdeep Parhar timevalsub(&tv, &interval);
2324e26e6373SNavdeep Parhar if (timevalcmp(&tv, &pi->last_refreshed, <))
2325e26e6373SNavdeep Parhar return;
2326e26e6373SNavdeep Parhar
2327e26e6373SNavdeep Parhar PORT_LOCK(pi);
2328e26e6373SNavdeep Parhar t3_mac_update_stats(&pi->mac);
2329e26e6373SNavdeep Parhar PORT_UNLOCK(pi);
2330e26e6373SNavdeep Parhar getmicrotime(&pi->last_refreshed);
2331e26e6373SNavdeep Parhar }
2332e26e6373SNavdeep Parhar
2333bb38cd2fSKip Macy static void
cxgb_tick_handler(void * arg,int count)2334bb38cd2fSKip Macy cxgb_tick_handler(void *arg, int count)
2335bb38cd2fSKip Macy {
2336bb38cd2fSKip Macy adapter_t *sc = (adapter_t *)arg;
2337bb38cd2fSKip Macy const struct adapter_params *p = &sc->params;
2338706cb31fSKip Macy int i;
2339f2d8ff04SGeorge V. Neville-Neil uint32_t cause, reset;
2340bb38cd2fSKip Macy
23410bbdea77SGeorge V. Neville-Neil if (sc->flags & CXGB_SHUTDOWN || !(sc->flags & FULL_INIT_DONE))
23428e10660fSKip Macy return;
23438e10660fSKip Macy
2344f35c2d65SKip Macy if (p->rev == T3_REV_B2 && p->nports < 4 && sc->open_device_map)
2345f35c2d65SKip Macy check_t3b2_mac(sc);
2346f35c2d65SKip Macy
2347489ca05bSNavdeep Parhar cause = t3_read_reg(sc, A_SG_INT_CAUSE) & (F_RSPQSTARVE | F_FLEMPTY);
2348489ca05bSNavdeep Parhar if (cause) {
2349f2d8ff04SGeorge V. Neville-Neil struct sge_qset *qs = &sc->sge.qs[0];
2350489ca05bSNavdeep Parhar uint32_t mask, v;
2351f2d8ff04SGeorge V. Neville-Neil
2352489ca05bSNavdeep Parhar v = t3_read_reg(sc, A_SG_RSPQ_FL_STATUS) & ~0xff00;
2353f2d8ff04SGeorge V. Neville-Neil
2354489ca05bSNavdeep Parhar mask = 1;
2355489ca05bSNavdeep Parhar for (i = 0; i < SGE_QSETS; i++) {
2356489ca05bSNavdeep Parhar if (v & mask)
2357489ca05bSNavdeep Parhar qs[i].rspq.starved++;
2358489ca05bSNavdeep Parhar mask <<= 1;
2359f2d8ff04SGeorge V. Neville-Neil }
2360489ca05bSNavdeep Parhar
2361489ca05bSNavdeep Parhar mask <<= SGE_QSETS; /* skip RSPQXDISABLED */
2362489ca05bSNavdeep Parhar
2363489ca05bSNavdeep Parhar for (i = 0; i < SGE_QSETS * 2; i++) {
2364489ca05bSNavdeep Parhar if (v & mask) {
2365489ca05bSNavdeep Parhar qs[i / 2].fl[i % 2].empty++;
2366f2d8ff04SGeorge V. Neville-Neil }
2367489ca05bSNavdeep Parhar mask <<= 1;
2368489ca05bSNavdeep Parhar }
2369489ca05bSNavdeep Parhar
2370489ca05bSNavdeep Parhar /* clear */
2371489ca05bSNavdeep Parhar t3_write_reg(sc, A_SG_RSPQ_FL_STATUS, v);
2372489ca05bSNavdeep Parhar t3_write_reg(sc, A_SG_INT_CAUSE, cause);
2373489ca05bSNavdeep Parhar }
2374f2d8ff04SGeorge V. Neville-Neil
2375ceac50ebSKip Macy for (i = 0; i < sc->params.nports; i++) {
2376ceac50ebSKip Macy struct port_info *pi = &sc->port[i];
2377f2d8ff04SGeorge V. Neville-Neil struct cmac *mac = &pi->mac;
23783f345a5dSKip Macy
23793f345a5dSKip Macy if (!isset(&sc->open_device_map, pi->port_id))
23803f345a5dSKip Macy continue;
23813f345a5dSKip Macy
2382e26e6373SNavdeep Parhar cxgb_refresh_stats(pi);
2383f2d8ff04SGeorge V. Neville-Neil
2384f2d8ff04SGeorge V. Neville-Neil if (mac->multiport)
2385f2d8ff04SGeorge V. Neville-Neil continue;
2386f2d8ff04SGeorge V. Neville-Neil
2387f2d8ff04SGeorge V. Neville-Neil /* Count rx fifo overflows, once per second */
2388f2d8ff04SGeorge V. Neville-Neil cause = t3_read_reg(sc, A_XGM_INT_CAUSE + mac->offset);
2389f2d8ff04SGeorge V. Neville-Neil reset = 0;
2390f2d8ff04SGeorge V. Neville-Neil if (cause & F_RXFIFO_OVERFLOW) {
2391f2d8ff04SGeorge V. Neville-Neil mac->stats.rx_fifo_ovfl++;
2392f2d8ff04SGeorge V. Neville-Neil reset |= F_RXFIFO_OVERFLOW;
2393f2d8ff04SGeorge V. Neville-Neil }
2394f2d8ff04SGeorge V. Neville-Neil t3_write_reg(sc, A_XGM_INT_CAUSE + mac->offset, reset);
2395ceac50ebSKip Macy }
2396577e9bbeSKip Macy }
2397577e9bbeSKip Macy
23987ac2e6c3SKip Macy static void
touch_bars(device_t dev)23997ac2e6c3SKip Macy touch_bars(device_t dev)
24007ac2e6c3SKip Macy {
24017ac2e6c3SKip Macy /*
24027ac2e6c3SKip Macy * Don't enable yet
24037ac2e6c3SKip Macy */
24047ac2e6c3SKip Macy #if !defined(__LP64__) && 0
24057ac2e6c3SKip Macy u32 v;
24067ac2e6c3SKip Macy
24077ac2e6c3SKip Macy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &v);
24087ac2e6c3SKip Macy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, v);
24097ac2e6c3SKip Macy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3, &v);
24107ac2e6c3SKip Macy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_3, v);
24117ac2e6c3SKip Macy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &v);
24127ac2e6c3SKip Macy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_5, v);
24137ac2e6c3SKip Macy #endif
24147ac2e6c3SKip Macy }
24157ac2e6c3SKip Macy
2416ac3a6d9cSKip Macy static int
set_eeprom(struct port_info * pi,const uint8_t * data,int len,int offset)2417ac3a6d9cSKip Macy set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset)
2418ac3a6d9cSKip Macy {
2419ac3a6d9cSKip Macy uint8_t *buf;
2420ac3a6d9cSKip Macy int err = 0;
2421ac3a6d9cSKip Macy u32 aligned_offset, aligned_len, *p;
2422ac3a6d9cSKip Macy struct adapter *adapter = pi->adapter;
2423ac3a6d9cSKip Macy
2424ac3a6d9cSKip Macy
2425ac3a6d9cSKip Macy aligned_offset = offset & ~3;
2426ac3a6d9cSKip Macy aligned_len = (len + (offset & 3) + 3) & ~3;
2427ac3a6d9cSKip Macy
2428ac3a6d9cSKip Macy if (aligned_offset != offset || aligned_len != len) {
2429ac3a6d9cSKip Macy buf = malloc(aligned_len, M_DEVBUF, M_WAITOK | M_ZERO);
2430ac3a6d9cSKip Macy err = t3_seeprom_read(adapter, aligned_offset, (u32 *)buf);
2431ac3a6d9cSKip Macy if (!err && aligned_len > 4)
2432ac3a6d9cSKip Macy err = t3_seeprom_read(adapter,
2433ac3a6d9cSKip Macy aligned_offset + aligned_len - 4,
2434ac3a6d9cSKip Macy (u32 *)&buf[aligned_len - 4]);
2435ac3a6d9cSKip Macy if (err)
2436ac3a6d9cSKip Macy goto out;
2437ac3a6d9cSKip Macy memcpy(buf + (offset & 3), data, len);
2438ac3a6d9cSKip Macy } else
2439ac3a6d9cSKip Macy buf = (uint8_t *)(uintptr_t)data;
2440ac3a6d9cSKip Macy
2441ac3a6d9cSKip Macy err = t3_seeprom_wp(adapter, 0);
2442ac3a6d9cSKip Macy if (err)
2443ac3a6d9cSKip Macy goto out;
2444ac3a6d9cSKip Macy
2445ac3a6d9cSKip Macy for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) {
2446ac3a6d9cSKip Macy err = t3_seeprom_write(adapter, aligned_offset, *p);
2447ac3a6d9cSKip Macy aligned_offset += 4;
2448ac3a6d9cSKip Macy }
2449ac3a6d9cSKip Macy
2450ac3a6d9cSKip Macy if (!err)
2451ac3a6d9cSKip Macy err = t3_seeprom_wp(adapter, 1);
2452ac3a6d9cSKip Macy out:
2453ac3a6d9cSKip Macy if (buf != data)
2454ac3a6d9cSKip Macy free(buf, M_DEVBUF);
2455ac3a6d9cSKip Macy return err;
2456ac3a6d9cSKip Macy }
2457ac3a6d9cSKip Macy
2458ac3a6d9cSKip Macy
2459b6d90eb7SKip Macy static int
in_range(int val,int lo,int hi)2460b6d90eb7SKip Macy in_range(int val, int lo, int hi)
2461b6d90eb7SKip Macy {
2462b6d90eb7SKip Macy return val < 0 || (val <= hi && val >= lo);
2463b6d90eb7SKip Macy }
2464b6d90eb7SKip Macy
2465b6d90eb7SKip Macy static int
cxgb_extension_open(struct cdev * dev,int flags,int fmp,struct thread * td)246600b4e54aSWarner Losh cxgb_extension_open(struct cdev *dev, int flags, int fmp, struct thread *td)
2467ef72318fSKip Macy {
2468ef72318fSKip Macy return (0);
2469ef72318fSKip Macy }
2470ef72318fSKip Macy
2471ef72318fSKip Macy static int
cxgb_extension_close(struct cdev * dev,int flags,int fmt,struct thread * td)247200b4e54aSWarner Losh cxgb_extension_close(struct cdev *dev, int flags, int fmt, struct thread *td)
2473ef72318fSKip Macy {
2474ef72318fSKip Macy return (0);
2475ef72318fSKip Macy }
2476ef72318fSKip Macy
2477ef72318fSKip Macy static int
cxgb_extension_ioctl(struct cdev * dev,unsigned long cmd,caddr_t data,int fflag,struct thread * td)2478b6d90eb7SKip Macy cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data,
2479b6d90eb7SKip Macy int fflag, struct thread *td)
2480b6d90eb7SKip Macy {
2481b6d90eb7SKip Macy int mmd, error = 0;
2482b6d90eb7SKip Macy struct port_info *pi = dev->si_drv1;
2483b6d90eb7SKip Macy adapter_t *sc = pi->adapter;
2484b6d90eb7SKip Macy
2485b6d90eb7SKip Macy #ifdef PRIV_SUPPORTED
2486b6d90eb7SKip Macy if (priv_check(td, PRIV_DRIVER)) {
2487b6d90eb7SKip Macy if (cxgb_debug)
2488b6d90eb7SKip Macy printf("user does not have access to privileged ioctls\n");
2489b6d90eb7SKip Macy return (EPERM);
2490b6d90eb7SKip Macy }
2491b6d90eb7SKip Macy #else
2492b6d90eb7SKip Macy if (suser(td)) {
2493b6d90eb7SKip Macy if (cxgb_debug)
2494b6d90eb7SKip Macy printf("user does not have access to privileged ioctls\n");
2495b6d90eb7SKip Macy return (EPERM);
2496b6d90eb7SKip Macy }
2497b6d90eb7SKip Macy #endif
2498b6d90eb7SKip Macy
2499b6d90eb7SKip Macy switch (cmd) {
25001ffd6e58SKip Macy case CHELSIO_GET_MIIREG: {
2501b6d90eb7SKip Macy uint32_t val;
2502b6d90eb7SKip Macy struct cphy *phy = &pi->phy;
25031ffd6e58SKip Macy struct ch_mii_data *mid = (struct ch_mii_data *)data;
2504b6d90eb7SKip Macy
2505b6d90eb7SKip Macy if (!phy->mdio_read)
2506b6d90eb7SKip Macy return (EOPNOTSUPP);
2507b6d90eb7SKip Macy if (is_10G(sc)) {
2508b6d90eb7SKip Macy mmd = mid->phy_id >> 8;
2509b6d90eb7SKip Macy if (!mmd)
2510b6d90eb7SKip Macy mmd = MDIO_DEV_PCS;
25110c1ff9c6SGeorge V. Neville-Neil else if (mmd > MDIO_DEV_VEND2)
2512ac3a6d9cSKip Macy return (EINVAL);
2513b6d90eb7SKip Macy
2514b6d90eb7SKip Macy error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd,
2515b6d90eb7SKip Macy mid->reg_num, &val);
2516b6d90eb7SKip Macy } else
2517b6d90eb7SKip Macy error = phy->mdio_read(sc, mid->phy_id & 0x1f, 0,
2518b6d90eb7SKip Macy mid->reg_num & 0x1f, &val);
2519b6d90eb7SKip Macy if (error == 0)
2520b6d90eb7SKip Macy mid->val_out = val;
2521b6d90eb7SKip Macy break;
2522b6d90eb7SKip Macy }
25231ffd6e58SKip Macy case CHELSIO_SET_MIIREG: {
2524b6d90eb7SKip Macy struct cphy *phy = &pi->phy;
25251ffd6e58SKip Macy struct ch_mii_data *mid = (struct ch_mii_data *)data;
2526b6d90eb7SKip Macy
2527b6d90eb7SKip Macy if (!phy->mdio_write)
2528b6d90eb7SKip Macy return (EOPNOTSUPP);
2529b6d90eb7SKip Macy if (is_10G(sc)) {
2530b6d90eb7SKip Macy mmd = mid->phy_id >> 8;
2531b6d90eb7SKip Macy if (!mmd)
2532b6d90eb7SKip Macy mmd = MDIO_DEV_PCS;
25330c1ff9c6SGeorge V. Neville-Neil else if (mmd > MDIO_DEV_VEND2)
2534b6d90eb7SKip Macy return (EINVAL);
2535b6d90eb7SKip Macy
2536b6d90eb7SKip Macy error = phy->mdio_write(sc, mid->phy_id & 0x1f,
2537b6d90eb7SKip Macy mmd, mid->reg_num, mid->val_in);
2538b6d90eb7SKip Macy } else
2539b6d90eb7SKip Macy error = phy->mdio_write(sc, mid->phy_id & 0x1f, 0,
2540b6d90eb7SKip Macy mid->reg_num & 0x1f,
2541b6d90eb7SKip Macy mid->val_in);
2542b6d90eb7SKip Macy break;
2543b6d90eb7SKip Macy }
2544b6d90eb7SKip Macy case CHELSIO_SETREG: {
2545b6d90eb7SKip Macy struct ch_reg *edata = (struct ch_reg *)data;
2546b6d90eb7SKip Macy if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2547b6d90eb7SKip Macy return (EFAULT);
2548b6d90eb7SKip Macy t3_write_reg(sc, edata->addr, edata->val);
2549b6d90eb7SKip Macy break;
2550b6d90eb7SKip Macy }
2551b6d90eb7SKip Macy case CHELSIO_GETREG: {
2552b6d90eb7SKip Macy struct ch_reg *edata = (struct ch_reg *)data;
2553b6d90eb7SKip Macy if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len)
2554b6d90eb7SKip Macy return (EFAULT);
2555b6d90eb7SKip Macy edata->val = t3_read_reg(sc, edata->addr);
2556b6d90eb7SKip Macy break;
2557b6d90eb7SKip Macy }
2558b6d90eb7SKip Macy case CHELSIO_GET_SGE_CONTEXT: {
2559b6d90eb7SKip Macy struct ch_cntxt *ecntxt = (struct ch_cntxt *)data;
25608e10660fSKip Macy mtx_lock_spin(&sc->sge.reg_lock);
2561b6d90eb7SKip Macy switch (ecntxt->cntxt_type) {
2562b6d90eb7SKip Macy case CNTXT_TYPE_EGRESS:
25631ffd6e58SKip Macy error = -t3_sge_read_ecntxt(sc, ecntxt->cntxt_id,
2564b6d90eb7SKip Macy ecntxt->data);
2565b6d90eb7SKip Macy break;
2566b6d90eb7SKip Macy case CNTXT_TYPE_FL:
25671ffd6e58SKip Macy error = -t3_sge_read_fl(sc, ecntxt->cntxt_id,
2568b6d90eb7SKip Macy ecntxt->data);
2569b6d90eb7SKip Macy break;
2570b6d90eb7SKip Macy case CNTXT_TYPE_RSP:
25711ffd6e58SKip Macy error = -t3_sge_read_rspq(sc, ecntxt->cntxt_id,
2572b6d90eb7SKip Macy ecntxt->data);
2573b6d90eb7SKip Macy break;
2574b6d90eb7SKip Macy case CNTXT_TYPE_CQ:
25751ffd6e58SKip Macy error = -t3_sge_read_cq(sc, ecntxt->cntxt_id,
2576b6d90eb7SKip Macy ecntxt->data);
2577b6d90eb7SKip Macy break;
2578b6d90eb7SKip Macy default:
2579b6d90eb7SKip Macy error = EINVAL;
2580b6d90eb7SKip Macy break;
2581b6d90eb7SKip Macy }
25828e10660fSKip Macy mtx_unlock_spin(&sc->sge.reg_lock);
2583b6d90eb7SKip Macy break;
2584b6d90eb7SKip Macy }
2585b6d90eb7SKip Macy case CHELSIO_GET_SGE_DESC: {
2586b6d90eb7SKip Macy struct ch_desc *edesc = (struct ch_desc *)data;
2587b6d90eb7SKip Macy int ret;
2588b6d90eb7SKip Macy if (edesc->queue_num >= SGE_QSETS * 6)
2589b6d90eb7SKip Macy return (EINVAL);
2590b6d90eb7SKip Macy ret = t3_get_desc(&sc->sge.qs[edesc->queue_num / 6],
2591b6d90eb7SKip Macy edesc->queue_num % 6, edesc->idx, edesc->data);
2592b6d90eb7SKip Macy if (ret < 0)
2593b6d90eb7SKip Macy return (EINVAL);
2594b6d90eb7SKip Macy edesc->size = ret;
2595b6d90eb7SKip Macy break;
2596b6d90eb7SKip Macy }
2597b6d90eb7SKip Macy case CHELSIO_GET_QSET_PARAMS: {
2598b6d90eb7SKip Macy struct qset_params *q;
2599b6d90eb7SKip Macy struct ch_qset_params *t = (struct ch_qset_params *)data;
26001ffd6e58SKip Macy int q1 = pi->first_qset;
26011ffd6e58SKip Macy int nqsets = pi->nqsets;
26021ffd6e58SKip Macy int i;
2603b6d90eb7SKip Macy
26041ffd6e58SKip Macy if (t->qset_idx >= nqsets)
26051ffd6e58SKip Macy return EINVAL;
2606b6d90eb7SKip Macy
26071ffd6e58SKip Macy i = q1 + t->qset_idx;
26081ffd6e58SKip Macy q = &sc->params.sge.qset[i];
2609b6d90eb7SKip Macy t->rspq_size = q->rspq_size;
2610b6d90eb7SKip Macy t->txq_size[0] = q->txq_size[0];
2611b6d90eb7SKip Macy t->txq_size[1] = q->txq_size[1];
2612b6d90eb7SKip Macy t->txq_size[2] = q->txq_size[2];
2613b6d90eb7SKip Macy t->fl_size[0] = q->fl_size;
2614b6d90eb7SKip Macy t->fl_size[1] = q->jumbo_size;
2615b6d90eb7SKip Macy t->polling = q->polling;
26161ffd6e58SKip Macy t->lro = q->lro;
26174af83c8cSKip Macy t->intr_lat = q->coalesce_usecs;
2618b6d90eb7SKip Macy t->cong_thres = q->cong_thres;
26191ffd6e58SKip Macy t->qnum = i;
2620b6d90eb7SKip Macy
26211d609d51SNavdeep Parhar if ((sc->flags & FULL_INIT_DONE) == 0)
26221d609d51SNavdeep Parhar t->vector = 0;
26231d609d51SNavdeep Parhar else if (sc->flags & USING_MSIX)
26241ffd6e58SKip Macy t->vector = rman_get_start(sc->msix_irq_res[i]);
26251ffd6e58SKip Macy else
26261ffd6e58SKip Macy t->vector = rman_get_start(sc->irq_res);
26271ffd6e58SKip Macy
2628b6d90eb7SKip Macy break;
2629b6d90eb7SKip Macy }
2630b6d90eb7SKip Macy case CHELSIO_GET_QSET_NUM: {
2631b6d90eb7SKip Macy struct ch_reg *edata = (struct ch_reg *)data;
2632b6d90eb7SKip Macy edata->val = pi->nqsets;
2633b6d90eb7SKip Macy break;
2634b6d90eb7SKip Macy }
26351ffd6e58SKip Macy case CHELSIO_LOAD_FW: {
26361ffd6e58SKip Macy uint8_t *fw_data;
26371ffd6e58SKip Macy uint32_t vers;
26381ffd6e58SKip Macy struct ch_mem_range *t = (struct ch_mem_range *)data;
26391ffd6e58SKip Macy
26401ffd6e58SKip Macy /*
26411ffd6e58SKip Macy * You're allowed to load a firmware only before FULL_INIT_DONE
26421ffd6e58SKip Macy *
26431ffd6e58SKip Macy * FW_UPTODATE is also set so the rest of the initialization
26441ffd6e58SKip Macy * will not overwrite what was loaded here. This gives you the
26451ffd6e58SKip Macy * flexibility to load any firmware (and maybe shoot yourself in
26461ffd6e58SKip Macy * the foot).
26471ffd6e58SKip Macy */
26481ffd6e58SKip Macy
26491ffd6e58SKip Macy ADAPTER_LOCK(sc);
26501ffd6e58SKip Macy if (sc->open_device_map || sc->flags & FULL_INIT_DONE) {
26511ffd6e58SKip Macy ADAPTER_UNLOCK(sc);
26521ffd6e58SKip Macy return (EBUSY);
26531ffd6e58SKip Macy }
26541ffd6e58SKip Macy
26551ffd6e58SKip Macy fw_data = malloc(t->len, M_DEVBUF, M_NOWAIT);
26561ffd6e58SKip Macy if (!fw_data)
26571ffd6e58SKip Macy error = ENOMEM;
26581ffd6e58SKip Macy else
26591ffd6e58SKip Macy error = copyin(t->buf, fw_data, t->len);
26601ffd6e58SKip Macy
26611ffd6e58SKip Macy if (!error)
26621ffd6e58SKip Macy error = -t3_load_fw(sc, fw_data, t->len);
26631ffd6e58SKip Macy
26641ffd6e58SKip Macy if (t3_get_fw_version(sc, &vers) == 0) {
26651ffd6e58SKip Macy snprintf(&sc->fw_version[0], sizeof(sc->fw_version),
26661ffd6e58SKip Macy "%d.%d.%d", G_FW_VERSION_MAJOR(vers),
26671ffd6e58SKip Macy G_FW_VERSION_MINOR(vers), G_FW_VERSION_MICRO(vers));
26681ffd6e58SKip Macy }
26691ffd6e58SKip Macy
26701ffd6e58SKip Macy if (!error)
26711ffd6e58SKip Macy sc->flags |= FW_UPTODATE;
26721ffd6e58SKip Macy
26731ffd6e58SKip Macy free(fw_data, M_DEVBUF);
26741ffd6e58SKip Macy ADAPTER_UNLOCK(sc);
2675b6d90eb7SKip Macy break;
26761ffd6e58SKip Macy }
26771ffd6e58SKip Macy case CHELSIO_LOAD_BOOT: {
26781ffd6e58SKip Macy uint8_t *boot_data;
26791ffd6e58SKip Macy struct ch_mem_range *t = (struct ch_mem_range *)data;
26801ffd6e58SKip Macy
26811ffd6e58SKip Macy boot_data = malloc(t->len, M_DEVBUF, M_NOWAIT);
26821ffd6e58SKip Macy if (!boot_data)
26831ffd6e58SKip Macy return ENOMEM;
26841ffd6e58SKip Macy
26851ffd6e58SKip Macy error = copyin(t->buf, boot_data, t->len);
26861ffd6e58SKip Macy if (!error)
26871ffd6e58SKip Macy error = -t3_load_boot(sc, boot_data, t->len);
26881ffd6e58SKip Macy
26891ffd6e58SKip Macy free(boot_data, M_DEVBUF);
26901ffd6e58SKip Macy break;
26911ffd6e58SKip Macy }
26921ffd6e58SKip Macy case CHELSIO_GET_PM: {
26931ffd6e58SKip Macy struct ch_pm *m = (struct ch_pm *)data;
26941ffd6e58SKip Macy struct tp_params *p = &sc->params.tp;
26951ffd6e58SKip Macy
26961ffd6e58SKip Macy if (!is_offload(sc))
26971ffd6e58SKip Macy return (EOPNOTSUPP);
26981ffd6e58SKip Macy
26991ffd6e58SKip Macy m->tx_pg_sz = p->tx_pg_size;
27001ffd6e58SKip Macy m->tx_num_pg = p->tx_num_pgs;
27011ffd6e58SKip Macy m->rx_pg_sz = p->rx_pg_size;
27021ffd6e58SKip Macy m->rx_num_pg = p->rx_num_pgs;
27031ffd6e58SKip Macy m->pm_total = p->pmtx_size + p->chan_rx_size * p->nchan;
27041ffd6e58SKip Macy
27051ffd6e58SKip Macy break;
27061ffd6e58SKip Macy }
27071ffd6e58SKip Macy case CHELSIO_SET_PM: {
27081ffd6e58SKip Macy struct ch_pm *m = (struct ch_pm *)data;
27091ffd6e58SKip Macy struct tp_params *p = &sc->params.tp;
27101ffd6e58SKip Macy
27111ffd6e58SKip Macy if (!is_offload(sc))
27121ffd6e58SKip Macy return (EOPNOTSUPP);
27131ffd6e58SKip Macy if (sc->flags & FULL_INIT_DONE)
27141ffd6e58SKip Macy return (EBUSY);
27151ffd6e58SKip Macy
27161ffd6e58SKip Macy if (!m->rx_pg_sz || (m->rx_pg_sz & (m->rx_pg_sz - 1)) ||
27171ffd6e58SKip Macy !m->tx_pg_sz || (m->tx_pg_sz & (m->tx_pg_sz - 1)))
27181ffd6e58SKip Macy return (EINVAL); /* not power of 2 */
27191ffd6e58SKip Macy if (!(m->rx_pg_sz & 0x14000))
27201ffd6e58SKip Macy return (EINVAL); /* not 16KB or 64KB */
27211ffd6e58SKip Macy if (!(m->tx_pg_sz & 0x1554000))
27221ffd6e58SKip Macy return (EINVAL);
27231ffd6e58SKip Macy if (m->tx_num_pg == -1)
27241ffd6e58SKip Macy m->tx_num_pg = p->tx_num_pgs;
27251ffd6e58SKip Macy if (m->rx_num_pg == -1)
27261ffd6e58SKip Macy m->rx_num_pg = p->rx_num_pgs;
27271ffd6e58SKip Macy if (m->tx_num_pg % 24 || m->rx_num_pg % 24)
27281ffd6e58SKip Macy return (EINVAL);
27291ffd6e58SKip Macy if (m->rx_num_pg * m->rx_pg_sz > p->chan_rx_size ||
27301ffd6e58SKip Macy m->tx_num_pg * m->tx_pg_sz > p->chan_tx_size)
27311ffd6e58SKip Macy return (EINVAL);
27321ffd6e58SKip Macy
27331ffd6e58SKip Macy p->rx_pg_size = m->rx_pg_sz;
27341ffd6e58SKip Macy p->tx_pg_size = m->tx_pg_sz;
27351ffd6e58SKip Macy p->rx_num_pgs = m->rx_num_pg;
27361ffd6e58SKip Macy p->tx_num_pgs = m->tx_num_pg;
27371ffd6e58SKip Macy break;
27381ffd6e58SKip Macy }
2739d722cab4SKip Macy case CHELSIO_SETMTUTAB: {
2740d722cab4SKip Macy struct ch_mtus *m = (struct ch_mtus *)data;
2741d722cab4SKip Macy int i;
2742d722cab4SKip Macy
2743d722cab4SKip Macy if (!is_offload(sc))
2744d722cab4SKip Macy return (EOPNOTSUPP);
2745d722cab4SKip Macy if (offload_running(sc))
2746d722cab4SKip Macy return (EBUSY);
2747d722cab4SKip Macy if (m->nmtus != NMTUS)
2748d722cab4SKip Macy return (EINVAL);
2749d722cab4SKip Macy if (m->mtus[0] < 81) /* accommodate SACK */
2750d722cab4SKip Macy return (EINVAL);
2751d722cab4SKip Macy
2752d722cab4SKip Macy /*
2753d722cab4SKip Macy * MTUs must be in ascending order
2754d722cab4SKip Macy */
2755d722cab4SKip Macy for (i = 1; i < NMTUS; ++i)
2756d722cab4SKip Macy if (m->mtus[i] < m->mtus[i - 1])
2757d722cab4SKip Macy return (EINVAL);
2758d722cab4SKip Macy
27591ffd6e58SKip Macy memcpy(sc->params.mtus, m->mtus, sizeof(sc->params.mtus));
2760d722cab4SKip Macy break;
2761d722cab4SKip Macy }
2762d722cab4SKip Macy case CHELSIO_GETMTUTAB: {
2763d722cab4SKip Macy struct ch_mtus *m = (struct ch_mtus *)data;
2764d722cab4SKip Macy
2765d722cab4SKip Macy if (!is_offload(sc))
2766d722cab4SKip Macy return (EOPNOTSUPP);
2767d722cab4SKip Macy
2768d722cab4SKip Macy memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus));
2769d722cab4SKip Macy m->nmtus = NMTUS;
2770d722cab4SKip Macy break;
2771d722cab4SKip Macy }
2772b6d90eb7SKip Macy case CHELSIO_GET_MEM: {
2773b6d90eb7SKip Macy struct ch_mem_range *t = (struct ch_mem_range *)data;
2774b6d90eb7SKip Macy struct mc7 *mem;
2775b6d90eb7SKip Macy uint8_t *useraddr;
2776b6d90eb7SKip Macy u64 buf[32];
2777b6d90eb7SKip Macy
27781ffd6e58SKip Macy /*
27796bccea7cSRebecca Cran * Use these to avoid modifying len/addr in the return
27801ffd6e58SKip Macy * struct
27811ffd6e58SKip Macy */
27821ffd6e58SKip Macy uint32_t len = t->len, addr = t->addr;
27831ffd6e58SKip Macy
2784b6d90eb7SKip Macy if (!is_offload(sc))
2785b6d90eb7SKip Macy return (EOPNOTSUPP);
2786b6d90eb7SKip Macy if (!(sc->flags & FULL_INIT_DONE))
2787b6d90eb7SKip Macy return (EIO); /* need the memory controllers */
27881ffd6e58SKip Macy if ((addr & 0x7) || (len & 0x7))
2789b6d90eb7SKip Macy return (EINVAL);
2790b6d90eb7SKip Macy if (t->mem_id == MEM_CM)
2791b6d90eb7SKip Macy mem = &sc->cm;
2792b6d90eb7SKip Macy else if (t->mem_id == MEM_PMRX)
2793b6d90eb7SKip Macy mem = &sc->pmrx;
2794b6d90eb7SKip Macy else if (t->mem_id == MEM_PMTX)
2795b6d90eb7SKip Macy mem = &sc->pmtx;
2796b6d90eb7SKip Macy else
2797b6d90eb7SKip Macy return (EINVAL);
2798b6d90eb7SKip Macy
2799b6d90eb7SKip Macy /*
2800b6d90eb7SKip Macy * Version scheme:
2801b6d90eb7SKip Macy * bits 0..9: chip version
2802b6d90eb7SKip Macy * bits 10..15: chip revision
2803b6d90eb7SKip Macy */
2804b6d90eb7SKip Macy t->version = 3 | (sc->params.rev << 10);
2805b6d90eb7SKip Macy
2806b6d90eb7SKip Macy /*
2807b6d90eb7SKip Macy * Read 256 bytes at a time as len can be large and we don't
2808b6d90eb7SKip Macy * want to use huge intermediate buffers.
2809b6d90eb7SKip Macy */
28108090c9f5SKip Macy useraddr = (uint8_t *)t->buf;
28111ffd6e58SKip Macy while (len) {
28121ffd6e58SKip Macy unsigned int chunk = min(len, sizeof(buf));
2813b6d90eb7SKip Macy
28141ffd6e58SKip Macy error = t3_mc7_bd_read(mem, addr / 8, chunk / 8, buf);
2815b6d90eb7SKip Macy if (error)
2816b6d90eb7SKip Macy return (-error);
2817b6d90eb7SKip Macy if (copyout(buf, useraddr, chunk))
2818b6d90eb7SKip Macy return (EFAULT);
2819b6d90eb7SKip Macy useraddr += chunk;
28201ffd6e58SKip Macy addr += chunk;
28211ffd6e58SKip Macy len -= chunk;
2822b6d90eb7SKip Macy }
2823b6d90eb7SKip Macy break;
2824b6d90eb7SKip Macy }
2825d722cab4SKip Macy case CHELSIO_READ_TCAM_WORD: {
2826d722cab4SKip Macy struct ch_tcam_word *t = (struct ch_tcam_word *)data;
2827d722cab4SKip Macy
2828d722cab4SKip Macy if (!is_offload(sc))
2829d722cab4SKip Macy return (EOPNOTSUPP);
2830ac3a6d9cSKip Macy if (!(sc->flags & FULL_INIT_DONE))
2831ac3a6d9cSKip Macy return (EIO); /* need MC5 */
2832d722cab4SKip Macy return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf);
2833d722cab4SKip Macy break;
2834d722cab4SKip Macy }
2835b6d90eb7SKip Macy case CHELSIO_SET_TRACE_FILTER: {
2836b6d90eb7SKip Macy struct ch_trace *t = (struct ch_trace *)data;
2837b6d90eb7SKip Macy const struct trace_params *tp;
2838b6d90eb7SKip Macy
2839b6d90eb7SKip Macy tp = (const struct trace_params *)&t->sip;
2840b6d90eb7SKip Macy if (t->config_tx)
2841b6d90eb7SKip Macy t3_config_trace_filter(sc, tp, 0, t->invert_match,
2842b6d90eb7SKip Macy t->trace_tx);
2843b6d90eb7SKip Macy if (t->config_rx)
2844b6d90eb7SKip Macy t3_config_trace_filter(sc, tp, 1, t->invert_match,
2845b6d90eb7SKip Macy t->trace_rx);
2846b6d90eb7SKip Macy break;
2847b6d90eb7SKip Macy }
2848b6d90eb7SKip Macy case CHELSIO_SET_PKTSCHED: {
2849b6d90eb7SKip Macy struct ch_pktsched_params *p = (struct ch_pktsched_params *)data;
2850b6d90eb7SKip Macy if (sc->open_device_map == 0)
2851b6d90eb7SKip Macy return (EAGAIN);
2852b6d90eb7SKip Macy send_pktsched_cmd(sc, p->sched, p->idx, p->min, p->max,
2853b6d90eb7SKip Macy p->binding);
2854b6d90eb7SKip Macy break;
2855b6d90eb7SKip Macy }
2856b6d90eb7SKip Macy case CHELSIO_IFCONF_GETREGS: {
28571ffd6e58SKip Macy struct ch_ifconf_regs *regs = (struct ch_ifconf_regs *)data;
2858b6d90eb7SKip Macy int reglen = cxgb_get_regs_len();
28591ffd6e58SKip Macy uint8_t *buf = malloc(reglen, M_DEVBUF, M_NOWAIT);
2860b6d90eb7SKip Macy if (buf == NULL) {
2861b6d90eb7SKip Macy return (ENOMEM);
2862b6d90eb7SKip Macy }
28631ffd6e58SKip Macy if (regs->len > reglen)
28641ffd6e58SKip Macy regs->len = reglen;
28651ffd6e58SKip Macy else if (regs->len < reglen)
2866f2d8ff04SGeorge V. Neville-Neil error = ENOBUFS;
28671ffd6e58SKip Macy
28681ffd6e58SKip Macy if (!error) {
2869b6d90eb7SKip Macy cxgb_get_regs(sc, regs, buf);
2870b6d90eb7SKip Macy error = copyout(buf, regs->data, reglen);
28711ffd6e58SKip Macy }
2872b6d90eb7SKip Macy free(buf, M_DEVBUF);
2873b6d90eb7SKip Macy
2874b6d90eb7SKip Macy break;
2875b6d90eb7SKip Macy }
2876d722cab4SKip Macy case CHELSIO_SET_HW_SCHED: {
2877d722cab4SKip Macy struct ch_hw_sched *t = (struct ch_hw_sched *)data;
2878d722cab4SKip Macy unsigned int ticks_per_usec = core_ticks_per_usec(sc);
2879d722cab4SKip Macy
2880d722cab4SKip Macy if ((sc->flags & FULL_INIT_DONE) == 0)
2881d722cab4SKip Macy return (EAGAIN); /* need TP to be initialized */
2882d722cab4SKip Macy if (t->sched >= NTX_SCHED || !in_range(t->mode, 0, 1) ||
2883d722cab4SKip Macy !in_range(t->channel, 0, 1) ||
2884d722cab4SKip Macy !in_range(t->kbps, 0, 10000000) ||
2885d722cab4SKip Macy !in_range(t->class_ipg, 0, 10000 * 65535 / ticks_per_usec) ||
2886d722cab4SKip Macy !in_range(t->flow_ipg, 0,
2887d722cab4SKip Macy dack_ticks_to_usec(sc, 0x7ff)))
2888d722cab4SKip Macy return (EINVAL);
2889d722cab4SKip Macy
2890d722cab4SKip Macy if (t->kbps >= 0) {
2891d722cab4SKip Macy error = t3_config_sched(sc, t->kbps, t->sched);
2892d722cab4SKip Macy if (error < 0)
2893d722cab4SKip Macy return (-error);
2894d722cab4SKip Macy }
2895d722cab4SKip Macy if (t->class_ipg >= 0)
2896d722cab4SKip Macy t3_set_sched_ipg(sc, t->sched, t->class_ipg);
2897d722cab4SKip Macy if (t->flow_ipg >= 0) {
2898d722cab4SKip Macy t->flow_ipg *= 1000; /* us -> ns */
2899d722cab4SKip Macy t3_set_pace_tbl(sc, &t->flow_ipg, t->sched, 1);
2900d722cab4SKip Macy }
2901d722cab4SKip Macy if (t->mode >= 0) {
2902d722cab4SKip Macy int bit = 1 << (S_TX_MOD_TIMER_MODE + t->sched);
2903d722cab4SKip Macy
2904d722cab4SKip Macy t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2905d722cab4SKip Macy bit, t->mode ? bit : 0);
2906d722cab4SKip Macy }
2907d722cab4SKip Macy if (t->channel >= 0)
2908d722cab4SKip Macy t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP,
2909d722cab4SKip Macy 1 << t->sched, t->channel << t->sched);
2910d722cab4SKip Macy break;
2911d722cab4SKip Macy }
29121ffd6e58SKip Macy case CHELSIO_GET_EEPROM: {
29131ffd6e58SKip Macy int i;
29141ffd6e58SKip Macy struct ch_eeprom *e = (struct ch_eeprom *)data;
291576aca1d6SNavdeep Parhar uint8_t *buf;
29161ffd6e58SKip Macy
291776aca1d6SNavdeep Parhar if (e->offset & 3 || e->offset >= EEPROMSIZE ||
291876aca1d6SNavdeep Parhar e->len > EEPROMSIZE || e->offset + e->len > EEPROMSIZE) {
291976aca1d6SNavdeep Parhar return (EINVAL);
292076aca1d6SNavdeep Parhar }
292176aca1d6SNavdeep Parhar
292276aca1d6SNavdeep Parhar buf = malloc(EEPROMSIZE, M_DEVBUF, M_NOWAIT);
29231ffd6e58SKip Macy if (buf == NULL) {
29241ffd6e58SKip Macy return (ENOMEM);
29251ffd6e58SKip Macy }
29261ffd6e58SKip Macy e->magic = EEPROM_MAGIC;
29271ffd6e58SKip Macy for (i = e->offset & ~3; !error && i < e->offset + e->len; i += 4)
29281ffd6e58SKip Macy error = -t3_seeprom_read(sc, i, (uint32_t *)&buf[i]);
29291ffd6e58SKip Macy
29301ffd6e58SKip Macy if (!error)
29311ffd6e58SKip Macy error = copyout(buf + e->offset, e->data, e->len);
29321ffd6e58SKip Macy
29331ffd6e58SKip Macy free(buf, M_DEVBUF);
29341ffd6e58SKip Macy break;
29351ffd6e58SKip Macy }
29361ffd6e58SKip Macy case CHELSIO_CLEAR_STATS: {
29371ffd6e58SKip Macy if (!(sc->flags & FULL_INIT_DONE))
29381ffd6e58SKip Macy return EAGAIN;
29391ffd6e58SKip Macy
29401ffd6e58SKip Macy PORT_LOCK(pi);
29411ffd6e58SKip Macy t3_mac_update_stats(&pi->mac);
29421ffd6e58SKip Macy memset(&pi->mac.stats, 0, sizeof(pi->mac.stats));
29431ffd6e58SKip Macy PORT_UNLOCK(pi);
29441ffd6e58SKip Macy break;
29451ffd6e58SKip Macy }
2946f2d8ff04SGeorge V. Neville-Neil case CHELSIO_GET_UP_LA: {
2947f2d8ff04SGeorge V. Neville-Neil struct ch_up_la *la = (struct ch_up_la *)data;
2948f2d8ff04SGeorge V. Neville-Neil uint8_t *buf = malloc(LA_BUFSIZE, M_DEVBUF, M_NOWAIT);
2949f2d8ff04SGeorge V. Neville-Neil if (buf == NULL) {
2950f2d8ff04SGeorge V. Neville-Neil return (ENOMEM);
2951f2d8ff04SGeorge V. Neville-Neil }
2952f2d8ff04SGeorge V. Neville-Neil if (la->bufsize < LA_BUFSIZE)
2953f2d8ff04SGeorge V. Neville-Neil error = ENOBUFS;
2954f2d8ff04SGeorge V. Neville-Neil
2955f2d8ff04SGeorge V. Neville-Neil if (!error)
2956f2d8ff04SGeorge V. Neville-Neil error = -t3_get_up_la(sc, &la->stopped, &la->idx,
2957f2d8ff04SGeorge V. Neville-Neil &la->bufsize, buf);
2958f2d8ff04SGeorge V. Neville-Neil if (!error)
2959f2d8ff04SGeorge V. Neville-Neil error = copyout(buf, la->data, la->bufsize);
2960f2d8ff04SGeorge V. Neville-Neil
2961f2d8ff04SGeorge V. Neville-Neil free(buf, M_DEVBUF);
2962f2d8ff04SGeorge V. Neville-Neil break;
2963f2d8ff04SGeorge V. Neville-Neil }
2964f2d8ff04SGeorge V. Neville-Neil case CHELSIO_GET_UP_IOQS: {
2965f2d8ff04SGeorge V. Neville-Neil struct ch_up_ioqs *ioqs = (struct ch_up_ioqs *)data;
2966f2d8ff04SGeorge V. Neville-Neil uint8_t *buf = malloc(IOQS_BUFSIZE, M_DEVBUF, M_NOWAIT);
2967f2d8ff04SGeorge V. Neville-Neil uint32_t *v;
2968f2d8ff04SGeorge V. Neville-Neil
2969f2d8ff04SGeorge V. Neville-Neil if (buf == NULL) {
2970f2d8ff04SGeorge V. Neville-Neil return (ENOMEM);
2971f2d8ff04SGeorge V. Neville-Neil }
2972f2d8ff04SGeorge V. Neville-Neil if (ioqs->bufsize < IOQS_BUFSIZE)
2973f2d8ff04SGeorge V. Neville-Neil error = ENOBUFS;
2974f2d8ff04SGeorge V. Neville-Neil
2975f2d8ff04SGeorge V. Neville-Neil if (!error)
2976f2d8ff04SGeorge V. Neville-Neil error = -t3_get_up_ioqs(sc, &ioqs->bufsize, buf);
2977f2d8ff04SGeorge V. Neville-Neil
2978f2d8ff04SGeorge V. Neville-Neil if (!error) {
2979f2d8ff04SGeorge V. Neville-Neil v = (uint32_t *)buf;
2980f2d8ff04SGeorge V. Neville-Neil
2981f2d8ff04SGeorge V. Neville-Neil ioqs->ioq_rx_enable = *v++;
2982f2d8ff04SGeorge V. Neville-Neil ioqs->ioq_tx_enable = *v++;
2983f2d8ff04SGeorge V. Neville-Neil ioqs->ioq_rx_status = *v++;
2984f2d8ff04SGeorge V. Neville-Neil ioqs->ioq_tx_status = *v++;
2985f2d8ff04SGeorge V. Neville-Neil
2986f2d8ff04SGeorge V. Neville-Neil error = copyout(v, ioqs->data, ioqs->bufsize);
2987f2d8ff04SGeorge V. Neville-Neil }
2988f2d8ff04SGeorge V. Neville-Neil
2989f2d8ff04SGeorge V. Neville-Neil free(buf, M_DEVBUF);
2990f2d8ff04SGeorge V. Neville-Neil break;
2991f2d8ff04SGeorge V. Neville-Neil }
2992d6da8362SNavdeep Parhar case CHELSIO_SET_FILTER: {
2993db702c59SEitan Adler struct ch_filter *f = (struct ch_filter *)data;
2994d6da8362SNavdeep Parhar struct filter_info *p;
2995d6da8362SNavdeep Parhar unsigned int nfilters = sc->params.mc5.nfilters;
2996d6da8362SNavdeep Parhar
2997d6da8362SNavdeep Parhar if (!is_offload(sc))
2998d6da8362SNavdeep Parhar return (EOPNOTSUPP); /* No TCAM */
2999d6da8362SNavdeep Parhar if (!(sc->flags & FULL_INIT_DONE))
3000d6da8362SNavdeep Parhar return (EAGAIN); /* mc5 not setup yet */
3001d6da8362SNavdeep Parhar if (nfilters == 0)
3002d6da8362SNavdeep Parhar return (EBUSY); /* TOE will use TCAM */
3003d6da8362SNavdeep Parhar
3004d6da8362SNavdeep Parhar /* sanity checks */
3005d6da8362SNavdeep Parhar if (f->filter_id >= nfilters ||
3006d6da8362SNavdeep Parhar (f->val.dip && f->mask.dip != 0xffffffff) ||
3007d6da8362SNavdeep Parhar (f->val.sport && f->mask.sport != 0xffff) ||
3008d6da8362SNavdeep Parhar (f->val.dport && f->mask.dport != 0xffff) ||
3009d6da8362SNavdeep Parhar (f->val.vlan && f->mask.vlan != 0xfff) ||
3010d6da8362SNavdeep Parhar (f->val.vlan_prio &&
3011d6da8362SNavdeep Parhar f->mask.vlan_prio != FILTER_NO_VLAN_PRI) ||
3012d6da8362SNavdeep Parhar (f->mac_addr_idx != 0xffff && f->mac_addr_idx > 15) ||
3013d6da8362SNavdeep Parhar f->qset >= SGE_QSETS ||
3014d6da8362SNavdeep Parhar sc->rrss_map[f->qset] >= RSS_TABLE_SIZE)
3015d6da8362SNavdeep Parhar return (EINVAL);
3016d6da8362SNavdeep Parhar
3017d6da8362SNavdeep Parhar /* Was allocated with M_WAITOK */
3018d6da8362SNavdeep Parhar KASSERT(sc->filters, ("filter table NULL\n"));
3019d6da8362SNavdeep Parhar
3020d6da8362SNavdeep Parhar p = &sc->filters[f->filter_id];
3021d6da8362SNavdeep Parhar if (p->locked)
3022d6da8362SNavdeep Parhar return (EPERM);
3023d6da8362SNavdeep Parhar
3024d6da8362SNavdeep Parhar bzero(p, sizeof(*p));
3025d6da8362SNavdeep Parhar p->sip = f->val.sip;
3026d6da8362SNavdeep Parhar p->sip_mask = f->mask.sip;
3027d6da8362SNavdeep Parhar p->dip = f->val.dip;
3028d6da8362SNavdeep Parhar p->sport = f->val.sport;
3029d6da8362SNavdeep Parhar p->dport = f->val.dport;
3030d6da8362SNavdeep Parhar p->vlan = f->mask.vlan ? f->val.vlan : 0xfff;
3031d6da8362SNavdeep Parhar p->vlan_prio = f->mask.vlan_prio ? (f->val.vlan_prio & 6) :
3032d6da8362SNavdeep Parhar FILTER_NO_VLAN_PRI;
3033d6da8362SNavdeep Parhar p->mac_hit = f->mac_hit;
3034d6da8362SNavdeep Parhar p->mac_vld = f->mac_addr_idx != 0xffff;
3035d6da8362SNavdeep Parhar p->mac_idx = f->mac_addr_idx;
3036d6da8362SNavdeep Parhar p->pkt_type = f->proto;
3037d6da8362SNavdeep Parhar p->report_filter_id = f->want_filter_id;
3038d6da8362SNavdeep Parhar p->pass = f->pass;
3039d6da8362SNavdeep Parhar p->rss = f->rss;
3040d6da8362SNavdeep Parhar p->qset = f->qset;
3041d6da8362SNavdeep Parhar
3042d6da8362SNavdeep Parhar error = set_filter(sc, f->filter_id, p);
3043d6da8362SNavdeep Parhar if (error == 0)
3044d6da8362SNavdeep Parhar p->valid = 1;
3045d6da8362SNavdeep Parhar break;
3046d6da8362SNavdeep Parhar }
3047d6da8362SNavdeep Parhar case CHELSIO_DEL_FILTER: {
3048d6da8362SNavdeep Parhar struct ch_filter *f = (struct ch_filter *)data;
3049d6da8362SNavdeep Parhar struct filter_info *p;
3050d6da8362SNavdeep Parhar unsigned int nfilters = sc->params.mc5.nfilters;
3051d6da8362SNavdeep Parhar
3052d6da8362SNavdeep Parhar if (!is_offload(sc))
3053d6da8362SNavdeep Parhar return (EOPNOTSUPP);
3054d6da8362SNavdeep Parhar if (!(sc->flags & FULL_INIT_DONE))
3055d6da8362SNavdeep Parhar return (EAGAIN);
3056d6da8362SNavdeep Parhar if (nfilters == 0 || sc->filters == NULL)
3057d6da8362SNavdeep Parhar return (EINVAL);
3058d6da8362SNavdeep Parhar if (f->filter_id >= nfilters)
3059d6da8362SNavdeep Parhar return (EINVAL);
3060d6da8362SNavdeep Parhar
3061d6da8362SNavdeep Parhar p = &sc->filters[f->filter_id];
3062d6da8362SNavdeep Parhar if (p->locked)
3063d6da8362SNavdeep Parhar return (EPERM);
3064d6da8362SNavdeep Parhar if (!p->valid)
3065d6da8362SNavdeep Parhar return (EFAULT); /* Read "Bad address" as "Bad index" */
3066d6da8362SNavdeep Parhar
3067d6da8362SNavdeep Parhar bzero(p, sizeof(*p));
3068d6da8362SNavdeep Parhar p->sip = p->sip_mask = 0xffffffff;
3069d6da8362SNavdeep Parhar p->vlan = 0xfff;
3070d6da8362SNavdeep Parhar p->vlan_prio = FILTER_NO_VLAN_PRI;
3071d6da8362SNavdeep Parhar p->pkt_type = 1;
3072d6da8362SNavdeep Parhar error = set_filter(sc, f->filter_id, p);
3073d6da8362SNavdeep Parhar break;
3074d6da8362SNavdeep Parhar }
3075d6da8362SNavdeep Parhar case CHELSIO_GET_FILTER: {
3076d6da8362SNavdeep Parhar struct ch_filter *f = (struct ch_filter *)data;
3077d6da8362SNavdeep Parhar struct filter_info *p;
3078d6da8362SNavdeep Parhar unsigned int i, nfilters = sc->params.mc5.nfilters;
3079d6da8362SNavdeep Parhar
3080d6da8362SNavdeep Parhar if (!is_offload(sc))
3081d6da8362SNavdeep Parhar return (EOPNOTSUPP);
3082d6da8362SNavdeep Parhar if (!(sc->flags & FULL_INIT_DONE))
3083d6da8362SNavdeep Parhar return (EAGAIN);
3084d6da8362SNavdeep Parhar if (nfilters == 0 || sc->filters == NULL)
3085d6da8362SNavdeep Parhar return (EINVAL);
3086d6da8362SNavdeep Parhar
3087d6da8362SNavdeep Parhar i = f->filter_id == 0xffffffff ? 0 : f->filter_id + 1;
3088d6da8362SNavdeep Parhar for (; i < nfilters; i++) {
3089d6da8362SNavdeep Parhar p = &sc->filters[i];
3090d6da8362SNavdeep Parhar if (!p->valid)
3091d6da8362SNavdeep Parhar continue;
3092d6da8362SNavdeep Parhar
3093d6da8362SNavdeep Parhar bzero(f, sizeof(*f));
3094d6da8362SNavdeep Parhar
3095d6da8362SNavdeep Parhar f->filter_id = i;
3096d6da8362SNavdeep Parhar f->val.sip = p->sip;
3097d6da8362SNavdeep Parhar f->mask.sip = p->sip_mask;
3098d6da8362SNavdeep Parhar f->val.dip = p->dip;
3099d6da8362SNavdeep Parhar f->mask.dip = p->dip ? 0xffffffff : 0;
3100d6da8362SNavdeep Parhar f->val.sport = p->sport;
3101d6da8362SNavdeep Parhar f->mask.sport = p->sport ? 0xffff : 0;
3102d6da8362SNavdeep Parhar f->val.dport = p->dport;
3103d6da8362SNavdeep Parhar f->mask.dport = p->dport ? 0xffff : 0;
3104d6da8362SNavdeep Parhar f->val.vlan = p->vlan == 0xfff ? 0 : p->vlan;
3105d6da8362SNavdeep Parhar f->mask.vlan = p->vlan == 0xfff ? 0 : 0xfff;
3106d6da8362SNavdeep Parhar f->val.vlan_prio = p->vlan_prio == FILTER_NO_VLAN_PRI ?
3107d6da8362SNavdeep Parhar 0 : p->vlan_prio;
3108d6da8362SNavdeep Parhar f->mask.vlan_prio = p->vlan_prio == FILTER_NO_VLAN_PRI ?
3109d6da8362SNavdeep Parhar 0 : FILTER_NO_VLAN_PRI;
3110d6da8362SNavdeep Parhar f->mac_hit = p->mac_hit;
3111d6da8362SNavdeep Parhar f->mac_addr_idx = p->mac_vld ? p->mac_idx : 0xffff;
3112d6da8362SNavdeep Parhar f->proto = p->pkt_type;
3113d6da8362SNavdeep Parhar f->want_filter_id = p->report_filter_id;
3114d6da8362SNavdeep Parhar f->pass = p->pass;
3115d6da8362SNavdeep Parhar f->rss = p->rss;
3116d6da8362SNavdeep Parhar f->qset = p->qset;
3117d6da8362SNavdeep Parhar
3118d6da8362SNavdeep Parhar break;
3119d6da8362SNavdeep Parhar }
3120d6da8362SNavdeep Parhar
3121d6da8362SNavdeep Parhar if (i == nfilters)
3122d6da8362SNavdeep Parhar f->filter_id = 0xffffffff;
3123d6da8362SNavdeep Parhar break;
3124d6da8362SNavdeep Parhar }
3125b6d90eb7SKip Macy default:
3126b6d90eb7SKip Macy return (EOPNOTSUPP);
3127b6d90eb7SKip Macy break;
3128b6d90eb7SKip Macy }
3129b6d90eb7SKip Macy
3130b6d90eb7SKip Macy return (error);
3131b6d90eb7SKip Macy }
3132b6d90eb7SKip Macy
3133b6d90eb7SKip Macy static __inline void
reg_block_dump(struct adapter * ap,uint8_t * buf,unsigned int start,unsigned int end)3134b6d90eb7SKip Macy reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start,
3135b6d90eb7SKip Macy unsigned int end)
3136b6d90eb7SKip Macy {
31371ffd6e58SKip Macy uint32_t *p = (uint32_t *)(buf + start);
3138b6d90eb7SKip Macy
3139b6d90eb7SKip Macy for ( ; start <= end; start += sizeof(uint32_t))
3140b6d90eb7SKip Macy *p++ = t3_read_reg(ap, start);
3141b6d90eb7SKip Macy }
3142b6d90eb7SKip Macy
3143b6d90eb7SKip Macy #define T3_REGMAP_SIZE (3 * 1024)
3144b6d90eb7SKip Macy static int
cxgb_get_regs_len(void)3145b6d90eb7SKip Macy cxgb_get_regs_len(void)
3146b6d90eb7SKip Macy {
3147b6d90eb7SKip Macy return T3_REGMAP_SIZE;
3148b6d90eb7SKip Macy }
3149b6d90eb7SKip Macy
3150b6d90eb7SKip Macy static void
cxgb_get_regs(adapter_t * sc,struct ch_ifconf_regs * regs,uint8_t * buf)31511ffd6e58SKip Macy cxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf)
3152b6d90eb7SKip Macy {
3153b6d90eb7SKip Macy
3154b6d90eb7SKip Macy /*
3155b6d90eb7SKip Macy * Version scheme:
3156b6d90eb7SKip Macy * bits 0..9: chip version
3157b6d90eb7SKip Macy * bits 10..15: chip revision
3158b6d90eb7SKip Macy * bit 31: set for PCIe cards
3159b6d90eb7SKip Macy */
3160b6d90eb7SKip Macy regs->version = 3 | (sc->params.rev << 10) | (is_pcie(sc) << 31);
3161b6d90eb7SKip Macy
3162b6d90eb7SKip Macy /*
3163b6d90eb7SKip Macy * We skip the MAC statistics registers because they are clear-on-read.
3164b6d90eb7SKip Macy * Also reading multi-register stats would need to synchronize with the
3165b6d90eb7SKip Macy * periodic mac stats accumulation. Hard to justify the complexity.
3166b6d90eb7SKip Macy */
31671ffd6e58SKip Macy memset(buf, 0, cxgb_get_regs_len());
3168b6d90eb7SKip Macy reg_block_dump(sc, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
3169b6d90eb7SKip Macy reg_block_dump(sc, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
3170b6d90eb7SKip Macy reg_block_dump(sc, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
3171b6d90eb7SKip Macy reg_block_dump(sc, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
3172b6d90eb7SKip Macy reg_block_dump(sc, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
3173b6d90eb7SKip Macy reg_block_dump(sc, buf, A_XGM_SERDES_STATUS0,
3174b6d90eb7SKip Macy XGM_REG(A_XGM_SERDES_STAT3, 1));
3175b6d90eb7SKip Macy reg_block_dump(sc, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
3176b6d90eb7SKip Macy XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
3177b6d90eb7SKip Macy }
3178404825a7SKip Macy
3179d6da8362SNavdeep Parhar static int
alloc_filters(struct adapter * sc)3180d6da8362SNavdeep Parhar alloc_filters(struct adapter *sc)
3181d6da8362SNavdeep Parhar {
3182d6da8362SNavdeep Parhar struct filter_info *p;
3183d6da8362SNavdeep Parhar unsigned int nfilters = sc->params.mc5.nfilters;
3184d6da8362SNavdeep Parhar
3185d6da8362SNavdeep Parhar if (nfilters == 0)
3186d6da8362SNavdeep Parhar return (0);
3187d6da8362SNavdeep Parhar
3188d6da8362SNavdeep Parhar p = malloc(sizeof(*p) * nfilters, M_DEVBUF, M_WAITOK | M_ZERO);
3189d6da8362SNavdeep Parhar sc->filters = p;
3190d6da8362SNavdeep Parhar
3191d6da8362SNavdeep Parhar p = &sc->filters[nfilters - 1];
3192d6da8362SNavdeep Parhar p->vlan = 0xfff;
3193d6da8362SNavdeep Parhar p->vlan_prio = FILTER_NO_VLAN_PRI;
3194d6da8362SNavdeep Parhar p->pass = p->rss = p->valid = p->locked = 1;
3195d6da8362SNavdeep Parhar
3196d6da8362SNavdeep Parhar return (0);
3197d6da8362SNavdeep Parhar }
3198d6da8362SNavdeep Parhar
3199d6da8362SNavdeep Parhar static int
setup_hw_filters(struct adapter * sc)3200d6da8362SNavdeep Parhar setup_hw_filters(struct adapter *sc)
3201d6da8362SNavdeep Parhar {
3202d6da8362SNavdeep Parhar int i, rc;
3203d6da8362SNavdeep Parhar unsigned int nfilters = sc->params.mc5.nfilters;
3204d6da8362SNavdeep Parhar
3205d6da8362SNavdeep Parhar if (!sc->filters)
3206d6da8362SNavdeep Parhar return (0);
3207d6da8362SNavdeep Parhar
3208d6da8362SNavdeep Parhar t3_enable_filters(sc);
3209d6da8362SNavdeep Parhar
3210d6da8362SNavdeep Parhar for (i = rc = 0; i < nfilters && !rc; i++) {
3211d6da8362SNavdeep Parhar if (sc->filters[i].locked)
3212d6da8362SNavdeep Parhar rc = set_filter(sc, i, &sc->filters[i]);
3213d6da8362SNavdeep Parhar }
3214d6da8362SNavdeep Parhar
3215d6da8362SNavdeep Parhar return (rc);
3216d6da8362SNavdeep Parhar }
3217d6da8362SNavdeep Parhar
3218d6da8362SNavdeep Parhar static int
set_filter(struct adapter * sc,int id,const struct filter_info * f)3219d6da8362SNavdeep Parhar set_filter(struct adapter *sc, int id, const struct filter_info *f)
3220d6da8362SNavdeep Parhar {
3221d6da8362SNavdeep Parhar int len;
3222d6da8362SNavdeep Parhar struct mbuf *m;
3223d6da8362SNavdeep Parhar struct ulp_txpkt *txpkt;
3224d6da8362SNavdeep Parhar struct work_request_hdr *wr;
3225d6da8362SNavdeep Parhar struct cpl_pass_open_req *oreq;
3226d6da8362SNavdeep Parhar struct cpl_set_tcb_field *sreq;
3227d6da8362SNavdeep Parhar
3228d6da8362SNavdeep Parhar len = sizeof(*wr) + sizeof(*oreq) + 2 * sizeof(*sreq);
3229d6da8362SNavdeep Parhar KASSERT(len <= MHLEN, ("filter request too big for an mbuf"));
3230d6da8362SNavdeep Parhar
3231d6da8362SNavdeep Parhar id += t3_mc5_size(&sc->mc5) - sc->params.mc5.nroutes -
3232d6da8362SNavdeep Parhar sc->params.mc5.nfilters;
3233d6da8362SNavdeep Parhar
3234d6da8362SNavdeep Parhar m = m_gethdr(M_WAITOK, MT_DATA);
3235d6da8362SNavdeep Parhar m->m_len = m->m_pkthdr.len = len;
3236d6da8362SNavdeep Parhar bzero(mtod(m, char *), len);
3237d6da8362SNavdeep Parhar
3238d6da8362SNavdeep Parhar wr = mtod(m, struct work_request_hdr *);
3239d6da8362SNavdeep Parhar wr->wrh_hi = htonl(V_WR_OP(FW_WROPCODE_BYPASS) | F_WR_ATOMIC);
3240d6da8362SNavdeep Parhar
3241d6da8362SNavdeep Parhar oreq = (struct cpl_pass_open_req *)(wr + 1);
3242d6da8362SNavdeep Parhar txpkt = (struct ulp_txpkt *)oreq;
3243d6da8362SNavdeep Parhar txpkt->cmd_dest = htonl(V_ULPTX_CMD(ULP_TXPKT));
3244d6da8362SNavdeep Parhar txpkt->len = htonl(V_ULPTX_NFLITS(sizeof(*oreq) / 8));
3245d6da8362SNavdeep Parhar OPCODE_TID(oreq) = htonl(MK_OPCODE_TID(CPL_PASS_OPEN_REQ, id));
3246d6da8362SNavdeep Parhar oreq->local_port = htons(f->dport);
3247d6da8362SNavdeep Parhar oreq->peer_port = htons(f->sport);
3248d6da8362SNavdeep Parhar oreq->local_ip = htonl(f->dip);
3249d6da8362SNavdeep Parhar oreq->peer_ip = htonl(f->sip);
3250d6da8362SNavdeep Parhar oreq->peer_netmask = htonl(f->sip_mask);
3251d6da8362SNavdeep Parhar oreq->opt0h = 0;
3252d6da8362SNavdeep Parhar oreq->opt0l = htonl(F_NO_OFFLOAD);
3253d6da8362SNavdeep Parhar oreq->opt1 = htonl(V_MAC_MATCH_VALID(f->mac_vld) |
3254d6da8362SNavdeep Parhar V_CONN_POLICY(CPL_CONN_POLICY_FILTER) |
3255d6da8362SNavdeep Parhar V_VLAN_PRI(f->vlan_prio >> 1) |
3256d6da8362SNavdeep Parhar V_VLAN_PRI_VALID(f->vlan_prio != FILTER_NO_VLAN_PRI) |
3257d6da8362SNavdeep Parhar V_PKT_TYPE(f->pkt_type) | V_OPT1_VLAN(f->vlan) |
3258d6da8362SNavdeep Parhar V_MAC_MATCH(f->mac_idx | (f->mac_hit << 4)));
3259d6da8362SNavdeep Parhar
3260d6da8362SNavdeep Parhar sreq = (struct cpl_set_tcb_field *)(oreq + 1);
3261d6da8362SNavdeep Parhar set_tcb_field_ulp(sreq, id, 1, 0x1800808000ULL,
3262d6da8362SNavdeep Parhar (f->report_filter_id << 15) | (1 << 23) |
3263d6da8362SNavdeep Parhar ((u64)f->pass << 35) | ((u64)!f->rss << 36));
3264d6da8362SNavdeep Parhar set_tcb_field_ulp(sreq + 1, id, 0, 0xffffffff, (2 << 19) | 1);
3265d6da8362SNavdeep Parhar t3_mgmt_tx(sc, m);
3266d6da8362SNavdeep Parhar
3267d6da8362SNavdeep Parhar if (f->pass && !f->rss) {
3268d6da8362SNavdeep Parhar len = sizeof(*sreq);
3269d6da8362SNavdeep Parhar m = m_gethdr(M_WAITOK, MT_DATA);
3270d6da8362SNavdeep Parhar m->m_len = m->m_pkthdr.len = len;
3271d6da8362SNavdeep Parhar bzero(mtod(m, char *), len);
3272d6da8362SNavdeep Parhar sreq = mtod(m, struct cpl_set_tcb_field *);
3273d6da8362SNavdeep Parhar sreq->wr.wrh_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
3274d6da8362SNavdeep Parhar mk_set_tcb_field(sreq, id, 25, 0x3f80000,
3275d6da8362SNavdeep Parhar (u64)sc->rrss_map[f->qset] << 19);
3276d6da8362SNavdeep Parhar t3_mgmt_tx(sc, m);
3277d6da8362SNavdeep Parhar }
3278d6da8362SNavdeep Parhar return 0;
3279d6da8362SNavdeep Parhar }
3280d6da8362SNavdeep Parhar
3281d6da8362SNavdeep Parhar static inline void
mk_set_tcb_field(struct cpl_set_tcb_field * req,unsigned int tid,unsigned int word,u64 mask,u64 val)3282d6da8362SNavdeep Parhar mk_set_tcb_field(struct cpl_set_tcb_field *req, unsigned int tid,
3283d6da8362SNavdeep Parhar unsigned int word, u64 mask, u64 val)
3284d6da8362SNavdeep Parhar {
3285d6da8362SNavdeep Parhar OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
3286d6da8362SNavdeep Parhar req->reply = V_NO_REPLY(1);
3287d6da8362SNavdeep Parhar req->cpu_idx = 0;
3288d6da8362SNavdeep Parhar req->word = htons(word);
3289d6da8362SNavdeep Parhar req->mask = htobe64(mask);
3290d6da8362SNavdeep Parhar req->val = htobe64(val);
3291d6da8362SNavdeep Parhar }
3292d6da8362SNavdeep Parhar
3293d6da8362SNavdeep Parhar static inline void
set_tcb_field_ulp(struct cpl_set_tcb_field * req,unsigned int tid,unsigned int word,u64 mask,u64 val)3294d6da8362SNavdeep Parhar set_tcb_field_ulp(struct cpl_set_tcb_field *req, unsigned int tid,
3295d6da8362SNavdeep Parhar unsigned int word, u64 mask, u64 val)
3296d6da8362SNavdeep Parhar {
3297d6da8362SNavdeep Parhar struct ulp_txpkt *txpkt = (struct ulp_txpkt *)req;
3298d6da8362SNavdeep Parhar
3299d6da8362SNavdeep Parhar txpkt->cmd_dest = htonl(V_ULPTX_CMD(ULP_TXPKT));
3300d6da8362SNavdeep Parhar txpkt->len = htonl(V_ULPTX_NFLITS(sizeof(*req) / 8));
3301d6da8362SNavdeep Parhar mk_set_tcb_field(req, tid, word, mask, val);
3302d6da8362SNavdeep Parhar }
330309fe6320SNavdeep Parhar
330409fe6320SNavdeep Parhar void
t3_iterate(void (* func)(struct adapter *,void *),void * arg)330509fe6320SNavdeep Parhar t3_iterate(void (*func)(struct adapter *, void *), void *arg)
330609fe6320SNavdeep Parhar {
330709fe6320SNavdeep Parhar struct adapter *sc;
330809fe6320SNavdeep Parhar
330909fe6320SNavdeep Parhar mtx_lock(&t3_list_lock);
331009fe6320SNavdeep Parhar SLIST_FOREACH(sc, &t3_list, link) {
331109fe6320SNavdeep Parhar /*
331209fe6320SNavdeep Parhar * func should not make any assumptions about what state sc is
331309fe6320SNavdeep Parhar * in - the only guarantee is that sc->sc_lock is a valid lock.
331409fe6320SNavdeep Parhar */
331509fe6320SNavdeep Parhar func(sc, arg);
331609fe6320SNavdeep Parhar }
331709fe6320SNavdeep Parhar mtx_unlock(&t3_list_lock);
331809fe6320SNavdeep Parhar }
331909fe6320SNavdeep Parhar
332009fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
332109fe6320SNavdeep Parhar static int
toe_capability(struct port_info * pi,int enable)332209fe6320SNavdeep Parhar toe_capability(struct port_info *pi, int enable)
332309fe6320SNavdeep Parhar {
332409fe6320SNavdeep Parhar int rc;
332509fe6320SNavdeep Parhar struct adapter *sc = pi->adapter;
332609fe6320SNavdeep Parhar
332709fe6320SNavdeep Parhar ADAPTER_LOCK_ASSERT_OWNED(sc);
332809fe6320SNavdeep Parhar
332909fe6320SNavdeep Parhar if (!is_offload(sc))
333009fe6320SNavdeep Parhar return (ENODEV);
333109fe6320SNavdeep Parhar
333209fe6320SNavdeep Parhar if (enable) {
333309fe6320SNavdeep Parhar if (!(sc->flags & FULL_INIT_DONE)) {
333409fe6320SNavdeep Parhar log(LOG_WARNING,
333509fe6320SNavdeep Parhar "You must enable a cxgb interface first\n");
333609fe6320SNavdeep Parhar return (EAGAIN);
333709fe6320SNavdeep Parhar }
333809fe6320SNavdeep Parhar
333909fe6320SNavdeep Parhar if (isset(&sc->offload_map, pi->port_id))
334009fe6320SNavdeep Parhar return (0);
334109fe6320SNavdeep Parhar
334209fe6320SNavdeep Parhar if (!(sc->flags & TOM_INIT_DONE)) {
334309fe6320SNavdeep Parhar rc = t3_activate_uld(sc, ULD_TOM);
334409fe6320SNavdeep Parhar if (rc == EAGAIN) {
334509fe6320SNavdeep Parhar log(LOG_WARNING,
334609fe6320SNavdeep Parhar "You must kldload t3_tom.ko before trying "
334709fe6320SNavdeep Parhar "to enable TOE on a cxgb interface.\n");
334809fe6320SNavdeep Parhar }
334909fe6320SNavdeep Parhar if (rc != 0)
335009fe6320SNavdeep Parhar return (rc);
335109fe6320SNavdeep Parhar KASSERT(sc->tom_softc != NULL,
335209fe6320SNavdeep Parhar ("%s: TOM activated but softc NULL", __func__));
335309fe6320SNavdeep Parhar KASSERT(sc->flags & TOM_INIT_DONE,
335409fe6320SNavdeep Parhar ("%s: TOM activated but flag not set", __func__));
335509fe6320SNavdeep Parhar }
335609fe6320SNavdeep Parhar
335709fe6320SNavdeep Parhar setbit(&sc->offload_map, pi->port_id);
335809fe6320SNavdeep Parhar
335909fe6320SNavdeep Parhar /*
336009fe6320SNavdeep Parhar * XXX: Temporary code to allow iWARP to be enabled when TOE is
336109fe6320SNavdeep Parhar * enabled on any port. Need to figure out how to enable,
336209fe6320SNavdeep Parhar * disable, load, and unload iWARP cleanly.
336309fe6320SNavdeep Parhar */
336409fe6320SNavdeep Parhar if (!isset(&sc->offload_map, MAX_NPORTS) &&
336509fe6320SNavdeep Parhar t3_activate_uld(sc, ULD_IWARP) == 0)
336609fe6320SNavdeep Parhar setbit(&sc->offload_map, MAX_NPORTS);
336709fe6320SNavdeep Parhar } else {
336809fe6320SNavdeep Parhar if (!isset(&sc->offload_map, pi->port_id))
336909fe6320SNavdeep Parhar return (0);
337009fe6320SNavdeep Parhar
337109fe6320SNavdeep Parhar KASSERT(sc->flags & TOM_INIT_DONE,
337209fe6320SNavdeep Parhar ("%s: TOM never initialized?", __func__));
337309fe6320SNavdeep Parhar clrbit(&sc->offload_map, pi->port_id);
337409fe6320SNavdeep Parhar }
337509fe6320SNavdeep Parhar
337609fe6320SNavdeep Parhar return (0);
337709fe6320SNavdeep Parhar }
337809fe6320SNavdeep Parhar
337909fe6320SNavdeep Parhar /*
338009fe6320SNavdeep Parhar * Add an upper layer driver to the global list.
338109fe6320SNavdeep Parhar */
338209fe6320SNavdeep Parhar int
t3_register_uld(struct uld_info * ui)338309fe6320SNavdeep Parhar t3_register_uld(struct uld_info *ui)
338409fe6320SNavdeep Parhar {
338509fe6320SNavdeep Parhar int rc = 0;
338609fe6320SNavdeep Parhar struct uld_info *u;
338709fe6320SNavdeep Parhar
338809fe6320SNavdeep Parhar mtx_lock(&t3_uld_list_lock);
338909fe6320SNavdeep Parhar SLIST_FOREACH(u, &t3_uld_list, link) {
339009fe6320SNavdeep Parhar if (u->uld_id == ui->uld_id) {
339109fe6320SNavdeep Parhar rc = EEXIST;
339209fe6320SNavdeep Parhar goto done;
339309fe6320SNavdeep Parhar }
339409fe6320SNavdeep Parhar }
339509fe6320SNavdeep Parhar
339609fe6320SNavdeep Parhar SLIST_INSERT_HEAD(&t3_uld_list, ui, link);
339709fe6320SNavdeep Parhar ui->refcount = 0;
339809fe6320SNavdeep Parhar done:
339909fe6320SNavdeep Parhar mtx_unlock(&t3_uld_list_lock);
340009fe6320SNavdeep Parhar return (rc);
340109fe6320SNavdeep Parhar }
340209fe6320SNavdeep Parhar
340309fe6320SNavdeep Parhar int
t3_unregister_uld(struct uld_info * ui)340409fe6320SNavdeep Parhar t3_unregister_uld(struct uld_info *ui)
340509fe6320SNavdeep Parhar {
340609fe6320SNavdeep Parhar int rc = EINVAL;
340709fe6320SNavdeep Parhar struct uld_info *u;
340809fe6320SNavdeep Parhar
340909fe6320SNavdeep Parhar mtx_lock(&t3_uld_list_lock);
341009fe6320SNavdeep Parhar
341109fe6320SNavdeep Parhar SLIST_FOREACH(u, &t3_uld_list, link) {
341209fe6320SNavdeep Parhar if (u == ui) {
341309fe6320SNavdeep Parhar if (ui->refcount > 0) {
341409fe6320SNavdeep Parhar rc = EBUSY;
341509fe6320SNavdeep Parhar goto done;
341609fe6320SNavdeep Parhar }
341709fe6320SNavdeep Parhar
341809fe6320SNavdeep Parhar SLIST_REMOVE(&t3_uld_list, ui, uld_info, link);
341909fe6320SNavdeep Parhar rc = 0;
342009fe6320SNavdeep Parhar goto done;
342109fe6320SNavdeep Parhar }
342209fe6320SNavdeep Parhar }
342309fe6320SNavdeep Parhar done:
342409fe6320SNavdeep Parhar mtx_unlock(&t3_uld_list_lock);
342509fe6320SNavdeep Parhar return (rc);
342609fe6320SNavdeep Parhar }
342709fe6320SNavdeep Parhar
342809fe6320SNavdeep Parhar int
t3_activate_uld(struct adapter * sc,int id)342909fe6320SNavdeep Parhar t3_activate_uld(struct adapter *sc, int id)
343009fe6320SNavdeep Parhar {
343109fe6320SNavdeep Parhar int rc = EAGAIN;
343209fe6320SNavdeep Parhar struct uld_info *ui;
343309fe6320SNavdeep Parhar
343409fe6320SNavdeep Parhar mtx_lock(&t3_uld_list_lock);
343509fe6320SNavdeep Parhar
343609fe6320SNavdeep Parhar SLIST_FOREACH(ui, &t3_uld_list, link) {
343709fe6320SNavdeep Parhar if (ui->uld_id == id) {
343809fe6320SNavdeep Parhar rc = ui->activate(sc);
343909fe6320SNavdeep Parhar if (rc == 0)
344009fe6320SNavdeep Parhar ui->refcount++;
344109fe6320SNavdeep Parhar goto done;
344209fe6320SNavdeep Parhar }
344309fe6320SNavdeep Parhar }
344409fe6320SNavdeep Parhar done:
344509fe6320SNavdeep Parhar mtx_unlock(&t3_uld_list_lock);
344609fe6320SNavdeep Parhar
344709fe6320SNavdeep Parhar return (rc);
344809fe6320SNavdeep Parhar }
344909fe6320SNavdeep Parhar
345009fe6320SNavdeep Parhar int
t3_deactivate_uld(struct adapter * sc,int id)345109fe6320SNavdeep Parhar t3_deactivate_uld(struct adapter *sc, int id)
345209fe6320SNavdeep Parhar {
345309fe6320SNavdeep Parhar int rc = EINVAL;
345409fe6320SNavdeep Parhar struct uld_info *ui;
345509fe6320SNavdeep Parhar
345609fe6320SNavdeep Parhar mtx_lock(&t3_uld_list_lock);
345709fe6320SNavdeep Parhar
345809fe6320SNavdeep Parhar SLIST_FOREACH(ui, &t3_uld_list, link) {
345909fe6320SNavdeep Parhar if (ui->uld_id == id) {
346009fe6320SNavdeep Parhar rc = ui->deactivate(sc);
346109fe6320SNavdeep Parhar if (rc == 0)
346209fe6320SNavdeep Parhar ui->refcount--;
346309fe6320SNavdeep Parhar goto done;
346409fe6320SNavdeep Parhar }
346509fe6320SNavdeep Parhar }
346609fe6320SNavdeep Parhar done:
346709fe6320SNavdeep Parhar mtx_unlock(&t3_uld_list_lock);
346809fe6320SNavdeep Parhar
346909fe6320SNavdeep Parhar return (rc);
347009fe6320SNavdeep Parhar }
347109fe6320SNavdeep Parhar
347209fe6320SNavdeep Parhar static int
cpl_not_handled(struct sge_qset * qs __unused,struct rsp_desc * r __unused,struct mbuf * m)347309fe6320SNavdeep Parhar cpl_not_handled(struct sge_qset *qs __unused, struct rsp_desc *r __unused,
347409fe6320SNavdeep Parhar struct mbuf *m)
347509fe6320SNavdeep Parhar {
347609fe6320SNavdeep Parhar m_freem(m);
347709fe6320SNavdeep Parhar return (EDOOFUS);
347809fe6320SNavdeep Parhar }
347909fe6320SNavdeep Parhar
348009fe6320SNavdeep Parhar int
t3_register_cpl_handler(struct adapter * sc,int opcode,cpl_handler_t h)348109fe6320SNavdeep Parhar t3_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h)
348209fe6320SNavdeep Parhar {
348309fe6320SNavdeep Parhar uintptr_t *loc, new;
348409fe6320SNavdeep Parhar
348509fe6320SNavdeep Parhar if (opcode >= NUM_CPL_HANDLERS)
348609fe6320SNavdeep Parhar return (EINVAL);
348709fe6320SNavdeep Parhar
348809fe6320SNavdeep Parhar new = h ? (uintptr_t)h : (uintptr_t)cpl_not_handled;
348909fe6320SNavdeep Parhar loc = (uintptr_t *) &sc->cpl_handler[opcode];
349009fe6320SNavdeep Parhar atomic_store_rel_ptr(loc, new);
349109fe6320SNavdeep Parhar
349209fe6320SNavdeep Parhar return (0);
349309fe6320SNavdeep Parhar }
349409fe6320SNavdeep Parhar #endif
349509fe6320SNavdeep Parhar
349609fe6320SNavdeep Parhar static int
cxgbc_mod_event(module_t mod,int cmd,void * arg)349709fe6320SNavdeep Parhar cxgbc_mod_event(module_t mod, int cmd, void *arg)
349809fe6320SNavdeep Parhar {
349909fe6320SNavdeep Parhar int rc = 0;
350009fe6320SNavdeep Parhar
350109fe6320SNavdeep Parhar switch (cmd) {
350209fe6320SNavdeep Parhar case MOD_LOAD:
350309fe6320SNavdeep Parhar mtx_init(&t3_list_lock, "T3 adapters", 0, MTX_DEF);
350409fe6320SNavdeep Parhar SLIST_INIT(&t3_list);
350509fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
350609fe6320SNavdeep Parhar mtx_init(&t3_uld_list_lock, "T3 ULDs", 0, MTX_DEF);
350709fe6320SNavdeep Parhar SLIST_INIT(&t3_uld_list);
350809fe6320SNavdeep Parhar #endif
350909fe6320SNavdeep Parhar break;
351009fe6320SNavdeep Parhar
351109fe6320SNavdeep Parhar case MOD_UNLOAD:
351209fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD
351309fe6320SNavdeep Parhar mtx_lock(&t3_uld_list_lock);
351409fe6320SNavdeep Parhar if (!SLIST_EMPTY(&t3_uld_list)) {
351509fe6320SNavdeep Parhar rc = EBUSY;
351609fe6320SNavdeep Parhar mtx_unlock(&t3_uld_list_lock);
351709fe6320SNavdeep Parhar break;
351809fe6320SNavdeep Parhar }
351909fe6320SNavdeep Parhar mtx_unlock(&t3_uld_list_lock);
352009fe6320SNavdeep Parhar mtx_destroy(&t3_uld_list_lock);
352109fe6320SNavdeep Parhar #endif
352209fe6320SNavdeep Parhar mtx_lock(&t3_list_lock);
352309fe6320SNavdeep Parhar if (!SLIST_EMPTY(&t3_list)) {
352409fe6320SNavdeep Parhar rc = EBUSY;
352509fe6320SNavdeep Parhar mtx_unlock(&t3_list_lock);
352609fe6320SNavdeep Parhar break;
352709fe6320SNavdeep Parhar }
352809fe6320SNavdeep Parhar mtx_unlock(&t3_list_lock);
352909fe6320SNavdeep Parhar mtx_destroy(&t3_list_lock);
353009fe6320SNavdeep Parhar break;
353109fe6320SNavdeep Parhar }
353209fe6320SNavdeep Parhar
353309fe6320SNavdeep Parhar return (rc);
353409fe6320SNavdeep Parhar }
3535eb07d67eSMark Johnston
35367790c8c1SConrad Meyer #ifdef DEBUGNET
3537eb07d67eSMark Johnston static void
cxgb_debugnet_init(if_t ifp,int * nrxr,int * ncl,int * clsize)3538954712e8SJustin Hibbits cxgb_debugnet_init(if_t ifp, int *nrxr, int *ncl, int *clsize)
3539eb07d67eSMark Johnston {
3540eb07d67eSMark Johnston struct port_info *pi;
3541eb07d67eSMark Johnston adapter_t *adap;
3542eb07d67eSMark Johnston
3543eb07d67eSMark Johnston pi = if_getsoftc(ifp);
3544eb07d67eSMark Johnston adap = pi->adapter;
3545eb07d67eSMark Johnston ADAPTER_LOCK(adap);
35463948ad29SConrad Meyer *nrxr = adap->nqsets;
3547eb07d67eSMark Johnston *ncl = adap->sge.qs[0].fl[1].size;
3548eb07d67eSMark Johnston *clsize = adap->sge.qs[0].fl[1].buf_size;
3549eb07d67eSMark Johnston ADAPTER_UNLOCK(adap);
3550eb07d67eSMark Johnston }
3551eb07d67eSMark Johnston
3552eb07d67eSMark Johnston static void
cxgb_debugnet_event(if_t ifp,enum debugnet_ev event)3553954712e8SJustin Hibbits cxgb_debugnet_event(if_t ifp, enum debugnet_ev event)
3554eb07d67eSMark Johnston {
3555eb07d67eSMark Johnston struct port_info *pi;
3556eb07d67eSMark Johnston struct sge_qset *qs;
3557eb07d67eSMark Johnston int i;
3558eb07d67eSMark Johnston
3559eb07d67eSMark Johnston pi = if_getsoftc(ifp);
35607790c8c1SConrad Meyer if (event == DEBUGNET_START)
35613948ad29SConrad Meyer for (i = 0; i < pi->adapter->nqsets; i++) {
3562eb07d67eSMark Johnston qs = &pi->adapter->sge.qs[i];
3563eb07d67eSMark Johnston
35647790c8c1SConrad Meyer /* Need to reinit after debugnet_mbuf_start(). */
3565eb07d67eSMark Johnston qs->fl[0].zone = zone_pack;
3566eb07d67eSMark Johnston qs->fl[1].zone = zone_clust;
3567eb07d67eSMark Johnston qs->lro.enabled = 0;
3568eb07d67eSMark Johnston }
3569eb07d67eSMark Johnston }
3570eb07d67eSMark Johnston
3571eb07d67eSMark Johnston static int
cxgb_debugnet_transmit(if_t ifp,struct mbuf * m)3572954712e8SJustin Hibbits cxgb_debugnet_transmit(if_t ifp, struct mbuf *m)
3573eb07d67eSMark Johnston {
3574eb07d67eSMark Johnston struct port_info *pi;
3575eb07d67eSMark Johnston struct sge_qset *qs;
3576eb07d67eSMark Johnston
3577eb07d67eSMark Johnston pi = if_getsoftc(ifp);
3578eb07d67eSMark Johnston if ((if_getdrvflags(ifp) & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
3579eb07d67eSMark Johnston IFF_DRV_RUNNING)
3580eb07d67eSMark Johnston return (ENOENT);
3581eb07d67eSMark Johnston
3582eb07d67eSMark Johnston qs = &pi->adapter->sge.qs[pi->first_qset];
35837790c8c1SConrad Meyer return (cxgb_debugnet_encap(qs, &m));
3584eb07d67eSMark Johnston }
3585eb07d67eSMark Johnston
3586eb07d67eSMark Johnston static int
cxgb_debugnet_poll(if_t ifp,int count)3587954712e8SJustin Hibbits cxgb_debugnet_poll(if_t ifp, int count)
3588eb07d67eSMark Johnston {
3589eb07d67eSMark Johnston struct port_info *pi;
3590eb07d67eSMark Johnston adapter_t *adap;
3591eb07d67eSMark Johnston int i;
3592eb07d67eSMark Johnston
3593eb07d67eSMark Johnston pi = if_getsoftc(ifp);
3594eb07d67eSMark Johnston if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
3595eb07d67eSMark Johnston return (ENOENT);
3596eb07d67eSMark Johnston
3597eb07d67eSMark Johnston adap = pi->adapter;
35983948ad29SConrad Meyer for (i = 0; i < adap->nqsets; i++)
35997790c8c1SConrad Meyer (void)cxgb_debugnet_poll_rx(adap, &adap->sge.qs[i]);
36007790c8c1SConrad Meyer (void)cxgb_debugnet_poll_tx(&adap->sge.qs[pi->first_qset]);
3601eb07d67eSMark Johnston return (0);
3602eb07d67eSMark Johnston }
36037790c8c1SConrad Meyer #endif /* DEBUGNET */
3604