1218792Snp/*- 2218792Snp * Copyright (c) 2011 Chelsio Communications, Inc. 3218792Snp * All rights reserved. 4218792Snp * Written by: Navdeep Parhar <np@FreeBSD.org> 5218792Snp * 6218792Snp * Redistribution and use in source and binary forms, with or without 7218792Snp * modification, are permitted provided that the following conditions 8218792Snp * are met: 9218792Snp * 1. Redistributions of source code must retain the above copyright 10218792Snp * notice, this list of conditions and the following disclaimer. 11218792Snp * 2. Redistributions in binary form must reproduce the above copyright 12218792Snp * notice, this list of conditions and the following disclaimer in the 13218792Snp * documentation and/or other materials provided with the distribution. 14218792Snp * 15218792Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16218792Snp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17218792Snp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18218792Snp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19218792Snp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20218792Snp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21218792Snp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22218792Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23218792Snp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24218792Snp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25218792Snp * SUCH DAMAGE. 26218792Snp */ 27218792Snp 28218792Snp#include <sys/cdefs.h> 29218792Snp__FBSDID("$FreeBSD: stable/10/sys/dev/cxgbe/t4_main.c 353418 2019-10-10 23:27:02Z np $"); 30218792Snp 31308318Sjhb#include "opt_ddb.h" 32218792Snp#include "opt_inet.h" 33237819Snp#include "opt_inet6.h" 34218792Snp 35218792Snp#include <sys/param.h> 36218792Snp#include <sys/conf.h> 37218792Snp#include <sys/priv.h> 38218792Snp#include <sys/kernel.h> 39218792Snp#include <sys/bus.h> 40284052Snp#include <sys/systm.h> 41284052Snp#include <sys/counter.h> 42218792Snp#include <sys/module.h> 43219286Snp#include <sys/malloc.h> 44219286Snp#include <sys/queue.h> 45219286Snp#include <sys/taskqueue.h> 46218792Snp#include <sys/pciio.h> 47218792Snp#include <dev/pci/pcireg.h> 48218792Snp#include <dev/pci/pcivar.h> 49218792Snp#include <dev/pci/pci_private.h> 50218792Snp#include <sys/firmware.h> 51219436Snp#include <sys/sbuf.h> 52218792Snp#include <sys/smp.h> 53218792Snp#include <sys/socket.h> 54218792Snp#include <sys/sockio.h> 55218792Snp#include <sys/sysctl.h> 56218792Snp#include <net/ethernet.h> 57218792Snp#include <net/if.h> 58218792Snp#include <net/if_types.h> 59218792Snp#include <net/if_dl.h> 60222003Snp#include <net/if_vlan_var.h> 61308153Sjhb#ifdef RSS 62308153Sjhb#include <net/rss_config.h> 63308153Sjhb#endif 64248925Snp#if defined(__i386__) || defined(__amd64__) 65248925Snp#include <vm/vm.h> 66248925Snp#include <vm/pmap.h> 67248925Snp#endif 68308318Sjhb#ifdef DDB 69308318Sjhb#include <ddb/ddb.h> 70308318Sjhb#include <ddb/db_lex.h> 71308318Sjhb#endif 72218792Snp 73218792Snp#include "common/common.h" 74221474Snp#include "common/t4_msg.h" 75218792Snp#include "common/t4_regs.h" 76218792Snp#include "common/t4_regs_values.h" 77218792Snp#include "t4_ioctl.h" 78222509Snp#include "t4_l2t.h" 79284052Snp#include "t4_mp_ring.h" 80218792Snp 81218792Snp/* T4 bus driver interface */ 82218792Snpstatic int t4_probe(device_t); 83218792Snpstatic int t4_attach(device_t); 84218792Snpstatic int t4_detach(device_t); 85218792Snpstatic device_method_t t4_methods[] = { 86218792Snp DEVMETHOD(device_probe, t4_probe), 87218792Snp DEVMETHOD(device_attach, t4_attach), 88218792Snp DEVMETHOD(device_detach, t4_detach), 89218792Snp 90227843Smarius DEVMETHOD_END 91218792Snp}; 92218792Snpstatic driver_t t4_driver = { 93218792Snp "t4nex", 94218792Snp t4_methods, 95218792Snp sizeof(struct adapter) 96218792Snp}; 97218792Snp 98218792Snp 99218792Snp/* T4 port (cxgbe) interface */ 100218792Snpstatic int cxgbe_probe(device_t); 101218792Snpstatic int cxgbe_attach(device_t); 102218792Snpstatic int cxgbe_detach(device_t); 103309447Sjhbdevice_method_t cxgbe_methods[] = { 104218792Snp DEVMETHOD(device_probe, cxgbe_probe), 105218792Snp DEVMETHOD(device_attach, cxgbe_attach), 106218792Snp DEVMETHOD(device_detach, cxgbe_detach), 107218792Snp { 0, 0 } 108218792Snp}; 109218792Snpstatic driver_t cxgbe_driver = { 110218792Snp "cxgbe", 111218792Snp cxgbe_methods, 112218792Snp sizeof(struct port_info) 113218792Snp}; 114218792Snp 115308154Sjhb/* T4 VI (vcxgbe) interface */ 116308154Sjhbstatic int vcxgbe_probe(device_t); 117308154Sjhbstatic int vcxgbe_attach(device_t); 118308154Sjhbstatic int vcxgbe_detach(device_t); 119308154Sjhbstatic device_method_t vcxgbe_methods[] = { 120308154Sjhb DEVMETHOD(device_probe, vcxgbe_probe), 121308154Sjhb DEVMETHOD(device_attach, vcxgbe_attach), 122308154Sjhb DEVMETHOD(device_detach, vcxgbe_detach), 123308154Sjhb { 0, 0 } 124308154Sjhb}; 125308154Sjhbstatic driver_t vcxgbe_driver = { 126308154Sjhb "vcxgbe", 127308154Sjhb vcxgbe_methods, 128308154Sjhb sizeof(struct vi_info) 129308154Sjhb}; 130308154Sjhb 131218792Snpstatic d_ioctl_t t4_ioctl; 132218792Snp 133218792Snpstatic struct cdevsw t4_cdevsw = { 134218792Snp .d_version = D_VERSION, 135218792Snp .d_ioctl = t4_ioctl, 136218792Snp .d_name = "t4nex", 137218792Snp}; 138218792Snp 139248925Snp/* T5 bus driver interface */ 140248925Snpstatic int t5_probe(device_t); 141248925Snpstatic device_method_t t5_methods[] = { 142248925Snp DEVMETHOD(device_probe, t5_probe), 143248925Snp DEVMETHOD(device_attach, t4_attach), 144248925Snp DEVMETHOD(device_detach, t4_detach), 145248925Snp 146248925Snp DEVMETHOD_END 147248925Snp}; 148248925Snpstatic driver_t t5_driver = { 149248925Snp "t5nex", 150248925Snp t5_methods, 151248925Snp sizeof(struct adapter) 152248925Snp}; 153248925Snp 154248925Snp 155248925Snp/* T5 port (cxl) interface */ 156248925Snpstatic driver_t cxl_driver = { 157248925Snp "cxl", 158248925Snp cxgbe_methods, 159248925Snp sizeof(struct port_info) 160248925Snp}; 161248925Snp 162308154Sjhb/* T5 VI (vcxl) interface */ 163308154Sjhbstatic driver_t vcxl_driver = { 164308154Sjhb "vcxl", 165308154Sjhb vcxgbe_methods, 166308154Sjhb sizeof(struct vi_info) 167308154Sjhb}; 168308154Sjhb 169309560Sjhb/* T6 bus driver interface */ 170309560Sjhbstatic int t6_probe(device_t); 171309560Sjhbstatic device_method_t t6_methods[] = { 172309560Sjhb DEVMETHOD(device_probe, t6_probe), 173309560Sjhb DEVMETHOD(device_attach, t4_attach), 174309560Sjhb DEVMETHOD(device_detach, t4_detach), 175309560Sjhb 176309560Sjhb DEVMETHOD_END 177309560Sjhb}; 178309560Sjhbstatic driver_t t6_driver = { 179309560Sjhb "t6nex", 180309560Sjhb t6_methods, 181309560Sjhb sizeof(struct adapter) 182309560Sjhb}; 183309560Sjhb 184309560Sjhb 185309560Sjhb/* T6 port (cc) interface */ 186309560Sjhbstatic driver_t cc_driver = { 187309560Sjhb "cc", 188309560Sjhb cxgbe_methods, 189309560Sjhb sizeof(struct port_info) 190309560Sjhb}; 191309560Sjhb 192309560Sjhb/* T6 VI (vcc) interface */ 193309560Sjhbstatic driver_t vcc_driver = { 194309560Sjhb "vcc", 195309560Sjhb vcxgbe_methods, 196309560Sjhb sizeof(struct vi_info) 197309560Sjhb}; 198309560Sjhb 199218792Snp/* ifnet + media interface */ 200218792Snpstatic void cxgbe_init(void *); 201218792Snpstatic int cxgbe_ioctl(struct ifnet *, unsigned long, caddr_t); 202218792Snpstatic int cxgbe_transmit(struct ifnet *, struct mbuf *); 203218792Snpstatic void cxgbe_qflush(struct ifnet *); 204218792Snpstatic int cxgbe_media_change(struct ifnet *); 205218792Snpstatic void cxgbe_media_status(struct ifnet *, struct ifmediareq *); 206218792Snp 207248925SnpMALLOC_DEFINE(M_CXGBE, "cxgbe", "Chelsio T4/T5 Ethernet driver and services"); 208218792Snp 209237263Snp/* 210237263Snp * Correct lock order when you need to acquire multiple locks is t4_list_lock, 211237263Snp * then ADAPTER_LOCK, then t4_uld_list_lock. 212237263Snp */ 213255006Snpstatic struct sx t4_list_lock; 214259241SnpSLIST_HEAD(, adapter) t4_list; 215237263Snp#ifdef TCP_OFFLOAD 216255006Snpstatic struct sx t4_uld_list_lock; 217259241SnpSLIST_HEAD(, uld_info) t4_uld_list; 218228561Snp#endif 219218792Snp 220218792Snp/* 221228561Snp * Tunables. See tweak_tunables() too. 222248925Snp * 223248925Snp * Each tunable is set to a default value here if it's known at compile-time. 224318809Snp * Otherwise it is set to -n as an indication to tweak_tunables() that it should 225318809Snp * provide a reasonable default (upto n) when the driver is loaded. 226248925Snp * 227248925Snp * Tunables applicable to both T4 and T5 are under hw.cxgbe. Those specific to 228248925Snp * T5 are under hw.cxl. 229218792Snp */ 230218792Snp 231218792Snp/* 232228561Snp * Number of queues for tx and rx, 10G and 1G, NIC and offload. 233218792Snp */ 234228561Snp#define NTXQ_10G 16 235318809Snpint t4_ntxq10g = -NTXQ_10G; 236228561SnpTUNABLE_INT("hw.cxgbe.ntxq10g", &t4_ntxq10g); 237218792Snp 238228561Snp#define NRXQ_10G 8 239318809Snpint t4_nrxq10g = -NRXQ_10G; 240228561SnpTUNABLE_INT("hw.cxgbe.nrxq10g", &t4_nrxq10g); 241218792Snp 242228561Snp#define NTXQ_1G 4 243318809Snpint t4_ntxq1g = -NTXQ_1G; 244228561SnpTUNABLE_INT("hw.cxgbe.ntxq1g", &t4_ntxq1g); 245218792Snp 246228561Snp#define NRXQ_1G 2 247318809Snpint t4_nrxq1g = -NRXQ_1G; 248228561SnpTUNABLE_INT("hw.cxgbe.nrxq1g", &t4_nrxq1g); 249218792Snp 250308154Sjhb#define NTXQ_VI 1 251318809Snpstatic int t4_ntxq_vi = -NTXQ_VI; 252308154SjhbTUNABLE_INT("hw.cxgbe.ntxq_vi", &t4_ntxq_vi); 253308154Sjhb 254308154Sjhb#define NRXQ_VI 1 255318809Snpstatic int t4_nrxq_vi = -NRXQ_VI; 256308154SjhbTUNABLE_INT("hw.cxgbe.nrxq_vi", &t4_nrxq_vi); 257308154Sjhb 258264493Sscottlstatic int t4_rsrv_noflowq = 0; 259264493SscottlTUNABLE_INT("hw.cxgbe.rsrv_noflowq", &t4_rsrv_noflowq); 260264493Sscottl 261237263Snp#ifdef TCP_OFFLOAD 262228561Snp#define NOFLDTXQ_10G 8 263318809Snpstatic int t4_nofldtxq10g = -NOFLDTXQ_10G; 264228561SnpTUNABLE_INT("hw.cxgbe.nofldtxq10g", &t4_nofldtxq10g); 265228561Snp 266228561Snp#define NOFLDRXQ_10G 2 267318809Snpstatic int t4_nofldrxq10g = -NOFLDRXQ_10G; 268228561SnpTUNABLE_INT("hw.cxgbe.nofldrxq10g", &t4_nofldrxq10g); 269228561Snp 270228561Snp#define NOFLDTXQ_1G 2 271318809Snpstatic int t4_nofldtxq1g = -NOFLDTXQ_1G; 272228561SnpTUNABLE_INT("hw.cxgbe.nofldtxq1g", &t4_nofldtxq1g); 273228561Snp 274228561Snp#define NOFLDRXQ_1G 1 275318809Snpstatic int t4_nofldrxq1g = -NOFLDRXQ_1G; 276228561SnpTUNABLE_INT("hw.cxgbe.nofldrxq1g", &t4_nofldrxq1g); 277308154Sjhb 278308154Sjhb#define NOFLDTXQ_VI 1 279318809Snpstatic int t4_nofldtxq_vi = -NOFLDTXQ_VI; 280308154SjhbTUNABLE_INT("hw.cxgbe.nofldtxq_vi", &t4_nofldtxq_vi); 281308154Sjhb 282308154Sjhb#define NOFLDRXQ_VI 1 283318809Snpstatic int t4_nofldrxq_vi = -NOFLDRXQ_VI; 284308154SjhbTUNABLE_INT("hw.cxgbe.nofldrxq_vi", &t4_nofldrxq_vi); 285228561Snp#endif 286228561Snp 287270297Snp#ifdef DEV_NETMAP 288308154Sjhb#define NNMTXQ_VI 2 289318809Snpstatic int t4_nnmtxq_vi = -NNMTXQ_VI; 290308154SjhbTUNABLE_INT("hw.cxgbe.nnmtxq_vi", &t4_nnmtxq_vi); 291270297Snp 292308154Sjhb#define NNMRXQ_VI 2 293318809Snpstatic int t4_nnmrxq_vi = -NNMRXQ_VI; 294308154SjhbTUNABLE_INT("hw.cxgbe.nnmrxq_vi", &t4_nnmrxq_vi); 295270297Snp#endif 296270297Snp 297218792Snp/* 298218792Snp * Holdoff parameters for 10G and 1G ports. 299218792Snp */ 300228561Snp#define TMR_IDX_10G 1 301309447Sjhbint t4_tmr_idx_10g = TMR_IDX_10G; 302228561SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_10G", &t4_tmr_idx_10g); 303218792Snp 304234833Snp#define PKTC_IDX_10G (-1) 305309447Sjhbint t4_pktc_idx_10g = PKTC_IDX_10G; 306228561SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_10G", &t4_pktc_idx_10g); 307218792Snp 308228561Snp#define TMR_IDX_1G 1 309309447Sjhbint t4_tmr_idx_1g = TMR_IDX_1G; 310228561SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_1G", &t4_tmr_idx_1g); 311218792Snp 312234833Snp#define PKTC_IDX_1G (-1) 313309447Sjhbint t4_pktc_idx_1g = PKTC_IDX_1G; 314228561SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_1G", &t4_pktc_idx_1g); 315218792Snp 316218792Snp/* 317218792Snp * Size (# of entries) of each tx and rx queue. 318218792Snp */ 319309447Sjhbunsigned int t4_qsize_txq = TX_EQ_QSIZE; 320228561SnpTUNABLE_INT("hw.cxgbe.qsize_txq", &t4_qsize_txq); 321218792Snp 322309447Sjhbunsigned int t4_qsize_rxq = RX_IQ_QSIZE; 323228561SnpTUNABLE_INT("hw.cxgbe.qsize_rxq", &t4_qsize_rxq); 324218792Snp 325218792Snp/* 326228561Snp * Interrupt types allowed (bits 0, 1, 2 = INTx, MSI, MSI-X respectively). 327218792Snp */ 328309447Sjhbint t4_intr_types = INTR_MSIX | INTR_MSI | INTR_INTX; 329228561SnpTUNABLE_INT("hw.cxgbe.interrupt_types", &t4_intr_types); 330218792Snp 331218792Snp/* 332228561Snp * Configuration file. 333218792Snp */ 334248925Snp#define DEFAULT_CF "default" 335248925Snp#define FLASH_CF "flash" 336248925Snp#define UWIRE_CF "uwire" 337249376Snp#define FPGA_CF "fpga" 338248925Snpstatic char t4_cfg_file[32] = DEFAULT_CF; 339228561SnpTUNABLE_STR("hw.cxgbe.config_file", t4_cfg_file, sizeof(t4_cfg_file)); 340218792Snp 341228561Snp/* 342271961Snp * PAUSE settings (bit 0, 1 = rx_pause, tx_pause respectively). 343271961Snp * rx_pause = 1 to heed incoming PAUSE frames, 0 to ignore them. 344271961Snp * tx_pause = 1 to emit PAUSE frames when the rx FIFO reaches its high water 345271961Snp * mark or when signalled to do so, 0 to never emit PAUSE. 346271961Snp */ 347271961Snpstatic int t4_pause_settings = PAUSE_TX | PAUSE_RX; 348271961SnpTUNABLE_INT("hw.cxgbe.pause_settings", &t4_pause_settings); 349271961Snp 350271961Snp/* 351311261Snp * Forward Error Correction settings (bit 0, 1, 2 = FEC_RS, FEC_BASER_RS, 352311261Snp * FEC_RESERVED respectively). 353311261Snp * -1 to run with the firmware default. 354311261Snp * 0 to disable FEC. 355311261Snp */ 356311261Snpstatic int t4_fec = -1; 357311261SnpTUNABLE_INT("hw.cxgbe.fec", &t4_fec); 358311261Snp 359311261Snp/* 360311261Snp * Link autonegotiation. 361311261Snp * -1 to run with the firmware default. 362311261Snp * 0 to disable. 363311261Snp * 1 to enable. 364311261Snp */ 365311261Snpstatic int t4_autoneg = -1; 366311261SnpTUNABLE_INT("hw.cxgbe.autoneg", &t4_autoneg); 367311261Snp 368311261Snp/* 369247347Snp * Firmware auto-install by driver during attach (0, 1, 2 = prohibited, allowed, 370247347Snp * encouraged respectively). 371247347Snp */ 372247347Snpstatic unsigned int t4_fw_install = 1; 373247347SnpTUNABLE_INT("hw.cxgbe.fw_install", &t4_fw_install); 374247347Snp 375247347Snp/* 376228561Snp * ASIC features that will be used. Disable the ones you don't want so that the 377228561Snp * chip resources aren't wasted on features that will not be used. 378228561Snp */ 379308304Sjhbstatic int t4_nbmcaps_allowed = 0; 380308304SjhbTUNABLE_INT("hw.cxgbe.nbmcaps_allowed", &t4_nbmcaps_allowed); 381308304Sjhb 382228561Snpstatic int t4_linkcaps_allowed = 0; /* No DCBX, PPP, etc. by default */ 383228561SnpTUNABLE_INT("hw.cxgbe.linkcaps_allowed", &t4_linkcaps_allowed); 384221474Snp 385308313Sjhbstatic int t4_switchcaps_allowed = FW_CAPS_CONFIG_SWITCH_INGRESS | 386308313Sjhb FW_CAPS_CONFIG_SWITCH_EGRESS; 387308304SjhbTUNABLE_INT("hw.cxgbe.switchcaps_allowed", &t4_switchcaps_allowed); 388308304Sjhb 389228561Snpstatic int t4_niccaps_allowed = FW_CAPS_CONFIG_NIC; 390228561SnpTUNABLE_INT("hw.cxgbe.niccaps_allowed", &t4_niccaps_allowed); 391228561Snp 392238028Snpstatic int t4_toecaps_allowed = -1; 393228561SnpTUNABLE_INT("hw.cxgbe.toecaps_allowed", &t4_toecaps_allowed); 394228561Snp 395308313Sjhbstatic int t4_rdmacaps_allowed = -1; 396228561SnpTUNABLE_INT("hw.cxgbe.rdmacaps_allowed", &t4_rdmacaps_allowed); 397228561Snp 398309560Sjhbstatic int t4_cryptocaps_allowed = 0; 399309560SjhbTUNABLE_INT("hw.cxgbe.cryptocaps_allowed", &t4_cryptocaps_allowed); 400308304Sjhb 401308313Sjhbstatic int t4_iscsicaps_allowed = -1; 402228561SnpTUNABLE_INT("hw.cxgbe.iscsicaps_allowed", &t4_iscsicaps_allowed); 403228561Snp 404228561Snpstatic int t4_fcoecaps_allowed = 0; 405228561SnpTUNABLE_INT("hw.cxgbe.fcoecaps_allowed", &t4_fcoecaps_allowed); 406228561Snp 407248925Snpstatic int t5_write_combine = 0; 408248925SnpTUNABLE_INT("hw.cxl.write_combine", &t5_write_combine); 409248925Snp 410308154Sjhbstatic int t4_num_vis = 1; 411308154SjhbTUNABLE_INT("hw.cxgbe.num_vis", &t4_num_vis); 412308154Sjhb 413308154Sjhb/* Functions used by extra VIs to obtain unique MAC addresses for each VI. */ 414308154Sjhbstatic int vi_mac_funcs[] = { 415308154Sjhb FW_VI_FUNC_OFLD, 416308154Sjhb FW_VI_FUNC_IWARP, 417308154Sjhb FW_VI_FUNC_OPENISCSI, 418308154Sjhb FW_VI_FUNC_OPENFCOE, 419308154Sjhb FW_VI_FUNC_FOISCSI, 420308154Sjhb FW_VI_FUNC_FOFCOE, 421308154Sjhb}; 422308154Sjhb 423218792Snpstruct intrs_and_queues { 424270297Snp uint16_t intr_type; /* INTx, MSI, or MSI-X */ 425270297Snp uint16_t nirq; /* Total # of vectors */ 426270297Snp uint16_t intr_flags_10g;/* Interrupt flags for each 10G port */ 427270297Snp uint16_t intr_flags_1g; /* Interrupt flags for each 1G port */ 428270297Snp uint16_t ntxq10g; /* # of NIC txq's for each 10G port */ 429270297Snp uint16_t nrxq10g; /* # of NIC rxq's for each 10G port */ 430270297Snp uint16_t ntxq1g; /* # of NIC txq's for each 1G port */ 431270297Snp uint16_t nrxq1g; /* # of NIC rxq's for each 1G port */ 432270297Snp uint16_t rsrv_noflowq; /* Flag whether to reserve queue 0 */ 433270297Snp uint16_t nofldtxq10g; /* # of TOE txq's for each 10G port */ 434270297Snp uint16_t nofldrxq10g; /* # of TOE rxq's for each 10G port */ 435270297Snp uint16_t nofldtxq1g; /* # of TOE txq's for each 1G port */ 436270297Snp uint16_t nofldrxq1g; /* # of TOE rxq's for each 1G port */ 437308154Sjhb 438308154Sjhb /* The vcxgbe/vcxl interfaces use these and not the ones above. */ 439308154Sjhb uint16_t ntxq_vi; /* # of NIC txq's */ 440308154Sjhb uint16_t nrxq_vi; /* # of NIC rxq's */ 441308154Sjhb uint16_t nofldtxq_vi; /* # of TOE txq's */ 442308154Sjhb uint16_t nofldrxq_vi; /* # of TOE rxq's */ 443308154Sjhb uint16_t nnmtxq_vi; /* # of netmap txq's */ 444308154Sjhb uint16_t nnmrxq_vi; /* # of netmap rxq's */ 445218792Snp}; 446218792Snp 447221474Snpstruct filter_entry { 448221474Snp uint32_t valid:1; /* filter allocated and valid */ 449221474Snp uint32_t locked:1; /* filter is administratively locked */ 450221474Snp uint32_t pending:1; /* filter action is pending firmware reply */ 451221474Snp uint32_t smtidx:8; /* Source MAC Table index for smac */ 452222509Snp struct l2t_entry *l2t; /* Layer Two Table entry for dmac */ 453221474Snp 454221474Snp struct t4_filter_specification fs; 455221474Snp}; 456221474Snp 457218792Snpstatic void setup_memwin(struct adapter *); 458308305Sjhbstatic void position_memwin(struct adapter *, int, uint32_t); 459308305Sjhbstatic int rw_via_memwin(struct adapter *, int, uint32_t, uint32_t *, int, int); 460308305Sjhbstatic inline int read_via_memwin(struct adapter *, int, uint32_t, uint32_t *, 461308305Sjhb int); 462308305Sjhbstatic inline int write_via_memwin(struct adapter *, int, uint32_t, 463308305Sjhb const uint32_t *, int); 464248925Snpstatic int validate_mem_range(struct adapter *, uint32_t, int); 465256791Snpstatic int fwmtype_to_hwmtype(int); 466248925Snpstatic int validate_mt_off_len(struct adapter *, int, uint32_t, int, 467248925Snp uint32_t *); 468308305Sjhbstatic int fixup_devlog_params(struct adapter *); 469308154Sjhbstatic int cfg_itype_and_nqueues(struct adapter *, int, int, int, 470218792Snp struct intrs_and_queues *); 471218792Snpstatic int prep_firmware(struct adapter *); 472248925Snpstatic int partition_resources(struct adapter *, const struct firmware *, 473248925Snp const char *); 474228561Snpstatic int get_params__pre_init(struct adapter *); 475228561Snpstatic int get_params__post_init(struct adapter *); 476247291Snpstatic int set_params__post_init(struct adapter *); 477218792Snpstatic void t4_set_desc(struct adapter *); 478270297Snpstatic void build_medialist(struct port_info *, struct ifmedia *); 479353418Snpstatic void init_l1cfg(struct port_info *); 480353418Snpstatic int apply_l1cfg(struct port_info *); 481308154Sjhbstatic int cxgbe_init_synchronized(struct vi_info *); 482308154Sjhbstatic int cxgbe_uninit_synchronized(struct vi_info *); 483284052Snpstatic void quiesce_txq(struct adapter *, struct sge_txq *); 484284052Snpstatic void quiesce_wrq(struct adapter *, struct sge_wrq *); 485228561Snpstatic void quiesce_iq(struct adapter *, struct sge_iq *); 486228561Snpstatic void quiesce_fl(struct adapter *, struct sge_fl *); 487218792Snpstatic int t4_alloc_irq(struct adapter *, struct irq *, int rid, 488228561Snp driver_intr_t *, void *, char *); 489218792Snpstatic int t4_free_irq(struct adapter *, struct irq *); 490308304Sjhbstatic void get_regs(struct adapter *, struct t4_regdump *, uint8_t *); 491308154Sjhbstatic void vi_refresh_stats(struct adapter *, struct vi_info *); 492282486Snpstatic void cxgbe_refresh_stats(struct adapter *, struct port_info *); 493218792Snpstatic void cxgbe_tick(void *); 494237263Snpstatic void cxgbe_vlan_config(void *, struct ifnet *, uint16_t); 495308154Sjhbstatic void cxgbe_sysctls(struct port_info *); 496219436Snpstatic int sysctl_int_array(SYSCTL_HANDLER_ARGS); 497228561Snpstatic int sysctl_bitfield(SYSCTL_HANDLER_ARGS); 498252747Snpstatic int sysctl_btphy(SYSCTL_HANDLER_ARGS); 499264493Sscottlstatic int sysctl_noflowq(SYSCTL_HANDLER_ARGS); 500218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS); 501218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS); 502218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS); 503218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS); 504271961Snpstatic int sysctl_pause_settings(SYSCTL_HANDLER_ARGS); 505311261Snpstatic int sysctl_fec(SYSCTL_HANDLER_ARGS); 506311261Snpstatic int sysctl_autoneg(SYSCTL_HANDLER_ARGS); 507218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS); 508253890Snpstatic int sysctl_temperature(SYSCTL_HANDLER_ARGS); 509231115Snp#ifdef SBUF_DRAIN 510228561Snpstatic int sysctl_cctrl(SYSCTL_HANDLER_ARGS); 511247122Snpstatic int sysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS); 512247122Snpstatic int sysctl_cim_la(SYSCTL_HANDLER_ARGS); 513308304Sjhbstatic int sysctl_cim_la_t6(SYSCTL_HANDLER_ARGS); 514251213Snpstatic int sysctl_cim_ma_la(SYSCTL_HANDLER_ARGS); 515251213Snpstatic int sysctl_cim_pif_la(SYSCTL_HANDLER_ARGS); 516247122Snpstatic int sysctl_cim_qcfg(SYSCTL_HANDLER_ARGS); 517228561Snpstatic int sysctl_cpl_stats(SYSCTL_HANDLER_ARGS); 518228561Snpstatic int sysctl_ddp_stats(SYSCTL_HANDLER_ARGS); 519222551Snpstatic int sysctl_devlog(SYSCTL_HANDLER_ARGS); 520228561Snpstatic int sysctl_fcoe_stats(SYSCTL_HANDLER_ARGS); 521228561Snpstatic int sysctl_hw_sched(SYSCTL_HANDLER_ARGS); 522228561Snpstatic int sysctl_lb_stats(SYSCTL_HANDLER_ARGS); 523253701Snpstatic int sysctl_linkdnrc(SYSCTL_HANDLER_ARGS); 524228561Snpstatic int sysctl_meminfo(SYSCTL_HANDLER_ARGS); 525251213Snpstatic int sysctl_mps_tcam(SYSCTL_HANDLER_ARGS); 526308304Sjhbstatic int sysctl_mps_tcam_t6(SYSCTL_HANDLER_ARGS); 527228561Snpstatic int sysctl_path_mtus(SYSCTL_HANDLER_ARGS); 528228561Snpstatic int sysctl_pm_stats(SYSCTL_HANDLER_ARGS); 529228561Snpstatic int sysctl_rdma_stats(SYSCTL_HANDLER_ARGS); 530228561Snpstatic int sysctl_tcp_stats(SYSCTL_HANDLER_ARGS); 531228561Snpstatic int sysctl_tids(SYSCTL_HANDLER_ARGS); 532228561Snpstatic int sysctl_tp_err_stats(SYSCTL_HANDLER_ARGS); 533308311Sjhbstatic int sysctl_tp_la_mask(SYSCTL_HANDLER_ARGS); 534251213Snpstatic int sysctl_tp_la(SYSCTL_HANDLER_ARGS); 535228561Snpstatic int sysctl_tx_rate(SYSCTL_HANDLER_ARGS); 536251213Snpstatic int sysctl_ulprx_la(SYSCTL_HANDLER_ARGS); 537249392Snpstatic int sysctl_wcwr_stats(SYSCTL_HANDLER_ARGS); 538308321Sjhbstatic int sysctl_tc_params(SYSCTL_HANDLER_ARGS); 539231115Snp#endif 540308311Sjhb#ifdef TCP_OFFLOAD 541308311Sjhbstatic int sysctl_tp_tick(SYSCTL_HANDLER_ARGS); 542308311Sjhbstatic int sysctl_tp_dack_timer(SYSCTL_HANDLER_ARGS); 543308311Sjhbstatic int sysctl_tp_timer(SYSCTL_HANDLER_ARGS); 544308311Sjhb#endif 545308304Sjhbstatic uint32_t fconf_iconf_to_mode(uint32_t, uint32_t); 546221474Snpstatic uint32_t mode_to_fconf(uint32_t); 547308304Sjhbstatic uint32_t mode_to_iconf(uint32_t); 548308304Sjhbstatic int check_fspec_against_fconf_iconf(struct adapter *, 549308304Sjhb struct t4_filter_specification *); 550221474Snpstatic int get_filter_mode(struct adapter *, uint32_t *); 551221474Snpstatic int set_filter_mode(struct adapter *, uint32_t); 552222552Snpstatic inline uint64_t get_filter_hits(struct adapter *, uint32_t); 553221474Snpstatic int get_filter(struct adapter *, struct t4_filter *); 554221474Snpstatic int set_filter(struct adapter *, struct t4_filter *); 555221474Snpstatic int del_filter(struct adapter *, struct t4_filter *); 556222509Snpstatic void clear_filter(struct filter_entry *); 557221474Snpstatic int set_filter_wr(struct adapter *, int); 558221474Snpstatic int del_filter_wr(struct adapter *, int); 559309442Sjhbstatic int set_tcb_rpl(struct sge_iq *, const struct rss_header *, 560309442Sjhb struct mbuf *); 561222973Snpstatic int get_sge_context(struct adapter *, struct t4_sge_context *); 562245274Snpstatic int load_fw(struct adapter *, struct t4_data *); 563309569Sjhbstatic int load_cfg(struct adapter *, struct t4_data *); 564248925Snpstatic int read_card_mem(struct adapter *, int, struct t4_mem_range *); 565241399Snpstatic int read_i2c(struct adapter *, struct t4_i2c_data *); 566237263Snp#ifdef TCP_OFFLOAD 567308154Sjhbstatic int toe_capability(struct vi_info *, int); 568228561Snp#endif 569249370Snpstatic int mod_event(module_t, int, void *); 570218792Snp 571248925Snpstruct { 572218792Snp uint16_t device; 573218792Snp char *desc; 574218792Snp} t4_pciids[] = { 575237587Snp {0xa000, "Chelsio Terminator 4 FPGA"}, 576237587Snp {0x4400, "Chelsio T440-dbg"}, 577237587Snp {0x4401, "Chelsio T420-CR"}, 578237587Snp {0x4402, "Chelsio T422-CR"}, 579237587Snp {0x4403, "Chelsio T440-CR"}, 580237587Snp {0x4404, "Chelsio T420-BCH"}, 581237587Snp {0x4405, "Chelsio T440-BCH"}, 582237587Snp {0x4406, "Chelsio T440-CH"}, 583237587Snp {0x4407, "Chelsio T420-SO"}, 584237587Snp {0x4408, "Chelsio T420-CX"}, 585237587Snp {0x4409, "Chelsio T420-BT"}, 586237587Snp {0x440a, "Chelsio T404-BT"}, 587244580Snp {0x440e, "Chelsio T440-LP-CR"}, 588248925Snp}, t5_pciids[] = { 589248925Snp {0xb000, "Chelsio Terminator 5 FPGA"}, 590248925Snp {0x5400, "Chelsio T580-dbg"}, 591253699Snp {0x5401, "Chelsio T520-CR"}, /* 2 x 10G */ 592253699Snp {0x5402, "Chelsio T522-CR"}, /* 2 x 10G, 2 X 1G */ 593253217Snp {0x5403, "Chelsio T540-CR"}, /* 4 x 10G */ 594253699Snp {0x5407, "Chelsio T520-SO"}, /* 2 x 10G, nomem */ 595253699Snp {0x5409, "Chelsio T520-BT"}, /* 2 x 10GBaseT */ 596253699Snp {0x540a, "Chelsio T504-BT"}, /* 4 x 1G */ 597253699Snp {0x540d, "Chelsio T580-CR"}, /* 2 x 40G */ 598253699Snp {0x540e, "Chelsio T540-LP-CR"}, /* 4 x 10G */ 599250093Snp {0x5410, "Chelsio T580-LP-CR"}, /* 2 x 40G */ 600253699Snp {0x5411, "Chelsio T520-LL-CR"}, /* 2 x 10G */ 601253699Snp {0x5412, "Chelsio T560-CR"}, /* 1 x 40G, 2 x 10G */ 602253699Snp {0x5414, "Chelsio T580-LP-SO-CR"}, /* 2 x 40G, nomem */ 603278286Sjhb {0x5415, "Chelsio T502-BT"}, /* 2 x 1G */ 604353418Snp {0x5418, "Chelsio T540-BT"}, /* 4 x 10GBaseT */ 605353418Snp {0x5419, "Chelsio T540-LP-BT"}, /* 4 x 10GBaseT */ 606353418Snp {0x541a, "Chelsio T540-SO-BT"}, /* 4 x 10GBaseT, nomem */ 607353418Snp {0x541b, "Chelsio T540-SO-CR"}, /* 4 x 10G, nomem */ 608353418Snp 609353418Snp /* Custom */ 610353418Snp {0x5483, "Custom T540-CR"}, 611353418Snp {0x5484, "Custom T540-BT"}, 612309560Sjhb}, t6_pciids[] = { 613309560Sjhb {0xc006, "Chelsio Terminator 6 FPGA"}, /* T6 PE10K6 FPGA (PF0) */ 614318844Snp {0x6400, "Chelsio T6-DBG-25"}, /* 2 x 10/25G, debug */ 615309560Sjhb {0x6401, "Chelsio T6225-CR"}, /* 2 x 10/25G */ 616309560Sjhb {0x6402, "Chelsio T6225-SO-CR"}, /* 2 x 10/25G, nomem */ 617318844Snp {0x6403, "Chelsio T6425-CR"}, /* 4 x 10/25G */ 618318844Snp {0x6404, "Chelsio T6425-SO-CR"}, /* 4 x 10/25G, nomem */ 619318844Snp {0x6405, "Chelsio T6225-OCP-SO"}, /* 2 x 10/25G, nomem */ 620318844Snp {0x6406, "Chelsio T62100-OCP-SO"}, /* 2 x 40/50/100G, nomem */ 621309560Sjhb {0x6407, "Chelsio T62100-LP-CR"}, /* 2 x 40/50/100G */ 622309560Sjhb {0x6408, "Chelsio T62100-SO-CR"}, /* 2 x 40/50/100G, nomem */ 623318844Snp {0x6409, "Chelsio T6210-BT"}, /* 2 x 10GBASE-T */ 624309560Sjhb {0x640d, "Chelsio T62100-CR"}, /* 2 x 40/50/100G */ 625318844Snp {0x6410, "Chelsio T6-DBG-100"}, /* 2 x 40/50/100G, debug */ 626318844Snp {0x6411, "Chelsio T6225-LL-CR"}, /* 2 x 10/25G */ 627318844Snp {0x6414, "Chelsio T61100-OCP-SO"}, /* 1 x 40/50/100G, nomem */ 628318844Snp {0x6415, "Chelsio T6201-BT"}, /* 2 x 1000BASE-T */ 629318844Snp 630318844Snp /* Custom */ 631353418Snp {0x6480, "Custom T6225-CR"}, 632353418Snp {0x6481, "Custom T62100-CR"}, 633353418Snp {0x6482, "Custom T6225-CR"}, 634353418Snp {0x6483, "Custom T62100-CR"}, 635353418Snp {0x6484, "Custom T64100-CR"}, 636353418Snp {0x6485, "Custom T6240-SO"}, 637353418Snp {0x6486, "Custom T6225-SO-CR"}, 638353418Snp {0x6487, "Custom T6225-CR"}, 639218792Snp}; 640218792Snp 641237263Snp#ifdef TCP_OFFLOAD 642237263Snp/* 643237263Snp * service_iq() has an iq and needs the fl. Offset of fl from the iq should be 644237263Snp * exactly the same for both rxq and ofld_rxq. 645237263Snp */ 646237263SnpCTASSERT(offsetof(struct sge_ofld_rxq, iq) == offsetof(struct sge_rxq, iq)); 647228561SnpCTASSERT(offsetof(struct sge_ofld_rxq, fl) == offsetof(struct sge_rxq, fl)); 648228561Snp#endif 649265425SnpCTASSERT(sizeof(struct cluster_metadata) <= CL_METADATA_SIZE); 650265425Snp 651218792Snpstatic int 652218792Snpt4_probe(device_t dev) 653218792Snp{ 654218792Snp int i; 655218792Snp uint16_t v = pci_get_vendor(dev); 656218792Snp uint16_t d = pci_get_device(dev); 657237587Snp uint8_t f = pci_get_function(dev); 658218792Snp 659218792Snp if (v != PCI_VENDOR_ID_CHELSIO) 660218792Snp return (ENXIO); 661218792Snp 662237587Snp /* Attach only to PF0 of the FPGA */ 663237587Snp if (d == 0xa000 && f != 0) 664237587Snp return (ENXIO); 665237587Snp 666240452Snp for (i = 0; i < nitems(t4_pciids); i++) { 667237587Snp if (d == t4_pciids[i].device) { 668218792Snp device_set_desc(dev, t4_pciids[i].desc); 669218792Snp return (BUS_PROBE_DEFAULT); 670218792Snp } 671218792Snp } 672218792Snp 673218792Snp return (ENXIO); 674218792Snp} 675218792Snp 676218792Snpstatic int 677248925Snpt5_probe(device_t dev) 678248925Snp{ 679248925Snp int i; 680248925Snp uint16_t v = pci_get_vendor(dev); 681248925Snp uint16_t d = pci_get_device(dev); 682248925Snp uint8_t f = pci_get_function(dev); 683248925Snp 684248925Snp if (v != PCI_VENDOR_ID_CHELSIO) 685248925Snp return (ENXIO); 686248925Snp 687248925Snp /* Attach only to PF0 of the FPGA */ 688248925Snp if (d == 0xb000 && f != 0) 689248925Snp return (ENXIO); 690248925Snp 691248925Snp for (i = 0; i < nitems(t5_pciids); i++) { 692248925Snp if (d == t5_pciids[i].device) { 693248925Snp device_set_desc(dev, t5_pciids[i].desc); 694248925Snp return (BUS_PROBE_DEFAULT); 695248925Snp } 696248925Snp } 697248925Snp 698248925Snp return (ENXIO); 699248925Snp} 700248925Snp 701309560Sjhbstatic int 702309560Sjhbt6_probe(device_t dev) 703309560Sjhb{ 704309560Sjhb int i; 705309560Sjhb uint16_t v = pci_get_vendor(dev); 706309560Sjhb uint16_t d = pci_get_device(dev); 707309560Sjhb 708309560Sjhb if (v != PCI_VENDOR_ID_CHELSIO) 709309560Sjhb return (ENXIO); 710309560Sjhb 711309560Sjhb for (i = 0; i < nitems(t6_pciids); i++) { 712309560Sjhb if (d == t6_pciids[i].device) { 713309560Sjhb device_set_desc(dev, t6_pciids[i].desc); 714309560Sjhb return (BUS_PROBE_DEFAULT); 715309560Sjhb } 716309560Sjhb } 717309560Sjhb 718309560Sjhb return (ENXIO); 719309560Sjhb} 720309560Sjhb 721291083Sjhbstatic void 722291083Sjhbt5_attribute_workaround(device_t dev) 723291083Sjhb{ 724291083Sjhb device_t root_port; 725291083Sjhb uint32_t v; 726291083Sjhb 727291083Sjhb /* 728291083Sjhb * The T5 chips do not properly echo the No Snoop and Relaxed 729291083Sjhb * Ordering attributes when replying to a TLP from a Root 730291083Sjhb * Port. As a workaround, find the parent Root Port and 731291083Sjhb * disable No Snoop and Relaxed Ordering. Note that this 732291083Sjhb * affects all devices under this root port. 733291083Sjhb */ 734291083Sjhb root_port = pci_find_pcie_root_port(dev); 735291083Sjhb if (root_port == NULL) { 736291083Sjhb device_printf(dev, "Unable to find parent root port\n"); 737291083Sjhb return; 738291083Sjhb } 739291083Sjhb 740291083Sjhb v = pcie_adjust_config(root_port, PCIER_DEVICE_CTL, 741291083Sjhb PCIEM_CTL_RELAXED_ORD_ENABLE | PCIEM_CTL_NOSNOOP_ENABLE, 0, 2); 742291083Sjhb if ((v & (PCIEM_CTL_RELAXED_ORD_ENABLE | PCIEM_CTL_NOSNOOP_ENABLE)) != 743291083Sjhb 0) 744291083Sjhb device_printf(dev, "Disabled No Snoop/Relaxed Ordering on %s\n", 745291083Sjhb device_get_nameunit(root_port)); 746291083Sjhb} 747291083Sjhb 748309560Sjhbstatic const struct devnames devnames[] = { 749309560Sjhb { 750309560Sjhb .nexus_name = "t4nex", 751309560Sjhb .ifnet_name = "cxgbe", 752309560Sjhb .vi_ifnet_name = "vcxgbe", 753309560Sjhb .pf03_drv_name = "t4iov", 754309560Sjhb .vf_nexus_name = "t4vf", 755309560Sjhb .vf_ifnet_name = "cxgbev" 756309560Sjhb }, { 757309560Sjhb .nexus_name = "t5nex", 758309560Sjhb .ifnet_name = "cxl", 759309560Sjhb .vi_ifnet_name = "vcxl", 760309560Sjhb .pf03_drv_name = "t5iov", 761309560Sjhb .vf_nexus_name = "t5vf", 762309560Sjhb .vf_ifnet_name = "cxlv" 763309560Sjhb }, { 764309560Sjhb .nexus_name = "t6nex", 765309560Sjhb .ifnet_name = "cc", 766309560Sjhb .vi_ifnet_name = "vcc", 767309560Sjhb .pf03_drv_name = "t6iov", 768309560Sjhb .vf_nexus_name = "t6vf", 769309560Sjhb .vf_ifnet_name = "ccv" 770309560Sjhb } 771309560Sjhb}; 772309560Sjhb 773309560Sjhbvoid 774309560Sjhbt4_init_devnames(struct adapter *sc) 775309560Sjhb{ 776309560Sjhb int id; 777309560Sjhb 778309560Sjhb id = chip_id(sc); 779309560Sjhb if (id >= CHELSIO_T4 && id - CHELSIO_T4 < nitems(devnames)) 780309560Sjhb sc->names = &devnames[id - CHELSIO_T4]; 781309560Sjhb else { 782309560Sjhb device_printf(sc->dev, "chip id %d is not supported.\n", id); 783309560Sjhb sc->names = NULL; 784309560Sjhb } 785309560Sjhb} 786309560Sjhb 787248925Snpstatic int 788218792Snpt4_attach(device_t dev) 789218792Snp{ 790218792Snp struct adapter *sc; 791308154Sjhb int rc = 0, i, j, n10g, n1g, rqidx, tqidx; 792309447Sjhb struct make_dev_args mda; 793218792Snp struct intrs_and_queues iaq; 794218792Snp struct sge *s; 795308304Sjhb uint8_t *buf; 796237263Snp#ifdef TCP_OFFLOAD 797228561Snp int ofld_rqidx, ofld_tqidx; 798228561Snp#endif 799270297Snp#ifdef DEV_NETMAP 800270297Snp int nm_rqidx, nm_tqidx; 801270297Snp#endif 802308154Sjhb int num_vis; 803218792Snp 804218792Snp sc = device_get_softc(dev); 805218792Snp sc->dev = dev; 806309458Sjhb TUNABLE_INT_FETCH("hw.cxgbe.dflags", &sc->debug_flags); 807218792Snp 808291083Sjhb if ((pci_get_device(dev) & 0xff00) == 0x5400) 809291083Sjhb t5_attribute_workaround(dev); 810218792Snp pci_enable_busmaster(dev); 811222085Snp if (pci_find_cap(dev, PCIY_EXPRESS, &i) == 0) { 812228561Snp uint32_t v; 813228561Snp 814222085Snp pci_set_max_read_req(dev, 4096); 815240680Sgavin v = pci_read_config(dev, i + PCIER_DEVICE_CTL, 2); 816240680Sgavin v |= PCIEM_CTL_RELAXED_ORD_ENABLE; 817240680Sgavin pci_write_config(dev, i + PCIER_DEVICE_CTL, v, 2); 818275092Snp 819275092Snp sc->params.pci.mps = 128 << ((v & PCIEM_CTL_MAX_PAYLOAD) >> 5); 820222085Snp } 821222085Snp 822309447Sjhb sc->sge_gts_reg = MYPF_REG(A_SGE_PF_GTS); 823309447Sjhb sc->sge_kdoorbell_reg = MYPF_REG(A_SGE_PF_KDOORBELL); 824253691Snp sc->traceq = -1; 825253691Snp mtx_init(&sc->ifp_lock, sc->ifp_lockname, 0, MTX_DEF); 826253691Snp snprintf(sc->ifp_lockname, sizeof(sc->ifp_lockname), "%s tracer", 827253691Snp device_get_nameunit(dev)); 828253691Snp 829218792Snp snprintf(sc->lockname, sizeof(sc->lockname), "%s", 830218792Snp device_get_nameunit(dev)); 831218792Snp mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF); 832309447Sjhb t4_add_adapter(sc); 833218792Snp 834228561Snp mtx_init(&sc->sfl_lock, "starving freelists", 0, MTX_DEF); 835228561Snp TAILQ_INIT(&sc->sfl); 836308154Sjhb callout_init_mtx(&sc->sfl_callout, &sc->sfl_lock, 0); 837228561Snp 838308305Sjhb mtx_init(&sc->reg_lock, "indirect register access", 0, MTX_DEF); 839282486Snp 840309447Sjhb rc = t4_map_bars_0_and_4(sc); 841218792Snp if (rc != 0) 842218792Snp goto done; /* error message displayed already */ 843218792Snp 844218792Snp memset(sc->chan_map, 0xff, sizeof(sc->chan_map)); 845218792Snp 846308304Sjhb /* Prepare the adapter for operation. */ 847308304Sjhb buf = malloc(PAGE_SIZE, M_CXGBE, M_ZERO | M_WAITOK); 848308304Sjhb rc = -t4_prep_adapter(sc, buf); 849308304Sjhb free(buf, M_CXGBE); 850218792Snp if (rc != 0) { 851218792Snp device_printf(dev, "failed to prepare adapter: %d.\n", rc); 852218792Snp goto done; 853218792Snp } 854218792Snp 855228561Snp /* 856309560Sjhb * This is the real PF# to which we're attaching. Works from within PCI 857309560Sjhb * passthrough environments too, where pci_get_function() could return a 858309560Sjhb * different PF# depending on the passthrough configuration. We need to 859309560Sjhb * use the real PF# in all our communication with the firmware. 860309560Sjhb */ 861309560Sjhb j = t4_read_reg(sc, A_PL_WHOAMI); 862309560Sjhb sc->pf = chip_id(sc) <= CHELSIO_T5 ? G_SOURCEPF(j) : G_T6_SOURCEPF(j); 863309560Sjhb sc->mbox = sc->pf; 864309560Sjhb 865309560Sjhb t4_init_devnames(sc); 866309560Sjhb if (sc->names == NULL) { 867309560Sjhb rc = ENOTSUP; 868309560Sjhb goto done; /* error message displayed already */ 869309560Sjhb } 870309560Sjhb 871309560Sjhb /* 872228561Snp * Do this really early, with the memory windows set up even before the 873228561Snp * character device. The userland tool's register i/o and mem read 874228561Snp * will work even in "recovery mode". 875228561Snp */ 876228561Snp setup_memwin(sc); 877308305Sjhb if (t4_init_devlog_params(sc, 0) == 0) 878308305Sjhb fixup_devlog_params(sc); 879309447Sjhb make_dev_args_init(&mda); 880309447Sjhb mda.mda_devsw = &t4_cdevsw; 881309447Sjhb mda.mda_uid = UID_ROOT; 882309447Sjhb mda.mda_gid = GID_WHEEL; 883309447Sjhb mda.mda_mode = 0600; 884309447Sjhb mda.mda_si_drv1 = sc; 885309447Sjhb rc = make_dev_s(&mda, &sc->cdev, "%s", device_get_nameunit(dev)); 886309447Sjhb if (rc != 0) 887309447Sjhb device_printf(dev, "failed to create nexus char device: %d.\n", 888309447Sjhb rc); 889218792Snp 890228561Snp /* Go no further if recovery mode has been requested. */ 891228561Snp if (TUNABLE_INT_FETCH("hw.cxgbe.sos", &i) && i != 0) { 892228561Snp device_printf(dev, "recovery mode.\n"); 893228561Snp goto done; 894228561Snp } 895228561Snp 896284052Snp#if defined(__i386__) 897284052Snp if ((cpu_feature & CPUID_CX8) == 0) { 898284052Snp device_printf(dev, "64 bit atomics not available.\n"); 899284052Snp rc = ENOTSUP; 900284052Snp goto done; 901284052Snp } 902284052Snp#endif 903284052Snp 904218792Snp /* Prepare the firmware for operation */ 905218792Snp rc = prep_firmware(sc); 906218792Snp if (rc != 0) 907218792Snp goto done; /* error message displayed already */ 908218792Snp 909248925Snp rc = get_params__post_init(sc); 910228561Snp if (rc != 0) 911228561Snp goto done; /* error message displayed already */ 912222551Snp 913248925Snp rc = set_params__post_init(sc); 914228561Snp if (rc != 0) 915228561Snp goto done; /* error message displayed already */ 916218792Snp 917309447Sjhb rc = t4_map_bar_2(sc); 918228561Snp if (rc != 0) 919228561Snp goto done; /* error message displayed already */ 920218792Snp 921218792Snp rc = t4_create_dma_tag(sc); 922218792Snp if (rc != 0) 923218792Snp goto done; /* error message displayed already */ 924218792Snp 925218792Snp /* 926308154Sjhb * Number of VIs to create per-port. The first VI is the "main" regular 927308154Sjhb * VI for the port. The rest are additional virtual interfaces on the 928308154Sjhb * same physical port. Note that the main VI does not have native 929308154Sjhb * netmap support but the extra VIs do. 930308154Sjhb * 931308154Sjhb * Limit the number of VIs per port to the number of available 932308154Sjhb * MAC addresses per port. 933308154Sjhb */ 934308154Sjhb if (t4_num_vis >= 1) 935308154Sjhb num_vis = t4_num_vis; 936308154Sjhb else 937308154Sjhb num_vis = 1; 938308154Sjhb if (num_vis > nitems(vi_mac_funcs)) { 939308154Sjhb num_vis = nitems(vi_mac_funcs); 940308154Sjhb device_printf(dev, "Number of VIs limited to %d\n", num_vis); 941308154Sjhb } 942308154Sjhb 943308154Sjhb /* 944218792Snp * First pass over all the ports - allocate VIs and initialize some 945218792Snp * basic parameters like mac address, port type, etc. We also figure 946218792Snp * out whether a port is 10G or 1G and use that information when 947218792Snp * calculating how many interrupts to attempt to allocate. 948218792Snp */ 949218792Snp n10g = n1g = 0; 950218792Snp for_each_port(sc, i) { 951218792Snp struct port_info *pi; 952218792Snp 953218792Snp pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK); 954218792Snp sc->port[i] = pi; 955218792Snp 956218792Snp /* These must be set before t4_port_init */ 957218792Snp pi->adapter = sc; 958218792Snp pi->port_id = i; 959308154Sjhb /* 960308154Sjhb * XXX: vi[0] is special so we can't delay this allocation until 961308154Sjhb * pi->nvi's final value is known. 962308154Sjhb */ 963308154Sjhb pi->vi = malloc(sizeof(struct vi_info) * num_vis, M_CXGBE, 964308154Sjhb M_ZERO | M_WAITOK); 965218792Snp 966308154Sjhb /* 967308154Sjhb * Allocate the "main" VI and initialize parameters 968308154Sjhb * like mac addr. 969308154Sjhb */ 970308304Sjhb rc = -t4_port_init(sc, sc->mbox, sc->pf, 0, i); 971218792Snp if (rc != 0) { 972218792Snp device_printf(dev, "unable to initialize port %d: %d\n", 973218792Snp i, rc); 974308154Sjhb free(pi->vi, M_CXGBE); 975218792Snp free(pi, M_CXGBE); 976222510Snp sc->port[i] = NULL; 977222510Snp goto done; 978218792Snp } 979271961Snp 980218792Snp snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d", 981218792Snp device_get_nameunit(dev), i); 982218792Snp mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF); 983253691Snp sc->chan_map[pi->tx_chan] = i; 984218792Snp 985309560Sjhb if (port_top_speed(pi) >= 10) { 986218792Snp n10g++; 987218792Snp } else { 988218792Snp n1g++; 989218792Snp } 990218792Snp 991353418Snp /* All VIs on this port share this media. */ 992353418Snp ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change, 993353418Snp cxgbe_media_status); 994353418Snp 995309560Sjhb pi->dev = device_add_child(dev, sc->names->ifnet_name, -1); 996218792Snp if (pi->dev == NULL) { 997218792Snp device_printf(dev, 998218792Snp "failed to add device for port %d.\n", i); 999218792Snp rc = ENXIO; 1000218792Snp goto done; 1001218792Snp } 1002308154Sjhb pi->vi[0].dev = pi->dev; 1003218792Snp device_set_softc(pi->dev, pi); 1004218792Snp } 1005218792Snp 1006218792Snp /* 1007218792Snp * Interrupt type, # of interrupts, # of rx/tx queues, etc. 1008218792Snp */ 1009308154Sjhb rc = cfg_itype_and_nqueues(sc, n10g, n1g, num_vis, &iaq); 1010218792Snp if (rc != 0) 1011218792Snp goto done; /* error message displayed already */ 1012308154Sjhb if (iaq.nrxq_vi + iaq.nofldrxq_vi + iaq.nnmrxq_vi == 0) 1013308154Sjhb num_vis = 1; 1014218792Snp 1015218792Snp sc->intr_type = iaq.intr_type; 1016218792Snp sc->intr_count = iaq.nirq; 1017218792Snp 1018218792Snp s = &sc->sge; 1019218792Snp s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g; 1020218792Snp s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g; 1021308154Sjhb if (num_vis > 1) { 1022308154Sjhb s->nrxq += (n10g + n1g) * (num_vis - 1) * iaq.nrxq_vi; 1023308154Sjhb s->ntxq += (n10g + n1g) * (num_vis - 1) * iaq.ntxq_vi; 1024308154Sjhb } 1025220873Snp s->neq = s->ntxq + s->nrxq; /* the free list in an rxq is an eq */ 1026228561Snp s->neq += sc->params.nports + 1;/* ctrl queues: 1 per port + 1 mgmt */ 1027218792Snp s->niq = s->nrxq + 1; /* 1 extra for firmware event queue */ 1028237263Snp#ifdef TCP_OFFLOAD 1029228561Snp if (is_offload(sc)) { 1030228561Snp s->nofldrxq = n10g * iaq.nofldrxq10g + n1g * iaq.nofldrxq1g; 1031228561Snp s->nofldtxq = n10g * iaq.nofldtxq10g + n1g * iaq.nofldtxq1g; 1032308154Sjhb if (num_vis > 1) { 1033308154Sjhb s->nofldrxq += (n10g + n1g) * (num_vis - 1) * 1034308154Sjhb iaq.nofldrxq_vi; 1035308154Sjhb s->nofldtxq += (n10g + n1g) * (num_vis - 1) * 1036308154Sjhb iaq.nofldtxq_vi; 1037308154Sjhb } 1038228561Snp s->neq += s->nofldtxq + s->nofldrxq; 1039228561Snp s->niq += s->nofldrxq; 1040228561Snp 1041228561Snp s->ofld_rxq = malloc(s->nofldrxq * sizeof(struct sge_ofld_rxq), 1042228561Snp M_CXGBE, M_ZERO | M_WAITOK); 1043228561Snp s->ofld_txq = malloc(s->nofldtxq * sizeof(struct sge_wrq), 1044228561Snp M_CXGBE, M_ZERO | M_WAITOK); 1045228561Snp } 1046228561Snp#endif 1047270297Snp#ifdef DEV_NETMAP 1048308154Sjhb if (num_vis > 1) { 1049308154Sjhb s->nnmrxq = (n10g + n1g) * (num_vis - 1) * iaq.nnmrxq_vi; 1050308154Sjhb s->nnmtxq = (n10g + n1g) * (num_vis - 1) * iaq.nnmtxq_vi; 1051308154Sjhb } 1052270297Snp s->neq += s->nnmtxq + s->nnmrxq; 1053270297Snp s->niq += s->nnmrxq; 1054228561Snp 1055270297Snp s->nm_rxq = malloc(s->nnmrxq * sizeof(struct sge_nm_rxq), 1056270297Snp M_CXGBE, M_ZERO | M_WAITOK); 1057270297Snp s->nm_txq = malloc(s->nnmtxq * sizeof(struct sge_nm_txq), 1058270297Snp M_CXGBE, M_ZERO | M_WAITOK); 1059270297Snp#endif 1060270297Snp 1061228561Snp s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_wrq), M_CXGBE, 1062220873Snp M_ZERO | M_WAITOK); 1063218792Snp s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE, 1064218792Snp M_ZERO | M_WAITOK); 1065218792Snp s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE, 1066218792Snp M_ZERO | M_WAITOK); 1067218792Snp s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE, 1068218792Snp M_ZERO | M_WAITOK); 1069218792Snp s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE, 1070218792Snp M_ZERO | M_WAITOK); 1071218792Snp 1072218792Snp sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE, 1073218792Snp M_ZERO | M_WAITOK); 1074218792Snp 1075228561Snp t4_init_l2t(sc, M_WAITOK); 1076318851Snp t4_init_tx_sched(sc); 1077222509Snp 1078218792Snp /* 1079218792Snp * Second pass over the ports. This time we know the number of rx and 1080218792Snp * tx queues that each port should get. 1081218792Snp */ 1082218792Snp rqidx = tqidx = 0; 1083237263Snp#ifdef TCP_OFFLOAD 1084228561Snp ofld_rqidx = ofld_tqidx = 0; 1085228561Snp#endif 1086270297Snp#ifdef DEV_NETMAP 1087270297Snp nm_rqidx = nm_tqidx = 0; 1088270297Snp#endif 1089218792Snp for_each_port(sc, i) { 1090218792Snp struct port_info *pi = sc->port[i]; 1091308154Sjhb struct vi_info *vi; 1092218792Snp 1093218792Snp if (pi == NULL) 1094218792Snp continue; 1095218792Snp 1096308154Sjhb pi->nvi = num_vis; 1097308154Sjhb for_each_vi(pi, j, vi) { 1098308154Sjhb vi->pi = pi; 1099308154Sjhb vi->qsize_rxq = t4_qsize_rxq; 1100308154Sjhb vi->qsize_txq = t4_qsize_txq; 1101218792Snp 1102308154Sjhb vi->first_rxq = rqidx; 1103308154Sjhb vi->first_txq = tqidx; 1104309560Sjhb if (port_top_speed(pi) >= 10) { 1105308154Sjhb vi->tmr_idx = t4_tmr_idx_10g; 1106308154Sjhb vi->pktc_idx = t4_pktc_idx_10g; 1107308154Sjhb vi->flags |= iaq.intr_flags_10g & INTR_RXQ; 1108308154Sjhb vi->nrxq = j == 0 ? iaq.nrxq10g : iaq.nrxq_vi; 1109308154Sjhb vi->ntxq = j == 0 ? iaq.ntxq10g : iaq.ntxq_vi; 1110308154Sjhb } else { 1111308154Sjhb vi->tmr_idx = t4_tmr_idx_1g; 1112308154Sjhb vi->pktc_idx = t4_pktc_idx_1g; 1113308154Sjhb vi->flags |= iaq.intr_flags_1g & INTR_RXQ; 1114308154Sjhb vi->nrxq = j == 0 ? iaq.nrxq1g : iaq.nrxq_vi; 1115308154Sjhb vi->ntxq = j == 0 ? iaq.ntxq1g : iaq.ntxq_vi; 1116308154Sjhb } 1117308154Sjhb rqidx += vi->nrxq; 1118308154Sjhb tqidx += vi->ntxq; 1119264493Sscottl 1120308154Sjhb if (j == 0 && vi->ntxq > 1) 1121308154Sjhb vi->rsrv_noflowq = iaq.rsrv_noflowq ? 1 : 0; 1122308154Sjhb else 1123308154Sjhb vi->rsrv_noflowq = 0; 1124308154Sjhb 1125237263Snp#ifdef TCP_OFFLOAD 1126308154Sjhb vi->first_ofld_rxq = ofld_rqidx; 1127308154Sjhb vi->first_ofld_txq = ofld_tqidx; 1128309560Sjhb if (port_top_speed(pi) >= 10) { 1129308154Sjhb vi->flags |= iaq.intr_flags_10g & INTR_OFLD_RXQ; 1130308154Sjhb vi->nofldrxq = j == 0 ? iaq.nofldrxq10g : 1131308154Sjhb iaq.nofldrxq_vi; 1132308154Sjhb vi->nofldtxq = j == 0 ? iaq.nofldtxq10g : 1133308154Sjhb iaq.nofldtxq_vi; 1134228561Snp } else { 1135308154Sjhb vi->flags |= iaq.intr_flags_1g & INTR_OFLD_RXQ; 1136308154Sjhb vi->nofldrxq = j == 0 ? iaq.nofldrxq1g : 1137308154Sjhb iaq.nofldrxq_vi; 1138308154Sjhb vi->nofldtxq = j == 0 ? iaq.nofldtxq1g : 1139308154Sjhb iaq.nofldtxq_vi; 1140228561Snp } 1141308154Sjhb ofld_rqidx += vi->nofldrxq; 1142308154Sjhb ofld_tqidx += vi->nofldtxq; 1143228561Snp#endif 1144270297Snp#ifdef DEV_NETMAP 1145308154Sjhb if (j > 0) { 1146308154Sjhb vi->first_nm_rxq = nm_rqidx; 1147308154Sjhb vi->first_nm_txq = nm_tqidx; 1148308154Sjhb vi->nnmrxq = iaq.nnmrxq_vi; 1149308154Sjhb vi->nnmtxq = iaq.nnmtxq_vi; 1150308154Sjhb nm_rqidx += vi->nnmrxq; 1151308154Sjhb nm_tqidx += vi->nnmtxq; 1152308154Sjhb } 1153308154Sjhb#endif 1154270297Snp } 1155218792Snp } 1156218792Snp 1157309447Sjhb rc = t4_setup_intr_handlers(sc); 1158240453Snp if (rc != 0) { 1159240453Snp device_printf(dev, 1160240453Snp "failed to setup interrupt handlers: %d\n", rc); 1161240453Snp goto done; 1162240453Snp } 1163240453Snp 1164331647Sjhb rc = bus_generic_probe(dev); 1165331647Sjhb if (rc != 0) { 1166331647Sjhb device_printf(dev, "failed to probe child drivers: %d\n", rc); 1167331647Sjhb goto done; 1168331647Sjhb } 1169331647Sjhb 1170218792Snp rc = bus_generic_attach(dev); 1171218792Snp if (rc != 0) { 1172218792Snp device_printf(dev, 1173218792Snp "failed to attach all child ports: %d\n", rc); 1174218792Snp goto done; 1175218792Snp } 1176218792Snp 1177218792Snp device_printf(dev, 1178284098Snp "PCIe gen%d x%d, %d ports, %d %s interrupt%s, %d eq, %d iq\n", 1179284098Snp sc->params.pci.speed, sc->params.pci.width, sc->params.nports, 1180284098Snp sc->intr_count, sc->intr_type == INTR_MSIX ? "MSI-X" : 1181228561Snp (sc->intr_type == INTR_MSI ? "MSI" : "INTx"), 1182228561Snp sc->intr_count > 1 ? "s" : "", sc->sge.neq, sc->sge.niq); 1183228561Snp 1184218792Snp t4_set_desc(sc); 1185218792Snp 1186218792Snpdone: 1187228561Snp if (rc != 0 && sc->cdev) { 1188228561Snp /* cdev was created and so cxgbetool works; recover that way. */ 1189228561Snp device_printf(dev, 1190228561Snp "error during attach, adapter is now in recovery mode.\n"); 1191228561Snp rc = 0; 1192228561Snp } 1193228561Snp 1194218792Snp if (rc != 0) 1195309447Sjhb t4_detach_common(dev); 1196228561Snp else 1197228561Snp t4_sysctls(sc); 1198218792Snp 1199218792Snp return (rc); 1200218792Snp} 1201218792Snp 1202218792Snp/* 1203218792Snp * Idempotent 1204218792Snp */ 1205218792Snpstatic int 1206218792Snpt4_detach(device_t dev) 1207218792Snp{ 1208218792Snp struct adapter *sc; 1209309447Sjhb 1210309447Sjhb sc = device_get_softc(dev); 1211309447Sjhb 1212309447Sjhb return (t4_detach_common(dev)); 1213309447Sjhb} 1214309447Sjhb 1215309447Sjhbint 1216309447Sjhbt4_detach_common(device_t dev) 1217309447Sjhb{ 1218309447Sjhb struct adapter *sc; 1219218792Snp struct port_info *pi; 1220228561Snp int i, rc; 1221218792Snp 1222218792Snp sc = device_get_softc(dev); 1223218792Snp 1224309447Sjhb if (sc->flags & FULL_INIT_DONE) { 1225309447Sjhb if (!(sc->flags & IS_VF)) 1226309447Sjhb t4_intr_disable(sc); 1227309447Sjhb } 1228228561Snp 1229228561Snp if (sc->cdev) { 1230218792Snp destroy_dev(sc->cdev); 1231228561Snp sc->cdev = NULL; 1232228561Snp } 1233218792Snp 1234309447Sjhb if (device_is_attached(dev)) { 1235309447Sjhb rc = bus_generic_detach(dev); 1236309447Sjhb if (rc) { 1237309447Sjhb device_printf(dev, 1238309447Sjhb "failed to detach child devices: %d\n", rc); 1239309447Sjhb return (rc); 1240309447Sjhb } 1241228561Snp } 1242228561Snp 1243240453Snp for (i = 0; i < sc->intr_count; i++) 1244240453Snp t4_free_irq(sc, &sc->irq[i]); 1245240453Snp 1246318851Snp if ((sc->flags & (IS_VF | FW_OK)) == FW_OK) 1247318851Snp t4_free_tx_sched(sc); 1248318851Snp 1249218792Snp for (i = 0; i < MAX_NPORTS; i++) { 1250218792Snp pi = sc->port[i]; 1251218792Snp if (pi) { 1252308154Sjhb t4_free_vi(sc, sc->mbox, sc->pf, 0, pi->vi[0].viid); 1253218792Snp if (pi->dev) 1254218792Snp device_delete_child(dev, pi->dev); 1255218792Snp 1256218792Snp mtx_destroy(&pi->pi_lock); 1257308154Sjhb free(pi->vi, M_CXGBE); 1258218792Snp free(pi, M_CXGBE); 1259218792Snp } 1260218792Snp } 1261218792Snp 1262331647Sjhb device_delete_children(dev); 1263331647Sjhb 1264228561Snp if (sc->flags & FULL_INIT_DONE) 1265228561Snp adapter_full_uninit(sc); 1266228561Snp 1267309447Sjhb if ((sc->flags & (IS_VF | FW_OK)) == FW_OK) 1268218792Snp t4_fw_bye(sc, sc->mbox); 1269218792Snp 1270219944Snp if (sc->intr_type == INTR_MSI || sc->intr_type == INTR_MSIX) 1271218792Snp pci_release_msi(dev); 1272218792Snp 1273218792Snp if (sc->regs_res) 1274218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid, 1275218792Snp sc->regs_res); 1276218792Snp 1277248925Snp if (sc->udbs_res) 1278248925Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->udbs_rid, 1279248925Snp sc->udbs_res); 1280248925Snp 1281218792Snp if (sc->msix_res) 1282218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid, 1283218792Snp sc->msix_res); 1284218792Snp 1285222509Snp if (sc->l2t) 1286222509Snp t4_free_l2t(sc->l2t); 1287222509Snp 1288237263Snp#ifdef TCP_OFFLOAD 1289228561Snp free(sc->sge.ofld_rxq, M_CXGBE); 1290228561Snp free(sc->sge.ofld_txq, M_CXGBE); 1291228561Snp#endif 1292270297Snp#ifdef DEV_NETMAP 1293270297Snp free(sc->sge.nm_rxq, M_CXGBE); 1294270297Snp free(sc->sge.nm_txq, M_CXGBE); 1295270297Snp#endif 1296218792Snp free(sc->irq, M_CXGBE); 1297218792Snp free(sc->sge.rxq, M_CXGBE); 1298218792Snp free(sc->sge.txq, M_CXGBE); 1299220873Snp free(sc->sge.ctrlq, M_CXGBE); 1300218792Snp free(sc->sge.iqmap, M_CXGBE); 1301218792Snp free(sc->sge.eqmap, M_CXGBE); 1302221474Snp free(sc->tids.ftid_tab, M_CXGBE); 1303218792Snp t4_destroy_dma_tag(sc); 1304228561Snp if (mtx_initialized(&sc->sc_lock)) { 1305255006Snp sx_xlock(&t4_list_lock); 1306228561Snp SLIST_REMOVE(&t4_list, sc, adapter, link); 1307255006Snp sx_xunlock(&t4_list_lock); 1308228561Snp mtx_destroy(&sc->sc_lock); 1309228561Snp } 1310218792Snp 1311308154Sjhb callout_drain(&sc->sfl_callout); 1312245274Snp if (mtx_initialized(&sc->tids.ftid_lock)) 1313245274Snp mtx_destroy(&sc->tids.ftid_lock); 1314228561Snp if (mtx_initialized(&sc->sfl_lock)) 1315228561Snp mtx_destroy(&sc->sfl_lock); 1316253691Snp if (mtx_initialized(&sc->ifp_lock)) 1317253691Snp mtx_destroy(&sc->ifp_lock); 1318308305Sjhb if (mtx_initialized(&sc->reg_lock)) 1319308305Sjhb mtx_destroy(&sc->reg_lock); 1320228561Snp 1321308305Sjhb for (i = 0; i < NUM_MEMWIN; i++) { 1322308305Sjhb struct memwin *mw = &sc->memwin[i]; 1323308305Sjhb 1324308305Sjhb if (rw_initialized(&mw->mw_lock)) 1325308305Sjhb rw_destroy(&mw->mw_lock); 1326308305Sjhb } 1327308305Sjhb 1328218792Snp bzero(sc, sizeof(*sc)); 1329218792Snp 1330218792Snp return (0); 1331218792Snp} 1332218792Snp 1333218792Snpstatic int 1334218792Snpcxgbe_probe(device_t dev) 1335218792Snp{ 1336218792Snp char buf[128]; 1337218792Snp struct port_info *pi = device_get_softc(dev); 1338218792Snp 1339228561Snp snprintf(buf, sizeof(buf), "port %d", pi->port_id); 1340218792Snp device_set_desc_copy(dev, buf); 1341218792Snp 1342218792Snp return (BUS_PROBE_DEFAULT); 1343218792Snp} 1344218792Snp 1345218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \ 1346218792Snp IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \ 1347256218Sglebius IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6 | IFCAP_HWSTATS) 1348237819Snp#define T4_CAP_ENABLE (T4_CAP) 1349218792Snp 1350218792Snpstatic int 1351308154Sjhbcxgbe_vi_attach(device_t dev, struct vi_info *vi) 1352218792Snp{ 1353218792Snp struct ifnet *ifp; 1354308154Sjhb struct sbuf *sb; 1355218792Snp 1356308154Sjhb vi->xact_addr_filt = -1; 1357308154Sjhb callout_init(&vi->tick, 1); 1358308154Sjhb 1359218792Snp /* Allocate an ifnet and set it up */ 1360218792Snp ifp = if_alloc(IFT_ETHER); 1361218792Snp if (ifp == NULL) { 1362218792Snp device_printf(dev, "Cannot allocate ifnet\n"); 1363218792Snp return (ENOMEM); 1364218792Snp } 1365308154Sjhb vi->ifp = ifp; 1366308154Sjhb ifp->if_softc = vi; 1367218792Snp 1368218792Snp if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 1369218792Snp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 1370218792Snp 1371218792Snp ifp->if_init = cxgbe_init; 1372218792Snp ifp->if_ioctl = cxgbe_ioctl; 1373218792Snp ifp->if_transmit = cxgbe_transmit; 1374218792Snp ifp->if_qflush = cxgbe_qflush; 1375218792Snp 1376218792Snp ifp->if_capabilities = T4_CAP; 1377237263Snp#ifdef TCP_OFFLOAD 1378308154Sjhb if (vi->nofldrxq != 0) 1379245933Snp ifp->if_capabilities |= IFCAP_TOE; 1380228561Snp#endif 1381318826Snp#ifdef DEV_NETMAP 1382318826Snp if (vi->nnmrxq != 0) 1383318826Snp ifp->if_capabilities |= IFCAP_NETMAP; 1384318826Snp#endif 1385218792Snp ifp->if_capenable = T4_CAP_ENABLE; 1386237799Snp ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO | 1387237799Snp CSUM_UDP_IPV6 | CSUM_TCP_IPV6; 1388218792Snp 1389274440Snp ifp->if_hw_tsomax = 65536 - (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 1390274440Snp ifp->if_hw_tsomaxsegcount = TX_SGL_SEGS; 1391274440Snp ifp->if_hw_tsomaxsegsize = 65536; 1392274440Snp 1393308154Sjhb vi->vlan_c = EVENTHANDLER_REGISTER(vlan_config, cxgbe_vlan_config, ifp, 1394237263Snp EVENTHANDLER_PRI_ANY); 1395237263Snp 1396308154Sjhb ether_ifattach(ifp, vi->hw_addr); 1397308154Sjhb#ifdef DEV_NETMAP 1398318826Snp if (ifp->if_capabilities & IFCAP_NETMAP) 1399308154Sjhb cxgbe_nm_attach(vi); 1400308154Sjhb#endif 1401308154Sjhb sb = sbuf_new_auto(); 1402308154Sjhb sbuf_printf(sb, "%d txq, %d rxq (NIC)", vi->ntxq, vi->nrxq); 1403237263Snp#ifdef TCP_OFFLOAD 1404308154Sjhb if (ifp->if_capabilities & IFCAP_TOE) 1405308154Sjhb sbuf_printf(sb, "; %d txq, %d rxq (TOE)", 1406308154Sjhb vi->nofldtxq, vi->nofldrxq); 1407218792Snp#endif 1408270297Snp#ifdef DEV_NETMAP 1409308154Sjhb if (ifp->if_capabilities & IFCAP_NETMAP) 1410308154Sjhb sbuf_printf(sb, "; %d txq, %d rxq (netmap)", 1411308154Sjhb vi->nnmtxq, vi->nnmrxq); 1412270297Snp#endif 1413308154Sjhb sbuf_finish(sb); 1414308154Sjhb device_printf(dev, "%s\n", sbuf_data(sb)); 1415308154Sjhb sbuf_delete(sb); 1416218792Snp 1417308154Sjhb vi_sysctls(vi); 1418308154Sjhb 1419308154Sjhb return (0); 1420308154Sjhb} 1421308154Sjhb 1422308154Sjhbstatic int 1423308154Sjhbcxgbe_attach(device_t dev) 1424308154Sjhb{ 1425308154Sjhb struct port_info *pi = device_get_softc(dev); 1426309560Sjhb struct adapter *sc = pi->adapter; 1427308154Sjhb struct vi_info *vi; 1428308154Sjhb int i, rc; 1429308154Sjhb 1430308154Sjhb callout_init_mtx(&pi->tick, &pi->pi_lock, 0); 1431308154Sjhb 1432308154Sjhb rc = cxgbe_vi_attach(dev, &pi->vi[0]); 1433308154Sjhb if (rc) 1434308154Sjhb return (rc); 1435308154Sjhb 1436308154Sjhb for_each_vi(pi, i, vi) { 1437308154Sjhb if (i == 0) 1438308154Sjhb continue; 1439309560Sjhb vi->dev = device_add_child(dev, sc->names->vi_ifnet_name, -1); 1440308154Sjhb if (vi->dev == NULL) { 1441308154Sjhb device_printf(dev, "failed to add VI %d\n", i); 1442308154Sjhb continue; 1443308154Sjhb } 1444308154Sjhb device_set_softc(vi->dev, vi); 1445308154Sjhb } 1446308154Sjhb 1447218792Snp cxgbe_sysctls(pi); 1448218792Snp 1449308154Sjhb bus_generic_attach(dev); 1450308154Sjhb 1451218792Snp return (0); 1452218792Snp} 1453218792Snp 1454308154Sjhbstatic void 1455308154Sjhbcxgbe_vi_detach(struct vi_info *vi) 1456308154Sjhb{ 1457308154Sjhb struct ifnet *ifp = vi->ifp; 1458308154Sjhb 1459308154Sjhb ether_ifdetach(ifp); 1460308154Sjhb 1461308154Sjhb if (vi->vlan_c) 1462308154Sjhb EVENTHANDLER_DEREGISTER(vlan_config, vi->vlan_c); 1463308154Sjhb 1464308154Sjhb /* Let detach proceed even if these fail. */ 1465308154Sjhb#ifdef DEV_NETMAP 1466308154Sjhb if (ifp->if_capabilities & IFCAP_NETMAP) 1467308154Sjhb cxgbe_nm_detach(vi); 1468308154Sjhb#endif 1469308154Sjhb cxgbe_uninit_synchronized(vi); 1470308154Sjhb callout_drain(&vi->tick); 1471308154Sjhb vi_full_uninit(vi); 1472308154Sjhb 1473308154Sjhb if_free(vi->ifp); 1474308154Sjhb vi->ifp = NULL; 1475308154Sjhb} 1476308154Sjhb 1477218792Snpstatic int 1478218792Snpcxgbe_detach(device_t dev) 1479218792Snp{ 1480218792Snp struct port_info *pi = device_get_softc(dev); 1481218792Snp struct adapter *sc = pi->adapter; 1482308154Sjhb int rc; 1483218792Snp 1484308154Sjhb /* Detach the extra VIs first. */ 1485308154Sjhb rc = bus_generic_detach(dev); 1486308154Sjhb if (rc) 1487308154Sjhb return (rc); 1488308154Sjhb device_delete_children(dev); 1489218792Snp 1490308154Sjhb doom_vi(sc, &pi->vi[0]); 1491308154Sjhb 1492253691Snp if (pi->flags & HAS_TRACEQ) { 1493253691Snp sc->traceq = -1; /* cloner should not create ifnet */ 1494253691Snp t4_tracer_port_detach(sc); 1495253691Snp } 1496253691Snp 1497308154Sjhb cxgbe_vi_detach(&pi->vi[0]); 1498228561Snp callout_drain(&pi->tick); 1499353418Snp ifmedia_removeall(&pi->media); 1500218792Snp 1501308154Sjhb end_synchronized_op(sc, 0); 1502219286Snp 1503218792Snp return (0); 1504218792Snp} 1505218792Snp 1506218792Snpstatic void 1507218792Snpcxgbe_init(void *arg) 1508218792Snp{ 1509308154Sjhb struct vi_info *vi = arg; 1510308154Sjhb struct adapter *sc = vi->pi->adapter; 1511218792Snp 1512308154Sjhb if (begin_synchronized_op(sc, vi, SLEEP_OK | INTR_OK, "t4init") != 0) 1513245274Snp return; 1514308154Sjhb cxgbe_init_synchronized(vi); 1515245274Snp end_synchronized_op(sc, 0); 1516218792Snp} 1517218792Snp 1518218792Snpstatic int 1519218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) 1520218792Snp{ 1521270297Snp int rc = 0, mtu, flags, can_sleep; 1522308154Sjhb struct vi_info *vi = ifp->if_softc; 1523353418Snp struct port_info *pi = vi->pi; 1524353418Snp struct adapter *sc = pi->adapter; 1525218792Snp struct ifreq *ifr = (struct ifreq *)data; 1526218792Snp uint32_t mask; 1527218792Snp 1528218792Snp switch (cmd) { 1529218792Snp case SIOCSIFMTU: 1530245274Snp mtu = ifr->ifr_mtu; 1531309575Sjhb if (mtu < ETHERMIN || mtu > MAX_MTU) 1532245274Snp return (EINVAL); 1533245274Snp 1534308154Sjhb rc = begin_synchronized_op(sc, vi, SLEEP_OK | INTR_OK, "t4mtu"); 1535245274Snp if (rc) 1536218792Snp return (rc); 1537245274Snp ifp->if_mtu = mtu; 1538308154Sjhb if (vi->flags & VI_INIT_DONE) { 1539245274Snp t4_update_fl_bufsize(ifp); 1540252728Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1541270297Snp rc = update_mac_settings(ifp, XGMAC_MTU); 1542218792Snp } 1543245274Snp end_synchronized_op(sc, 0); 1544218792Snp break; 1545218792Snp 1546218792Snp case SIOCSIFFLAGS: 1547270297Snp can_sleep = 0; 1548270297Snpredo_sifflags: 1549308154Sjhb rc = begin_synchronized_op(sc, vi, 1550270297Snp can_sleep ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4flg"); 1551245274Snp if (rc) 1552245274Snp return (rc); 1553245274Snp 1554218792Snp if (ifp->if_flags & IFF_UP) { 1555218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1556308154Sjhb flags = vi->if_flags; 1557218792Snp if ((ifp->if_flags ^ flags) & 1558218792Snp (IFF_PROMISC | IFF_ALLMULTI)) { 1559270297Snp if (can_sleep == 1) { 1560270297Snp end_synchronized_op(sc, 0); 1561270297Snp can_sleep = 0; 1562270297Snp goto redo_sifflags; 1563270297Snp } 1564270297Snp rc = update_mac_settings(ifp, 1565218792Snp XGMAC_PROMISC | XGMAC_ALLMULTI); 1566218792Snp } 1567270297Snp } else { 1568270297Snp if (can_sleep == 0) { 1569270297Snp end_synchronized_op(sc, LOCK_HELD); 1570270297Snp can_sleep = 1; 1571270297Snp goto redo_sifflags; 1572270297Snp } 1573308154Sjhb rc = cxgbe_init_synchronized(vi); 1574270297Snp } 1575308154Sjhb vi->if_flags = ifp->if_flags; 1576270297Snp } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1577270297Snp if (can_sleep == 0) { 1578270297Snp end_synchronized_op(sc, LOCK_HELD); 1579270297Snp can_sleep = 1; 1580270297Snp goto redo_sifflags; 1581270297Snp } 1582308154Sjhb rc = cxgbe_uninit_synchronized(vi); 1583270297Snp } 1584270297Snp end_synchronized_op(sc, can_sleep ? 0 : LOCK_HELD); 1585218792Snp break; 1586218792Snp 1587270297Snp case SIOCADDMULTI: 1588245274Snp case SIOCDELMULTI: /* these two are called with a mutex held :-( */ 1589308154Sjhb rc = begin_synchronized_op(sc, vi, HOLD_LOCK, "t4multi"); 1590218792Snp if (rc) 1591245274Snp return (rc); 1592245274Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1593270297Snp rc = update_mac_settings(ifp, XGMAC_MCADDRS); 1594245274Snp end_synchronized_op(sc, LOCK_HELD); 1595218792Snp break; 1596218792Snp 1597218792Snp case SIOCSIFCAP: 1598308154Sjhb rc = begin_synchronized_op(sc, vi, SLEEP_OK | INTR_OK, "t4cap"); 1599218792Snp if (rc) 1600245274Snp return (rc); 1601218792Snp 1602218792Snp mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1603218792Snp if (mask & IFCAP_TXCSUM) { 1604218792Snp ifp->if_capenable ^= IFCAP_TXCSUM; 1605218792Snp ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 1606218792Snp 1607237831Snp if (IFCAP_TSO4 & ifp->if_capenable && 1608218792Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1609237799Snp ifp->if_capenable &= ~IFCAP_TSO4; 1610218792Snp if_printf(ifp, 1611237831Snp "tso4 disabled due to -txcsum.\n"); 1612218792Snp } 1613218792Snp } 1614237799Snp if (mask & IFCAP_TXCSUM_IPV6) { 1615237799Snp ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 1616237799Snp ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); 1617237799Snp 1618237799Snp if (IFCAP_TSO6 & ifp->if_capenable && 1619237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1620237799Snp ifp->if_capenable &= ~IFCAP_TSO6; 1621237799Snp if_printf(ifp, 1622237799Snp "tso6 disabled due to -txcsum6.\n"); 1623237799Snp } 1624237799Snp } 1625218792Snp if (mask & IFCAP_RXCSUM) 1626218792Snp ifp->if_capenable ^= IFCAP_RXCSUM; 1627237799Snp if (mask & IFCAP_RXCSUM_IPV6) 1628237799Snp ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 1629237799Snp 1630237799Snp /* 1631237799Snp * Note that we leave CSUM_TSO alone (it is always set). The 1632237799Snp * kernel takes both IFCAP_TSOx and CSUM_TSO into account before 1633237799Snp * sending a TSO request our way, so it's sufficient to toggle 1634237799Snp * IFCAP_TSOx only. 1635237799Snp */ 1636218792Snp if (mask & IFCAP_TSO4) { 1637237799Snp if (!(IFCAP_TSO4 & ifp->if_capenable) && 1638237799Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1639237799Snp if_printf(ifp, "enable txcsum first.\n"); 1640237799Snp rc = EAGAIN; 1641237799Snp goto fail; 1642237799Snp } 1643218792Snp ifp->if_capenable ^= IFCAP_TSO4; 1644218792Snp } 1645237799Snp if (mask & IFCAP_TSO6) { 1646237799Snp if (!(IFCAP_TSO6 & ifp->if_capenable) && 1647237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1648237799Snp if_printf(ifp, "enable txcsum6 first.\n"); 1649237799Snp rc = EAGAIN; 1650237799Snp goto fail; 1651237799Snp } 1652237799Snp ifp->if_capenable ^= IFCAP_TSO6; 1653237799Snp } 1654218792Snp if (mask & IFCAP_LRO) { 1655237819Snp#if defined(INET) || defined(INET6) 1656218792Snp int i; 1657218792Snp struct sge_rxq *rxq; 1658218792Snp 1659218792Snp ifp->if_capenable ^= IFCAP_LRO; 1660308154Sjhb for_each_rxq(vi, i, rxq) { 1661218792Snp if (ifp->if_capenable & IFCAP_LRO) 1662228561Snp rxq->iq.flags |= IQ_LRO_ENABLED; 1663218792Snp else 1664228561Snp rxq->iq.flags &= ~IQ_LRO_ENABLED; 1665218792Snp } 1666218792Snp#endif 1667218792Snp } 1668237263Snp#ifdef TCP_OFFLOAD 1669228561Snp if (mask & IFCAP_TOE) { 1670228561Snp int enable = (ifp->if_capenable ^ mask) & IFCAP_TOE; 1671228561Snp 1672308154Sjhb rc = toe_capability(vi, enable); 1673228561Snp if (rc != 0) 1674228561Snp goto fail; 1675228561Snp 1676228561Snp ifp->if_capenable ^= mask; 1677218792Snp } 1678218792Snp#endif 1679218792Snp if (mask & IFCAP_VLAN_HWTAGGING) { 1680218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1681245274Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1682270297Snp rc = update_mac_settings(ifp, XGMAC_VLANEX); 1683218792Snp } 1684218792Snp if (mask & IFCAP_VLAN_MTU) { 1685218792Snp ifp->if_capenable ^= IFCAP_VLAN_MTU; 1686218792Snp 1687218792Snp /* Need to find out how to disable auto-mtu-inflation */ 1688218792Snp } 1689218792Snp if (mask & IFCAP_VLAN_HWTSO) 1690218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1691218792Snp if (mask & IFCAP_VLAN_HWCSUM) 1692218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 1693218792Snp 1694218792Snp#ifdef VLAN_CAPABILITIES 1695218792Snp VLAN_CAPABILITIES(ifp); 1696218792Snp#endif 1697245274Snpfail: 1698245274Snp end_synchronized_op(sc, 0); 1699218792Snp break; 1700218792Snp 1701218792Snp case SIOCSIFMEDIA: 1702218792Snp case SIOCGIFMEDIA: 1703309560Sjhb case SIOCGIFXMEDIA: 1704353418Snp ifmedia_ioctl(ifp, ifr, &pi->media, cmd); 1705218792Snp break; 1706218792Snp 1707286898Snp case SIOCGI2C: { 1708286898Snp struct ifi2creq i2c; 1709286898Snp 1710286898Snp rc = copyin(ifr->ifr_data, &i2c, sizeof(i2c)); 1711286898Snp if (rc != 0) 1712286898Snp break; 1713286898Snp if (i2c.dev_addr != 0xA0 && i2c.dev_addr != 0xA2) { 1714286898Snp rc = EPERM; 1715286898Snp break; 1716286898Snp } 1717286898Snp if (i2c.len > sizeof(i2c.data)) { 1718286898Snp rc = EINVAL; 1719286898Snp break; 1720286898Snp } 1721308154Sjhb rc = begin_synchronized_op(sc, vi, SLEEP_OK | INTR_OK, "t4i2c"); 1722286898Snp if (rc) 1723286898Snp return (rc); 1724353418Snp rc = -t4_i2c_rd(sc, sc->mbox, pi->port_id, i2c.dev_addr, 1725286898Snp i2c.offset, i2c.len, &i2c.data[0]); 1726286898Snp end_synchronized_op(sc, 0); 1727286898Snp if (rc == 0) 1728286898Snp rc = copyout(&i2c, ifr->ifr_data, sizeof(i2c)); 1729286898Snp break; 1730286898Snp } 1731286898Snp 1732218792Snp default: 1733218792Snp rc = ether_ioctl(ifp, cmd, data); 1734218792Snp } 1735218792Snp 1736218792Snp return (rc); 1737218792Snp} 1738218792Snp 1739218792Snpstatic int 1740218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m) 1741218792Snp{ 1742308154Sjhb struct vi_info *vi = ifp->if_softc; 1743308154Sjhb struct port_info *pi = vi->pi; 1744218792Snp struct adapter *sc = pi->adapter; 1745284052Snp struct sge_txq *txq; 1746284052Snp void *items[1]; 1747218792Snp int rc; 1748218792Snp 1749218792Snp M_ASSERTPKTHDR(m); 1750284052Snp MPASS(m->m_nextpkt == NULL); /* not quite ready for this yet */ 1751218792Snp 1752228561Snp if (__predict_false(pi->link_cfg.link_ok == 0)) { 1753218792Snp m_freem(m); 1754228561Snp return (ENETDOWN); 1755218792Snp } 1756218792Snp 1757309447Sjhb rc = parse_pkt(sc, &m); 1758284052Snp if (__predict_false(rc != 0)) { 1759284052Snp MPASS(m == NULL); /* was freed already */ 1760284052Snp atomic_add_int(&pi->tx_parse_error, 1); /* rare, atomic is ok */ 1761228561Snp return (rc); 1762218792Snp } 1763218792Snp 1764284052Snp /* Select a txq. */ 1765308154Sjhb txq = &sc->sge.txq[vi->first_txq]; 1766284052Snp if (M_HASHTYPE_GET(m) != M_HASHTYPE_NONE) 1767308154Sjhb txq += ((m->m_pkthdr.flowid % (vi->ntxq - vi->rsrv_noflowq)) + 1768308154Sjhb vi->rsrv_noflowq); 1769218792Snp 1770284052Snp items[0] = m; 1771284052Snp rc = mp_ring_enqueue(txq->r, items, 1, 4096); 1772284052Snp if (__predict_false(rc != 0)) 1773284052Snp m_freem(m); 1774218792Snp 1775218792Snp return (rc); 1776218792Snp} 1777218792Snp 1778218792Snpstatic void 1779218792Snpcxgbe_qflush(struct ifnet *ifp) 1780218792Snp{ 1781308154Sjhb struct vi_info *vi = ifp->if_softc; 1782220649Snp struct sge_txq *txq; 1783220649Snp int i; 1784218792Snp 1785308154Sjhb /* queues do not exist if !VI_INIT_DONE. */ 1786308154Sjhb if (vi->flags & VI_INIT_DONE) { 1787308154Sjhb for_each_txq(vi, i, txq) { 1788220649Snp TXQ_LOCK(txq); 1789318855Snp txq->eq.flags |= EQ_QFLUSH; 1790220649Snp TXQ_UNLOCK(txq); 1791284052Snp while (!mp_ring_is_idle(txq->r)) { 1792284052Snp mp_ring_check_drainage(txq->r, 0); 1793284052Snp pause("qflush", 1); 1794284052Snp } 1795318855Snp TXQ_LOCK(txq); 1796318855Snp txq->eq.flags &= ~EQ_QFLUSH; 1797318855Snp TXQ_UNLOCK(txq); 1798220649Snp } 1799220649Snp } 1800220649Snp if_qflush(ifp); 1801218792Snp} 1802218792Snp 1803353418Snp/* 1804353418Snp * The kernel picks a media from the list we had provided so we do not have to 1805353418Snp * validate the request. 1806353418Snp */ 1807218792Snpstatic int 1808218792Snpcxgbe_media_change(struct ifnet *ifp) 1809218792Snp{ 1810308154Sjhb struct vi_info *vi = ifp->if_softc; 1811353418Snp struct port_info *pi = vi->pi; 1812353418Snp struct ifmedia *ifm = &pi->media; 1813353418Snp struct link_config *lc = &pi->link_cfg; 1814353418Snp struct adapter *sc = pi->adapter; 1815353418Snp int rc; 1816218792Snp 1817353418Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4mec"); 1818353418Snp if (rc != 0) 1819353418Snp return (rc); 1820353418Snp PORT_LOCK(pi); 1821353418Snp if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) { 1822353418Snp MPASS(lc->supported & FW_PORT_CAP_ANEG); 1823353418Snp lc->requested_aneg = AUTONEG_ENABLE; 1824353418Snp } else { 1825353418Snp lc->requested_aneg = AUTONEG_DISABLE; 1826353418Snp lc->requested_speed = 1827353418Snp ifmedia_baudrate(ifm->ifm_media) / 1000000; 1828353418Snp lc->requested_fc = 0; 1829353418Snp if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_RXPAUSE) 1830353418Snp lc->requested_fc |= PAUSE_RX; 1831353418Snp if (IFM_OPTIONS(ifm->ifm_media) & IFM_ETH_TXPAUSE) 1832353418Snp lc->requested_fc |= PAUSE_TX; 1833353418Snp } 1834353418Snp if (pi->up_vis > 0) 1835353418Snp rc = apply_l1cfg(pi); 1836353418Snp PORT_UNLOCK(pi); 1837353418Snp end_synchronized_op(sc, 0); 1838353418Snp return (rc); 1839353418Snp} 1840218792Snp 1841353418Snp/* 1842353418Snp * Mbps to FW_PORT_CAP_SPEED_* bit. 1843353418Snp */ 1844353418Snpstatic uint16_t 1845353418Snpspeed_to_fwspeed(int speed) 1846353418Snp{ 1847353418Snp 1848353418Snp switch (speed) { 1849353418Snp case 100000: 1850353418Snp return (FW_PORT_CAP_SPEED_100G); 1851353418Snp case 40000: 1852353418Snp return (FW_PORT_CAP_SPEED_40G); 1853353418Snp case 25000: 1854353418Snp return (FW_PORT_CAP_SPEED_25G); 1855353418Snp case 10000: 1856353418Snp return (FW_PORT_CAP_SPEED_10G); 1857353418Snp case 1000: 1858353418Snp return (FW_PORT_CAP_SPEED_1G); 1859353418Snp case 100: 1860353418Snp return (FW_PORT_CAP_SPEED_100M); 1861353418Snp } 1862353418Snp 1863353418Snp return (0); 1864218792Snp} 1865218792Snp 1866353418Snp/* 1867353418Snp * Base media word (without ETHER, pause, link active, etc.) for the port at the 1868353418Snp * given speed. 1869353418Snp */ 1870353418Snpstatic int 1871353418Snpport_mword(struct port_info *pi, uint16_t speed) 1872353418Snp{ 1873353418Snp 1874353418Snp MPASS(speed & M_FW_PORT_CAP_SPEED); 1875353418Snp MPASS(powerof2(speed)); 1876353418Snp 1877353418Snp switch(pi->port_type) { 1878353418Snp case FW_PORT_TYPE_BT_SGMII: 1879353418Snp case FW_PORT_TYPE_BT_XFI: 1880353418Snp case FW_PORT_TYPE_BT_XAUI: 1881353418Snp /* BaseT */ 1882353418Snp switch (speed) { 1883353418Snp case FW_PORT_CAP_SPEED_100M: 1884353418Snp return (IFM_100_T); 1885353418Snp case FW_PORT_CAP_SPEED_1G: 1886353418Snp return (IFM_1000_T); 1887353418Snp case FW_PORT_CAP_SPEED_10G: 1888353418Snp return (IFM_10G_T); 1889353418Snp } 1890353418Snp break; 1891353418Snp case FW_PORT_TYPE_KX4: 1892353418Snp if (speed == FW_PORT_CAP_SPEED_10G) 1893353418Snp return (IFM_10G_KX4); 1894353418Snp break; 1895353418Snp case FW_PORT_TYPE_CX4: 1896353418Snp if (speed == FW_PORT_CAP_SPEED_10G) 1897353418Snp return (IFM_10G_CX4); 1898353418Snp break; 1899353418Snp case FW_PORT_TYPE_KX: 1900353418Snp if (speed == FW_PORT_CAP_SPEED_1G) 1901353418Snp return (IFM_1000_KX); 1902353418Snp break; 1903353418Snp case FW_PORT_TYPE_KR: 1904353418Snp case FW_PORT_TYPE_BP_AP: 1905353418Snp case FW_PORT_TYPE_BP4_AP: 1906353418Snp case FW_PORT_TYPE_BP40_BA: 1907353418Snp case FW_PORT_TYPE_KR4_100G: 1908353418Snp case FW_PORT_TYPE_KR_SFP28: 1909353418Snp case FW_PORT_TYPE_KR_XLAUI: 1910353418Snp switch (speed) { 1911353418Snp case FW_PORT_CAP_SPEED_1G: 1912353418Snp return (IFM_1000_KX); 1913353418Snp case FW_PORT_CAP_SPEED_10G: 1914353418Snp return (IFM_10G_KR); 1915353418Snp case FW_PORT_CAP_SPEED_25G: 1916353418Snp return (IFM_25G_KR); 1917353418Snp case FW_PORT_CAP_SPEED_40G: 1918353418Snp return (IFM_40G_KR4); 1919353418Snp case FW_PORT_CAP_SPEED_100G: 1920353418Snp return (IFM_100G_KR4); 1921353418Snp } 1922353418Snp break; 1923353418Snp case FW_PORT_TYPE_FIBER_XFI: 1924353418Snp case FW_PORT_TYPE_FIBER_XAUI: 1925353418Snp case FW_PORT_TYPE_SFP: 1926353418Snp case FW_PORT_TYPE_QSFP_10G: 1927353418Snp case FW_PORT_TYPE_QSA: 1928353418Snp case FW_PORT_TYPE_QSFP: 1929353418Snp case FW_PORT_TYPE_CR4_QSFP: 1930353418Snp case FW_PORT_TYPE_CR_QSFP: 1931353418Snp case FW_PORT_TYPE_CR2_QSFP: 1932353418Snp case FW_PORT_TYPE_SFP28: 1933353418Snp /* Pluggable transceiver */ 1934353418Snp switch (pi->mod_type) { 1935353418Snp case FW_PORT_MOD_TYPE_LR: 1936353418Snp switch (speed) { 1937353418Snp case FW_PORT_CAP_SPEED_1G: 1938353418Snp return (IFM_1000_LX); 1939353418Snp case FW_PORT_CAP_SPEED_10G: 1940353418Snp return (IFM_10G_LR); 1941353418Snp case FW_PORT_CAP_SPEED_25G: 1942353418Snp return (IFM_25G_LR); 1943353418Snp case FW_PORT_CAP_SPEED_40G: 1944353418Snp return (IFM_40G_LR4); 1945353418Snp case FW_PORT_CAP_SPEED_100G: 1946353418Snp return (IFM_100G_LR4); 1947353418Snp } 1948353418Snp break; 1949353418Snp case FW_PORT_MOD_TYPE_SR: 1950353418Snp switch (speed) { 1951353418Snp case FW_PORT_CAP_SPEED_1G: 1952353418Snp return (IFM_1000_SX); 1953353418Snp case FW_PORT_CAP_SPEED_10G: 1954353418Snp return (IFM_10G_SR); 1955353418Snp case FW_PORT_CAP_SPEED_25G: 1956353418Snp return (IFM_25G_SR); 1957353418Snp case FW_PORT_CAP_SPEED_40G: 1958353418Snp return (IFM_40G_SR4); 1959353418Snp case FW_PORT_CAP_SPEED_100G: 1960353418Snp return (IFM_100G_SR4); 1961353418Snp } 1962353418Snp break; 1963353418Snp case FW_PORT_MOD_TYPE_ER: 1964353418Snp if (speed == FW_PORT_CAP_SPEED_10G) 1965353418Snp return (IFM_10G_ER); 1966353418Snp break; 1967353418Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 1968353418Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 1969353418Snp switch (speed) { 1970353418Snp case FW_PORT_CAP_SPEED_1G: 1971353418Snp return (IFM_1000_CX); 1972353418Snp case FW_PORT_CAP_SPEED_10G: 1973353418Snp return (IFM_10G_TWINAX); 1974353418Snp case FW_PORT_CAP_SPEED_25G: 1975353418Snp return (IFM_25G_CR); 1976353418Snp case FW_PORT_CAP_SPEED_40G: 1977353418Snp return (IFM_40G_CR4); 1978353418Snp case FW_PORT_CAP_SPEED_100G: 1979353418Snp return (IFM_100G_CR4); 1980353418Snp } 1981353418Snp break; 1982353418Snp case FW_PORT_MOD_TYPE_LRM: 1983353418Snp if (speed == FW_PORT_CAP_SPEED_10G) 1984353418Snp return (IFM_10G_LRM); 1985353418Snp break; 1986353418Snp case FW_PORT_MOD_TYPE_NA: 1987353418Snp MPASS(0); /* Not pluggable? */ 1988353418Snp /* fall throough */ 1989353418Snp case FW_PORT_MOD_TYPE_ERROR: 1990353418Snp case FW_PORT_MOD_TYPE_UNKNOWN: 1991353418Snp case FW_PORT_MOD_TYPE_NOTSUPPORTED: 1992353418Snp break; 1993353418Snp case FW_PORT_MOD_TYPE_NONE: 1994353418Snp return (IFM_NONE); 1995353418Snp } 1996353418Snp break; 1997353418Snp case FW_PORT_TYPE_NONE: 1998353418Snp return (IFM_NONE); 1999353418Snp } 2000353418Snp 2001353418Snp return (IFM_UNKNOWN); 2002353418Snp} 2003353418Snp 2004218792Snpstatic void 2005218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 2006218792Snp{ 2007308154Sjhb struct vi_info *vi = ifp->if_softc; 2008308154Sjhb struct port_info *pi = vi->pi; 2009353418Snp struct adapter *sc = pi->adapter; 2010353418Snp struct link_config *lc = &pi->link_cfg; 2011218792Snp 2012353418Snp if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4med") != 0) 2013353418Snp return; 2014353418Snp PORT_LOCK(pi); 2015270297Snp 2016353418Snp if (pi->up_vis == 0) { 2017353418Snp /* 2018353418Snp * If all the interfaces are administratively down the firmware 2019353418Snp * does not report transceiver changes. Refresh port info here 2020353418Snp * so that ifconfig displays accurate ifmedia at all times. 2021353418Snp * This is the only reason we have a synchronized op in this 2022353418Snp * function. Just PORT_LOCK would have been enough otherwise. 2023353418Snp */ 2024353418Snp t4_update_port_info(pi); 2025353418Snp build_medialist(pi, &pi->media); 2026353418Snp } 2027353418Snp 2028353418Snp /* ifm_status */ 2029218792Snp ifmr->ifm_status = IFM_AVALID; 2030353418Snp if (lc->link_ok == 0) 2031353418Snp goto done; 2032218792Snp ifmr->ifm_status |= IFM_ACTIVE; 2033218792Snp 2034353418Snp /* ifm_active */ 2035218792Snp ifmr->ifm_active = IFM_ETHER | IFM_FDX; 2036353418Snp ifmr->ifm_active &= ~(IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE); 2037353418Snp if (lc->fc & PAUSE_RX) 2038353418Snp ifmr->ifm_active |= IFM_ETH_RXPAUSE; 2039353418Snp if (lc->fc & PAUSE_TX) 2040353418Snp ifmr->ifm_active |= IFM_ETH_TXPAUSE; 2041353418Snp ifmr->ifm_active |= port_mword(pi, speed_to_fwspeed(lc->speed)); 2042353418Snpdone: 2043353418Snp PORT_UNLOCK(pi); 2044353418Snp end_synchronized_op(sc, 0); 2045218792Snp} 2046218792Snp 2047308154Sjhbstatic int 2048308154Sjhbvcxgbe_probe(device_t dev) 2049308154Sjhb{ 2050308154Sjhb char buf[128]; 2051308154Sjhb struct vi_info *vi = device_get_softc(dev); 2052308154Sjhb 2053308154Sjhb snprintf(buf, sizeof(buf), "port %d vi %td", vi->pi->port_id, 2054308154Sjhb vi - vi->pi->vi); 2055308154Sjhb device_set_desc_copy(dev, buf); 2056308154Sjhb 2057308154Sjhb return (BUS_PROBE_DEFAULT); 2058308154Sjhb} 2059308154Sjhb 2060308154Sjhbstatic int 2061308154Sjhbvcxgbe_attach(device_t dev) 2062308154Sjhb{ 2063308154Sjhb struct vi_info *vi; 2064308154Sjhb struct port_info *pi; 2065308154Sjhb struct adapter *sc; 2066308154Sjhb int func, index, rc; 2067308154Sjhb u32 param, val; 2068308154Sjhb 2069308154Sjhb vi = device_get_softc(dev); 2070308154Sjhb pi = vi->pi; 2071308154Sjhb sc = pi->adapter; 2072308154Sjhb 2073308154Sjhb index = vi - pi->vi; 2074308154Sjhb KASSERT(index < nitems(vi_mac_funcs), 2075308154Sjhb ("%s: VI %s doesn't have a MAC func", __func__, 2076308154Sjhb device_get_nameunit(dev))); 2077308154Sjhb func = vi_mac_funcs[index]; 2078308154Sjhb rc = t4_alloc_vi_func(sc, sc->mbox, pi->tx_chan, sc->pf, 0, 1, 2079308154Sjhb vi->hw_addr, &vi->rss_size, func, 0); 2080308154Sjhb if (rc < 0) { 2081308154Sjhb device_printf(dev, "Failed to allocate virtual interface " 2082308154Sjhb "for port %d: %d\n", pi->port_id, -rc); 2083308154Sjhb return (-rc); 2084308154Sjhb } 2085308154Sjhb vi->viid = rc; 2086309560Sjhb if (chip_id(sc) <= CHELSIO_T5) 2087309560Sjhb vi->smt_idx = (rc & 0x7f) << 1; 2088309560Sjhb else 2089309560Sjhb vi->smt_idx = (rc & 0x7f); 2090308154Sjhb 2091308154Sjhb param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | 2092308154Sjhb V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_RSSINFO) | 2093308154Sjhb V_FW_PARAMS_PARAM_YZ(vi->viid); 2094308154Sjhb rc = t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 2095308154Sjhb if (rc) 2096308154Sjhb vi->rss_base = 0xffff; 2097308154Sjhb else { 2098308154Sjhb /* MPASS((val >> 16) == rss_size); */ 2099308154Sjhb vi->rss_base = val & 0xffff; 2100308154Sjhb } 2101308154Sjhb 2102308154Sjhb rc = cxgbe_vi_attach(dev, vi); 2103308154Sjhb if (rc) { 2104308154Sjhb t4_free_vi(sc, sc->mbox, sc->pf, 0, vi->viid); 2105308154Sjhb return (rc); 2106308154Sjhb } 2107308154Sjhb return (0); 2108308154Sjhb} 2109308154Sjhb 2110308154Sjhbstatic int 2111308154Sjhbvcxgbe_detach(device_t dev) 2112308154Sjhb{ 2113308154Sjhb struct vi_info *vi; 2114308154Sjhb struct adapter *sc; 2115308154Sjhb 2116308154Sjhb vi = device_get_softc(dev); 2117308154Sjhb sc = vi->pi->adapter; 2118308154Sjhb 2119308154Sjhb doom_vi(sc, vi); 2120308154Sjhb 2121308154Sjhb cxgbe_vi_detach(vi); 2122308154Sjhb t4_free_vi(sc, sc->mbox, sc->pf, 0, vi->viid); 2123308154Sjhb 2124308154Sjhb end_synchronized_op(sc, 0); 2125308154Sjhb 2126308154Sjhb return (0); 2127308154Sjhb} 2128308154Sjhb 2129218792Snpvoid 2130218792Snpt4_fatal_err(struct adapter *sc) 2131218792Snp{ 2132218792Snp t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0); 2133218792Snp t4_intr_disable(sc); 2134218792Snp log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n", 2135218792Snp device_get_nameunit(sc->dev)); 2136218792Snp} 2137218792Snp 2138309447Sjhbvoid 2139309447Sjhbt4_add_adapter(struct adapter *sc) 2140218792Snp{ 2141309447Sjhb sx_xlock(&t4_list_lock); 2142309447Sjhb SLIST_INSERT_HEAD(&t4_list, sc, link); 2143309447Sjhb sx_xunlock(&t4_list_lock); 2144309447Sjhb} 2145309447Sjhb 2146309447Sjhbint 2147309447Sjhbt4_map_bars_0_and_4(struct adapter *sc) 2148309447Sjhb{ 2149218792Snp sc->regs_rid = PCIR_BAR(0); 2150218792Snp sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 2151218792Snp &sc->regs_rid, RF_ACTIVE); 2152218792Snp if (sc->regs_res == NULL) { 2153218792Snp device_printf(sc->dev, "cannot map registers.\n"); 2154218792Snp return (ENXIO); 2155218792Snp } 2156218792Snp sc->bt = rman_get_bustag(sc->regs_res); 2157218792Snp sc->bh = rman_get_bushandle(sc->regs_res); 2158218792Snp sc->mmio_len = rman_get_size(sc->regs_res); 2159248925Snp setbit(&sc->doorbells, DOORBELL_KDB); 2160218792Snp 2161218792Snp sc->msix_rid = PCIR_BAR(4); 2162218792Snp sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 2163218792Snp &sc->msix_rid, RF_ACTIVE); 2164218792Snp if (sc->msix_res == NULL) { 2165218792Snp device_printf(sc->dev, "cannot map MSI-X BAR.\n"); 2166218792Snp return (ENXIO); 2167218792Snp } 2168218792Snp 2169218792Snp return (0); 2170218792Snp} 2171218792Snp 2172309447Sjhbint 2173309447Sjhbt4_map_bar_2(struct adapter *sc) 2174248925Snp{ 2175248925Snp 2176248925Snp /* 2177248925Snp * T4: only iWARP driver uses the userspace doorbells. There is no need 2178248925Snp * to map it if RDMA is disabled. 2179248925Snp */ 2180248925Snp if (is_t4(sc) && sc->rdmacaps == 0) 2181248925Snp return (0); 2182248925Snp 2183248925Snp sc->udbs_rid = PCIR_BAR(2); 2184248925Snp sc->udbs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 2185248925Snp &sc->udbs_rid, RF_ACTIVE); 2186248925Snp if (sc->udbs_res == NULL) { 2187248925Snp device_printf(sc->dev, "cannot map doorbell BAR.\n"); 2188248925Snp return (ENXIO); 2189248925Snp } 2190248925Snp sc->udbs_base = rman_get_virtual(sc->udbs_res); 2191248925Snp 2192309560Sjhb if (chip_id(sc) >= CHELSIO_T5) { 2193248925Snp setbit(&sc->doorbells, DOORBELL_UDB); 2194248925Snp#if defined(__i386__) || defined(__amd64__) 2195248925Snp if (t5_write_combine) { 2196309560Sjhb int rc, mode; 2197248925Snp 2198248925Snp /* 2199248925Snp * Enable write combining on BAR2. This is the 2200248925Snp * userspace doorbell BAR and is split into 128B 2201248925Snp * (UDBS_SEG_SIZE) doorbell regions, each associated 2202248925Snp * with an egress queue. The first 64B has the doorbell 2203248925Snp * and the second 64B can be used to submit a tx work 2204248925Snp * request with an implicit doorbell. 2205248925Snp */ 2206248925Snp 2207248925Snp rc = pmap_change_attr((vm_offset_t)sc->udbs_base, 2208248925Snp rman_get_size(sc->udbs_res), PAT_WRITE_COMBINING); 2209248925Snp if (rc == 0) { 2210248925Snp clrbit(&sc->doorbells, DOORBELL_UDB); 2211249392Snp setbit(&sc->doorbells, DOORBELL_WCWR); 2212248925Snp setbit(&sc->doorbells, DOORBELL_UDBWC); 2213248925Snp } else { 2214248925Snp device_printf(sc->dev, 2215248925Snp "couldn't enable write combining: %d\n", 2216248925Snp rc); 2217248925Snp } 2218248925Snp 2219309560Sjhb mode = is_t5(sc) ? V_STATMODE(0) : V_T6_STATMODE(0); 2220248925Snp t4_write_reg(sc, A_SGE_STAT_CFG, 2221309560Sjhb V_STATSOURCE_T5(7) | mode); 2222248925Snp } 2223248925Snp#endif 2224248925Snp } 2225248925Snp 2226248925Snp return (0); 2227248925Snp} 2228248925Snp 2229308305Sjhbstruct memwin_init { 2230308305Sjhb uint32_t base; 2231308305Sjhb uint32_t aperture; 2232308305Sjhb}; 2233308305Sjhb 2234308305Sjhbstatic const struct memwin_init t4_memwin[NUM_MEMWIN] = { 2235248925Snp { MEMWIN0_BASE, MEMWIN0_APERTURE }, 2236248925Snp { MEMWIN1_BASE, MEMWIN1_APERTURE }, 2237248925Snp { MEMWIN2_BASE_T4, MEMWIN2_APERTURE_T4 } 2238248925Snp}; 2239248925Snp 2240308305Sjhbstatic const struct memwin_init t5_memwin[NUM_MEMWIN] = { 2241248925Snp { MEMWIN0_BASE, MEMWIN0_APERTURE }, 2242248925Snp { MEMWIN1_BASE, MEMWIN1_APERTURE }, 2243248925Snp { MEMWIN2_BASE_T5, MEMWIN2_APERTURE_T5 }, 2244248925Snp}; 2245248925Snp 2246218792Snpstatic void 2247218792Snpsetup_memwin(struct adapter *sc) 2248218792Snp{ 2249308305Sjhb const struct memwin_init *mw_init; 2250308305Sjhb struct memwin *mw; 2251308305Sjhb int i; 2252237587Snp uint32_t bar0; 2253218792Snp 2254248925Snp if (is_t4(sc)) { 2255248925Snp /* 2256248925Snp * Read low 32b of bar0 indirectly via the hardware backdoor 2257248925Snp * mechanism. Works from within PCI passthrough environments 2258248925Snp * too, where rman_get_start() can return a different value. We 2259248925Snp * need to program the T4 memory window decoders with the actual 2260248925Snp * addresses that will be coming across the PCIe link. 2261248925Snp */ 2262248925Snp bar0 = t4_hw_pci_read_cfg4(sc, PCIR_BAR(0)); 2263248925Snp bar0 &= (uint32_t) PCIM_BAR_MEM_BASE; 2264218792Snp 2265308305Sjhb mw_init = &t4_memwin[0]; 2266248925Snp } else { 2267308305Sjhb /* T5+ use the relative offset inside the PCIe BAR */ 2268248925Snp bar0 = 0; 2269218792Snp 2270308305Sjhb mw_init = &t5_memwin[0]; 2271248925Snp } 2272218792Snp 2273308305Sjhb for (i = 0, mw = &sc->memwin[0]; i < NUM_MEMWIN; i++, mw_init++, mw++) { 2274308305Sjhb rw_init(&mw->mw_lock, "memory window access"); 2275308305Sjhb mw->mw_base = mw_init->base; 2276308305Sjhb mw->mw_aperture = mw_init->aperture; 2277308305Sjhb mw->mw_curpos = 0; 2278248925Snp t4_write_reg(sc, 2279248925Snp PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, i), 2280308305Sjhb (mw->mw_base + bar0) | V_BIR(0) | 2281308305Sjhb V_WINDOW(ilog2(mw->mw_aperture) - 10)); 2282308305Sjhb rw_wlock(&mw->mw_lock); 2283308305Sjhb position_memwin(sc, i, 0); 2284308305Sjhb rw_wunlock(&mw->mw_lock); 2285248925Snp } 2286237587Snp 2287237587Snp /* flush */ 2288237587Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2)); 2289218792Snp} 2290218792Snp 2291248925Snp/* 2292308305Sjhb * Positions the memory window at the given address in the card's address space. 2293308305Sjhb * There are some alignment requirements and the actual position may be at an 2294308305Sjhb * address prior to the requested address. mw->mw_curpos always has the actual 2295308305Sjhb * position of the window. 2296248925Snp */ 2297308305Sjhbstatic void 2298308305Sjhbposition_memwin(struct adapter *sc, int idx, uint32_t addr) 2299308305Sjhb{ 2300308305Sjhb struct memwin *mw; 2301308305Sjhb uint32_t pf; 2302308305Sjhb uint32_t reg; 2303308305Sjhb 2304308305Sjhb MPASS(idx >= 0 && idx < NUM_MEMWIN); 2305308305Sjhb mw = &sc->memwin[idx]; 2306308305Sjhb rw_assert(&mw->mw_lock, RA_WLOCKED); 2307308305Sjhb 2308308305Sjhb if (is_t4(sc)) { 2309308305Sjhb pf = 0; 2310308305Sjhb mw->mw_curpos = addr & ~0xf; /* start must be 16B aligned */ 2311308305Sjhb } else { 2312308305Sjhb pf = V_PFNUM(sc->pf); 2313308305Sjhb mw->mw_curpos = addr & ~0x7f; /* start must be 128B aligned */ 2314308305Sjhb } 2315308305Sjhb reg = PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, idx); 2316308305Sjhb t4_write_reg(sc, reg, mw->mw_curpos | pf); 2317308305Sjhb t4_read_reg(sc, reg); /* flush */ 2318308305Sjhb} 2319308305Sjhb 2320218792Snpstatic int 2321308305Sjhbrw_via_memwin(struct adapter *sc, int idx, uint32_t addr, uint32_t *val, 2322308305Sjhb int len, int rw) 2323308305Sjhb{ 2324308305Sjhb struct memwin *mw; 2325308305Sjhb uint32_t mw_end, v; 2326308305Sjhb 2327308305Sjhb MPASS(idx >= 0 && idx < NUM_MEMWIN); 2328308305Sjhb 2329308305Sjhb /* Memory can only be accessed in naturally aligned 4 byte units */ 2330308305Sjhb if (addr & 3 || len & 3 || len <= 0) 2331308305Sjhb return (EINVAL); 2332308305Sjhb 2333308305Sjhb mw = &sc->memwin[idx]; 2334308305Sjhb while (len > 0) { 2335308305Sjhb rw_rlock(&mw->mw_lock); 2336308305Sjhb mw_end = mw->mw_curpos + mw->mw_aperture; 2337308305Sjhb if (addr >= mw_end || addr < mw->mw_curpos) { 2338308305Sjhb /* Will need to reposition the window */ 2339308305Sjhb if (!rw_try_upgrade(&mw->mw_lock)) { 2340308305Sjhb rw_runlock(&mw->mw_lock); 2341308305Sjhb rw_wlock(&mw->mw_lock); 2342308305Sjhb } 2343308305Sjhb rw_assert(&mw->mw_lock, RA_WLOCKED); 2344308305Sjhb position_memwin(sc, idx, addr); 2345308305Sjhb rw_downgrade(&mw->mw_lock); 2346308305Sjhb mw_end = mw->mw_curpos + mw->mw_aperture; 2347308305Sjhb } 2348308305Sjhb rw_assert(&mw->mw_lock, RA_RLOCKED); 2349308305Sjhb while (addr < mw_end && len > 0) { 2350308305Sjhb if (rw == 0) { 2351308305Sjhb v = t4_read_reg(sc, mw->mw_base + addr - 2352308305Sjhb mw->mw_curpos); 2353308305Sjhb *val++ = le32toh(v); 2354308305Sjhb } else { 2355308305Sjhb v = *val++; 2356308305Sjhb t4_write_reg(sc, mw->mw_base + addr - 2357308305Sjhb mw->mw_curpos, htole32(v));; 2358308305Sjhb } 2359308305Sjhb addr += 4; 2360308305Sjhb len -= 4; 2361308305Sjhb } 2362308305Sjhb rw_runlock(&mw->mw_lock); 2363308305Sjhb } 2364308305Sjhb 2365308305Sjhb return (0); 2366308305Sjhb} 2367308305Sjhb 2368308305Sjhbstatic inline int 2369308305Sjhbread_via_memwin(struct adapter *sc, int idx, uint32_t addr, uint32_t *val, 2370308305Sjhb int len) 2371308305Sjhb{ 2372308305Sjhb 2373308305Sjhb return (rw_via_memwin(sc, idx, addr, val, len, 0)); 2374308305Sjhb} 2375308305Sjhb 2376308305Sjhbstatic inline int 2377308305Sjhbwrite_via_memwin(struct adapter *sc, int idx, uint32_t addr, 2378308305Sjhb const uint32_t *val, int len) 2379308305Sjhb{ 2380308305Sjhb 2381308305Sjhb return (rw_via_memwin(sc, idx, addr, (void *)(uintptr_t)val, len, 1)); 2382308305Sjhb} 2383308305Sjhb 2384308305Sjhbstatic int 2385308305Sjhbt4_range_cmp(const void *a, const void *b) 2386308305Sjhb{ 2387308305Sjhb return ((const struct t4_range *)a)->start - 2388308305Sjhb ((const struct t4_range *)b)->start; 2389308305Sjhb} 2390308305Sjhb 2391308305Sjhb/* 2392308305Sjhb * Verify that the memory range specified by the addr/len pair is valid within 2393308305Sjhb * the card's address space. 2394308305Sjhb */ 2395308305Sjhbstatic int 2396248925Snpvalidate_mem_range(struct adapter *sc, uint32_t addr, int len) 2397248925Snp{ 2398308305Sjhb struct t4_range mem_ranges[4], *r, *next; 2399308305Sjhb uint32_t em, addr_len; 2400308305Sjhb int i, n, remaining; 2401248925Snp 2402248925Snp /* Memory can only be accessed in naturally aligned 4 byte units */ 2403308305Sjhb if (addr & 3 || len & 3 || len <= 0) 2404248925Snp return (EINVAL); 2405248925Snp 2406248925Snp /* Enabled memories */ 2407248925Snp em = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 2408308305Sjhb 2409308305Sjhb r = &mem_ranges[0]; 2410308305Sjhb n = 0; 2411308305Sjhb bzero(r, sizeof(mem_ranges)); 2412248925Snp if (em & F_EDRAM0_ENABLE) { 2413248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM0_BAR); 2414308305Sjhb r->size = G_EDRAM0_SIZE(addr_len) << 20; 2415308305Sjhb if (r->size > 0) { 2416308305Sjhb r->start = G_EDRAM0_BASE(addr_len) << 20; 2417308305Sjhb if (addr >= r->start && 2418308305Sjhb addr + len <= r->start + r->size) 2419308305Sjhb return (0); 2420308305Sjhb r++; 2421308305Sjhb n++; 2422308305Sjhb } 2423248925Snp } 2424248925Snp if (em & F_EDRAM1_ENABLE) { 2425248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM1_BAR); 2426308305Sjhb r->size = G_EDRAM1_SIZE(addr_len) << 20; 2427308305Sjhb if (r->size > 0) { 2428308305Sjhb r->start = G_EDRAM1_BASE(addr_len) << 20; 2429308305Sjhb if (addr >= r->start && 2430308305Sjhb addr + len <= r->start + r->size) 2431308305Sjhb return (0); 2432308305Sjhb r++; 2433308305Sjhb n++; 2434308305Sjhb } 2435248925Snp } 2436248925Snp if (em & F_EXT_MEM_ENABLE) { 2437248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 2438308305Sjhb r->size = G_EXT_MEM_SIZE(addr_len) << 20; 2439308305Sjhb if (r->size > 0) { 2440308305Sjhb r->start = G_EXT_MEM_BASE(addr_len) << 20; 2441308305Sjhb if (addr >= r->start && 2442308305Sjhb addr + len <= r->start + r->size) 2443308305Sjhb return (0); 2444308305Sjhb r++; 2445308305Sjhb n++; 2446308305Sjhb } 2447248925Snp } 2448308305Sjhb if (is_t5(sc) && em & F_EXT_MEM1_ENABLE) { 2449248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 2450308305Sjhb r->size = G_EXT_MEM1_SIZE(addr_len) << 20; 2451308305Sjhb if (r->size > 0) { 2452308305Sjhb r->start = G_EXT_MEM1_BASE(addr_len) << 20; 2453308305Sjhb if (addr >= r->start && 2454308305Sjhb addr + len <= r->start + r->size) 2455308305Sjhb return (0); 2456308305Sjhb r++; 2457308305Sjhb n++; 2458308305Sjhb } 2459248925Snp } 2460308305Sjhb MPASS(n <= nitems(mem_ranges)); 2461248925Snp 2462308305Sjhb if (n > 1) { 2463308305Sjhb /* Sort and merge the ranges. */ 2464308305Sjhb qsort(mem_ranges, n, sizeof(struct t4_range), t4_range_cmp); 2465308305Sjhb 2466308305Sjhb /* Start from index 0 and examine the next n - 1 entries. */ 2467308305Sjhb r = &mem_ranges[0]; 2468308305Sjhb for (remaining = n - 1; remaining > 0; remaining--, r++) { 2469308305Sjhb 2470308305Sjhb MPASS(r->size > 0); /* r is a valid entry. */ 2471308305Sjhb next = r + 1; 2472308305Sjhb MPASS(next->size > 0); /* and so is the next one. */ 2473308305Sjhb 2474308305Sjhb while (r->start + r->size >= next->start) { 2475308305Sjhb /* Merge the next one into the current entry. */ 2476308305Sjhb r->size = max(r->start + r->size, 2477308305Sjhb next->start + next->size) - r->start; 2478308305Sjhb n--; /* One fewer entry in total. */ 2479308305Sjhb if (--remaining == 0) 2480308305Sjhb goto done; /* short circuit */ 2481308305Sjhb next++; 2482308305Sjhb } 2483308305Sjhb if (next != r + 1) { 2484308305Sjhb /* 2485308305Sjhb * Some entries were merged into r and next 2486308305Sjhb * points to the first valid entry that couldn't 2487308305Sjhb * be merged. 2488308305Sjhb */ 2489308305Sjhb MPASS(next->size > 0); /* must be valid */ 2490308305Sjhb memcpy(r + 1, next, remaining * sizeof(*r)); 2491308305Sjhb#ifdef INVARIANTS 2492308305Sjhb /* 2493308305Sjhb * This so that the foo->size assertion in the 2494308305Sjhb * next iteration of the loop do the right 2495308305Sjhb * thing for entries that were pulled up and are 2496308305Sjhb * no longer valid. 2497308305Sjhb */ 2498308305Sjhb MPASS(n < nitems(mem_ranges)); 2499308305Sjhb bzero(&mem_ranges[n], (nitems(mem_ranges) - n) * 2500308305Sjhb sizeof(struct t4_range)); 2501308305Sjhb#endif 2502308305Sjhb } 2503308305Sjhb } 2504308305Sjhbdone: 2505308305Sjhb /* Done merging the ranges. */ 2506308305Sjhb MPASS(n > 0); 2507308305Sjhb r = &mem_ranges[0]; 2508308305Sjhb for (i = 0; i < n; i++, r++) { 2509308305Sjhb if (addr >= r->start && 2510308305Sjhb addr + len <= r->start + r->size) 2511308305Sjhb return (0); 2512308305Sjhb } 2513308305Sjhb } 2514308305Sjhb 2515248925Snp return (EFAULT); 2516248925Snp} 2517248925Snp 2518256791Snpstatic int 2519256791Snpfwmtype_to_hwmtype(int mtype) 2520256791Snp{ 2521256791Snp 2522256791Snp switch (mtype) { 2523256791Snp case FW_MEMTYPE_EDC0: 2524256791Snp return (MEM_EDC0); 2525256791Snp case FW_MEMTYPE_EDC1: 2526256791Snp return (MEM_EDC1); 2527256791Snp case FW_MEMTYPE_EXTMEM: 2528256791Snp return (MEM_MC0); 2529256791Snp case FW_MEMTYPE_EXTMEM1: 2530256791Snp return (MEM_MC1); 2531256791Snp default: 2532256791Snp panic("%s: cannot translate fw mtype %d.", __func__, mtype); 2533256791Snp } 2534256791Snp} 2535256791Snp 2536248925Snp/* 2537248925Snp * Verify that the memory range specified by the memtype/offset/len pair is 2538248925Snp * valid and lies entirely within the memtype specified. The global address of 2539248925Snp * the start of the range is returned in addr. 2540248925Snp */ 2541248925Snpstatic int 2542248925Snpvalidate_mt_off_len(struct adapter *sc, int mtype, uint32_t off, int len, 2543248925Snp uint32_t *addr) 2544248925Snp{ 2545308305Sjhb uint32_t em, addr_len, maddr; 2546248925Snp 2547248925Snp /* Memory can only be accessed in naturally aligned 4 byte units */ 2548248925Snp if (off & 3 || len & 3 || len == 0) 2549248925Snp return (EINVAL); 2550248925Snp 2551248925Snp em = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 2552256791Snp switch (fwmtype_to_hwmtype(mtype)) { 2553248925Snp case MEM_EDC0: 2554248925Snp if (!(em & F_EDRAM0_ENABLE)) 2555248925Snp return (EINVAL); 2556248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM0_BAR); 2557248925Snp maddr = G_EDRAM0_BASE(addr_len) << 20; 2558248925Snp break; 2559248925Snp case MEM_EDC1: 2560248925Snp if (!(em & F_EDRAM1_ENABLE)) 2561248925Snp return (EINVAL); 2562248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM1_BAR); 2563248925Snp maddr = G_EDRAM1_BASE(addr_len) << 20; 2564248925Snp break; 2565248925Snp case MEM_MC: 2566248925Snp if (!(em & F_EXT_MEM_ENABLE)) 2567248925Snp return (EINVAL); 2568248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 2569248925Snp maddr = G_EXT_MEM_BASE(addr_len) << 20; 2570248925Snp break; 2571248925Snp case MEM_MC1: 2572308305Sjhb if (!is_t5(sc) || !(em & F_EXT_MEM1_ENABLE)) 2573248925Snp return (EINVAL); 2574248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 2575248925Snp maddr = G_EXT_MEM1_BASE(addr_len) << 20; 2576248925Snp break; 2577248925Snp default: 2578248925Snp return (EINVAL); 2579248925Snp } 2580248925Snp 2581308305Sjhb *addr = maddr + off; /* global address */ 2582308305Sjhb return (validate_mem_range(sc, *addr, len)); 2583248925Snp} 2584248925Snp 2585308305Sjhbstatic int 2586308305Sjhbfixup_devlog_params(struct adapter *sc) 2587248925Snp{ 2588308305Sjhb struct devlog_params *dparams = &sc->params.devlog; 2589308305Sjhb int rc; 2590248925Snp 2591308305Sjhb rc = validate_mt_off_len(sc, dparams->memtype, dparams->start, 2592308305Sjhb dparams->size, &dparams->addr); 2593248925Snp 2594308305Sjhb return (rc); 2595248925Snp} 2596248925Snp 2597248925Snpstatic int 2598308154Sjhbcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g, int num_vis, 2599218792Snp struct intrs_and_queues *iaq) 2600218792Snp{ 2601228561Snp int rc, itype, navail, nrxq10g, nrxq1g, n; 2602228561Snp int nofldrxq10g = 0, nofldrxq1g = 0; 2603218792Snp 2604218792Snp bzero(iaq, sizeof(*iaq)); 2605218792Snp 2606228561Snp iaq->ntxq10g = t4_ntxq10g; 2607228561Snp iaq->ntxq1g = t4_ntxq1g; 2608308154Sjhb iaq->ntxq_vi = t4_ntxq_vi; 2609228561Snp iaq->nrxq10g = nrxq10g = t4_nrxq10g; 2610228561Snp iaq->nrxq1g = nrxq1g = t4_nrxq1g; 2611308154Sjhb iaq->nrxq_vi = t4_nrxq_vi; 2612264493Sscottl iaq->rsrv_noflowq = t4_rsrv_noflowq; 2613237263Snp#ifdef TCP_OFFLOAD 2614237463Snp if (is_offload(sc)) { 2615237463Snp iaq->nofldtxq10g = t4_nofldtxq10g; 2616237463Snp iaq->nofldtxq1g = t4_nofldtxq1g; 2617308154Sjhb iaq->nofldtxq_vi = t4_nofldtxq_vi; 2618237463Snp iaq->nofldrxq10g = nofldrxq10g = t4_nofldrxq10g; 2619237463Snp iaq->nofldrxq1g = nofldrxq1g = t4_nofldrxq1g; 2620308154Sjhb iaq->nofldrxq_vi = t4_nofldrxq_vi; 2621237463Snp } 2622228561Snp#endif 2623270297Snp#ifdef DEV_NETMAP 2624308154Sjhb iaq->nnmtxq_vi = t4_nnmtxq_vi; 2625308154Sjhb iaq->nnmrxq_vi = t4_nnmrxq_vi; 2626270297Snp#endif 2627228561Snp 2628219944Snp for (itype = INTR_MSIX; itype; itype >>= 1) { 2629218792Snp 2630228561Snp if ((itype & t4_intr_types) == 0) 2631218792Snp continue; /* not allowed */ 2632218792Snp 2633219944Snp if (itype == INTR_MSIX) 2634218792Snp navail = pci_msix_count(sc->dev); 2635219944Snp else if (itype == INTR_MSI) 2636218792Snp navail = pci_msi_count(sc->dev); 2637218792Snp else 2638218792Snp navail = 1; 2639228561Snprestart: 2640218792Snp if (navail == 0) 2641218792Snp continue; 2642218792Snp 2643218792Snp iaq->intr_type = itype; 2644270297Snp iaq->intr_flags_10g = 0; 2645270297Snp iaq->intr_flags_1g = 0; 2646218792Snp 2647228561Snp /* 2648228561Snp * Best option: an interrupt vector for errors, one for the 2649308154Sjhb * firmware event queue, and one for every rxq (NIC and TOE) of 2650308154Sjhb * every VI. The VIs that support netmap use the same 2651308154Sjhb * interrupts for the NIC rx queues and the netmap rx queues 2652308154Sjhb * because only one set of queues is active at a time. 2653228561Snp */ 2654228561Snp iaq->nirq = T4_EXTRA_INTR; 2655308154Sjhb iaq->nirq += n10g * (nrxq10g + nofldrxq10g); 2656308154Sjhb iaq->nirq += n1g * (nrxq1g + nofldrxq1g); 2657308154Sjhb iaq->nirq += (n10g + n1g) * (num_vis - 1) * 2658308154Sjhb max(iaq->nrxq_vi, iaq->nnmrxq_vi); /* See comment above. */ 2659308154Sjhb iaq->nirq += (n10g + n1g) * (num_vis - 1) * iaq->nofldrxq_vi; 2660228561Snp if (iaq->nirq <= navail && 2661228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) { 2662270297Snp iaq->intr_flags_10g = INTR_ALL; 2663270297Snp iaq->intr_flags_1g = INTR_ALL; 2664228561Snp goto allocate; 2665228561Snp } 2666218792Snp 2667308154Sjhb /* Disable the VIs (and netmap) if there aren't enough intrs */ 2668308154Sjhb if (num_vis > 1) { 2669308154Sjhb device_printf(sc->dev, "virtual interfaces disabled " 2670308154Sjhb "because num_vis=%u with current settings " 2671308154Sjhb "(nrxq10g=%u, nrxq1g=%u, nofldrxq10g=%u, " 2672308154Sjhb "nofldrxq1g=%u, nrxq_vi=%u nofldrxq_vi=%u, " 2673308154Sjhb "nnmrxq_vi=%u) would need %u interrupts but " 2674308154Sjhb "only %u are available.\n", num_vis, nrxq10g, 2675308154Sjhb nrxq1g, nofldrxq10g, nofldrxq1g, iaq->nrxq_vi, 2676308154Sjhb iaq->nofldrxq_vi, iaq->nnmrxq_vi, iaq->nirq, 2677308154Sjhb navail); 2678308154Sjhb num_vis = 1; 2679308154Sjhb iaq->ntxq_vi = iaq->nrxq_vi = 0; 2680308154Sjhb iaq->nofldtxq_vi = iaq->nofldrxq_vi = 0; 2681308154Sjhb iaq->nnmtxq_vi = iaq->nnmrxq_vi = 0; 2682308154Sjhb goto restart; 2683308154Sjhb } 2684308154Sjhb 2685228561Snp /* 2686270297Snp * Second best option: a vector for errors, one for the firmware 2687270297Snp * event queue, and vectors for either all the NIC rx queues or 2688270297Snp * all the TOE rx queues. The queues that don't get vectors 2689270297Snp * will forward their interrupts to those that do. 2690228561Snp */ 2691228561Snp iaq->nirq = T4_EXTRA_INTR; 2692270297Snp if (nrxq10g >= nofldrxq10g) { 2693270297Snp iaq->intr_flags_10g = INTR_RXQ; 2694270297Snp iaq->nirq += n10g * nrxq10g; 2695270297Snp } else { 2696270297Snp iaq->intr_flags_10g = INTR_OFLD_RXQ; 2697270297Snp iaq->nirq += n10g * nofldrxq10g; 2698270297Snp } 2699270297Snp if (nrxq1g >= nofldrxq1g) { 2700270297Snp iaq->intr_flags_1g = INTR_RXQ; 2701270297Snp iaq->nirq += n1g * nrxq1g; 2702270297Snp } else { 2703270297Snp iaq->intr_flags_1g = INTR_OFLD_RXQ; 2704270297Snp iaq->nirq += n1g * nofldrxq1g; 2705270297Snp } 2706228561Snp if (iaq->nirq <= navail && 2707228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) 2708228561Snp goto allocate; 2709218792Snp 2710228561Snp /* 2711228561Snp * Next best option: an interrupt vector for errors, one for the 2712308154Sjhb * firmware event queue, and at least one per main-VI. At this 2713308154Sjhb * point we know we'll have to downsize nrxq and/or nofldrxq to 2714308154Sjhb * fit what's available to us. 2715228561Snp */ 2716228561Snp iaq->nirq = T4_EXTRA_INTR; 2717228561Snp iaq->nirq += n10g + n1g; 2718228561Snp if (iaq->nirq <= navail) { 2719228561Snp int leftover = navail - iaq->nirq; 2720218792Snp 2721228561Snp if (n10g > 0) { 2722228561Snp int target = max(nrxq10g, nofldrxq10g); 2723219944Snp 2724270297Snp iaq->intr_flags_10g = nrxq10g >= nofldrxq10g ? 2725270297Snp INTR_RXQ : INTR_OFLD_RXQ; 2726270297Snp 2727228561Snp n = 1; 2728228561Snp while (n < target && leftover >= n10g) { 2729228561Snp leftover -= n10g; 2730228561Snp iaq->nirq += n10g; 2731228561Snp n++; 2732228561Snp } 2733228561Snp iaq->nrxq10g = min(n, nrxq10g); 2734237263Snp#ifdef TCP_OFFLOAD 2735270297Snp iaq->nofldrxq10g = min(n, nofldrxq10g); 2736228561Snp#endif 2737228561Snp } 2738218792Snp 2739228561Snp if (n1g > 0) { 2740228561Snp int target = max(nrxq1g, nofldrxq1g); 2741219944Snp 2742270297Snp iaq->intr_flags_1g = nrxq1g >= nofldrxq1g ? 2743270297Snp INTR_RXQ : INTR_OFLD_RXQ; 2744270297Snp 2745228561Snp n = 1; 2746228561Snp while (n < target && leftover >= n1g) { 2747228561Snp leftover -= n1g; 2748228561Snp iaq->nirq += n1g; 2749228561Snp n++; 2750219944Snp } 2751228561Snp iaq->nrxq1g = min(n, nrxq1g); 2752237263Snp#ifdef TCP_OFFLOAD 2753270297Snp iaq->nofldrxq1g = min(n, nofldrxq1g); 2754228561Snp#endif 2755219944Snp } 2756219944Snp 2757228561Snp if (itype != INTR_MSI || powerof2(iaq->nirq)) 2758228561Snp goto allocate; 2759218792Snp } 2760218792Snp 2761228561Snp /* 2762228561Snp * Least desirable option: one interrupt vector for everything. 2763228561Snp */ 2764228561Snp iaq->nirq = iaq->nrxq10g = iaq->nrxq1g = 1; 2765270297Snp iaq->intr_flags_10g = iaq->intr_flags_1g = 0; 2766237263Snp#ifdef TCP_OFFLOAD 2767237463Snp if (is_offload(sc)) 2768237463Snp iaq->nofldrxq10g = iaq->nofldrxq1g = 1; 2769228561Snp#endif 2770228561Snpallocate: 2771218792Snp navail = iaq->nirq; 2772218792Snp rc = 0; 2773219944Snp if (itype == INTR_MSIX) 2774218792Snp rc = pci_alloc_msix(sc->dev, &navail); 2775219944Snp else if (itype == INTR_MSI) 2776218792Snp rc = pci_alloc_msi(sc->dev, &navail); 2777218792Snp 2778218792Snp if (rc == 0) { 2779218792Snp if (navail == iaq->nirq) 2780218792Snp return (0); 2781218792Snp 2782218792Snp /* 2783218792Snp * Didn't get the number requested. Use whatever number 2784218792Snp * the kernel is willing to allocate (it's in navail). 2785218792Snp */ 2786228561Snp device_printf(sc->dev, "fewer vectors than requested, " 2787228561Snp "type=%d, req=%d, rcvd=%d; will downshift req.\n", 2788228561Snp itype, iaq->nirq, navail); 2789218792Snp pci_release_msi(sc->dev); 2790228561Snp goto restart; 2791218792Snp } 2792218792Snp 2793218792Snp device_printf(sc->dev, 2794218792Snp "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n", 2795218792Snp itype, rc, iaq->nirq, navail); 2796218792Snp } 2797218792Snp 2798218792Snp device_printf(sc->dev, 2799218792Snp "failed to find a usable interrupt type. " 2800228561Snp "allowed=%d, msi-x=%d, msi=%d, intx=1", t4_intr_types, 2801218792Snp pci_msix_count(sc->dev), pci_msi_count(sc->dev)); 2802218792Snp 2803218792Snp return (ENXIO); 2804218792Snp} 2805218792Snp 2806248925Snp#define FW_VERSION(chip) ( \ 2807252661Snp V_FW_HDR_FW_VER_MAJOR(chip##FW_VERSION_MAJOR) | \ 2808252661Snp V_FW_HDR_FW_VER_MINOR(chip##FW_VERSION_MINOR) | \ 2809252661Snp V_FW_HDR_FW_VER_MICRO(chip##FW_VERSION_MICRO) | \ 2810252661Snp V_FW_HDR_FW_VER_BUILD(chip##FW_VERSION_BUILD)) 2811252661Snp#define FW_INTFVER(chip, intf) (chip##FW_HDR_INTFVER_##intf) 2812248925Snp 2813248925Snpstruct fw_info { 2814248925Snp uint8_t chip; 2815248925Snp char *kld_name; 2816248925Snp char *fw_mod_name; 2817248925Snp struct fw_hdr fw_hdr; /* XXX: waste of space, need a sparse struct */ 2818248925Snp} fw_info[] = { 2819248925Snp { 2820248925Snp .chip = CHELSIO_T4, 2821248925Snp .kld_name = "t4fw_cfg", 2822248925Snp .fw_mod_name = "t4fw", 2823248925Snp .fw_hdr = { 2824248925Snp .chip = FW_HDR_CHIP_T4, 2825248925Snp .fw_ver = htobe32_const(FW_VERSION(T4)), 2826248925Snp .intfver_nic = FW_INTFVER(T4, NIC), 2827248925Snp .intfver_vnic = FW_INTFVER(T4, VNIC), 2828248925Snp .intfver_ofld = FW_INTFVER(T4, OFLD), 2829248925Snp .intfver_ri = FW_INTFVER(T4, RI), 2830248925Snp .intfver_iscsipdu = FW_INTFVER(T4, ISCSIPDU), 2831248925Snp .intfver_iscsi = FW_INTFVER(T4, ISCSI), 2832248925Snp .intfver_fcoepdu = FW_INTFVER(T4, FCOEPDU), 2833248925Snp .intfver_fcoe = FW_INTFVER(T4, FCOE), 2834248925Snp }, 2835248925Snp }, { 2836248925Snp .chip = CHELSIO_T5, 2837248925Snp .kld_name = "t5fw_cfg", 2838248925Snp .fw_mod_name = "t5fw", 2839248925Snp .fw_hdr = { 2840248925Snp .chip = FW_HDR_CHIP_T5, 2841248925Snp .fw_ver = htobe32_const(FW_VERSION(T5)), 2842248925Snp .intfver_nic = FW_INTFVER(T5, NIC), 2843248925Snp .intfver_vnic = FW_INTFVER(T5, VNIC), 2844248925Snp .intfver_ofld = FW_INTFVER(T5, OFLD), 2845248925Snp .intfver_ri = FW_INTFVER(T5, RI), 2846248925Snp .intfver_iscsipdu = FW_INTFVER(T5, ISCSIPDU), 2847248925Snp .intfver_iscsi = FW_INTFVER(T5, ISCSI), 2848248925Snp .intfver_fcoepdu = FW_INTFVER(T5, FCOEPDU), 2849248925Snp .intfver_fcoe = FW_INTFVER(T5, FCOE), 2850248925Snp }, 2851309560Sjhb }, { 2852309560Sjhb .chip = CHELSIO_T6, 2853309560Sjhb .kld_name = "t6fw_cfg", 2854309560Sjhb .fw_mod_name = "t6fw", 2855309560Sjhb .fw_hdr = { 2856309560Sjhb .chip = FW_HDR_CHIP_T6, 2857309560Sjhb .fw_ver = htobe32_const(FW_VERSION(T6)), 2858309560Sjhb .intfver_nic = FW_INTFVER(T6, NIC), 2859309560Sjhb .intfver_vnic = FW_INTFVER(T6, VNIC), 2860309560Sjhb .intfver_ofld = FW_INTFVER(T6, OFLD), 2861309560Sjhb .intfver_ri = FW_INTFVER(T6, RI), 2862309560Sjhb .intfver_iscsipdu = FW_INTFVER(T6, ISCSIPDU), 2863309560Sjhb .intfver_iscsi = FW_INTFVER(T6, ISCSI), 2864309560Sjhb .intfver_fcoepdu = FW_INTFVER(T6, FCOEPDU), 2865309560Sjhb .intfver_fcoe = FW_INTFVER(T6, FCOE), 2866309560Sjhb }, 2867248925Snp } 2868248925Snp}; 2869248925Snp 2870248925Snpstatic struct fw_info * 2871248925Snpfind_fw_info(int chip) 2872248925Snp{ 2873248925Snp int i; 2874248925Snp 2875248925Snp for (i = 0; i < nitems(fw_info); i++) { 2876248925Snp if (fw_info[i].chip == chip) 2877248925Snp return (&fw_info[i]); 2878248925Snp } 2879248925Snp return (NULL); 2880248925Snp} 2881248925Snp 2882218792Snp/* 2883248925Snp * Is the given firmware API compatible with the one the driver was compiled 2884248925Snp * with? 2885247347Snp */ 2886247347Snpstatic int 2887248925Snpfw_compatible(const struct fw_hdr *hdr1, const struct fw_hdr *hdr2) 2888247347Snp{ 2889247347Snp 2890248925Snp /* short circuit if it's the exact same firmware version */ 2891248925Snp if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver) 2892247347Snp return (1); 2893247347Snp 2894247347Snp /* 2895247347Snp * XXX: Is this too conservative? Perhaps I should limit this to the 2896247347Snp * features that are supported in the driver. 2897247347Snp */ 2898248925Snp#define SAME_INTF(x) (hdr1->intfver_##x == hdr2->intfver_##x) 2899248925Snp if (hdr1->chip == hdr2->chip && SAME_INTF(nic) && SAME_INTF(vnic) && 2900248925Snp SAME_INTF(ofld) && SAME_INTF(ri) && SAME_INTF(iscsipdu) && 2901248925Snp SAME_INTF(iscsi) && SAME_INTF(fcoepdu) && SAME_INTF(fcoe)) 2902247347Snp return (1); 2903248925Snp#undef SAME_INTF 2904247347Snp 2905247347Snp return (0); 2906247347Snp} 2907247347Snp 2908247347Snp/* 2909251434Snp * The firmware in the KLD is usable, but should it be installed? This routine 2910251434Snp * explains itself in detail if it indicates the KLD firmware should be 2911251434Snp * installed. 2912249376Snp */ 2913249376Snpstatic int 2914249376Snpshould_install_kld_fw(struct adapter *sc, int card_fw_usable, int k, int c) 2915249376Snp{ 2916249376Snp const char *reason; 2917249376Snp 2918249376Snp if (!card_fw_usable) { 2919249376Snp reason = "incompatible or unusable"; 2920249376Snp goto install; 2921249376Snp } 2922249376Snp 2923249376Snp if (k > c) { 2924249376Snp reason = "older than the version bundled with this driver"; 2925249376Snp goto install; 2926249376Snp } 2927249376Snp 2928249376Snp if (t4_fw_install == 2 && k != c) { 2929249376Snp reason = "different than the version bundled with this driver"; 2930249376Snp goto install; 2931249376Snp } 2932249376Snp 2933249376Snp return (0); 2934249376Snp 2935249376Snpinstall: 2936251434Snp if (t4_fw_install == 0) { 2937251434Snp device_printf(sc->dev, "firmware on card (%u.%u.%u.%u) is %s, " 2938251434Snp "but the driver is prohibited from installing a different " 2939251434Snp "firmware on the card.\n", 2940251434Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 2941251434Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), reason); 2942251434Snp 2943251434Snp return (0); 2944251434Snp } 2945251434Snp 2946249376Snp device_printf(sc->dev, "firmware on card (%u.%u.%u.%u) is %s, " 2947249376Snp "installing firmware %u.%u.%u.%u on card.\n", 2948249376Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 2949249376Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), reason, 2950249376Snp G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k), 2951249376Snp G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k)); 2952249376Snp 2953249376Snp return (1); 2954249376Snp} 2955249376Snp/* 2956248925Snp * Establish contact with the firmware and determine if we are the master driver 2957248925Snp * or not, and whether we are responsible for chip initialization. 2958218792Snp */ 2959218792Snpstatic int 2960218792Snpprep_firmware(struct adapter *sc) 2961218792Snp{ 2962248925Snp const struct firmware *fw = NULL, *default_cfg; 2963248925Snp int rc, pf, card_fw_usable, kld_fw_usable, need_fw_reset = 1; 2964218792Snp enum dev_state state; 2965248925Snp struct fw_info *fw_info; 2966248925Snp struct fw_hdr *card_fw; /* fw on the card */ 2967248925Snp const struct fw_hdr *kld_fw; /* fw in the KLD */ 2968248925Snp const struct fw_hdr *drv_fw; /* fw header the driver was compiled 2969248925Snp against */ 2970218792Snp 2971248925Snp /* Contact firmware. */ 2972248925Snp rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state); 2973248925Snp if (rc < 0 || state == DEV_STATE_ERR) { 2974248925Snp rc = -rc; 2975248925Snp device_printf(sc->dev, 2976248925Snp "failed to connect to the firmware: %d, %d.\n", rc, state); 2977248925Snp return (rc); 2978248925Snp } 2979248925Snp pf = rc; 2980248925Snp if (pf == sc->mbox) 2981248925Snp sc->flags |= MASTER_PF; 2982248925Snp else if (state == DEV_STATE_UNINIT) { 2983248925Snp /* 2984248925Snp * We didn't get to be the master so we definitely won't be 2985248925Snp * configuring the chip. It's a bug if someone else hasn't 2986248925Snp * configured it already. 2987248925Snp */ 2988248925Snp device_printf(sc->dev, "couldn't be master(%d), " 2989248925Snp "device not already initialized either(%d).\n", rc, state); 2990248925Snp return (EDOOFUS); 2991248925Snp } 2992228561Snp 2993248925Snp /* This is the firmware whose headers the driver was compiled against */ 2994248925Snp fw_info = find_fw_info(chip_id(sc)); 2995248925Snp if (fw_info == NULL) { 2996248925Snp device_printf(sc->dev, 2997248925Snp "unable to look up firmware information for chip %d.\n", 2998248925Snp chip_id(sc)); 2999248925Snp return (EINVAL); 3000248925Snp } 3001248925Snp drv_fw = &fw_info->fw_hdr; 3002248925Snp 3003248925Snp /* 3004248925Snp * The firmware KLD contains many modules. The KLD name is also the 3005248925Snp * name of the module that contains the default config file. 3006248925Snp */ 3007248925Snp default_cfg = firmware_get(fw_info->kld_name); 3008248925Snp 3009247347Snp /* Read the header of the firmware on the card */ 3010247347Snp card_fw = malloc(sizeof(*card_fw), M_CXGBE, M_ZERO | M_WAITOK); 3011247347Snp rc = -t4_read_flash(sc, FLASH_FW_START, 3012247347Snp sizeof (*card_fw) / sizeof (uint32_t), (uint32_t *)card_fw, 1); 3013247347Snp if (rc == 0) 3014248925Snp card_fw_usable = fw_compatible(drv_fw, (const void*)card_fw); 3015247347Snp else { 3016247347Snp device_printf(sc->dev, 3017247347Snp "Unable to read card's firmware header: %d\n", rc); 3018247347Snp card_fw_usable = 0; 3019247347Snp } 3020218792Snp 3021247347Snp /* This is the firmware in the KLD */ 3022248925Snp fw = firmware_get(fw_info->fw_mod_name); 3023247347Snp if (fw != NULL) { 3024247347Snp kld_fw = (const void *)fw->data; 3025248925Snp kld_fw_usable = fw_compatible(drv_fw, kld_fw); 3026247347Snp } else { 3027247347Snp kld_fw = NULL; 3028247347Snp kld_fw_usable = 0; 3029247347Snp } 3030219287Snp 3031248925Snp if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver && 3032251434Snp (!kld_fw_usable || kld_fw->fw_ver == drv_fw->fw_ver)) { 3033248925Snp /* 3034248925Snp * Common case: the firmware on the card is an exact match and 3035248925Snp * the KLD is an exact match too, or the KLD is 3036251434Snp * absent/incompatible. Note that t4_fw_install = 2 is ignored 3037251434Snp * here -- use cxgbetool loadfw if you want to reinstall the 3038251434Snp * same firmware as the one on the card. 3039248925Snp */ 3040248925Snp } else if (kld_fw_usable && state == DEV_STATE_UNINIT && 3041249376Snp should_install_kld_fw(sc, card_fw_usable, be32toh(kld_fw->fw_ver), 3042249376Snp be32toh(card_fw->fw_ver))) { 3043219287Snp 3044250221Snp rc = -t4_fw_upgrade(sc, sc->mbox, fw->data, fw->datasize, 0); 3045247347Snp if (rc != 0) { 3046247347Snp device_printf(sc->dev, 3047247347Snp "failed to install firmware: %d\n", rc); 3048228561Snp goto done; 3049219287Snp } 3050219287Snp 3051247347Snp /* Installed successfully, update the cached header too. */ 3052247347Snp memcpy(card_fw, kld_fw, sizeof(*card_fw)); 3053247347Snp card_fw_usable = 1; 3054248925Snp need_fw_reset = 0; /* already reset as part of load_fw */ 3055247347Snp } 3056219287Snp 3057247347Snp if (!card_fw_usable) { 3058248925Snp uint32_t d, c, k; 3059247347Snp 3060248925Snp d = ntohl(drv_fw->fw_ver); 3061247347Snp c = ntohl(card_fw->fw_ver); 3062247347Snp k = kld_fw ? ntohl(kld_fw->fw_ver) : 0; 3063247347Snp 3064247347Snp device_printf(sc->dev, "Cannot find a usable firmware: " 3065248925Snp "fw_install %d, chip state %d, " 3066248925Snp "driver compiled with %d.%d.%d.%d, " 3067247347Snp "card has %d.%d.%d.%d, KLD has %d.%d.%d.%d\n", 3068248925Snp t4_fw_install, state, 3069248925Snp G_FW_HDR_FW_VER_MAJOR(d), G_FW_HDR_FW_VER_MINOR(d), 3070248925Snp G_FW_HDR_FW_VER_MICRO(d), G_FW_HDR_FW_VER_BUILD(d), 3071247347Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 3072247347Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), 3073247347Snp G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k), 3074247347Snp G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k)); 3075248925Snp rc = EINVAL; 3076247347Snp goto done; 3077218792Snp } 3078218792Snp 3079218792Snp /* Reset device */ 3080248925Snp if (need_fw_reset && 3081248925Snp (rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST)) != 0) { 3082218792Snp device_printf(sc->dev, "firmware reset failed: %d.\n", rc); 3083218792Snp if (rc != ETIMEDOUT && rc != EIO) 3084218792Snp t4_fw_bye(sc, sc->mbox); 3085228561Snp goto done; 3086218792Snp } 3087248925Snp sc->flags |= FW_OK; 3088218792Snp 3089248925Snp rc = get_params__pre_init(sc); 3090248925Snp if (rc != 0) 3091248925Snp goto done; /* error message displayed already */ 3092248925Snp 3093228561Snp /* Partition adapter resources as specified in the config file. */ 3094248925Snp if (state == DEV_STATE_UNINIT) { 3095228561Snp 3096248925Snp KASSERT(sc->flags & MASTER_PF, 3097248925Snp ("%s: trying to change chip settings when not master.", 3098248925Snp __func__)); 3099228561Snp 3100248925Snp rc = partition_resources(sc, default_cfg, fw_info->kld_name); 3101228561Snp if (rc != 0) 3102228561Snp goto done; /* error message displayed already */ 3103248925Snp 3104248925Snp t4_tweak_chip_settings(sc); 3105248925Snp 3106248925Snp /* get basic stuff going */ 3107248925Snp rc = -t4_fw_initialize(sc, sc->mbox); 3108248925Snp if (rc != 0) { 3109248925Snp device_printf(sc->dev, "fw init failed: %d.\n", rc); 3110248925Snp goto done; 3111248925Snp } 3112245936Snp } else { 3113248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "pf%d", pf); 3114248925Snp sc->cfcsum = 0; 3115228561Snp } 3116228561Snp 3117228561Snpdone: 3118247347Snp free(card_fw, M_CXGBE); 3119228561Snp if (fw != NULL) 3120228561Snp firmware_put(fw, FIRMWARE_UNLOAD); 3121228561Snp if (default_cfg != NULL) 3122228561Snp firmware_put(default_cfg, FIRMWARE_UNLOAD); 3123228561Snp 3124228561Snp return (rc); 3125218792Snp} 3126218792Snp 3127228561Snp#define FW_PARAM_DEV(param) \ 3128228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ 3129228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) 3130228561Snp#define FW_PARAM_PFVF(param) \ 3131228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ 3132228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)) 3133228561Snp 3134228561Snp/* 3135248925Snp * Partition chip resources for use between various PFs, VFs, etc. 3136228561Snp */ 3137218792Snpstatic int 3138248925Snppartition_resources(struct adapter *sc, const struct firmware *default_cfg, 3139248925Snp const char *name_prefix) 3140222551Snp{ 3141248925Snp const struct firmware *cfg = NULL; 3142248925Snp int rc = 0; 3143248925Snp struct fw_caps_config_cmd caps; 3144248925Snp uint32_t mtype, moff, finicsum, cfcsum; 3145222551Snp 3146248925Snp /* 3147248925Snp * Figure out what configuration file to use. Pick the default config 3148248925Snp * file for the card if the user hasn't specified one explicitly. 3149248925Snp */ 3150248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", t4_cfg_file); 3151248925Snp if (strncmp(t4_cfg_file, DEFAULT_CF, sizeof(t4_cfg_file)) == 0) { 3152248925Snp /* Card specific overrides go here. */ 3153248925Snp if (pci_get_device(sc->dev) == 0x440a) 3154248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), UWIRE_CF); 3155249376Snp if (is_fpga(sc)) 3156249376Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), FPGA_CF); 3157222551Snp } 3158222551Snp 3159248925Snp /* 3160248925Snp * We need to load another module if the profile is anything except 3161248925Snp * "default" or "flash". 3162248925Snp */ 3163248925Snp if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) != 0 && 3164248925Snp strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) { 3165248925Snp char s[32]; 3166248925Snp 3167248925Snp snprintf(s, sizeof(s), "%s_%s", name_prefix, sc->cfg_file); 3168248925Snp cfg = firmware_get(s); 3169248925Snp if (cfg == NULL) { 3170248925Snp if (default_cfg != NULL) { 3171249376Snp device_printf(sc->dev, 3172249376Snp "unable to load module \"%s\" for " 3173249376Snp "configuration profile \"%s\", will use " 3174249376Snp "the default config file instead.\n", 3175249376Snp s, sc->cfg_file); 3176248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), 3177248925Snp "%s", DEFAULT_CF); 3178248925Snp } else { 3179249376Snp device_printf(sc->dev, 3180249376Snp "unable to load module \"%s\" for " 3181249376Snp "configuration profile \"%s\", will use " 3182249376Snp "the config file on the card's flash " 3183249376Snp "instead.\n", s, sc->cfg_file); 3184248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), 3185248925Snp "%s", FLASH_CF); 3186248925Snp } 3187248925Snp } 3188228561Snp } 3189222551Snp 3190248925Snp if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) == 0 && 3191248925Snp default_cfg == NULL) { 3192228561Snp device_printf(sc->dev, 3193248925Snp "default config file not available, will use the config " 3194248925Snp "file on the card's flash instead.\n"); 3195248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", FLASH_CF); 3196228561Snp } 3197228561Snp 3198248925Snp if (strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) { 3199308305Sjhb u_int cflen; 3200248925Snp const uint32_t *cfdata; 3201308305Sjhb uint32_t param, val, addr; 3202228561Snp 3203248925Snp KASSERT(cfg != NULL || default_cfg != NULL, 3204248925Snp ("%s: no config to upload", __func__)); 3205228561Snp 3206248925Snp /* 3207248925Snp * Ask the firmware where it wants us to upload the config file. 3208248925Snp */ 3209248925Snp param = FW_PARAM_DEV(CF); 3210248925Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 3211248925Snp if (rc != 0) { 3212248925Snp /* No support for config file? Shouldn't happen. */ 3213248925Snp device_printf(sc->dev, 3214248925Snp "failed to query config file location: %d.\n", rc); 3215248925Snp goto done; 3216248925Snp } 3217248925Snp mtype = G_FW_PARAMS_PARAM_Y(val); 3218248925Snp moff = G_FW_PARAMS_PARAM_Z(val) << 16; 3219228561Snp 3220248925Snp /* 3221248925Snp * XXX: sheer laziness. We deliberately added 4 bytes of 3222248925Snp * useless stuffing/comments at the end of the config file so 3223248925Snp * it's ok to simply throw away the last remaining bytes when 3224248925Snp * the config file is not an exact multiple of 4. This also 3225248925Snp * helps with the validate_mt_off_len check. 3226248925Snp */ 3227248925Snp if (cfg != NULL) { 3228248925Snp cflen = cfg->datasize & ~3; 3229248925Snp cfdata = cfg->data; 3230248925Snp } else { 3231248925Snp cflen = default_cfg->datasize & ~3; 3232248925Snp cfdata = default_cfg->data; 3233248925Snp } 3234222551Snp 3235248925Snp if (cflen > FLASH_CFG_MAX_SIZE) { 3236248925Snp device_printf(sc->dev, 3237248925Snp "config file too long (%d, max allowed is %d). " 3238248925Snp "Will try to use the config on the card, if any.\n", 3239248925Snp cflen, FLASH_CFG_MAX_SIZE); 3240248925Snp goto use_config_on_flash; 3241248925Snp } 3242218792Snp 3243248925Snp rc = validate_mt_off_len(sc, mtype, moff, cflen, &addr); 3244248925Snp if (rc != 0) { 3245248925Snp device_printf(sc->dev, 3246248925Snp "%s: addr (%d/0x%x) or len %d is not valid: %d. " 3247248925Snp "Will try to use the config on the card, if any.\n", 3248248925Snp __func__, mtype, moff, cflen, rc); 3249248925Snp goto use_config_on_flash; 3250248925Snp } 3251308305Sjhb write_via_memwin(sc, 2, addr, cfdata, cflen); 3252248925Snp } else { 3253248925Snpuse_config_on_flash: 3254256791Snp mtype = FW_MEMTYPE_FLASH; 3255248925Snp moff = t4_flash_cfg_addr(sc); 3256228561Snp } 3257228561Snp 3258228561Snp bzero(&caps, sizeof(caps)); 3259228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 3260218792Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 3261228561Snp caps.cfvalid_to_len16 = htobe32(F_FW_CAPS_CONFIG_CMD_CFVALID | 3262228561Snp V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) | 3263248925Snp V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(moff >> 16) | FW_LEN16(caps)); 3264228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 3265228561Snp if (rc != 0) { 3266228561Snp device_printf(sc->dev, 3267249376Snp "failed to pre-process config file: %d " 3268249376Snp "(mtype %d, moff 0x%x).\n", rc, mtype, moff); 3269248925Snp goto done; 3270228561Snp } 3271218792Snp 3272228561Snp finicsum = be32toh(caps.finicsum); 3273228561Snp cfcsum = be32toh(caps.cfcsum); 3274228561Snp if (finicsum != cfcsum) { 3275228561Snp device_printf(sc->dev, 3276228561Snp "WARNING: config file checksum mismatch: %08x %08x\n", 3277228561Snp finicsum, cfcsum); 3278228561Snp } 3279228561Snp sc->cfcsum = cfcsum; 3280218792Snp 3281228561Snp#define LIMIT_CAPS(x) do { \ 3282228561Snp caps.x &= htobe16(t4_##x##_allowed); \ 3283228561Snp} while (0) 3284228561Snp 3285228561Snp /* 3286228561Snp * Let the firmware know what features will (not) be used so it can tune 3287228561Snp * things accordingly. 3288228561Snp */ 3289308304Sjhb LIMIT_CAPS(nbmcaps); 3290228561Snp LIMIT_CAPS(linkcaps); 3291308304Sjhb LIMIT_CAPS(switchcaps); 3292228561Snp LIMIT_CAPS(niccaps); 3293228561Snp LIMIT_CAPS(toecaps); 3294228561Snp LIMIT_CAPS(rdmacaps); 3295309560Sjhb LIMIT_CAPS(cryptocaps); 3296228561Snp LIMIT_CAPS(iscsicaps); 3297228561Snp LIMIT_CAPS(fcoecaps); 3298228561Snp#undef LIMIT_CAPS 3299228561Snp 3300228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 3301218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE); 3302228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 3303228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), NULL); 3304228561Snp if (rc != 0) { 3305228561Snp device_printf(sc->dev, 3306228561Snp "failed to process config file: %d.\n", rc); 3307228561Snp } 3308248925Snpdone: 3309248925Snp if (cfg != NULL) 3310248925Snp firmware_put(cfg, FIRMWARE_UNLOAD); 3311248925Snp return (rc); 3312218792Snp} 3313218792Snp 3314228561Snp/* 3315248925Snp * Retrieve parameters that are needed (or nice to have) very early. 3316228561Snp */ 3317218792Snpstatic int 3318228561Snpget_params__pre_init(struct adapter *sc) 3319218792Snp{ 3320218792Snp int rc; 3321228561Snp uint32_t param[2], val[2]; 3322218792Snp 3323309458Sjhb t4_get_version_info(sc); 3324309458Sjhb 3325309458Sjhb snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u", 3326309458Sjhb G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 3327309458Sjhb G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 3328309458Sjhb G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 3329309458Sjhb G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 3330309458Sjhb 3331309458Sjhb snprintf(sc->bs_version, sizeof(sc->bs_version), "%u.%u.%u.%u", 3332309458Sjhb G_FW_HDR_FW_VER_MAJOR(sc->params.bs_vers), 3333309458Sjhb G_FW_HDR_FW_VER_MINOR(sc->params.bs_vers), 3334309458Sjhb G_FW_HDR_FW_VER_MICRO(sc->params.bs_vers), 3335309458Sjhb G_FW_HDR_FW_VER_BUILD(sc->params.bs_vers)); 3336309458Sjhb 3337309458Sjhb snprintf(sc->tp_version, sizeof(sc->tp_version), "%u.%u.%u.%u", 3338309458Sjhb G_FW_HDR_FW_VER_MAJOR(sc->params.tp_vers), 3339309458Sjhb G_FW_HDR_FW_VER_MINOR(sc->params.tp_vers), 3340309458Sjhb G_FW_HDR_FW_VER_MICRO(sc->params.tp_vers), 3341309458Sjhb G_FW_HDR_FW_VER_BUILD(sc->params.tp_vers)); 3342309458Sjhb 3343309458Sjhb snprintf(sc->er_version, sizeof(sc->er_version), "%u.%u.%u.%u", 3344309458Sjhb G_FW_HDR_FW_VER_MAJOR(sc->params.er_vers), 3345309458Sjhb G_FW_HDR_FW_VER_MINOR(sc->params.er_vers), 3346309458Sjhb G_FW_HDR_FW_VER_MICRO(sc->params.er_vers), 3347309458Sjhb G_FW_HDR_FW_VER_BUILD(sc->params.er_vers)); 3348309458Sjhb 3349228561Snp param[0] = FW_PARAM_DEV(PORTVEC); 3350228561Snp param[1] = FW_PARAM_DEV(CCLK); 3351228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 3352218792Snp if (rc != 0) { 3353218792Snp device_printf(sc->dev, 3354228561Snp "failed to query parameters (pre_init): %d.\n", rc); 3355228561Snp return (rc); 3356218792Snp } 3357218792Snp 3358218792Snp sc->params.portvec = val[0]; 3359240452Snp sc->params.nports = bitcount32(val[0]); 3360228561Snp sc->params.vpd.cclk = val[1]; 3361218792Snp 3362228561Snp /* Read device log parameters. */ 3363308305Sjhb rc = -t4_init_devlog_params(sc, 1); 3364308305Sjhb if (rc == 0) 3365308305Sjhb fixup_devlog_params(sc); 3366308305Sjhb else { 3367228561Snp device_printf(sc->dev, 3368228561Snp "failed to get devlog parameters: %d.\n", rc); 3369228561Snp rc = 0; /* devlog isn't critical for device operation */ 3370228561Snp } 3371228561Snp 3372228561Snp return (rc); 3373228561Snp} 3374228561Snp 3375228561Snp/* 3376228561Snp * Retrieve various parameters that are of interest to the driver. The device 3377228561Snp * has been initialized by the firmware at this point. 3378228561Snp */ 3379228561Snpstatic int 3380228561Snpget_params__post_init(struct adapter *sc) 3381228561Snp{ 3382228561Snp int rc; 3383228561Snp uint32_t param[7], val[7]; 3384228561Snp struct fw_caps_config_cmd caps; 3385228561Snp 3386228561Snp param[0] = FW_PARAM_PFVF(IQFLINT_START); 3387228561Snp param[1] = FW_PARAM_PFVF(EQ_START); 3388228561Snp param[2] = FW_PARAM_PFVF(FILTER_START); 3389228561Snp param[3] = FW_PARAM_PFVF(FILTER_END); 3390245434Snp param[4] = FW_PARAM_PFVF(L2T_START); 3391245434Snp param[5] = FW_PARAM_PFVF(L2T_END); 3392245434Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 3393228561Snp if (rc != 0) { 3394228561Snp device_printf(sc->dev, 3395228561Snp "failed to query parameters (post_init): %d.\n", rc); 3396228561Snp return (rc); 3397228561Snp } 3398228561Snp 3399228561Snp sc->sge.iq_start = val[0]; 3400228561Snp sc->sge.eq_start = val[1]; 3401228561Snp sc->tids.ftid_base = val[2]; 3402228561Snp sc->tids.nftids = val[3] - val[2] + 1; 3403265426Snp sc->params.ftid_min = val[2]; 3404265426Snp sc->params.ftid_max = val[3]; 3405245434Snp sc->vres.l2t.start = val[4]; 3406245434Snp sc->vres.l2t.size = val[5] - val[4] + 1; 3407245434Snp KASSERT(sc->vres.l2t.size <= L2T_SIZE, 3408245434Snp ("%s: L2 table size (%u) larger than expected (%u)", 3409245434Snp __func__, sc->vres.l2t.size, L2T_SIZE)); 3410228561Snp 3411228561Snp /* get capabilites */ 3412228561Snp bzero(&caps, sizeof(caps)); 3413228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 3414228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 3415228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 3416228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 3417228561Snp if (rc != 0) { 3418228561Snp device_printf(sc->dev, 3419228561Snp "failed to get card capabilities: %d.\n", rc); 3420228561Snp return (rc); 3421228561Snp } 3422228561Snp 3423265426Snp#define READ_CAPS(x) do { \ 3424265426Snp sc->x = htobe16(caps.x); \ 3425265426Snp} while (0) 3426308304Sjhb READ_CAPS(nbmcaps); 3427265426Snp READ_CAPS(linkcaps); 3428308304Sjhb READ_CAPS(switchcaps); 3429265426Snp READ_CAPS(niccaps); 3430265426Snp READ_CAPS(toecaps); 3431265426Snp READ_CAPS(rdmacaps); 3432309560Sjhb READ_CAPS(cryptocaps); 3433265426Snp READ_CAPS(iscsicaps); 3434265426Snp READ_CAPS(fcoecaps); 3435265426Snp 3436265426Snp if (sc->niccaps & FW_CAPS_CONFIG_NIC_ETHOFLD) { 3437265426Snp param[0] = FW_PARAM_PFVF(ETHOFLD_START); 3438265426Snp param[1] = FW_PARAM_PFVF(ETHOFLD_END); 3439265426Snp param[2] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 3440265426Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 3, param, val); 3441265426Snp if (rc != 0) { 3442265426Snp device_printf(sc->dev, 3443265426Snp "failed to query NIC parameters: %d.\n", rc); 3444265426Snp return (rc); 3445265426Snp } 3446265426Snp sc->tids.etid_base = val[0]; 3447265426Snp sc->params.etid_min = val[0]; 3448265426Snp sc->tids.netids = val[1] - val[0] + 1; 3449265426Snp sc->params.netids = sc->tids.netids; 3450265426Snp sc->params.eo_wr_cred = val[2]; 3451265426Snp sc->params.ethoffload = 1; 3452265426Snp } 3453265426Snp 3454265426Snp if (sc->toecaps) { 3455218792Snp /* query offload-related parameters */ 3456228561Snp param[0] = FW_PARAM_DEV(NTID); 3457228561Snp param[1] = FW_PARAM_PFVF(SERVER_START); 3458228561Snp param[2] = FW_PARAM_PFVF(SERVER_END); 3459228561Snp param[3] = FW_PARAM_PFVF(TDDP_START); 3460228561Snp param[4] = FW_PARAM_PFVF(TDDP_END); 3461228561Snp param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 3462228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 3463218792Snp if (rc != 0) { 3464218792Snp device_printf(sc->dev, 3465218792Snp "failed to query TOE parameters: %d.\n", rc); 3466228561Snp return (rc); 3467218792Snp } 3468218792Snp sc->tids.ntids = val[0]; 3469218792Snp sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS); 3470218792Snp sc->tids.stid_base = val[1]; 3471218792Snp sc->tids.nstids = val[2] - val[1] + 1; 3472218792Snp sc->vres.ddp.start = val[3]; 3473218792Snp sc->vres.ddp.size = val[4] - val[3] + 1; 3474218792Snp sc->params.ofldq_wr_cred = val[5]; 3475218792Snp sc->params.offload = 1; 3476218792Snp } 3477265426Snp if (sc->rdmacaps) { 3478228561Snp param[0] = FW_PARAM_PFVF(STAG_START); 3479228561Snp param[1] = FW_PARAM_PFVF(STAG_END); 3480228561Snp param[2] = FW_PARAM_PFVF(RQ_START); 3481228561Snp param[3] = FW_PARAM_PFVF(RQ_END); 3482228561Snp param[4] = FW_PARAM_PFVF(PBL_START); 3483228561Snp param[5] = FW_PARAM_PFVF(PBL_END); 3484228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 3485218792Snp if (rc != 0) { 3486218792Snp device_printf(sc->dev, 3487228561Snp "failed to query RDMA parameters(1): %d.\n", rc); 3488228561Snp return (rc); 3489218792Snp } 3490218792Snp sc->vres.stag.start = val[0]; 3491218792Snp sc->vres.stag.size = val[1] - val[0] + 1; 3492218792Snp sc->vres.rq.start = val[2]; 3493218792Snp sc->vres.rq.size = val[3] - val[2] + 1; 3494218792Snp sc->vres.pbl.start = val[4]; 3495218792Snp sc->vres.pbl.size = val[5] - val[4] + 1; 3496228561Snp 3497228561Snp param[0] = FW_PARAM_PFVF(SQRQ_START); 3498228561Snp param[1] = FW_PARAM_PFVF(SQRQ_END); 3499228561Snp param[2] = FW_PARAM_PFVF(CQ_START); 3500228561Snp param[3] = FW_PARAM_PFVF(CQ_END); 3501228561Snp param[4] = FW_PARAM_PFVF(OCQ_START); 3502228561Snp param[5] = FW_PARAM_PFVF(OCQ_END); 3503254933Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 3504228561Snp if (rc != 0) { 3505228561Snp device_printf(sc->dev, 3506228561Snp "failed to query RDMA parameters(2): %d.\n", rc); 3507228561Snp return (rc); 3508228561Snp } 3509228561Snp sc->vres.qp.start = val[0]; 3510228561Snp sc->vres.qp.size = val[1] - val[0] + 1; 3511228561Snp sc->vres.cq.start = val[2]; 3512228561Snp sc->vres.cq.size = val[3] - val[2] + 1; 3513228561Snp sc->vres.ocq.start = val[4]; 3514228561Snp sc->vres.ocq.size = val[5] - val[4] + 1; 3515318797Snp 3516318797Snp param[0] = FW_PARAM_PFVF(SRQ_START); 3517318797Snp param[1] = FW_PARAM_PFVF(SRQ_END); 3518318797Snp param[2] = FW_PARAM_DEV(MAXORDIRD_QP); 3519318797Snp param[3] = FW_PARAM_DEV(MAXIRD_ADAPTER); 3520318797Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 4, param, val); 3521318797Snp if (rc != 0) { 3522318797Snp device_printf(sc->dev, 3523318797Snp "failed to query RDMA parameters(3): %d.\n", rc); 3524318797Snp return (rc); 3525318797Snp } 3526318797Snp sc->vres.srq.start = val[0]; 3527318797Snp sc->vres.srq.size = val[1] - val[0] + 1; 3528318797Snp sc->params.max_ordird_qp = val[2]; 3529318797Snp sc->params.max_ird_adapter = val[3]; 3530218792Snp } 3531265426Snp if (sc->iscsicaps) { 3532228561Snp param[0] = FW_PARAM_PFVF(ISCSI_START); 3533228561Snp param[1] = FW_PARAM_PFVF(ISCSI_END); 3534228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 3535218792Snp if (rc != 0) { 3536218792Snp device_printf(sc->dev, 3537218792Snp "failed to query iSCSI parameters: %d.\n", rc); 3538228561Snp return (rc); 3539218792Snp } 3540218792Snp sc->vres.iscsi.start = val[0]; 3541218792Snp sc->vres.iscsi.size = val[1] - val[0] + 1; 3542218792Snp } 3543218792Snp 3544309447Sjhb t4_init_sge_params(sc); 3545309447Sjhb 3546248925Snp /* 3547248925Snp * We've got the params we wanted to query via the firmware. Now grab 3548248925Snp * some others directly from the chip. 3549248925Snp */ 3550248925Snp rc = t4_read_chip_settings(sc); 3551228561Snp 3552218792Snp return (rc); 3553218792Snp} 3554218792Snp 3555247291Snpstatic int 3556247291Snpset_params__post_init(struct adapter *sc) 3557247291Snp{ 3558247291Snp uint32_t param, val; 3559247291Snp 3560249382Snp /* ask for encapsulated CPLs */ 3561247291Snp param = FW_PARAM_PFVF(CPLFW4MSG_ENCAP); 3562249382Snp val = 1; 3563249382Snp (void)t4_set_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 3564247291Snp 3565249382Snp return (0); 3566247291Snp} 3567247291Snp 3568228561Snp#undef FW_PARAM_PFVF 3569228561Snp#undef FW_PARAM_DEV 3570228561Snp 3571218792Snpstatic void 3572218792Snpt4_set_desc(struct adapter *sc) 3573218792Snp{ 3574218792Snp char buf[128]; 3575218792Snp struct adapter_params *p = &sc->params; 3576218792Snp 3577309458Sjhb snprintf(buf, sizeof(buf), "Chelsio %s", p->vpd.id); 3578218792Snp 3579218792Snp device_set_desc_copy(sc->dev, buf); 3580218792Snp} 3581218792Snp 3582353418Snpstatic inline void 3583353418Snpifmedia_add4(struct ifmedia *ifm, int m) 3584218792Snp{ 3585218792Snp 3586353418Snp ifmedia_add(ifm, m, 0, NULL); 3587353418Snp ifmedia_add(ifm, m | IFM_ETH_TXPAUSE, 0, NULL); 3588353418Snp ifmedia_add(ifm, m | IFM_ETH_RXPAUSE, 0, NULL); 3589353418Snp ifmedia_add(ifm, m | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE, 0, NULL); 3590353418Snp} 3591218792Snp 3592353418Snpstatic void 3593353418Snpset_current_media(struct port_info *pi, struct ifmedia *ifm) 3594353418Snp{ 3595353418Snp struct link_config *lc; 3596353418Snp int mword; 3597218792Snp 3598353418Snp PORT_LOCK_ASSERT_OWNED(pi); 3599218792Snp 3600353418Snp /* Leave current media alone if it's already set to IFM_NONE. */ 3601353418Snp if (ifm->ifm_cur != NULL && 3602353418Snp IFM_SUBTYPE(ifm->ifm_cur->ifm_media) == IFM_NONE) 3603353418Snp return; 3604218792Snp 3605353418Snp lc = &pi->link_cfg; 3606353418Snp if (lc->requested_aneg == AUTONEG_ENABLE && 3607353418Snp lc->supported & FW_PORT_CAP_ANEG) { 3608353418Snp ifmedia_set(ifm, IFM_ETHER | IFM_AUTO); 3609353418Snp return; 3610353418Snp } 3611353418Snp mword = IFM_ETHER | IFM_FDX; 3612353418Snp if (lc->requested_fc & PAUSE_TX) 3613353418Snp mword |= IFM_ETH_TXPAUSE; 3614353418Snp if (lc->requested_fc & PAUSE_RX) 3615353418Snp mword |= IFM_ETH_RXPAUSE; 3616353418Snp mword |= port_mword(pi, speed_to_fwspeed(lc->requested_speed)); 3617353418Snp ifmedia_set(ifm, mword); 3618353418Snp} 3619218792Snp 3620353418Snpstatic void 3621353418Snpbuild_medialist(struct port_info *pi, struct ifmedia *ifm) 3622353418Snp{ 3623353418Snp uint16_t ss, speed; 3624353418Snp int unknown, mword, bit; 3625353418Snp struct link_config *lc; 3626218792Snp 3627353418Snp PORT_LOCK_ASSERT_OWNED(pi); 3628218792Snp 3629353418Snp if (pi->flags & FIXED_IFMEDIA) 3630353418Snp return; 3631218792Snp 3632353418Snp /* 3633353418Snp * First setup all the requested_ fields so that they comply with what's 3634353418Snp * supported by the port + transceiver. Note that this clobbers any 3635353418Snp * user preferences set via sysctl_pause_settings or sysctl_autoneg. 3636353418Snp */ 3637353418Snp init_l1cfg(pi); 3638218792Snp 3639353418Snp /* 3640353418Snp * Now (re)build the ifmedia list. 3641353418Snp */ 3642353418Snp ifmedia_removeall(ifm); 3643353418Snp lc = &pi->link_cfg; 3644353418Snp ss = G_FW_PORT_CAP_SPEED(lc->supported); /* Supported Speeds */ 3645353418Snp if (__predict_false(ss == 0)) { /* not supposed to happen. */ 3646353418Snp MPASS(ss != 0); 3647353418Snpno_media: 3648353418Snp MPASS(LIST_EMPTY(&ifm->ifm_list)); 3649353418Snp ifmedia_add(ifm, IFM_ETHER | IFM_NONE, 0, NULL); 3650353418Snp ifmedia_set(ifm, IFM_ETHER | IFM_NONE); 3651353418Snp return; 3652353418Snp } 3653218792Snp 3654353418Snp unknown = 0; 3655353418Snp for (bit = 0; bit < fls(ss); bit++) { 3656353418Snp speed = 1 << bit; 3657353418Snp MPASS(speed & M_FW_PORT_CAP_SPEED); 3658353418Snp if (ss & speed) { 3659353418Snp mword = port_mword(pi, speed); 3660353418Snp if (mword == IFM_NONE) { 3661353418Snp goto no_media; 3662353418Snp } else if (mword == IFM_UNKNOWN) 3663353418Snp unknown++; 3664353418Snp else 3665353418Snp ifmedia_add4(ifm, IFM_ETHER | IFM_FDX | mword); 3666218792Snp } 3667353418Snp } 3668353418Snp if (unknown > 0) /* Add one unknown for all unknown media types. */ 3669353418Snp ifmedia_add4(ifm, IFM_ETHER | IFM_FDX | IFM_UNKNOWN); 3670353418Snp if (lc->supported & FW_PORT_CAP_ANEG) 3671353418Snp ifmedia_add(ifm, IFM_ETHER | IFM_AUTO, 0, NULL); 3672218792Snp 3673353418Snp set_current_media(pi, ifm); 3674353418Snp} 3675309560Sjhb 3676353418Snp/* 3677353418Snp * Update all the requested_* fields in the link config to something valid (and 3678353418Snp * reasonable). 3679353418Snp */ 3680353418Snpstatic void 3681353418Snpinit_l1cfg(struct port_info *pi) 3682353418Snp{ 3683353418Snp struct link_config *lc = &pi->link_cfg; 3684309560Sjhb 3685353418Snp PORT_LOCK_ASSERT_OWNED(pi); 3686309560Sjhb 3687353418Snp /* Gbps -> Mbps */ 3688353418Snp lc->requested_speed = port_top_speed(pi) * 1000; 3689309560Sjhb 3690353418Snp if (t4_autoneg != 0 && lc->supported & FW_PORT_CAP_ANEG) { 3691353418Snp lc->requested_aneg = AUTONEG_ENABLE; 3692353418Snp } else { 3693353418Snp lc->requested_aneg = AUTONEG_DISABLE; 3694353418Snp } 3695309560Sjhb 3696353418Snp lc->requested_fc = t4_pause_settings & (PAUSE_TX | PAUSE_RX); 3697250092Snp 3698353418Snp if (t4_fec != -1) { 3699353418Snp if (t4_fec & FEC_RS && lc->supported & FW_PORT_CAP_FEC_RS) { 3700353418Snp lc->requested_fec = FEC_RS; 3701353418Snp } else if (t4_fec & FEC_BASER_RS && 3702353418Snp lc->supported & FW_PORT_CAP_FEC_BASER_RS) { 3703353418Snp lc->requested_fec = FEC_BASER_RS; 3704353418Snp } else { 3705353418Snp lc->requested_fec = 0; 3706250092Snp } 3707353418Snp } else { 3708353418Snp /* Use the suggested value provided by the firmware in acaps */ 3709353418Snp if (lc->advertising & FW_PORT_CAP_FEC_RS && 3710353418Snp lc->supported & FW_PORT_CAP_FEC_RS) { 3711353418Snp lc->requested_fec = FEC_RS; 3712353418Snp } else if (lc->advertising & FW_PORT_CAP_FEC_BASER_RS && 3713353418Snp lc->supported & FW_PORT_CAP_FEC_BASER_RS) { 3714353418Snp lc->requested_fec = FEC_BASER_RS; 3715353418Snp } else { 3716353418Snp lc->requested_fec = 0; 3717353418Snp } 3718353418Snp } 3719353418Snp} 3720250092Snp 3721353418Snp/* 3722353418Snp * Apply the settings in requested_* to the hardware. The parameters are 3723353418Snp * expected to be sane. 3724353418Snp */ 3725353418Snpstatic int 3726353418Snpapply_l1cfg(struct port_info *pi) 3727353418Snp{ 3728353418Snp struct adapter *sc = pi->adapter; 3729353418Snp struct link_config *lc = &pi->link_cfg; 3730353418Snp int rc; 3731353418Snp#ifdef INVARIANTS 3732353418Snp uint16_t fwspeed; 3733309560Sjhb 3734353418Snp ASSERT_SYNCHRONIZED_OP(sc); 3735353418Snp PORT_LOCK_ASSERT_OWNED(pi); 3736309560Sjhb 3737353418Snp if (lc->requested_aneg == AUTONEG_ENABLE) 3738353418Snp MPASS(lc->supported & FW_PORT_CAP_ANEG); 3739353418Snp if (lc->requested_fc & PAUSE_TX) 3740353418Snp MPASS(lc->supported & FW_PORT_CAP_FC_TX); 3741353418Snp if (lc->requested_fc & PAUSE_RX) 3742353418Snp MPASS(lc->supported & FW_PORT_CAP_FC_RX); 3743353418Snp if (lc->requested_fec == FEC_RS) 3744353418Snp MPASS(lc->supported & FW_PORT_CAP_FEC_RS); 3745353418Snp if (lc->requested_fec == FEC_BASER_RS) 3746353418Snp MPASS(lc->supported & FW_PORT_CAP_FEC_BASER_RS); 3747353418Snp fwspeed = speed_to_fwspeed(lc->requested_speed); 3748353418Snp MPASS(fwspeed != 0); 3749353418Snp MPASS(lc->supported & fwspeed); 3750353418Snp#endif 3751353418Snp rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc); 3752353418Snp if (rc != 0) { 3753353418Snp device_printf(pi->dev, "l1cfg failed: %d\n", rc); 3754353418Snp } else { 3755353418Snp lc->fc = lc->requested_fc; 3756353418Snp lc->fec = lc->requested_fec; 3757218792Snp } 3758353418Snp return (rc); 3759218792Snp} 3760218792Snp 3761231172Snp#define FW_MAC_EXACT_CHUNK 7 3762231172Snp 3763218792Snp/* 3764218792Snp * Program the port's XGMAC based on parameters in ifnet. The caller also 3765218792Snp * indicates which parameters should be programmed (the rest are left alone). 3766218792Snp */ 3767270297Snpint 3768270297Snpupdate_mac_settings(struct ifnet *ifp, int flags) 3769218792Snp{ 3770270297Snp int rc = 0; 3771308154Sjhb struct vi_info *vi = ifp->if_softc; 3772308154Sjhb struct port_info *pi = vi->pi; 3773218792Snp struct adapter *sc = pi->adapter; 3774218792Snp int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1; 3775218792Snp 3776245274Snp ASSERT_SYNCHRONIZED_OP(sc); 3777218792Snp KASSERT(flags, ("%s: not told what to update.", __func__)); 3778218792Snp 3779218792Snp if (flags & XGMAC_MTU) 3780218792Snp mtu = ifp->if_mtu; 3781218792Snp 3782218792Snp if (flags & XGMAC_PROMISC) 3783218792Snp promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0; 3784218792Snp 3785218792Snp if (flags & XGMAC_ALLMULTI) 3786218792Snp allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0; 3787218792Snp 3788218792Snp if (flags & XGMAC_VLANEX) 3789218792Snp vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0; 3790218792Snp 3791270297Snp if (flags & (XGMAC_MTU|XGMAC_PROMISC|XGMAC_ALLMULTI|XGMAC_VLANEX)) { 3792308154Sjhb rc = -t4_set_rxmode(sc, sc->mbox, vi->viid, mtu, promisc, 3793308154Sjhb allmulti, 1, vlanex, false); 3794270297Snp if (rc) { 3795270297Snp if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, 3796270297Snp rc); 3797270297Snp return (rc); 3798270297Snp } 3799218792Snp } 3800218792Snp 3801218792Snp if (flags & XGMAC_UCADDR) { 3802218792Snp uint8_t ucaddr[ETHER_ADDR_LEN]; 3803218792Snp 3804218792Snp bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr)); 3805308154Sjhb rc = t4_change_mac(sc, sc->mbox, vi->viid, vi->xact_addr_filt, 3806308154Sjhb ucaddr, true, true); 3807218792Snp if (rc < 0) { 3808218792Snp rc = -rc; 3809218792Snp if_printf(ifp, "change_mac failed: %d\n", rc); 3810218792Snp return (rc); 3811218792Snp } else { 3812308154Sjhb vi->xact_addr_filt = rc; 3813218792Snp rc = 0; 3814218792Snp } 3815218792Snp } 3816218792Snp 3817218792Snp if (flags & XGMAC_MCADDRS) { 3818231172Snp const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK]; 3819218792Snp int del = 1; 3820218792Snp uint64_t hash = 0; 3821218792Snp struct ifmultiaddr *ifma; 3822231172Snp int i = 0, j; 3823218792Snp 3824218792Snp if_maddr_rlock(ifp); 3825218792Snp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 3826238054Snp if (ifma->ifma_addr->sa_family != AF_LINK) 3827218792Snp continue; 3828282365Snp mcaddr[i] = 3829231172Snp LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 3830282365Snp MPASS(ETHER_IS_MULTICAST(mcaddr[i])); 3831282365Snp i++; 3832218792Snp 3833231172Snp if (i == FW_MAC_EXACT_CHUNK) { 3834308154Sjhb rc = t4_alloc_mac_filt(sc, sc->mbox, vi->viid, 3835308154Sjhb del, i, mcaddr, NULL, &hash, 0); 3836231172Snp if (rc < 0) { 3837231172Snp rc = -rc; 3838231172Snp for (j = 0; j < i; j++) { 3839231172Snp if_printf(ifp, 3840231172Snp "failed to add mc address" 3841231172Snp " %02x:%02x:%02x:" 3842231172Snp "%02x:%02x:%02x rc=%d\n", 3843231172Snp mcaddr[j][0], mcaddr[j][1], 3844231172Snp mcaddr[j][2], mcaddr[j][3], 3845231172Snp mcaddr[j][4], mcaddr[j][5], 3846231172Snp rc); 3847231172Snp } 3848231172Snp goto mcfail; 3849231172Snp } 3850231172Snp del = 0; 3851231172Snp i = 0; 3852231172Snp } 3853231172Snp } 3854231172Snp if (i > 0) { 3855308154Sjhb rc = t4_alloc_mac_filt(sc, sc->mbox, vi->viid, del, i, 3856270297Snp mcaddr, NULL, &hash, 0); 3857218792Snp if (rc < 0) { 3858218792Snp rc = -rc; 3859231172Snp for (j = 0; j < i; j++) { 3860231172Snp if_printf(ifp, 3861231172Snp "failed to add mc address" 3862231172Snp " %02x:%02x:%02x:" 3863231172Snp "%02x:%02x:%02x rc=%d\n", 3864231172Snp mcaddr[j][0], mcaddr[j][1], 3865231172Snp mcaddr[j][2], mcaddr[j][3], 3866231172Snp mcaddr[j][4], mcaddr[j][5], 3867231172Snp rc); 3868231172Snp } 3869218792Snp goto mcfail; 3870218792Snp } 3871218792Snp } 3872218792Snp 3873308154Sjhb rc = -t4_set_addr_hash(sc, sc->mbox, vi->viid, 0, hash, 0); 3874218792Snp if (rc != 0) 3875218792Snp if_printf(ifp, "failed to set mc address hash: %d", rc); 3876218792Snpmcfail: 3877218792Snp if_maddr_runlock(ifp); 3878218792Snp } 3879218792Snp 3880218792Snp return (rc); 3881218792Snp} 3882218792Snp 3883281249Snp/* 3884281249Snp * {begin|end}_synchronized_op must be called from the same thread. 3885281249Snp */ 3886245274Snpint 3887308154Sjhbbegin_synchronized_op(struct adapter *sc, struct vi_info *vi, int flags, 3888245274Snp char *wmesg) 3889218792Snp{ 3890245274Snp int rc, pri; 3891218792Snp 3892245274Snp#ifdef WITNESS 3893245274Snp /* the caller thinks it's ok to sleep, but is it really? */ 3894245274Snp if (flags & SLEEP_OK) 3895308154Sjhb WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 3896308154Sjhb "begin_synchronized_op"); 3897245274Snp#endif 3898218792Snp 3899245274Snp if (INTR_OK) 3900245274Snp pri = PCATCH; 3901245274Snp else 3902245274Snp pri = 0; 3903245274Snp 3904245274Snp ADAPTER_LOCK(sc); 3905245274Snp for (;;) { 3906245274Snp 3907308154Sjhb if (vi && IS_DOOMED(vi)) { 3908245274Snp rc = ENXIO; 3909245274Snp goto done; 3910245274Snp } 3911245274Snp 3912245274Snp if (!IS_BUSY(sc)) { 3913245274Snp rc = 0; 3914245274Snp break; 3915245274Snp } 3916245274Snp 3917245274Snp if (!(flags & SLEEP_OK)) { 3918245274Snp rc = EBUSY; 3919245274Snp goto done; 3920245274Snp } 3921245274Snp 3922245274Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, pri, wmesg, 0)) { 3923218792Snp rc = EINTR; 3924218792Snp goto done; 3925218792Snp } 3926218792Snp } 3927245274Snp 3928218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 3929218792Snp SET_BUSY(sc); 3930245274Snp#ifdef INVARIANTS 3931245274Snp sc->last_op = wmesg; 3932245274Snp sc->last_op_thr = curthread; 3933287149Snp sc->last_op_flags = flags; 3934245274Snp#endif 3935218792Snp 3936245274Snpdone: 3937245274Snp if (!(flags & HOLD_LOCK) || rc) 3938245274Snp ADAPTER_UNLOCK(sc); 3939218792Snp 3940245274Snp return (rc); 3941245274Snp} 3942245274Snp 3943281249Snp/* 3944308154Sjhb * Tell if_ioctl and if_init that the VI is going away. This is 3945308154Sjhb * special variant of begin_synchronized_op and must be paired with a 3946308154Sjhb * call to end_synchronized_op. 3947308154Sjhb */ 3948308154Sjhbvoid 3949308154Sjhbdoom_vi(struct adapter *sc, struct vi_info *vi) 3950308154Sjhb{ 3951308154Sjhb 3952308154Sjhb ADAPTER_LOCK(sc); 3953308154Sjhb SET_DOOMED(vi); 3954308154Sjhb wakeup(&sc->flags); 3955308154Sjhb while (IS_BUSY(sc)) 3956308154Sjhb mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0); 3957308154Sjhb SET_BUSY(sc); 3958308154Sjhb#ifdef INVARIANTS 3959308154Sjhb sc->last_op = "t4detach"; 3960308154Sjhb sc->last_op_thr = curthread; 3961308154Sjhb sc->last_op_flags = 0; 3962308154Sjhb#endif 3963308154Sjhb ADAPTER_UNLOCK(sc); 3964308154Sjhb} 3965308154Sjhb 3966308154Sjhb/* 3967281249Snp * {begin|end}_synchronized_op must be called from the same thread. 3968281249Snp */ 3969245274Snpvoid 3970245274Snpend_synchronized_op(struct adapter *sc, int flags) 3971245274Snp{ 3972245274Snp 3973245274Snp if (flags & LOCK_HELD) 3974245274Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 3975245274Snp else 3976245274Snp ADAPTER_LOCK(sc); 3977245274Snp 3978218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 3979218792Snp CLR_BUSY(sc); 3980245274Snp wakeup(&sc->flags); 3981218792Snp ADAPTER_UNLOCK(sc); 3982218792Snp} 3983218792Snp 3984218792Snpstatic int 3985308154Sjhbcxgbe_init_synchronized(struct vi_info *vi) 3986218792Snp{ 3987308154Sjhb struct port_info *pi = vi->pi; 3988218792Snp struct adapter *sc = pi->adapter; 3989308154Sjhb struct ifnet *ifp = vi->ifp; 3990284052Snp int rc = 0, i; 3991284052Snp struct sge_txq *txq; 3992218792Snp 3993245274Snp ASSERT_SYNCHRONIZED_OP(sc); 3994218792Snp 3995308154Sjhb if (ifp->if_drv_flags & IFF_DRV_RUNNING) 3996218792Snp return (0); /* already running */ 3997218792Snp 3998228561Snp if (!(sc->flags & FULL_INIT_DONE) && 3999228561Snp ((rc = adapter_full_init(sc)) != 0)) 4000218792Snp return (rc); /* error message displayed already */ 4001218792Snp 4002308154Sjhb if (!(vi->flags & VI_INIT_DONE) && 4003308154Sjhb ((rc = vi_full_init(vi)) != 0)) 4004228561Snp return (rc); /* error message displayed already */ 4005218792Snp 4006270297Snp rc = update_mac_settings(ifp, XGMAC_ALL); 4007218792Snp if (rc) 4008218792Snp goto done; /* error message displayed already */ 4009218792Snp 4010308154Sjhb rc = -t4_enable_vi(sc, sc->mbox, vi->viid, true, true); 4011218792Snp if (rc != 0) { 4012218792Snp if_printf(ifp, "enable_vi failed: %d\n", rc); 4013218792Snp goto done; 4014218792Snp } 4015218792Snp 4016253691Snp /* 4017284052Snp * Can't fail from this point onwards. Review cxgbe_uninit_synchronized 4018284052Snp * if this changes. 4019284052Snp */ 4020284052Snp 4021308154Sjhb for_each_txq(vi, i, txq) { 4022284052Snp TXQ_LOCK(txq); 4023284052Snp txq->eq.flags |= EQ_ENABLED; 4024284052Snp TXQ_UNLOCK(txq); 4025284052Snp } 4026284052Snp 4027284052Snp /* 4028253691Snp * The first iq of the first port to come up is used for tracing. 4029253691Snp */ 4030308154Sjhb if (sc->traceq < 0 && IS_MAIN_VI(vi)) { 4031308154Sjhb sc->traceq = sc->sge.rxq[vi->first_rxq].iq.abs_id; 4032253691Snp t4_write_reg(sc, is_t4(sc) ? A_MPS_TRC_RSS_CONTROL : 4033253691Snp A_MPS_T5_TRC_RSS_CONTROL, V_RSSCONTROL(pi->tx_chan) | 4034253691Snp V_QUEUENUMBER(sc->traceq)); 4035253691Snp pi->flags |= HAS_TRACEQ; 4036253691Snp } 4037253691Snp 4038218792Snp /* all ok */ 4039245274Snp PORT_LOCK(pi); 4040353418Snp if (pi->up_vis++ == 0) { 4041353418Snp t4_update_port_info(pi); 4042353418Snp build_medialist(pi, &pi->media); 4043353418Snp apply_l1cfg(pi); 4044353418Snp } 4045218792Snp ifp->if_drv_flags |= IFF_DRV_RUNNING; 4046308154Sjhb 4047309447Sjhb if (pi->nvi > 1 || sc->flags & IS_VF) 4048308154Sjhb callout_reset(&vi->tick, hz, vi_tick, vi); 4049308154Sjhb else 4050308154Sjhb callout_reset(&pi->tick, hz, cxgbe_tick, pi); 4051245274Snp PORT_UNLOCK(pi); 4052218792Snpdone: 4053218792Snp if (rc != 0) 4054308154Sjhb cxgbe_uninit_synchronized(vi); 4055218792Snp 4056218792Snp return (rc); 4057218792Snp} 4058218792Snp 4059218792Snp/* 4060218792Snp * Idempotent. 4061218792Snp */ 4062218792Snpstatic int 4063308154Sjhbcxgbe_uninit_synchronized(struct vi_info *vi) 4064218792Snp{ 4065308154Sjhb struct port_info *pi = vi->pi; 4066218792Snp struct adapter *sc = pi->adapter; 4067308154Sjhb struct ifnet *ifp = vi->ifp; 4068284052Snp int rc, i; 4069284052Snp struct sge_txq *txq; 4070218792Snp 4071245274Snp ASSERT_SYNCHRONIZED_OP(sc); 4072218792Snp 4073308154Sjhb if (!(vi->flags & VI_INIT_DONE)) { 4074297059Snp KASSERT(!(ifp->if_drv_flags & IFF_DRV_RUNNING), 4075308154Sjhb ("uninited VI is running")); 4076297059Snp return (0); 4077297059Snp } 4078297059Snp 4079218792Snp /* 4080228561Snp * Disable the VI so that all its data in either direction is discarded 4081228561Snp * by the MPS. Leave everything else (the queues, interrupts, and 1Hz 4082228561Snp * tick) intact as the TP can deliver negative advice or data that it's 4083228561Snp * holding in its RAM (for an offloaded connection) even after the VI is 4084228561Snp * disabled. 4085218792Snp */ 4086308154Sjhb rc = -t4_enable_vi(sc, sc->mbox, vi->viid, false, false); 4087228561Snp if (rc) { 4088228561Snp if_printf(ifp, "disable_vi failed: %d\n", rc); 4089228561Snp return (rc); 4090228561Snp } 4091228561Snp 4092308154Sjhb for_each_txq(vi, i, txq) { 4093284052Snp TXQ_LOCK(txq); 4094284052Snp txq->eq.flags &= ~EQ_ENABLED; 4095284052Snp TXQ_UNLOCK(txq); 4096284052Snp } 4097284052Snp 4098245274Snp PORT_LOCK(pi); 4099309447Sjhb if (pi->nvi > 1 || sc->flags & IS_VF) 4100309447Sjhb callout_stop(&vi->tick); 4101309447Sjhb else 4102308154Sjhb callout_stop(&pi->tick); 4103308154Sjhb if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 4104308154Sjhb PORT_UNLOCK(pi); 4105308154Sjhb return (0); 4106308154Sjhb } 4107228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 4108308154Sjhb pi->up_vis--; 4109308154Sjhb if (pi->up_vis > 0) { 4110308154Sjhb PORT_UNLOCK(pi); 4111308154Sjhb return (0); 4112308154Sjhb } 4113218792Snp 4114218792Snp pi->link_cfg.link_ok = 0; 4115218792Snp pi->link_cfg.speed = 0; 4116311261Snp pi->link_cfg.link_down_rc = 255; 4117353418Snp t4_os_link_changed(pi); 4118353418Snp pi->old_link_cfg = pi->link_cfg; 4119353418Snp PORT_UNLOCK(pi); 4120218792Snp 4121218792Snp return (0); 4122218792Snp} 4123218792Snp 4124240453Snp/* 4125240453Snp * It is ok for this function to fail midway and return right away. t4_detach 4126240453Snp * will walk the entire sc->irq list and clean up whatever is valid. 4127240453Snp */ 4128309447Sjhbint 4129309447Sjhbt4_setup_intr_handlers(struct adapter *sc) 4130218792Snp{ 4131308154Sjhb int rc, rid, p, q, v; 4132222510Snp char s[8]; 4133222510Snp struct irq *irq; 4134228561Snp struct port_info *pi; 4135308154Sjhb struct vi_info *vi; 4136308154Sjhb struct sge *sge = &sc->sge; 4137228561Snp struct sge_rxq *rxq; 4138237263Snp#ifdef TCP_OFFLOAD 4139228561Snp struct sge_ofld_rxq *ofld_rxq; 4140228561Snp#endif 4141270297Snp#ifdef DEV_NETMAP 4142270297Snp struct sge_nm_rxq *nm_rxq; 4143270297Snp#endif 4144218792Snp 4145218792Snp /* 4146218792Snp * Setup interrupts. 4147218792Snp */ 4148222510Snp irq = &sc->irq[0]; 4149222510Snp rid = sc->intr_type == INTR_INTX ? 0 : 1; 4150270297Snp if (sc->intr_count == 1) 4151270297Snp return (t4_alloc_irq(sc, irq, rid, t4_intr_all, sc, "all")); 4152222510Snp 4153270297Snp /* Multiple interrupts. */ 4154309447Sjhb if (sc->flags & IS_VF) 4155309447Sjhb KASSERT(sc->intr_count >= T4VF_EXTRA_INTR + sc->params.nports, 4156309447Sjhb ("%s: too few intr.", __func__)); 4157309447Sjhb else 4158309447Sjhb KASSERT(sc->intr_count >= T4_EXTRA_INTR + sc->params.nports, 4159309447Sjhb ("%s: too few intr.", __func__)); 4160228561Snp 4161309447Sjhb /* The first one is always error intr on PFs */ 4162309447Sjhb if (!(sc->flags & IS_VF)) { 4163309447Sjhb rc = t4_alloc_irq(sc, irq, rid, t4_intr_err, sc, "err"); 4164309447Sjhb if (rc != 0) 4165309447Sjhb return (rc); 4166309447Sjhb irq++; 4167309447Sjhb rid++; 4168309447Sjhb } 4169218792Snp 4170309447Sjhb /* The second one is always the firmware event queue (first on VFs) */ 4171308154Sjhb rc = t4_alloc_irq(sc, irq, rid, t4_intr_evt, &sge->fwq, "evt"); 4172270297Snp if (rc != 0) 4173270297Snp return (rc); 4174270297Snp irq++; 4175270297Snp rid++; 4176222510Snp 4177270297Snp for_each_port(sc, p) { 4178270297Snp pi = sc->port[p]; 4179308154Sjhb for_each_vi(pi, v, vi) { 4180308154Sjhb vi->first_intr = rid - 1; 4181222510Snp 4182308154Sjhb if (vi->nnmrxq > 0) { 4183308154Sjhb int n = max(vi->nrxq, vi->nnmrxq); 4184308154Sjhb 4185308154Sjhb MPASS(vi->flags & INTR_RXQ); 4186308154Sjhb 4187308154Sjhb rxq = &sge->rxq[vi->first_rxq]; 4188308154Sjhb#ifdef DEV_NETMAP 4189308154Sjhb nm_rxq = &sge->nm_rxq[vi->first_nm_rxq]; 4190308154Sjhb#endif 4191308154Sjhb for (q = 0; q < n; q++) { 4192308154Sjhb snprintf(s, sizeof(s), "%x%c%x", p, 4193308154Sjhb 'a' + v, q); 4194308154Sjhb if (q < vi->nrxq) 4195308154Sjhb irq->rxq = rxq++; 4196308154Sjhb#ifdef DEV_NETMAP 4197308154Sjhb if (q < vi->nnmrxq) 4198308154Sjhb irq->nm_rxq = nm_rxq++; 4199308154Sjhb#endif 4200308154Sjhb rc = t4_alloc_irq(sc, irq, rid, 4201308154Sjhb t4_vi_intr, irq, s); 4202308154Sjhb if (rc != 0) 4203308154Sjhb return (rc); 4204308154Sjhb irq++; 4205308154Sjhb rid++; 4206308154Sjhb vi->nintr++; 4207308154Sjhb } 4208308154Sjhb } else if (vi->flags & INTR_RXQ) { 4209308154Sjhb for_each_rxq(vi, q, rxq) { 4210308154Sjhb snprintf(s, sizeof(s), "%x%c%x", p, 4211308154Sjhb 'a' + v, q); 4212308154Sjhb rc = t4_alloc_irq(sc, irq, rid, 4213308154Sjhb t4_intr, rxq, s); 4214308154Sjhb if (rc != 0) 4215308154Sjhb return (rc); 4216308154Sjhb irq++; 4217308154Sjhb rid++; 4218308154Sjhb vi->nintr++; 4219308154Sjhb } 4220218792Snp } 4221237263Snp#ifdef TCP_OFFLOAD 4222308154Sjhb if (vi->flags & INTR_OFLD_RXQ) { 4223308154Sjhb for_each_ofld_rxq(vi, q, ofld_rxq) { 4224308154Sjhb snprintf(s, sizeof(s), "%x%c%x", p, 4225308154Sjhb 'A' + v, q); 4226308154Sjhb rc = t4_alloc_irq(sc, irq, rid, 4227308154Sjhb t4_intr, ofld_rxq, s); 4228308154Sjhb if (rc != 0) 4229308154Sjhb return (rc); 4230308154Sjhb irq++; 4231308154Sjhb rid++; 4232308154Sjhb vi->nintr++; 4233308154Sjhb } 4234218792Snp } 4235228561Snp#endif 4236218792Snp } 4237218792Snp } 4238270297Snp MPASS(irq == &sc->irq[sc->intr_count]); 4239218792Snp 4240240453Snp return (0); 4241240453Snp} 4242240453Snp 4243270297Snpint 4244240453Snpadapter_full_init(struct adapter *sc) 4245240453Snp{ 4246240453Snp int rc, i; 4247318838Snp#ifdef RSS 4248318838Snp uint32_t raw_rss_key[RSS_KEYSIZE / sizeof(uint32_t)]; 4249318838Snp uint32_t rss_key[RSS_KEYSIZE / sizeof(uint32_t)]; 4250318838Snp#endif 4251240453Snp 4252281250Snp ASSERT_SYNCHRONIZED_OP(sc); 4253240453Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 4254240453Snp KASSERT((sc->flags & FULL_INIT_DONE) == 0, 4255240453Snp ("%s: FULL_INIT_DONE already", __func__)); 4256240453Snp 4257240453Snp /* 4258240453Snp * queues that belong to the adapter (not any particular port). 4259240453Snp */ 4260240453Snp rc = t4_setup_adapter_queues(sc); 4261240453Snp if (rc != 0) 4262240453Snp goto done; 4263240453Snp 4264240453Snp for (i = 0; i < nitems(sc->tq); i++) { 4265240453Snp sc->tq[i] = taskqueue_create("t4 taskq", M_NOWAIT, 4266240453Snp taskqueue_thread_enqueue, &sc->tq[i]); 4267240453Snp if (sc->tq[i] == NULL) { 4268240453Snp device_printf(sc->dev, 4269240453Snp "failed to allocate task queue %d\n", i); 4270240453Snp rc = ENOMEM; 4271240453Snp goto done; 4272240453Snp } 4273240453Snp taskqueue_start_threads(&sc->tq[i], 1, PI_NET, "%s tq%d", 4274240453Snp device_get_nameunit(sc->dev), i); 4275240453Snp } 4276318838Snp#ifdef RSS 4277318838Snp MPASS(RSS_KEYSIZE == 40); 4278318838Snp rss_getkey((void *)&raw_rss_key[0]); 4279318838Snp for (i = 0; i < nitems(rss_key); i++) { 4280318838Snp rss_key[i] = htobe32(raw_rss_key[nitems(rss_key) - 1 - i]); 4281318838Snp } 4282353418Snp t4_write_rss_key(sc, &rss_key[0], -1, 1); 4283318838Snp#endif 4284240453Snp 4285309447Sjhb if (!(sc->flags & IS_VF)) 4286309447Sjhb t4_intr_enable(sc); 4287218792Snp sc->flags |= FULL_INIT_DONE; 4288218792Snpdone: 4289218792Snp if (rc != 0) 4290228561Snp adapter_full_uninit(sc); 4291218792Snp 4292218792Snp return (rc); 4293218792Snp} 4294218792Snp 4295270297Snpint 4296228561Snpadapter_full_uninit(struct adapter *sc) 4297218792Snp{ 4298218792Snp int i; 4299218792Snp 4300218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 4301218792Snp 4302220873Snp t4_teardown_adapter_queues(sc); 4303218792Snp 4304240452Snp for (i = 0; i < nitems(sc->tq) && sc->tq[i]; i++) { 4305228561Snp taskqueue_free(sc->tq[i]); 4306228561Snp sc->tq[i] = NULL; 4307228561Snp } 4308228561Snp 4309218792Snp sc->flags &= ~FULL_INIT_DONE; 4310218792Snp 4311218792Snp return (0); 4312218792Snp} 4313218792Snp 4314308153Sjhb#ifdef RSS 4315308153Sjhb#define SUPPORTED_RSS_HASHTYPES (RSS_HASHTYPE_RSS_IPV4 | \ 4316308153Sjhb RSS_HASHTYPE_RSS_TCP_IPV4 | RSS_HASHTYPE_RSS_IPV6 | \ 4317308153Sjhb RSS_HASHTYPE_RSS_TCP_IPV6 | RSS_HASHTYPE_RSS_UDP_IPV4 | \ 4318308153Sjhb RSS_HASHTYPE_RSS_UDP_IPV6) 4319308153Sjhb 4320308153Sjhb/* Translates kernel hash types to hardware. */ 4321308153Sjhbstatic int 4322308153Sjhbhashconfig_to_hashen(int hashconfig) 4323308153Sjhb{ 4324308153Sjhb int hashen = 0; 4325308153Sjhb 4326308153Sjhb if (hashconfig & RSS_HASHTYPE_RSS_IPV4) 4327308153Sjhb hashen |= F_FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN; 4328308153Sjhb if (hashconfig & RSS_HASHTYPE_RSS_IPV6) 4329308153Sjhb hashen |= F_FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN; 4330308153Sjhb if (hashconfig & RSS_HASHTYPE_RSS_UDP_IPV4) { 4331308153Sjhb hashen |= F_FW_RSS_VI_CONFIG_CMD_UDPEN | 4332308153Sjhb F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN; 4333308153Sjhb } 4334308153Sjhb if (hashconfig & RSS_HASHTYPE_RSS_UDP_IPV6) { 4335308153Sjhb hashen |= F_FW_RSS_VI_CONFIG_CMD_UDPEN | 4336308153Sjhb F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN; 4337308153Sjhb } 4338308153Sjhb if (hashconfig & RSS_HASHTYPE_RSS_TCP_IPV4) 4339308153Sjhb hashen |= F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN; 4340308153Sjhb if (hashconfig & RSS_HASHTYPE_RSS_TCP_IPV6) 4341308153Sjhb hashen |= F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN; 4342308153Sjhb 4343308153Sjhb return (hashen); 4344308153Sjhb} 4345308153Sjhb 4346308153Sjhb/* Translates hardware hash types to kernel. */ 4347308153Sjhbstatic int 4348308153Sjhbhashen_to_hashconfig(int hashen) 4349308153Sjhb{ 4350308153Sjhb int hashconfig = 0; 4351308153Sjhb 4352308153Sjhb if (hashen & F_FW_RSS_VI_CONFIG_CMD_UDPEN) { 4353308153Sjhb /* 4354308153Sjhb * If UDP hashing was enabled it must have been enabled for 4355308153Sjhb * either IPv4 or IPv6 (inclusive or). Enabling UDP without 4356308153Sjhb * enabling any 4-tuple hash is nonsense configuration. 4357308153Sjhb */ 4358308153Sjhb MPASS(hashen & (F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN | 4359308153Sjhb F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN)); 4360308153Sjhb 4361308153Sjhb if (hashen & F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN) 4362308153Sjhb hashconfig |= RSS_HASHTYPE_RSS_UDP_IPV4; 4363308153Sjhb if (hashen & F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN) 4364308153Sjhb hashconfig |= RSS_HASHTYPE_RSS_UDP_IPV6; 4365308153Sjhb } 4366308153Sjhb if (hashen & F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN) 4367308153Sjhb hashconfig |= RSS_HASHTYPE_RSS_TCP_IPV4; 4368308153Sjhb if (hashen & F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN) 4369308153Sjhb hashconfig |= RSS_HASHTYPE_RSS_TCP_IPV6; 4370308153Sjhb if (hashen & F_FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN) 4371308153Sjhb hashconfig |= RSS_HASHTYPE_RSS_IPV4; 4372308153Sjhb if (hashen & F_FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN) 4373308153Sjhb hashconfig |= RSS_HASHTYPE_RSS_IPV6; 4374308153Sjhb 4375308153Sjhb return (hashconfig); 4376308153Sjhb} 4377308153Sjhb#endif 4378308153Sjhb 4379270297Snpint 4380308154Sjhbvi_full_init(struct vi_info *vi) 4381228561Snp{ 4382308154Sjhb struct adapter *sc = vi->pi->adapter; 4383308154Sjhb struct ifnet *ifp = vi->ifp; 4384228561Snp uint16_t *rss; 4385228561Snp struct sge_rxq *rxq; 4386308153Sjhb int rc, i, j, hashen; 4387308153Sjhb#ifdef RSS 4388308153Sjhb int nbuckets = rss_getnumbuckets(); 4389308153Sjhb int hashconfig = rss_gethashconfig(); 4390308153Sjhb int extra; 4391308153Sjhb#endif 4392228561Snp 4393245274Snp ASSERT_SYNCHRONIZED_OP(sc); 4394308154Sjhb KASSERT((vi->flags & VI_INIT_DONE) == 0, 4395308154Sjhb ("%s: VI_INIT_DONE already", __func__)); 4396228561Snp 4397308154Sjhb sysctl_ctx_init(&vi->ctx); 4398308154Sjhb vi->flags |= VI_SYSCTL_CTX; 4399228561Snp 4400228561Snp /* 4401308154Sjhb * Allocate tx/rx/fl queues for this VI. 4402228561Snp */ 4403308154Sjhb rc = t4_setup_vi_queues(vi); 4404228561Snp if (rc != 0) 4405228561Snp goto done; /* error message displayed already */ 4406228561Snp 4407228561Snp /* 4408308154Sjhb * Setup RSS for this VI. Save a copy of the RSS table for later use. 4409228561Snp */ 4410308154Sjhb if (vi->nrxq > vi->rss_size) { 4411308153Sjhb if_printf(ifp, "nrxq (%d) > hw RSS table size (%d); " 4412308154Sjhb "some queues will never receive traffic.\n", vi->nrxq, 4413308154Sjhb vi->rss_size); 4414308154Sjhb } else if (vi->rss_size % vi->nrxq) { 4415308153Sjhb if_printf(ifp, "nrxq (%d), hw RSS table size (%d); " 4416308154Sjhb "expect uneven traffic distribution.\n", vi->nrxq, 4417308154Sjhb vi->rss_size); 4418308153Sjhb } 4419308153Sjhb#ifdef RSS 4420308154Sjhb if (vi->nrxq != nbuckets) { 4421308153Sjhb if_printf(ifp, "nrxq (%d) != kernel RSS buckets (%d);" 4422308154Sjhb "performance will be impacted.\n", vi->nrxq, nbuckets); 4423308153Sjhb } 4424308153Sjhb#endif 4425308154Sjhb rss = malloc(vi->rss_size * sizeof (*rss), M_CXGBE, M_ZERO | M_WAITOK); 4426308154Sjhb for (i = 0; i < vi->rss_size;) { 4427308153Sjhb#ifdef RSS 4428308153Sjhb j = rss_get_indirection_to_bucket(i); 4429308154Sjhb j %= vi->nrxq; 4430308154Sjhb rxq = &sc->sge.rxq[vi->first_rxq + j]; 4431308153Sjhb rss[i++] = rxq->iq.abs_id; 4432308153Sjhb#else 4433308154Sjhb for_each_rxq(vi, j, rxq) { 4434259142Snp rss[i++] = rxq->iq.abs_id; 4435308154Sjhb if (i == vi->rss_size) 4436259142Snp break; 4437259142Snp } 4438308153Sjhb#endif 4439228561Snp } 4440259142Snp 4441308154Sjhb rc = -t4_config_rss_range(sc, sc->mbox, vi->viid, 0, vi->rss_size, rss, 4442308154Sjhb vi->rss_size); 4443228561Snp if (rc != 0) { 4444228561Snp if_printf(ifp, "rss_config failed: %d\n", rc); 4445228561Snp goto done; 4446228561Snp } 4447228561Snp 4448308153Sjhb#ifdef RSS 4449308153Sjhb hashen = hashconfig_to_hashen(hashconfig); 4450308153Sjhb 4451308153Sjhb /* 4452308153Sjhb * We may have had to enable some hashes even though the global config 4453308153Sjhb * wants them disabled. This is a potential problem that must be 4454308153Sjhb * reported to the user. 4455308153Sjhb */ 4456308153Sjhb extra = hashen_to_hashconfig(hashen) ^ hashconfig; 4457308153Sjhb 4458308153Sjhb /* 4459308153Sjhb * If we consider only the supported hash types, then the enabled hashes 4460308153Sjhb * are a superset of the requested hashes. In other words, there cannot 4461308153Sjhb * be any supported hash that was requested but not enabled, but there 4462308153Sjhb * can be hashes that were not requested but had to be enabled. 4463308153Sjhb */ 4464308153Sjhb extra &= SUPPORTED_RSS_HASHTYPES; 4465308153Sjhb MPASS((extra & hashconfig) == 0); 4466308153Sjhb 4467308153Sjhb if (extra) { 4468308153Sjhb if_printf(ifp, 4469308153Sjhb "global RSS config (0x%x) cannot be accomodated.\n", 4470308153Sjhb hashconfig); 4471308153Sjhb } 4472308153Sjhb if (extra & RSS_HASHTYPE_RSS_IPV4) 4473308153Sjhb if_printf(ifp, "IPv4 2-tuple hashing forced on.\n"); 4474308153Sjhb if (extra & RSS_HASHTYPE_RSS_TCP_IPV4) 4475308153Sjhb if_printf(ifp, "TCP/IPv4 4-tuple hashing forced on.\n"); 4476308153Sjhb if (extra & RSS_HASHTYPE_RSS_IPV6) 4477308153Sjhb if_printf(ifp, "IPv6 2-tuple hashing forced on.\n"); 4478308153Sjhb if (extra & RSS_HASHTYPE_RSS_TCP_IPV6) 4479308153Sjhb if_printf(ifp, "TCP/IPv6 4-tuple hashing forced on.\n"); 4480308153Sjhb if (extra & RSS_HASHTYPE_RSS_UDP_IPV4) 4481308153Sjhb if_printf(ifp, "UDP/IPv4 4-tuple hashing forced on.\n"); 4482308153Sjhb if (extra & RSS_HASHTYPE_RSS_UDP_IPV6) 4483308153Sjhb if_printf(ifp, "UDP/IPv6 4-tuple hashing forced on.\n"); 4484308153Sjhb#else 4485308153Sjhb hashen = F_FW_RSS_VI_CONFIG_CMD_IP6FOURTUPEN | 4486308153Sjhb F_FW_RSS_VI_CONFIG_CMD_IP6TWOTUPEN | 4487308153Sjhb F_FW_RSS_VI_CONFIG_CMD_IP4FOURTUPEN | 4488308153Sjhb F_FW_RSS_VI_CONFIG_CMD_IP4TWOTUPEN | F_FW_RSS_VI_CONFIG_CMD_UDPEN; 4489308153Sjhb#endif 4490309560Sjhb rc = -t4_config_vi_rss(sc, sc->mbox, vi->viid, hashen, rss[0], 0, 0); 4491308153Sjhb if (rc != 0) { 4492308153Sjhb if_printf(ifp, "rss hash/defaultq config failed: %d\n", rc); 4493308153Sjhb goto done; 4494308153Sjhb } 4495308153Sjhb 4496308154Sjhb vi->rss = rss; 4497308154Sjhb vi->flags |= VI_INIT_DONE; 4498228561Snpdone: 4499228561Snp if (rc != 0) 4500308154Sjhb vi_full_uninit(vi); 4501228561Snp 4502228561Snp return (rc); 4503228561Snp} 4504228561Snp 4505228561Snp/* 4506228561Snp * Idempotent. 4507228561Snp */ 4508270297Snpint 4509308154Sjhbvi_full_uninit(struct vi_info *vi) 4510228561Snp{ 4511308154Sjhb struct port_info *pi = vi->pi; 4512228561Snp struct adapter *sc = pi->adapter; 4513228561Snp int i; 4514228561Snp struct sge_rxq *rxq; 4515228561Snp struct sge_txq *txq; 4516237263Snp#ifdef TCP_OFFLOAD 4517228561Snp struct sge_ofld_rxq *ofld_rxq; 4518228561Snp struct sge_wrq *ofld_txq; 4519228561Snp#endif 4520228561Snp 4521308154Sjhb if (vi->flags & VI_INIT_DONE) { 4522228561Snp 4523284052Snp /* Need to quiesce queues. */ 4524228561Snp 4525308154Sjhb /* XXX: Only for the first VI? */ 4526309447Sjhb if (IS_MAIN_VI(vi) && !(sc->flags & IS_VF)) 4527308154Sjhb quiesce_wrq(sc, &sc->sge.ctrlq[pi->port_id]); 4528284052Snp 4529308154Sjhb for_each_txq(vi, i, txq) { 4530284052Snp quiesce_txq(sc, txq); 4531228561Snp } 4532228561Snp 4533237263Snp#ifdef TCP_OFFLOAD 4534308154Sjhb for_each_ofld_txq(vi, i, ofld_txq) { 4535284052Snp quiesce_wrq(sc, ofld_txq); 4536228561Snp } 4537228561Snp#endif 4538228561Snp 4539308154Sjhb for_each_rxq(vi, i, rxq) { 4540228561Snp quiesce_iq(sc, &rxq->iq); 4541228561Snp quiesce_fl(sc, &rxq->fl); 4542228561Snp } 4543228561Snp 4544237263Snp#ifdef TCP_OFFLOAD 4545308154Sjhb for_each_ofld_rxq(vi, i, ofld_rxq) { 4546228561Snp quiesce_iq(sc, &ofld_rxq->iq); 4547228561Snp quiesce_fl(sc, &ofld_rxq->fl); 4548228561Snp } 4549228561Snp#endif 4550308154Sjhb free(vi->rss, M_CXGBE); 4551308154Sjhb free(vi->nm_rss, M_CXGBE); 4552228561Snp } 4553228561Snp 4554308154Sjhb t4_teardown_vi_queues(vi); 4555308154Sjhb vi->flags &= ~VI_INIT_DONE; 4556228561Snp 4557228561Snp return (0); 4558228561Snp} 4559228561Snp 4560228561Snpstatic void 4561284052Snpquiesce_txq(struct adapter *sc, struct sge_txq *txq) 4562228561Snp{ 4563284052Snp struct sge_eq *eq = &txq->eq; 4564284052Snp struct sge_qstat *spg = (void *)&eq->desc[eq->sidx]; 4565228561Snp 4566284052Snp (void) sc; /* unused */ 4567228561Snp 4568284052Snp#ifdef INVARIANTS 4569284052Snp TXQ_LOCK(txq); 4570284052Snp MPASS((eq->flags & EQ_ENABLED) == 0); 4571284052Snp TXQ_UNLOCK(txq); 4572284052Snp#endif 4573228561Snp 4574284052Snp /* Wait for the mp_ring to empty. */ 4575284052Snp while (!mp_ring_is_idle(txq->r)) { 4576284052Snp mp_ring_check_drainage(txq->r, 0); 4577284052Snp pause("rquiesce", 1); 4578284052Snp } 4579284052Snp 4580284052Snp /* Then wait for the hardware to finish. */ 4581284052Snp while (spg->cidx != htobe16(eq->pidx)) 4582284052Snp pause("equiesce", 1); 4583284052Snp 4584284052Snp /* Finally, wait for the driver to reclaim all descriptors. */ 4585284052Snp while (eq->cidx != eq->pidx) 4586284052Snp pause("dquiesce", 1); 4587228561Snp} 4588228561Snp 4589228561Snpstatic void 4590284052Snpquiesce_wrq(struct adapter *sc, struct sge_wrq *wrq) 4591284052Snp{ 4592284052Snp 4593284052Snp /* XXXTX */ 4594284052Snp} 4595284052Snp 4596284052Snpstatic void 4597228561Snpquiesce_iq(struct adapter *sc, struct sge_iq *iq) 4598228561Snp{ 4599228561Snp (void) sc; /* unused */ 4600228561Snp 4601228561Snp /* Synchronize with the interrupt handler */ 4602228561Snp while (!atomic_cmpset_int(&iq->state, IQS_IDLE, IQS_DISABLED)) 4603228561Snp pause("iqfree", 1); 4604228561Snp} 4605228561Snp 4606228561Snpstatic void 4607228561Snpquiesce_fl(struct adapter *sc, struct sge_fl *fl) 4608228561Snp{ 4609228561Snp mtx_lock(&sc->sfl_lock); 4610228561Snp FL_LOCK(fl); 4611228561Snp fl->flags |= FL_DOOMED; 4612228561Snp FL_UNLOCK(fl); 4613308154Sjhb callout_stop(&sc->sfl_callout); 4614228561Snp mtx_unlock(&sc->sfl_lock); 4615228561Snp 4616228561Snp KASSERT((fl->flags & FL_STARVING) == 0, 4617228561Snp ("%s: still starving", __func__)); 4618228561Snp} 4619228561Snp 4620228561Snpstatic int 4621218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid, 4622228561Snp driver_intr_t *handler, void *arg, char *name) 4623218792Snp{ 4624218792Snp int rc; 4625218792Snp 4626218792Snp irq->rid = rid; 4627218792Snp irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid, 4628218792Snp RF_SHAREABLE | RF_ACTIVE); 4629218792Snp if (irq->res == NULL) { 4630218792Snp device_printf(sc->dev, 4631218792Snp "failed to allocate IRQ for rid %d, name %s.\n", rid, name); 4632218792Snp return (ENOMEM); 4633218792Snp } 4634218792Snp 4635218792Snp rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET, 4636218792Snp NULL, handler, arg, &irq->tag); 4637218792Snp if (rc != 0) { 4638218792Snp device_printf(sc->dev, 4639218792Snp "failed to setup interrupt for rid %d, name %s: %d\n", 4640218792Snp rid, name, rc); 4641218792Snp } else if (name) 4642218792Snp bus_describe_intr(sc->dev, irq->res, irq->tag, name); 4643218792Snp 4644218792Snp return (rc); 4645218792Snp} 4646218792Snp 4647218792Snpstatic int 4648218792Snpt4_free_irq(struct adapter *sc, struct irq *irq) 4649218792Snp{ 4650218792Snp if (irq->tag) 4651218792Snp bus_teardown_intr(sc->dev, irq->res, irq->tag); 4652218792Snp if (irq->res) 4653218792Snp bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res); 4654218792Snp 4655218792Snp bzero(irq, sizeof(*irq)); 4656218792Snp 4657218792Snp return (0); 4658218792Snp} 4659218792Snp 4660218792Snpstatic void 4661308304Sjhbget_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf) 4662218792Snp{ 4663218792Snp 4664248925Snp regs->version = chip_id(sc) | chip_rev(sc) << 10; 4665308304Sjhb t4_get_regs(sc, buf, regs->len); 4666218792Snp} 4667218792Snp 4668308154Sjhb#define A_PL_INDIR_CMD 0x1f8 4669308154Sjhb 4670308154Sjhb#define S_PL_AUTOINC 31 4671308154Sjhb#define M_PL_AUTOINC 0x1U 4672308154Sjhb#define V_PL_AUTOINC(x) ((x) << S_PL_AUTOINC) 4673308154Sjhb#define G_PL_AUTOINC(x) (((x) >> S_PL_AUTOINC) & M_PL_AUTOINC) 4674308154Sjhb 4675308154Sjhb#define S_PL_VFID 20 4676308154Sjhb#define M_PL_VFID 0xffU 4677308154Sjhb#define V_PL_VFID(x) ((x) << S_PL_VFID) 4678308154Sjhb#define G_PL_VFID(x) (((x) >> S_PL_VFID) & M_PL_VFID) 4679308154Sjhb 4680308154Sjhb#define S_PL_ADDR 0 4681308154Sjhb#define M_PL_ADDR 0xfffffU 4682308154Sjhb#define V_PL_ADDR(x) ((x) << S_PL_ADDR) 4683308154Sjhb#define G_PL_ADDR(x) (((x) >> S_PL_ADDR) & M_PL_ADDR) 4684308154Sjhb 4685308154Sjhb#define A_PL_INDIR_DATA 0x1fc 4686308154Sjhb 4687308154Sjhbstatic uint64_t 4688308154Sjhbread_vf_stat(struct adapter *sc, unsigned int viid, int reg) 4689308154Sjhb{ 4690308154Sjhb u32 stats[2]; 4691308154Sjhb 4692308305Sjhb mtx_assert(&sc->reg_lock, MA_OWNED); 4693309447Sjhb if (sc->flags & IS_VF) { 4694309447Sjhb stats[0] = t4_read_reg(sc, VF_MPS_REG(reg)); 4695309447Sjhb stats[1] = t4_read_reg(sc, VF_MPS_REG(reg + 4)); 4696309447Sjhb } else { 4697309447Sjhb t4_write_reg(sc, A_PL_INDIR_CMD, V_PL_AUTOINC(1) | 4698309447Sjhb V_PL_VFID(G_FW_VIID_VIN(viid)) | 4699309447Sjhb V_PL_ADDR(VF_MPS_REG(reg))); 4700309447Sjhb stats[0] = t4_read_reg(sc, A_PL_INDIR_DATA); 4701309447Sjhb stats[1] = t4_read_reg(sc, A_PL_INDIR_DATA); 4702309447Sjhb } 4703308154Sjhb return (((uint64_t)stats[1]) << 32 | stats[0]); 4704308154Sjhb} 4705308154Sjhb 4706218792Snpstatic void 4707308154Sjhbt4_get_vi_stats(struct adapter *sc, unsigned int viid, 4708308154Sjhb struct fw_vi_stats_vf *stats) 4709308154Sjhb{ 4710308154Sjhb 4711308154Sjhb#define GET_STAT(name) \ 4712308154Sjhb read_vf_stat(sc, viid, A_MPS_VF_STAT_##name##_L) 4713308154Sjhb 4714308154Sjhb stats->tx_bcast_bytes = GET_STAT(TX_VF_BCAST_BYTES); 4715308154Sjhb stats->tx_bcast_frames = GET_STAT(TX_VF_BCAST_FRAMES); 4716308154Sjhb stats->tx_mcast_bytes = GET_STAT(TX_VF_MCAST_BYTES); 4717308154Sjhb stats->tx_mcast_frames = GET_STAT(TX_VF_MCAST_FRAMES); 4718308154Sjhb stats->tx_ucast_bytes = GET_STAT(TX_VF_UCAST_BYTES); 4719308154Sjhb stats->tx_ucast_frames = GET_STAT(TX_VF_UCAST_FRAMES); 4720308154Sjhb stats->tx_drop_frames = GET_STAT(TX_VF_DROP_FRAMES); 4721308154Sjhb stats->tx_offload_bytes = GET_STAT(TX_VF_OFFLOAD_BYTES); 4722308154Sjhb stats->tx_offload_frames = GET_STAT(TX_VF_OFFLOAD_FRAMES); 4723308154Sjhb stats->rx_bcast_bytes = GET_STAT(RX_VF_BCAST_BYTES); 4724308154Sjhb stats->rx_bcast_frames = GET_STAT(RX_VF_BCAST_FRAMES); 4725308154Sjhb stats->rx_mcast_bytes = GET_STAT(RX_VF_MCAST_BYTES); 4726308154Sjhb stats->rx_mcast_frames = GET_STAT(RX_VF_MCAST_FRAMES); 4727308154Sjhb stats->rx_ucast_bytes = GET_STAT(RX_VF_UCAST_BYTES); 4728308154Sjhb stats->rx_ucast_frames = GET_STAT(RX_VF_UCAST_FRAMES); 4729308154Sjhb stats->rx_err_frames = GET_STAT(RX_VF_ERR_FRAMES); 4730308154Sjhb 4731308154Sjhb#undef GET_STAT 4732308154Sjhb} 4733308154Sjhb 4734308154Sjhbstatic void 4735308154Sjhbt4_clr_vi_stats(struct adapter *sc, unsigned int viid) 4736308154Sjhb{ 4737308154Sjhb int reg; 4738308154Sjhb 4739308154Sjhb t4_write_reg(sc, A_PL_INDIR_CMD, V_PL_AUTOINC(1) | 4740308154Sjhb V_PL_VFID(G_FW_VIID_VIN(viid)) | 4741308154Sjhb V_PL_ADDR(VF_MPS_REG(A_MPS_VF_STAT_TX_VF_BCAST_BYTES_L))); 4742308154Sjhb for (reg = A_MPS_VF_STAT_TX_VF_BCAST_BYTES_L; 4743308154Sjhb reg <= A_MPS_VF_STAT_RX_VF_ERR_FRAMES_H; reg += 4) 4744308154Sjhb t4_write_reg(sc, A_PL_INDIR_DATA, 0); 4745308154Sjhb} 4746308154Sjhb 4747308154Sjhbstatic void 4748308154Sjhbvi_refresh_stats(struct adapter *sc, struct vi_info *vi) 4749308154Sjhb{ 4750308154Sjhb struct ifnet *ifp = vi->ifp; 4751308154Sjhb struct sge_txq *txq; 4752308154Sjhb int i, drops; 4753308154Sjhb struct fw_vi_stats_vf *s = &vi->stats; 4754308154Sjhb struct timeval tv; 4755308154Sjhb const struct timeval interval = {0, 250000}; /* 250ms */ 4756308154Sjhb 4757308154Sjhb if (!(vi->flags & VI_INIT_DONE)) 4758308154Sjhb return; 4759308154Sjhb 4760308154Sjhb getmicrotime(&tv); 4761308154Sjhb timevalsub(&tv, &interval); 4762308154Sjhb if (timevalcmp(&tv, &vi->last_refreshed, <)) 4763308154Sjhb return; 4764308154Sjhb 4765308305Sjhb mtx_lock(&sc->reg_lock); 4766308154Sjhb t4_get_vi_stats(sc, vi->viid, &vi->stats); 4767308154Sjhb 4768308154Sjhb ifp->if_ipackets = s->rx_bcast_frames + s->rx_mcast_frames + 4769308154Sjhb s->rx_ucast_frames; 4770308154Sjhb ifp->if_ierrors = s->rx_err_frames; 4771308154Sjhb ifp->if_opackets = s->tx_bcast_frames + s->tx_mcast_frames + 4772308154Sjhb s->tx_ucast_frames + s->tx_offload_frames; 4773308154Sjhb ifp->if_oerrors = s->tx_drop_frames; 4774308154Sjhb ifp->if_ibytes = s->rx_bcast_bytes + s->rx_mcast_bytes + 4775308154Sjhb s->rx_ucast_bytes; 4776308154Sjhb ifp->if_obytes = s->tx_bcast_bytes + s->tx_mcast_bytes + 4777308154Sjhb s->tx_ucast_bytes + s->tx_offload_bytes; 4778308154Sjhb ifp->if_imcasts = s->rx_mcast_frames; 4779308154Sjhb ifp->if_omcasts = s->tx_mcast_frames; 4780308154Sjhb 4781308154Sjhb drops = 0; 4782308154Sjhb for_each_txq(vi, i, txq) 4783308154Sjhb drops += counter_u64_fetch(txq->r->drops); 4784308154Sjhb ifp->if_snd.ifq_drops = drops; 4785308154Sjhb 4786308154Sjhb getmicrotime(&vi->last_refreshed); 4787308305Sjhb mtx_unlock(&sc->reg_lock); 4788308154Sjhb} 4789308154Sjhb 4790308154Sjhbstatic void 4791282486Snpcxgbe_refresh_stats(struct adapter *sc, struct port_info *pi) 4792218792Snp{ 4793308154Sjhb struct vi_info *vi = &pi->vi[0]; 4794308154Sjhb struct ifnet *ifp = vi->ifp; 4795218792Snp struct sge_txq *txq; 4796218792Snp int i, drops; 4797218792Snp struct port_stats *s = &pi->stats; 4798282486Snp struct timeval tv; 4799282486Snp const struct timeval interval = {0, 250000}; /* 250ms */ 4800218792Snp 4801282486Snp getmicrotime(&tv); 4802282486Snp timevalsub(&tv, &interval); 4803282486Snp if (timevalcmp(&tv, &pi->last_refreshed, <)) 4804282486Snp return; 4805218792Snp 4806265425Snp t4_get_port_stats(sc, pi->tx_chan, s); 4807218792Snp 4808308315Sjhb ifp->if_opackets = s->tx_frames; 4809308315Sjhb ifp->if_ipackets = s->rx_frames; 4810308315Sjhb ifp->if_obytes = s->tx_octets; 4811308315Sjhb ifp->if_ibytes = s->rx_octets; 4812308315Sjhb ifp->if_omcasts = s->tx_mcast_frames; 4813308315Sjhb ifp->if_imcasts = s->rx_mcast_frames; 4814218792Snp ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 + 4815239259Snp s->rx_ovflow3 + s->rx_trunc0 + s->rx_trunc1 + s->rx_trunc2 + 4816239259Snp s->rx_trunc3; 4817308304Sjhb for (i = 0; i < sc->chip_params->nchan; i++) { 4818265425Snp if (pi->rx_chan_map & (1 << i)) { 4819265425Snp uint32_t v; 4820218792Snp 4821308305Sjhb mtx_lock(&sc->reg_lock); 4822265425Snp t4_read_indirect(sc, A_TP_MIB_INDEX, A_TP_MIB_DATA, &v, 4823265425Snp 1, A_TP_MIB_TNL_CNG_DROP_0 + i); 4824308305Sjhb mtx_unlock(&sc->reg_lock); 4825265425Snp ifp->if_iqdrops += v; 4826265425Snp } 4827265425Snp } 4828265425Snp 4829218792Snp drops = s->tx_drop; 4830308154Sjhb for_each_txq(vi, i, txq) 4831284052Snp drops += counter_u64_fetch(txq->r->drops); 4832218792Snp ifp->if_snd.ifq_drops = drops; 4833218792Snp 4834218792Snp ifp->if_oerrors = s->tx_error_frames; 4835218792Snp ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long + 4836218792Snp s->rx_fcs_err + s->rx_len_err; 4837218792Snp 4838282486Snp getmicrotime(&pi->last_refreshed); 4839282486Snp} 4840282486Snp 4841282486Snpstatic void 4842282486Snpcxgbe_tick(void *arg) 4843282486Snp{ 4844282486Snp struct port_info *pi = arg; 4845282486Snp struct adapter *sc = pi->adapter; 4846282486Snp 4847308154Sjhb PORT_LOCK_ASSERT_OWNED(pi); 4848282486Snp cxgbe_refresh_stats(sc, pi); 4849282486Snp 4850218792Snp callout_schedule(&pi->tick, hz); 4851218792Snp} 4852218792Snp 4853308154Sjhbvoid 4854308154Sjhbvi_tick(void *arg) 4855308154Sjhb{ 4856308154Sjhb struct vi_info *vi = arg; 4857308154Sjhb struct adapter *sc = vi->pi->adapter; 4858308154Sjhb 4859308154Sjhb vi_refresh_stats(sc, vi); 4860308154Sjhb 4861308154Sjhb callout_schedule(&vi->tick, hz); 4862308154Sjhb} 4863308154Sjhb 4864237263Snpstatic void 4865237263Snpcxgbe_vlan_config(void *arg, struct ifnet *ifp, uint16_t vid) 4866237263Snp{ 4867237263Snp struct ifnet *vlan; 4868237263Snp 4869241494Snp if (arg != ifp || ifp->if_type != IFT_ETHER) 4870237263Snp return; 4871237263Snp 4872237263Snp vlan = VLAN_DEVAT(ifp, vid); 4873237263Snp VLAN_SETCOOKIE(vlan, ifp); 4874237263Snp} 4875237263Snp 4876308304Sjhb/* 4877308304Sjhb * Should match fw_caps_config_<foo> enums in t4fw_interface.h 4878308304Sjhb */ 4879308304Sjhbstatic char *caps_decoder[] = { 4880308304Sjhb "\20\001IPMI\002NCSI", /* 0: NBM */ 4881308304Sjhb "\20\001PPP\002QFC\003DCBX", /* 1: link */ 4882308304Sjhb "\20\001INGRESS\002EGRESS", /* 2: switch */ 4883308304Sjhb "\20\001NIC\002VM\003IDS\004UM\005UM_ISGL" /* 3: NIC */ 4884308304Sjhb "\006HASHFILTER\007ETHOFLD", 4885308304Sjhb "\20\001TOE", /* 4: TOE */ 4886308304Sjhb "\20\001RDDP\002RDMAC", /* 5: RDMA */ 4887308304Sjhb "\20\001INITIATOR_PDU\002TARGET_PDU" /* 6: iSCSI */ 4888308304Sjhb "\003INITIATOR_CNXOFLD\004TARGET_CNXOFLD" 4889308304Sjhb "\005INITIATOR_SSNOFLD\006TARGET_SSNOFLD" 4890308304Sjhb "\007T10DIF" 4891308304Sjhb "\010INITIATOR_CMDOFLD\011TARGET_CMDOFLD", 4892309560Sjhb "\20\001LOOKASIDE\002TLSKEYS", /* 7: Crypto */ 4893308304Sjhb "\20\001INITIATOR\002TARGET\003CTRL_OFLD" /* 8: FCoE */ 4894308304Sjhb "\004PO_INITIATOR\005PO_TARGET", 4895308304Sjhb}; 4896308304Sjhb 4897309447Sjhbvoid 4898218792Snpt4_sysctls(struct adapter *sc) 4899218792Snp{ 4900218792Snp struct sysctl_ctx_list *ctx; 4901218792Snp struct sysctl_oid *oid; 4902228561Snp struct sysctl_oid_list *children, *c0; 4903249392Snp static char *doorbells = {"\20\1UDB\2WCWR\3UDBWC\4KDB"}; 4904218792Snp 4905218792Snp ctx = device_get_sysctl_ctx(sc->dev); 4906228561Snp 4907228561Snp /* 4908228561Snp * dev.t4nex.X. 4909228561Snp */ 4910218792Snp oid = device_get_sysctl_tree(sc->dev); 4911228561Snp c0 = children = SYSCTL_CHILDREN(oid); 4912218792Snp 4913265421Snp sc->sc_do_rxcopy = 1; 4914265421Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "do_rx_copy", CTLFLAG_RW, 4915265421Snp &sc->sc_do_rxcopy, 1, "Do RX copy of small frames"); 4916265421Snp 4917248925Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, NULL, 4918248925Snp sc->params.nports, "# of ports"); 4919218792Snp 4920309447Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "doorbells", 4921309447Sjhb CTLTYPE_STRING | CTLFLAG_RD, doorbells, sc->doorbells, 4922309447Sjhb sysctl_bitfield, "A", "available doorbells"); 4923218792Snp 4924309447Sjhb SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, NULL, 4925309447Sjhb sc->params.vpd.cclk, "core clock frequency (in KHz)"); 4926309447Sjhb 4927309447Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers", 4928309447Sjhb CTLTYPE_STRING | CTLFLAG_RD, sc->params.sge.timer_val, 4929309447Sjhb sizeof(sc->params.sge.timer_val), sysctl_int_array, "A", 4930309447Sjhb "interrupt holdoff timer values (us)"); 4931309447Sjhb 4932309447Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts", 4933309447Sjhb CTLTYPE_STRING | CTLFLAG_RD, sc->params.sge.counter_val, 4934309447Sjhb sizeof(sc->params.sge.counter_val), sysctl_int_array, "A", 4935309447Sjhb "interrupt holdoff packet counter values"); 4936309447Sjhb 4937309447Sjhb t4_sge_sysctls(sc, ctx, children); 4938309447Sjhb 4939309447Sjhb sc->lro_timeout = 100; 4940309447Sjhb SYSCTL_ADD_INT(ctx, children, OID_AUTO, "lro_timeout", CTLFLAG_RW, 4941309447Sjhb &sc->lro_timeout, 0, "lro inactive-flush timeout (in us)"); 4942309447Sjhb 4943309458Sjhb SYSCTL_ADD_INT(ctx, children, OID_AUTO, "dflags", CTLFLAG_RW, 4944309447Sjhb &sc->debug_flags, 0, "flags to enable runtime debugging"); 4945309447Sjhb 4946308311Sjhb SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "tp_version", 4947308311Sjhb CTLFLAG_RD, sc->tp_version, 0, "TP microcode version"); 4948308311Sjhb 4949309447Sjhb SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 4950309447Sjhb CTLFLAG_RD, sc->fw_version, 0, "firmware version"); 4951309447Sjhb 4952309447Sjhb if (sc->flags & IS_VF) 4953309447Sjhb return; 4954309447Sjhb 4955309447Sjhb SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD, 4956309447Sjhb NULL, chip_rev(sc), "chip hardware revision"); 4957309447Sjhb 4958309458Sjhb SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "sn", 4959309458Sjhb CTLFLAG_RD, sc->params.vpd.sn, 0, "serial number"); 4960308311Sjhb 4961309458Sjhb SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "pn", 4962309458Sjhb CTLFLAG_RD, sc->params.vpd.pn, 0, "part number"); 4963309458Sjhb 4964309458Sjhb SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "ec", 4965309458Sjhb CTLFLAG_RD, sc->params.vpd.ec, 0, "engineering change"); 4966309458Sjhb 4967309458Sjhb SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "na", 4968309458Sjhb CTLFLAG_RD, sc->params.vpd.na, 0, "network address"); 4969309458Sjhb 4970309458Sjhb SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "er_version", CTLFLAG_RD, 4971309458Sjhb sc->er_version, 0, "expansion ROM version"); 4972309458Sjhb 4973309458Sjhb SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "bs_version", CTLFLAG_RD, 4974309458Sjhb sc->bs_version, 0, "bootstrap firmware version"); 4975309458Sjhb 4976309458Sjhb SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "scfg_version", CTLFLAG_RD, 4977309458Sjhb NULL, sc->params.scfg_vers, "serial config version"); 4978309458Sjhb 4979309458Sjhb SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "vpd_version", CTLFLAG_RD, 4980309458Sjhb NULL, sc->params.vpd_vers, "VPD version"); 4981309458Sjhb 4982228561Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "cf", 4983273736Shselasky CTLFLAG_RD, sc->cfg_file, 0, "configuration file"); 4984218792Snp 4985248925Snp SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cfcsum", CTLFLAG_RD, NULL, 4986248925Snp sc->cfcsum, "config file checksum"); 4987228561Snp 4988308304Sjhb#define SYSCTL_CAP(name, n, text) \ 4989308304Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, #name, \ 4990308304Sjhb CTLTYPE_STRING | CTLFLAG_RD, caps_decoder[n], sc->name, \ 4991309458Sjhb sysctl_bitfield, "A", "available " text " capabilities") 4992228561Snp 4993308304Sjhb SYSCTL_CAP(nbmcaps, 0, "NBM"); 4994308304Sjhb SYSCTL_CAP(linkcaps, 1, "link"); 4995308304Sjhb SYSCTL_CAP(switchcaps, 2, "switch"); 4996308304Sjhb SYSCTL_CAP(niccaps, 3, "NIC"); 4997308304Sjhb SYSCTL_CAP(toecaps, 4, "TCP offload"); 4998308304Sjhb SYSCTL_CAP(rdmacaps, 5, "RDMA"); 4999308304Sjhb SYSCTL_CAP(iscsicaps, 6, "iSCSI"); 5000309560Sjhb SYSCTL_CAP(cryptocaps, 7, "crypto"); 5001308304Sjhb SYSCTL_CAP(fcoecaps, 8, "FCoE"); 5002308304Sjhb#undef SYSCTL_CAP 5003228561Snp 5004252469Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nfilters", CTLFLAG_RD, 5005252469Snp NULL, sc->tids.nftids, "number of filters"); 5006252469Snp 5007253890Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "temperature", CTLTYPE_INT | 5008264736Semax CTLFLAG_RD, sc, 0, sysctl_temperature, "I", 5009253890Snp "chip temperature (in Celsius)"); 5010253890Snp 5011231115Snp#ifdef SBUF_DRAIN 5012228561Snp /* 5013228561Snp * dev.t4nex.X.misc. Marked CTLFLAG_SKIP to avoid information overload. 5014228561Snp */ 5015228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "misc", 5016228561Snp CTLFLAG_RD | CTLFLAG_SKIP, NULL, 5017228561Snp "logs and miscellaneous information"); 5018228561Snp children = SYSCTL_CHILDREN(oid); 5019228561Snp 5020228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cctrl", 5021228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5022228561Snp sysctl_cctrl, "A", "congestion control"); 5023228561Snp 5024247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp0", 5025247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5026247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 0 (TP0)"); 5027247122Snp 5028247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp1", 5029247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 1, 5030247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 1 (TP1)"); 5031247122Snp 5032247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ulp", 5033247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 2, 5034247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 2 (ULP)"); 5035247122Snp 5036247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge0", 5037247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 3, 5038247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 3 (SGE0)"); 5039247122Snp 5040247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge1", 5041247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 4, 5042247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 4 (SGE1)"); 5043247122Snp 5044247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ncsi", 5045247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 5, 5046247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 5 (NCSI)"); 5047247122Snp 5048247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_la", 5049247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5050308304Sjhb chip_id(sc) <= CHELSIO_T5 ? sysctl_cim_la : sysctl_cim_la_t6, 5051308304Sjhb "A", "CIM logic analyzer"); 5052247122Snp 5053251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ma_la", 5054251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5055251213Snp sysctl_cim_ma_la, "A", "CIM MA logic analyzer"); 5056251213Snp 5057247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp0", 5058247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0 + CIM_NUM_IBQ, 5059247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 0 (ULP0)"); 5060247122Snp 5061247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp1", 5062247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 1 + CIM_NUM_IBQ, 5063247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 1 (ULP1)"); 5064247122Snp 5065247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp2", 5066247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 2 + CIM_NUM_IBQ, 5067247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 2 (ULP2)"); 5068247122Snp 5069247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp3", 5070247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 3 + CIM_NUM_IBQ, 5071247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 3 (ULP3)"); 5072247122Snp 5073247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge", 5074247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 4 + CIM_NUM_IBQ, 5075247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 4 (SGE)"); 5076247122Snp 5077247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ncsi", 5078247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 5 + CIM_NUM_IBQ, 5079247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 5 (NCSI)"); 5080247122Snp 5081308304Sjhb if (chip_id(sc) > CHELSIO_T4) { 5082248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge0_rx", 5083248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 6 + CIM_NUM_IBQ, 5084248925Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 6 (SGE0-RX)"); 5085248925Snp 5086248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge1_rx", 5087248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 7 + CIM_NUM_IBQ, 5088248925Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 7 (SGE1-RX)"); 5089248925Snp } 5090248925Snp 5091251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_pif_la", 5092251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5093251213Snp sysctl_cim_pif_la, "A", "CIM PIF logic analyzer"); 5094251213Snp 5095247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_qcfg", 5096247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5097247122Snp sysctl_cim_qcfg, "A", "CIM queue configuration"); 5098247122Snp 5099228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats", 5100228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5101228561Snp sysctl_cpl_stats, "A", "CPL statistics"); 5102228561Snp 5103228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ddp_stats", 5104228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5105281241Snp sysctl_ddp_stats, "A", "non-TCP DDP statistics"); 5106228561Snp 5107222551Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog", 5108222551Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5109228561Snp sysctl_devlog, "A", "firmware's device log"); 5110222551Snp 5111228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoe_stats", 5112228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5113228561Snp sysctl_fcoe_stats, "A", "FCoE statistics"); 5114228561Snp 5115228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hw_sched", 5116228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5117228561Snp sysctl_hw_sched, "A", "hardware scheduler "); 5118228561Snp 5119228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "l2t", 5120228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5121228561Snp sysctl_l2t, "A", "hardware L2 table"); 5122228561Snp 5123228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats", 5124228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5125228561Snp sysctl_lb_stats, "A", "loopback statistics"); 5126228561Snp 5127228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "meminfo", 5128228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5129228561Snp sysctl_meminfo, "A", "memory regions"); 5130228561Snp 5131251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "mps_tcam", 5132251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5133308304Sjhb chip_id(sc) <= CHELSIO_T5 ? sysctl_mps_tcam : sysctl_mps_tcam_t6, 5134308304Sjhb "A", "MPS TCAM entries"); 5135251213Snp 5136228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "path_mtus", 5137228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5138228561Snp sysctl_path_mtus, "A", "path MTUs"); 5139228561Snp 5140228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pm_stats", 5141228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5142228561Snp sysctl_pm_stats, "A", "PM statistics"); 5143228561Snp 5144228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_stats", 5145228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5146228561Snp sysctl_rdma_stats, "A", "RDMA statistics"); 5147228561Snp 5148228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tcp_stats", 5149228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5150228561Snp sysctl_tcp_stats, "A", "TCP statistics"); 5151228561Snp 5152228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tids", 5153228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5154228561Snp sysctl_tids, "A", "TID information"); 5155228561Snp 5156228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_err_stats", 5157228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5158228561Snp sysctl_tp_err_stats, "A", "TP error statistics"); 5159228561Snp 5160308311Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_la_mask", 5161308311Sjhb CTLTYPE_INT | CTLFLAG_RW, sc, 0, sysctl_tp_la_mask, "I", 5162308311Sjhb "TP logic analyzer event capture mask"); 5163308311Sjhb 5164251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_la", 5165251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5166251213Snp sysctl_tp_la, "A", "TP logic analyzer"); 5167251213Snp 5168228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_rate", 5169228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5170228561Snp sysctl_tx_rate, "A", "Tx rate"); 5171248925Snp 5172251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ulprx_la", 5173251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5174251213Snp sysctl_ulprx_la, "A", "ULPRX logic analyzer"); 5175251213Snp 5176309560Sjhb if (chip_id(sc) >= CHELSIO_T5) { 5177249392Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "wcwr_stats", 5178248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 5179249392Snp sysctl_wcwr_stats, "A", "write combined work requests"); 5180248925Snp } 5181231115Snp#endif 5182228561Snp 5183237263Snp#ifdef TCP_OFFLOAD 5184228561Snp if (is_offload(sc)) { 5185228561Snp /* 5186228561Snp * dev.t4nex.X.toe. 5187228561Snp */ 5188228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "toe", CTLFLAG_RD, 5189228561Snp NULL, "TOE parameters"); 5190228561Snp children = SYSCTL_CHILDREN(oid); 5191228561Snp 5192228561Snp sc->tt.sndbuf = 256 * 1024; 5193228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "sndbuf", CTLFLAG_RW, 5194228561Snp &sc->tt.sndbuf, 0, "max hardware send buffer size"); 5195228561Snp 5196228561Snp sc->tt.ddp = 0; 5197228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp", CTLFLAG_RW, 5198228561Snp &sc->tt.ddp, 0, "DDP allowed"); 5199239341Snp 5200239341Snp sc->tt.indsz = G_INDICATESIZE(t4_read_reg(sc, A_TP_PARA_REG5)); 5201228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "indsz", CTLFLAG_RW, 5202228561Snp &sc->tt.indsz, 0, "DDP max indicate size allowed"); 5203239341Snp 5204239341Snp sc->tt.ddp_thres = 5205239341Snp G_RXCOALESCESIZE(t4_read_reg(sc, A_TP_PARA_REG2)); 5206228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp_thres", CTLFLAG_RW, 5207228561Snp &sc->tt.ddp_thres, 0, "DDP threshold"); 5208252728Snp 5209252728Snp sc->tt.rx_coalesce = 1; 5210252728Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_coalesce", 5211252728Snp CTLFLAG_RW, &sc->tt.rx_coalesce, 0, "receive coalescing"); 5212281244Snp 5213281244Snp sc->tt.tx_align = 1; 5214281244Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "tx_align", 5215281244Snp CTLFLAG_RW, &sc->tt.tx_align, 0, "chop and align payload"); 5216308311Sjhb 5217308311Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "timer_tick", 5218308311Sjhb CTLTYPE_STRING | CTLFLAG_RD, sc, 0, sysctl_tp_tick, "A", 5219308311Sjhb "TP timer tick (us)"); 5220308311Sjhb 5221308311Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "timestamp_tick", 5222308311Sjhb CTLTYPE_STRING | CTLFLAG_RD, sc, 1, sysctl_tp_tick, "A", 5223308311Sjhb "TCP timestamp tick (us)"); 5224308311Sjhb 5225308311Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dack_tick", 5226308311Sjhb CTLTYPE_STRING | CTLFLAG_RD, sc, 2, sysctl_tp_tick, "A", 5227308311Sjhb "DACK tick (us)"); 5228308311Sjhb 5229308311Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "dack_timer", 5230308311Sjhb CTLTYPE_UINT | CTLFLAG_RD, sc, 0, sysctl_tp_dack_timer, 5231308311Sjhb "IU", "DACK timer (us)"); 5232308311Sjhb 5233308311Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rexmt_min", 5234308311Sjhb CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_RXT_MIN, 5235308311Sjhb sysctl_tp_timer, "LU", "Retransmit min (us)"); 5236308311Sjhb 5237308311Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rexmt_max", 5238308311Sjhb CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_RXT_MAX, 5239308311Sjhb sysctl_tp_timer, "LU", "Retransmit max (us)"); 5240308311Sjhb 5241308311Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "persist_min", 5242308311Sjhb CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_PERS_MIN, 5243308311Sjhb sysctl_tp_timer, "LU", "Persist timer min (us)"); 5244308311Sjhb 5245308311Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "persist_max", 5246308311Sjhb CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_PERS_MAX, 5247308311Sjhb sysctl_tp_timer, "LU", "Persist timer max (us)"); 5248308311Sjhb 5249308311Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "keepalive_idle", 5250308311Sjhb CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_KEEP_IDLE, 5251308311Sjhb sysctl_tp_timer, "LU", "Keepidle idle timer (us)"); 5252308311Sjhb 5253308311Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "keepalive_intvl", 5254308311Sjhb CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_KEEP_INTVL, 5255308311Sjhb sysctl_tp_timer, "LU", "Keepidle interval (us)"); 5256308311Sjhb 5257308311Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "initial_srtt", 5258308311Sjhb CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_INIT_SRTT, 5259308311Sjhb sysctl_tp_timer, "LU", "Initial SRTT (us)"); 5260308311Sjhb 5261308311Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "finwait2_timer", 5262308311Sjhb CTLTYPE_ULONG | CTLFLAG_RD, sc, A_TP_FINWAIT2_TIMER, 5263308311Sjhb sysctl_tp_timer, "LU", "FINWAIT2 timer (us)"); 5264228561Snp } 5265228561Snp#endif 5266218792Snp} 5267218792Snp 5268308154Sjhbvoid 5269308154Sjhbvi_sysctls(struct vi_info *vi) 5270218792Snp{ 5271218792Snp struct sysctl_ctx_list *ctx; 5272218792Snp struct sysctl_oid *oid; 5273218792Snp struct sysctl_oid_list *children; 5274218792Snp 5275308154Sjhb ctx = device_get_sysctl_ctx(vi->dev); 5276218792Snp 5277218792Snp /* 5278308154Sjhb * dev.v?(cxgbe|cxl).X. 5279218792Snp */ 5280308154Sjhb oid = device_get_sysctl_tree(vi->dev); 5281218792Snp children = SYSCTL_CHILDREN(oid); 5282218792Snp 5283308154Sjhb SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "viid", CTLFLAG_RD, NULL, 5284308154Sjhb vi->viid, "VI identifer"); 5285218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD, 5286308154Sjhb &vi->nrxq, 0, "# of rx queues"); 5287218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD, 5288308154Sjhb &vi->ntxq, 0, "# of tx queues"); 5289218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD, 5290308154Sjhb &vi->first_rxq, 0, "index of first rx queue"); 5291218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD, 5292308154Sjhb &vi->first_txq, 0, "index of first tx queue"); 5293309458Sjhb SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "rss_size", CTLFLAG_RD, NULL, 5294309458Sjhb vi->rss_size, "size of RSS indirection table"); 5295218792Snp 5296308154Sjhb if (IS_MAIN_VI(vi)) { 5297308154Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rsrv_noflowq", 5298308154Sjhb CTLTYPE_INT | CTLFLAG_RW, vi, 0, sysctl_noflowq, "IU", 5299308154Sjhb "Reserve queue 0 for non-flowid packets"); 5300308154Sjhb } 5301308154Sjhb 5302237263Snp#ifdef TCP_OFFLOAD 5303308154Sjhb if (vi->nofldrxq != 0) { 5304228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldrxq", CTLFLAG_RD, 5305308154Sjhb &vi->nofldrxq, 0, 5306228561Snp "# of rx queues for offloaded TCP connections"); 5307228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldtxq", CTLFLAG_RD, 5308308154Sjhb &vi->nofldtxq, 0, 5309228561Snp "# of tx queues for offloaded TCP connections"); 5310228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_rxq", 5311308154Sjhb CTLFLAG_RD, &vi->first_ofld_rxq, 0, 5312228561Snp "index of first TOE rx queue"); 5313228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_txq", 5314308154Sjhb CTLFLAG_RD, &vi->first_ofld_txq, 0, 5315228561Snp "index of first TOE tx queue"); 5316228561Snp } 5317228561Snp#endif 5318270297Snp#ifdef DEV_NETMAP 5319308154Sjhb if (vi->nnmrxq != 0) { 5320308154Sjhb SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nnmrxq", CTLFLAG_RD, 5321308154Sjhb &vi->nnmrxq, 0, "# of netmap rx queues"); 5322308154Sjhb SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nnmtxq", CTLFLAG_RD, 5323308154Sjhb &vi->nnmtxq, 0, "# of netmap tx queues"); 5324308154Sjhb SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_nm_rxq", 5325308154Sjhb CTLFLAG_RD, &vi->first_nm_rxq, 0, 5326308154Sjhb "index of first netmap rx queue"); 5327308154Sjhb SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_nm_txq", 5328308154Sjhb CTLFLAG_RD, &vi->first_nm_txq, 0, 5329308154Sjhb "index of first netmap tx queue"); 5330308154Sjhb } 5331270297Snp#endif 5332228561Snp 5333218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx", 5334308154Sjhb CTLTYPE_INT | CTLFLAG_RW, vi, 0, sysctl_holdoff_tmr_idx, "I", 5335218792Snp "holdoff timer index"); 5336218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx", 5337308154Sjhb CTLTYPE_INT | CTLFLAG_RW, vi, 0, sysctl_holdoff_pktc_idx, "I", 5338218792Snp "holdoff packet counter index"); 5339218792Snp 5340218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq", 5341308154Sjhb CTLTYPE_INT | CTLFLAG_RW, vi, 0, sysctl_qsize_rxq, "I", 5342218792Snp "rx queue size"); 5343218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq", 5344308154Sjhb CTLTYPE_INT | CTLFLAG_RW, vi, 0, sysctl_qsize_txq, "I", 5345218792Snp "tx queue size"); 5346308154Sjhb} 5347218792Snp 5348308154Sjhbstatic void 5349308154Sjhbcxgbe_sysctls(struct port_info *pi) 5350308154Sjhb{ 5351308154Sjhb struct sysctl_ctx_list *ctx; 5352308154Sjhb struct sysctl_oid *oid; 5353308321Sjhb struct sysctl_oid_list *children, *children2; 5354308154Sjhb struct adapter *sc = pi->adapter; 5355308321Sjhb int i; 5356308321Sjhb char name[16]; 5357308154Sjhb 5358308154Sjhb ctx = device_get_sysctl_ctx(pi->dev); 5359308154Sjhb 5360308154Sjhb /* 5361308154Sjhb * dev.cxgbe.X. 5362308154Sjhb */ 5363308154Sjhb oid = device_get_sysctl_tree(pi->dev); 5364308154Sjhb children = SYSCTL_CHILDREN(oid); 5365308154Sjhb 5366308154Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkdnrc", CTLTYPE_STRING | 5367308154Sjhb CTLFLAG_RD, pi, 0, sysctl_linkdnrc, "A", "reason why link is down"); 5368308154Sjhb if (pi->port_type == FW_PORT_TYPE_BT_XAUI) { 5369308154Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "temperature", 5370308154Sjhb CTLTYPE_INT | CTLFLAG_RD, pi, 0, sysctl_btphy, "I", 5371308154Sjhb "PHY temperature (in Celsius)"); 5372308154Sjhb SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fw_version", 5373308154Sjhb CTLTYPE_INT | CTLFLAG_RD, pi, 1, sysctl_btphy, "I", 5374308154Sjhb "PHY firmware version"); 5375308154Sjhb } 5376308154Sjhb 5377271961Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pause_settings", 5378311261Snp CTLTYPE_STRING | CTLFLAG_RW, pi, 0, sysctl_pause_settings, "A", 5379311261Snp "PAUSE settings (bit 0 = rx_pause, bit 1 = tx_pause)"); 5380311261Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fec", 5381311261Snp CTLTYPE_STRING | CTLFLAG_RW, pi, 0, sysctl_fec, "A", 5382311261Snp "Forward Error Correction (bit 0 = RS, bit 1 = BASER_RS)"); 5383311261Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "autoneg", 5384311261Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_autoneg, "I", 5385311261Snp "autonegotiation (-1 = not supported)"); 5386271961Snp 5387308311Sjhb SYSCTL_ADD_INT(ctx, children, OID_AUTO, "max_speed", CTLFLAG_RD, NULL, 5388308311Sjhb port_top_speed(pi), "max speed (in Gbps)"); 5389308311Sjhb 5390309447Sjhb if (sc->flags & IS_VF) 5391309447Sjhb return; 5392309447Sjhb 5393218792Snp /* 5394308321Sjhb * dev.(cxgbe|cxl).X.tc. 5395308321Sjhb */ 5396308321Sjhb oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "tc", CTLFLAG_RD, NULL, 5397318851Snp "Tx scheduler traffic classes (cl_rl)"); 5398308321Sjhb for (i = 0; i < sc->chip_params->nsched_cls; i++) { 5399318851Snp struct tx_cl_rl_params *tc = &pi->sched_params->cl_rl[i]; 5400308321Sjhb 5401308321Sjhb snprintf(name, sizeof(name), "%d", i); 5402308321Sjhb children2 = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(ctx, 5403308321Sjhb SYSCTL_CHILDREN(oid), OID_AUTO, name, CTLFLAG_RD, NULL, 5404308321Sjhb "traffic class")); 5405308321Sjhb SYSCTL_ADD_UINT(ctx, children2, OID_AUTO, "flags", CTLFLAG_RD, 5406308321Sjhb &tc->flags, 0, "flags"); 5407308321Sjhb SYSCTL_ADD_UINT(ctx, children2, OID_AUTO, "refcount", 5408308321Sjhb CTLFLAG_RD, &tc->refcount, 0, "references to this class"); 5409308321Sjhb#ifdef SBUF_DRAIN 5410308321Sjhb SYSCTL_ADD_PROC(ctx, children2, OID_AUTO, "params", 5411308321Sjhb CTLTYPE_STRING | CTLFLAG_RD, sc, (pi->port_id << 16) | i, 5412308321Sjhb sysctl_tc_params, "A", "traffic class parameters"); 5413308321Sjhb#endif 5414308321Sjhb } 5415308321Sjhb 5416308321Sjhb /* 5417218792Snp * dev.cxgbe.X.stats. 5418218792Snp */ 5419218792Snp oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, 5420218792Snp NULL, "port statistics"); 5421218792Snp children = SYSCTL_CHILDREN(oid); 5422284052Snp SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "tx_parse_error", CTLFLAG_RD, 5423284052Snp &pi->tx_parse_error, 0, 5424284052Snp "# of tx packets with invalid length or # of segments"); 5425218792Snp 5426218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \ 5427218792Snp SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \ 5428265426Snp CTLTYPE_U64 | CTLFLAG_RD, sc, reg, \ 5429218792Snp sysctl_handle_t4_reg64, "QU", desc) 5430218792Snp 5431218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames", 5432218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L)); 5433218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames", 5434218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L)); 5435218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames", 5436218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L)); 5437218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames", 5438218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L)); 5439218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames", 5440218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L)); 5441218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames", 5442218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L)); 5443218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_64", 5444218792Snp "# of tx frames in this range", 5445218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L)); 5446218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127", 5447218792Snp "# of tx frames in this range", 5448218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L)); 5449218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255", 5450218792Snp "# of tx frames in this range", 5451218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L)); 5452218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511", 5453218792Snp "# of tx frames in this range", 5454218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L)); 5455218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023", 5456218792Snp "# of tx frames in this range", 5457218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L)); 5458218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518", 5459218792Snp "# of tx frames in this range", 5460218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L)); 5461218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max", 5462218792Snp "# of tx frames in this range", 5463218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L)); 5464218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames", 5465218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L)); 5466218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted", 5467218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L)); 5468218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted", 5469218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L)); 5470218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted", 5471218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L)); 5472218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted", 5473218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L)); 5474218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted", 5475218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L)); 5476218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted", 5477218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L)); 5478218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted", 5479218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L)); 5480218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted", 5481218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L)); 5482218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted", 5483218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L)); 5484218792Snp 5485218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames", 5486218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L)); 5487218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames", 5488218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L)); 5489218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames", 5490218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L)); 5491218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames", 5492218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L)); 5493218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames", 5494218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L)); 5495218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU", 5496218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L)); 5497218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames", 5498218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L)); 5499218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err", 5500218792Snp "# of frames received with bad FCS", 5501218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L)); 5502218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_len_err", 5503218792Snp "# of frames received with length error", 5504218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L)); 5505218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors", 5506218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L)); 5507218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received", 5508218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L)); 5509218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_64", 5510218792Snp "# of rx frames in this range", 5511218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L)); 5512218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127", 5513218792Snp "# of rx frames in this range", 5514218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L)); 5515218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255", 5516218792Snp "# of rx frames in this range", 5517218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L)); 5518218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511", 5519218792Snp "# of rx frames in this range", 5520218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L)); 5521218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023", 5522218792Snp "# of rx frames in this range", 5523218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L)); 5524218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518", 5525218792Snp "# of rx frames in this range", 5526218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L)); 5527218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max", 5528218792Snp "# of rx frames in this range", 5529218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L)); 5530218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received", 5531218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L)); 5532218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received", 5533218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L)); 5534218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received", 5535218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L)); 5536218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received", 5537218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L)); 5538218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received", 5539218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L)); 5540218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received", 5541218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L)); 5542218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received", 5543218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L)); 5544218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received", 5545218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L)); 5546218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received", 5547218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L)); 5548218792Snp 5549218792Snp#undef SYSCTL_ADD_T4_REG64 5550218792Snp 5551218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \ 5552218792Snp SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \ 5553218792Snp &pi->stats.name, desc) 5554218792Snp 5555218792Snp /* We get these from port_stats and they may be stale by upto 1s */ 5556218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0, 5557218792Snp "# drops due to buffer-group 0 overflows"); 5558218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1, 5559218792Snp "# drops due to buffer-group 1 overflows"); 5560218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2, 5561218792Snp "# drops due to buffer-group 2 overflows"); 5562218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3, 5563218792Snp "# drops due to buffer-group 3 overflows"); 5564218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc0, 5565218792Snp "# of buffer-group 0 truncated packets"); 5566218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc1, 5567218792Snp "# of buffer-group 1 truncated packets"); 5568218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc2, 5569218792Snp "# of buffer-group 2 truncated packets"); 5570218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc3, 5571218792Snp "# of buffer-group 3 truncated packets"); 5572218792Snp 5573218792Snp#undef SYSCTL_ADD_T4_PORTSTAT 5574218792Snp} 5575218792Snp 5576218792Snpstatic int 5577219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS) 5578219436Snp{ 5579281252Snp int rc, *i, space = 0; 5580219436Snp struct sbuf sb; 5581219436Snp 5582219436Snp sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); 5583281252Snp for (i = arg1; arg2; arg2 -= sizeof(int), i++) { 5584281252Snp if (space) 5585281252Snp sbuf_printf(&sb, " "); 5586281252Snp sbuf_printf(&sb, "%d", *i); 5587281252Snp space = 1; 5588281252Snp } 5589219436Snp sbuf_finish(&sb); 5590219436Snp rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 5591219436Snp sbuf_delete(&sb); 5592219436Snp return (rc); 5593219436Snp} 5594219436Snp 5595219436Snpstatic int 5596228561Snpsysctl_bitfield(SYSCTL_HANDLER_ARGS) 5597228561Snp{ 5598228561Snp int rc; 5599228561Snp struct sbuf *sb; 5600228561Snp 5601228561Snp rc = sysctl_wire_old_buffer(req, 0); 5602228561Snp if (rc != 0) 5603228561Snp return(rc); 5604228561Snp 5605228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 5606228561Snp if (sb == NULL) 5607228561Snp return (ENOMEM); 5608228561Snp 5609228561Snp sbuf_printf(sb, "%b", (int)arg2, (char *)arg1); 5610228561Snp rc = sbuf_finish(sb); 5611228561Snp sbuf_delete(sb); 5612228561Snp 5613228561Snp return (rc); 5614228561Snp} 5615228561Snp 5616228561Snpstatic int 5617252747Snpsysctl_btphy(SYSCTL_HANDLER_ARGS) 5618252747Snp{ 5619252747Snp struct port_info *pi = arg1; 5620252747Snp int op = arg2; 5621252747Snp struct adapter *sc = pi->adapter; 5622252747Snp u_int v; 5623252747Snp int rc; 5624252747Snp 5625308154Sjhb rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK, "t4btt"); 5626252747Snp if (rc) 5627252747Snp return (rc); 5628252747Snp /* XXX: magic numbers */ 5629252747Snp rc = -t4_mdio_rd(sc, sc->mbox, pi->mdio_addr, 0x1e, op ? 0x20 : 0xc820, 5630252747Snp &v); 5631252747Snp end_synchronized_op(sc, 0); 5632252747Snp if (rc) 5633252747Snp return (rc); 5634252747Snp if (op == 0) 5635252747Snp v /= 256; 5636252747Snp 5637252747Snp rc = sysctl_handle_int(oidp, &v, 0, req); 5638252747Snp return (rc); 5639252747Snp} 5640252747Snp 5641252747Snpstatic int 5642264493Sscottlsysctl_noflowq(SYSCTL_HANDLER_ARGS) 5643264493Sscottl{ 5644308154Sjhb struct vi_info *vi = arg1; 5645264493Sscottl int rc, val; 5646264493Sscottl 5647308154Sjhb val = vi->rsrv_noflowq; 5648264493Sscottl rc = sysctl_handle_int(oidp, &val, 0, req); 5649264493Sscottl if (rc != 0 || req->newptr == NULL) 5650264493Sscottl return (rc); 5651264493Sscottl 5652308154Sjhb if ((val >= 1) && (vi->ntxq > 1)) 5653308154Sjhb vi->rsrv_noflowq = 1; 5654264493Sscottl else 5655308154Sjhb vi->rsrv_noflowq = 0; 5656264493Sscottl 5657264493Sscottl return (rc); 5658264493Sscottl} 5659264493Sscottl 5660264493Sscottlstatic int 5661218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS) 5662218792Snp{ 5663308154Sjhb struct vi_info *vi = arg1; 5664308154Sjhb struct adapter *sc = vi->pi->adapter; 5665218792Snp int idx, rc, i; 5666245274Snp struct sge_rxq *rxq; 5667252724Snp#ifdef TCP_OFFLOAD 5668252724Snp struct sge_ofld_rxq *ofld_rxq; 5669252724Snp#endif 5670245274Snp uint8_t v; 5671218792Snp 5672308154Sjhb idx = vi->tmr_idx; 5673218792Snp 5674218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 5675218792Snp if (rc != 0 || req->newptr == NULL) 5676218792Snp return (rc); 5677218792Snp 5678218792Snp if (idx < 0 || idx >= SGE_NTIMERS) 5679218792Snp return (EINVAL); 5680218792Snp 5681308154Sjhb rc = begin_synchronized_op(sc, vi, HOLD_LOCK | SLEEP_OK | INTR_OK, 5682245274Snp "t4tmr"); 5683245274Snp if (rc) 5684245274Snp return (rc); 5685228561Snp 5686308154Sjhb v = V_QINTR_TIMER_IDX(idx) | V_QINTR_CNT_EN(vi->pktc_idx != -1); 5687308154Sjhb for_each_rxq(vi, i, rxq) { 5688228561Snp#ifdef atomic_store_rel_8 5689245274Snp atomic_store_rel_8(&rxq->iq.intr_params, v); 5690228561Snp#else 5691245274Snp rxq->iq.intr_params = v; 5692228561Snp#endif 5693218792Snp } 5694252724Snp#ifdef TCP_OFFLOAD 5695308154Sjhb for_each_ofld_rxq(vi, i, ofld_rxq) { 5696252724Snp#ifdef atomic_store_rel_8 5697252724Snp atomic_store_rel_8(&ofld_rxq->iq.intr_params, v); 5698252724Snp#else 5699252724Snp ofld_rxq->iq.intr_params = v; 5700252724Snp#endif 5701252724Snp } 5702252724Snp#endif 5703308154Sjhb vi->tmr_idx = idx; 5704218792Snp 5705245274Snp end_synchronized_op(sc, LOCK_HELD); 5706245274Snp return (0); 5707218792Snp} 5708218792Snp 5709218792Snpstatic int 5710218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS) 5711218792Snp{ 5712308154Sjhb struct vi_info *vi = arg1; 5713308154Sjhb struct adapter *sc = vi->pi->adapter; 5714218792Snp int idx, rc; 5715218792Snp 5716308154Sjhb idx = vi->pktc_idx; 5717218792Snp 5718218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 5719218792Snp if (rc != 0 || req->newptr == NULL) 5720218792Snp return (rc); 5721218792Snp 5722218792Snp if (idx < -1 || idx >= SGE_NCOUNTERS) 5723218792Snp return (EINVAL); 5724218792Snp 5725308154Sjhb rc = begin_synchronized_op(sc, vi, HOLD_LOCK | SLEEP_OK | INTR_OK, 5726245274Snp "t4pktc"); 5727245274Snp if (rc) 5728245274Snp return (rc); 5729245274Snp 5730308154Sjhb if (vi->flags & VI_INIT_DONE) 5731228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 5732245274Snp else 5733308154Sjhb vi->pktc_idx = idx; 5734218792Snp 5735245274Snp end_synchronized_op(sc, LOCK_HELD); 5736218792Snp return (rc); 5737218792Snp} 5738218792Snp 5739218792Snpstatic int 5740218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS) 5741218792Snp{ 5742308154Sjhb struct vi_info *vi = arg1; 5743308154Sjhb struct adapter *sc = vi->pi->adapter; 5744218792Snp int qsize, rc; 5745218792Snp 5746308154Sjhb qsize = vi->qsize_rxq; 5747218792Snp 5748218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 5749218792Snp if (rc != 0 || req->newptr == NULL) 5750218792Snp return (rc); 5751218792Snp 5752218792Snp if (qsize < 128 || (qsize & 7)) 5753218792Snp return (EINVAL); 5754218792Snp 5755308154Sjhb rc = begin_synchronized_op(sc, vi, HOLD_LOCK | SLEEP_OK | INTR_OK, 5756245274Snp "t4rxqs"); 5757245274Snp if (rc) 5758245274Snp return (rc); 5759245274Snp 5760308154Sjhb if (vi->flags & VI_INIT_DONE) 5761228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 5762245274Snp else 5763308154Sjhb vi->qsize_rxq = qsize; 5764218792Snp 5765245274Snp end_synchronized_op(sc, LOCK_HELD); 5766218792Snp return (rc); 5767218792Snp} 5768218792Snp 5769218792Snpstatic int 5770218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS) 5771218792Snp{ 5772308154Sjhb struct vi_info *vi = arg1; 5773308154Sjhb struct adapter *sc = vi->pi->adapter; 5774218792Snp int qsize, rc; 5775218792Snp 5776308154Sjhb qsize = vi->qsize_txq; 5777218792Snp 5778218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 5779218792Snp if (rc != 0 || req->newptr == NULL) 5780218792Snp return (rc); 5781218792Snp 5782284052Snp if (qsize < 128 || qsize > 65536) 5783218792Snp return (EINVAL); 5784218792Snp 5785308154Sjhb rc = begin_synchronized_op(sc, vi, HOLD_LOCK | SLEEP_OK | INTR_OK, 5786245274Snp "t4txqs"); 5787245274Snp if (rc) 5788245274Snp return (rc); 5789245274Snp 5790308154Sjhb if (vi->flags & VI_INIT_DONE) 5791228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 5792245274Snp else 5793308154Sjhb vi->qsize_txq = qsize; 5794218792Snp 5795245274Snp end_synchronized_op(sc, LOCK_HELD); 5796218792Snp return (rc); 5797218792Snp} 5798218792Snp 5799218792Snpstatic int 5800271961Snpsysctl_pause_settings(SYSCTL_HANDLER_ARGS) 5801271961Snp{ 5802271961Snp struct port_info *pi = arg1; 5803271961Snp struct adapter *sc = pi->adapter; 5804271961Snp struct link_config *lc = &pi->link_cfg; 5805271961Snp int rc; 5806271961Snp 5807271961Snp if (req->newptr == NULL) { 5808271961Snp struct sbuf *sb; 5809271961Snp static char *bits = "\20\1PAUSE_RX\2PAUSE_TX"; 5810271961Snp 5811271961Snp rc = sysctl_wire_old_buffer(req, 0); 5812271961Snp if (rc != 0) 5813271961Snp return(rc); 5814271961Snp 5815271961Snp sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 5816271961Snp if (sb == NULL) 5817271961Snp return (ENOMEM); 5818271961Snp 5819271961Snp sbuf_printf(sb, "%b", lc->fc & (PAUSE_TX | PAUSE_RX), bits); 5820271961Snp rc = sbuf_finish(sb); 5821271961Snp sbuf_delete(sb); 5822271961Snp } else { 5823271961Snp char s[2]; 5824271961Snp int n; 5825271961Snp 5826271961Snp s[0] = '0' + (lc->requested_fc & (PAUSE_TX | PAUSE_RX)); 5827271961Snp s[1] = 0; 5828271961Snp 5829271961Snp rc = sysctl_handle_string(oidp, s, sizeof(s), req); 5830271961Snp if (rc != 0) 5831271961Snp return(rc); 5832271961Snp 5833271961Snp if (s[1] != 0) 5834271961Snp return (EINVAL); 5835271961Snp if (s[0] < '0' || s[0] > '9') 5836271961Snp return (EINVAL); /* not a number */ 5837271961Snp n = s[0] - '0'; 5838271961Snp if (n & ~(PAUSE_TX | PAUSE_RX)) 5839271961Snp return (EINVAL); /* some other bit is set too */ 5840271961Snp 5841308154Sjhb rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK, 5842308154Sjhb "t4PAUSE"); 5843271961Snp if (rc) 5844271961Snp return (rc); 5845353418Snp PORT_LOCK(pi); 5846271961Snp if ((lc->requested_fc & (PAUSE_TX | PAUSE_RX)) != n) { 5847271961Snp lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX); 5848271961Snp lc->requested_fc |= n; 5849308304Sjhb rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc); 5850353418Snp if (rc == 0) { 5851353418Snp lc->fc = lc->requested_fc; 5852353418Snp set_current_media(pi, &pi->media); 5853353418Snp } 5854271961Snp } 5855353418Snp PORT_UNLOCK(pi); 5856271961Snp end_synchronized_op(sc, 0); 5857271961Snp } 5858271961Snp 5859271961Snp return (rc); 5860271961Snp} 5861271961Snp 5862271961Snpstatic int 5863311261Snpsysctl_fec(SYSCTL_HANDLER_ARGS) 5864311261Snp{ 5865311261Snp struct port_info *pi = arg1; 5866311261Snp struct adapter *sc = pi->adapter; 5867311261Snp struct link_config *lc = &pi->link_cfg; 5868311261Snp int rc; 5869311261Snp 5870311261Snp if (req->newptr == NULL) { 5871311261Snp struct sbuf *sb; 5872311261Snp static char *bits = "\20\1RS\2BASER_RS\3RESERVED"; 5873311261Snp 5874311261Snp rc = sysctl_wire_old_buffer(req, 0); 5875311261Snp if (rc != 0) 5876311261Snp return(rc); 5877311261Snp 5878311261Snp sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 5879311261Snp if (sb == NULL) 5880311261Snp return (ENOMEM); 5881311261Snp 5882311261Snp sbuf_printf(sb, "%b", lc->fec & M_FW_PORT_CAP_FEC, bits); 5883311261Snp rc = sbuf_finish(sb); 5884311261Snp sbuf_delete(sb); 5885311261Snp } else { 5886311261Snp char s[2]; 5887311261Snp int n; 5888311261Snp 5889311261Snp s[0] = '0' + (lc->requested_fec & M_FW_PORT_CAP_FEC); 5890311261Snp s[1] = 0; 5891311261Snp 5892311261Snp rc = sysctl_handle_string(oidp, s, sizeof(s), req); 5893311261Snp if (rc != 0) 5894311261Snp return(rc); 5895311261Snp 5896311261Snp if (s[1] != 0) 5897311261Snp return (EINVAL); 5898311261Snp if (s[0] < '0' || s[0] > '9') 5899311261Snp return (EINVAL); /* not a number */ 5900311261Snp n = s[0] - '0'; 5901311261Snp if (n & ~M_FW_PORT_CAP_FEC) 5902311261Snp return (EINVAL); /* some other bit is set too */ 5903353418Snp if (!powerof2(n)) 5904353418Snp return (EINVAL); /* one bit can be set at most */ 5905311261Snp 5906311261Snp rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK, 5907311261Snp "t4fec"); 5908311261Snp if (rc) 5909311261Snp return (rc); 5910353418Snp PORT_LOCK(pi); 5911311261Snp if ((lc->requested_fec & M_FW_PORT_CAP_FEC) != n) { 5912311261Snp lc->requested_fec = n & 5913311261Snp G_FW_PORT_CAP_FEC(lc->supported); 5914311261Snp rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc); 5915353418Snp if (rc == 0) { 5916353418Snp lc->fec = lc->requested_fec; 5917353418Snp } 5918311261Snp } 5919353418Snp PORT_UNLOCK(pi); 5920311261Snp end_synchronized_op(sc, 0); 5921311261Snp } 5922311261Snp 5923311261Snp return (rc); 5924311261Snp} 5925311261Snp 5926311261Snpstatic int 5927311261Snpsysctl_autoneg(SYSCTL_HANDLER_ARGS) 5928311261Snp{ 5929311261Snp struct port_info *pi = arg1; 5930311261Snp struct adapter *sc = pi->adapter; 5931311261Snp struct link_config *lc = &pi->link_cfg; 5932311261Snp int rc, val, old; 5933311261Snp 5934311261Snp if (lc->supported & FW_PORT_CAP_ANEG) 5935353418Snp val = lc->requested_aneg == AUTONEG_ENABLE ? 1 : 0; 5936311261Snp else 5937311261Snp val = -1; 5938311261Snp rc = sysctl_handle_int(oidp, &val, 0, req); 5939311261Snp if (rc != 0 || req->newptr == NULL) 5940311261Snp return (rc); 5941318855Snp if (val == 0) 5942318855Snp val = AUTONEG_DISABLE; 5943318855Snp else if (val == 1) 5944318855Snp val = AUTONEG_ENABLE; 5945318855Snp else 5946318855Snp return (EINVAL); 5947311261Snp 5948311261Snp rc = begin_synchronized_op(sc, &pi->vi[0], SLEEP_OK | INTR_OK, 5949311261Snp "t4aneg"); 5950311261Snp if (rc) 5951311261Snp return (rc); 5952353418Snp PORT_LOCK(pi); 5953353418Snp if ((lc->supported & FW_PORT_CAP_ANEG) == 0) { 5954353418Snp rc = ENOTSUP; 5955353418Snp goto done; 5956353418Snp } 5957353418Snp if (lc->requested_aneg == val) { 5958353418Snp rc = 0; /* no change, do nothing. */ 5959353418Snp goto done; 5960353418Snp } 5961353418Snp old = lc->requested_aneg; 5962353418Snp lc->requested_aneg = val; 5963311261Snp rc = -t4_link_l1cfg(sc, sc->mbox, pi->tx_chan, lc); 5964311261Snp if (rc != 0) 5965353418Snp lc->requested_aneg = old; 5966353418Snp else 5967353418Snp set_current_media(pi, &pi->media); 5968353418Snpdone: 5969353418Snp PORT_UNLOCK(pi); 5970318855Snp end_synchronized_op(sc, 0); 5971311261Snp return (rc); 5972311261Snp} 5973311261Snp 5974311261Snpstatic int 5975218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS) 5976218792Snp{ 5977218792Snp struct adapter *sc = arg1; 5978218792Snp int reg = arg2; 5979218792Snp uint64_t val; 5980218792Snp 5981218792Snp val = t4_read_reg64(sc, reg); 5982218792Snp 5983218792Snp return (sysctl_handle_64(oidp, &val, 0, req)); 5984218792Snp} 5985218792Snp 5986253890Snpstatic int 5987253890Snpsysctl_temperature(SYSCTL_HANDLER_ARGS) 5988253890Snp{ 5989253890Snp struct adapter *sc = arg1; 5990253890Snp int rc, t; 5991253890Snp uint32_t param, val; 5992253890Snp 5993253890Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4temp"); 5994253890Snp if (rc) 5995253890Snp return (rc); 5996253890Snp param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | 5997253890Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_DIAG) | 5998253890Snp V_FW_PARAMS_PARAM_Y(FW_PARAM_DEV_DIAG_TMP); 5999253890Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 6000253890Snp end_synchronized_op(sc, 0); 6001253890Snp if (rc) 6002253890Snp return (rc); 6003253890Snp 6004253890Snp /* unknown is returned as 0 but we display -1 in that case */ 6005253890Snp t = val == 0 ? -1 : val; 6006253890Snp 6007253890Snp rc = sysctl_handle_int(oidp, &t, 0, req); 6008253890Snp return (rc); 6009253890Snp} 6010253890Snp 6011231115Snp#ifdef SBUF_DRAIN 6012228561Snpstatic int 6013228561Snpsysctl_cctrl(SYSCTL_HANDLER_ARGS) 6014228561Snp{ 6015228561Snp struct adapter *sc = arg1; 6016228561Snp struct sbuf *sb; 6017228561Snp int rc, i; 6018228561Snp uint16_t incr[NMTUS][NCCTRL_WIN]; 6019228561Snp static const char *dec_fac[] = { 6020228561Snp "0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875", 6021228561Snp "0.9375" 6022228561Snp }; 6023228561Snp 6024228561Snp rc = sysctl_wire_old_buffer(req, 0); 6025228561Snp if (rc != 0) 6026228561Snp return (rc); 6027228561Snp 6028228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6029228561Snp if (sb == NULL) 6030228561Snp return (ENOMEM); 6031228561Snp 6032228561Snp t4_read_cong_tbl(sc, incr); 6033228561Snp 6034228561Snp for (i = 0; i < NCCTRL_WIN; ++i) { 6035228561Snp sbuf_printf(sb, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i, 6036228561Snp incr[0][i], incr[1][i], incr[2][i], incr[3][i], incr[4][i], 6037228561Snp incr[5][i], incr[6][i], incr[7][i]); 6038228561Snp sbuf_printf(sb, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n", 6039228561Snp incr[8][i], incr[9][i], incr[10][i], incr[11][i], 6040228561Snp incr[12][i], incr[13][i], incr[14][i], incr[15][i], 6041228561Snp sc->params.a_wnd[i], dec_fac[sc->params.b_wnd[i]]); 6042228561Snp } 6043228561Snp 6044228561Snp rc = sbuf_finish(sb); 6045228561Snp sbuf_delete(sb); 6046228561Snp 6047228561Snp return (rc); 6048228561Snp} 6049228561Snp 6050248925Snpstatic const char *qname[CIM_NUM_IBQ + CIM_NUM_OBQ_T5] = { 6051247122Snp "TP0", "TP1", "ULP", "SGE0", "SGE1", "NC-SI", /* ibq's */ 6052248925Snp "ULP0", "ULP1", "ULP2", "ULP3", "SGE", "NC-SI", /* obq's */ 6053248925Snp "SGE0-RX", "SGE1-RX" /* additional obq's (T5 onwards) */ 6054247122Snp}; 6055247122Snp 6056228561Snpstatic int 6057247122Snpsysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS) 6058247122Snp{ 6059247122Snp struct adapter *sc = arg1; 6060247122Snp struct sbuf *sb; 6061247122Snp int rc, i, n, qid = arg2; 6062247122Snp uint32_t *buf, *p; 6063247122Snp char *qtype; 6064308304Sjhb u_int cim_num_obq = sc->chip_params->cim_num_obq; 6065247122Snp 6066248925Snp KASSERT(qid >= 0 && qid < CIM_NUM_IBQ + cim_num_obq, 6067247122Snp ("%s: bad qid %d\n", __func__, qid)); 6068247122Snp 6069247122Snp if (qid < CIM_NUM_IBQ) { 6070247122Snp /* inbound queue */ 6071247122Snp qtype = "IBQ"; 6072247122Snp n = 4 * CIM_IBQ_SIZE; 6073247122Snp buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); 6074247122Snp rc = t4_read_cim_ibq(sc, qid, buf, n); 6075247122Snp } else { 6076247122Snp /* outbound queue */ 6077247122Snp qtype = "OBQ"; 6078247122Snp qid -= CIM_NUM_IBQ; 6079248925Snp n = 4 * cim_num_obq * CIM_OBQ_SIZE; 6080247122Snp buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); 6081247122Snp rc = t4_read_cim_obq(sc, qid, buf, n); 6082247122Snp } 6083247122Snp 6084247122Snp if (rc < 0) { 6085247122Snp rc = -rc; 6086247122Snp goto done; 6087247122Snp } 6088247122Snp n = rc * sizeof(uint32_t); /* rc has # of words actually read */ 6089247122Snp 6090247122Snp rc = sysctl_wire_old_buffer(req, 0); 6091247122Snp if (rc != 0) 6092247122Snp goto done; 6093247122Snp 6094248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req); 6095247122Snp if (sb == NULL) { 6096247122Snp rc = ENOMEM; 6097247122Snp goto done; 6098247122Snp } 6099247122Snp 6100247122Snp sbuf_printf(sb, "%s%d %s", qtype , qid, qname[arg2]); 6101247122Snp for (i = 0, p = buf; i < n; i += 16, p += 4) 6102247122Snp sbuf_printf(sb, "\n%#06x: %08x %08x %08x %08x", i, p[0], p[1], 6103247122Snp p[2], p[3]); 6104247122Snp 6105247122Snp rc = sbuf_finish(sb); 6106247122Snp sbuf_delete(sb); 6107247122Snpdone: 6108247122Snp free(buf, M_CXGBE); 6109247122Snp return (rc); 6110247122Snp} 6111247122Snp 6112247122Snpstatic int 6113247122Snpsysctl_cim_la(SYSCTL_HANDLER_ARGS) 6114247122Snp{ 6115247122Snp struct adapter *sc = arg1; 6116247122Snp u_int cfg; 6117247122Snp struct sbuf *sb; 6118247122Snp uint32_t *buf, *p; 6119247122Snp int rc; 6120247122Snp 6121308304Sjhb MPASS(chip_id(sc) <= CHELSIO_T5); 6122308304Sjhb 6123247122Snp rc = -t4_cim_read(sc, A_UP_UP_DBG_LA_CFG, 1, &cfg); 6124247122Snp if (rc != 0) 6125247122Snp return (rc); 6126247122Snp 6127247122Snp rc = sysctl_wire_old_buffer(req, 0); 6128247122Snp if (rc != 0) 6129247122Snp return (rc); 6130247122Snp 6131247122Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6132247122Snp if (sb == NULL) 6133247122Snp return (ENOMEM); 6134247122Snp 6135247122Snp buf = malloc(sc->params.cim_la_size * sizeof(uint32_t), M_CXGBE, 6136247122Snp M_ZERO | M_WAITOK); 6137247122Snp 6138247122Snp rc = -t4_cim_read_la(sc, buf, NULL); 6139247122Snp if (rc != 0) 6140247122Snp goto done; 6141247122Snp 6142247122Snp sbuf_printf(sb, "Status Data PC%s", 6143247122Snp cfg & F_UPDBGLACAPTPCONLY ? "" : 6144247122Snp " LS0Stat LS0Addr LS0Data"); 6145247122Snp 6146308304Sjhb for (p = buf; p <= &buf[sc->params.cim_la_size - 8]; p += 8) { 6147247122Snp if (cfg & F_UPDBGLACAPTPCONLY) { 6148247122Snp sbuf_printf(sb, "\n %02x %08x %08x", p[5] & 0xff, 6149247122Snp p[6], p[7]); 6150247122Snp sbuf_printf(sb, "\n %02x %02x%06x %02x%06x", 6151247122Snp (p[3] >> 8) & 0xff, p[3] & 0xff, p[4] >> 8, 6152247122Snp p[4] & 0xff, p[5] >> 8); 6153247122Snp sbuf_printf(sb, "\n %02x %x%07x %x%07x", 6154247122Snp (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, 6155247122Snp p[1] & 0xf, p[2] >> 4); 6156247122Snp } else { 6157247122Snp sbuf_printf(sb, 6158247122Snp "\n %02x %x%07x %x%07x %08x %08x " 6159247122Snp "%08x%08x%08x%08x", 6160247122Snp (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, 6161247122Snp p[1] & 0xf, p[2] >> 4, p[2] & 0xf, p[3], p[4], p[5], 6162247122Snp p[6], p[7]); 6163247122Snp } 6164247122Snp } 6165247122Snp 6166247122Snp rc = sbuf_finish(sb); 6167247122Snp sbuf_delete(sb); 6168247122Snpdone: 6169247122Snp free(buf, M_CXGBE); 6170247122Snp return (rc); 6171247122Snp} 6172247122Snp 6173247122Snpstatic int 6174308304Sjhbsysctl_cim_la_t6(SYSCTL_HANDLER_ARGS) 6175308304Sjhb{ 6176308304Sjhb struct adapter *sc = arg1; 6177308304Sjhb u_int cfg; 6178308304Sjhb struct sbuf *sb; 6179308304Sjhb uint32_t *buf, *p; 6180308304Sjhb int rc; 6181308304Sjhb 6182308304Sjhb MPASS(chip_id(sc) > CHELSIO_T5); 6183308304Sjhb 6184308304Sjhb rc = -t4_cim_read(sc, A_UP_UP_DBG_LA_CFG, 1, &cfg); 6185308304Sjhb if (rc != 0) 6186308304Sjhb return (rc); 6187308304Sjhb 6188308304Sjhb rc = sysctl_wire_old_buffer(req, 0); 6189308304Sjhb if (rc != 0) 6190308304Sjhb return (rc); 6191308304Sjhb 6192308304Sjhb sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6193308304Sjhb if (sb == NULL) 6194308304Sjhb return (ENOMEM); 6195308304Sjhb 6196308304Sjhb buf = malloc(sc->params.cim_la_size * sizeof(uint32_t), M_CXGBE, 6197308304Sjhb M_ZERO | M_WAITOK); 6198308304Sjhb 6199308304Sjhb rc = -t4_cim_read_la(sc, buf, NULL); 6200308304Sjhb if (rc != 0) 6201308304Sjhb goto done; 6202308304Sjhb 6203308304Sjhb sbuf_printf(sb, "Status Inst Data PC%s", 6204308304Sjhb cfg & F_UPDBGLACAPTPCONLY ? "" : 6205308304Sjhb " LS0Stat LS0Addr LS0Data LS1Stat LS1Addr LS1Data"); 6206308304Sjhb 6207308304Sjhb for (p = buf; p <= &buf[sc->params.cim_la_size - 10]; p += 10) { 6208308304Sjhb if (cfg & F_UPDBGLACAPTPCONLY) { 6209308304Sjhb sbuf_printf(sb, "\n %02x %08x %08x %08x", 6210308304Sjhb p[3] & 0xff, p[2], p[1], p[0]); 6211308304Sjhb sbuf_printf(sb, "\n %02x %02x%06x %02x%06x %02x%06x", 6212308304Sjhb (p[6] >> 8) & 0xff, p[6] & 0xff, p[5] >> 8, 6213308304Sjhb p[5] & 0xff, p[4] >> 8, p[4] & 0xff, p[3] >> 8); 6214308304Sjhb sbuf_printf(sb, "\n %02x %04x%04x %04x%04x %04x%04x", 6215308304Sjhb (p[9] >> 16) & 0xff, p[9] & 0xffff, p[8] >> 16, 6216308304Sjhb p[8] & 0xffff, p[7] >> 16, p[7] & 0xffff, 6217308304Sjhb p[6] >> 16); 6218308304Sjhb } else { 6219308304Sjhb sbuf_printf(sb, "\n %02x %04x%04x %04x%04x %04x%04x " 6220308304Sjhb "%08x %08x %08x %08x %08x %08x", 6221308304Sjhb (p[9] >> 16) & 0xff, 6222308304Sjhb p[9] & 0xffff, p[8] >> 16, 6223308304Sjhb p[8] & 0xffff, p[7] >> 16, 6224308304Sjhb p[7] & 0xffff, p[6] >> 16, 6225308304Sjhb p[2], p[1], p[0], p[5], p[4], p[3]); 6226308304Sjhb } 6227308304Sjhb } 6228308304Sjhb 6229308304Sjhb rc = sbuf_finish(sb); 6230308304Sjhb sbuf_delete(sb); 6231308304Sjhbdone: 6232308304Sjhb free(buf, M_CXGBE); 6233308304Sjhb return (rc); 6234308304Sjhb} 6235308304Sjhb 6236308304Sjhbstatic int 6237251213Snpsysctl_cim_ma_la(SYSCTL_HANDLER_ARGS) 6238251213Snp{ 6239251213Snp struct adapter *sc = arg1; 6240251213Snp u_int i; 6241251213Snp struct sbuf *sb; 6242251213Snp uint32_t *buf, *p; 6243251213Snp int rc; 6244251213Snp 6245251213Snp rc = sysctl_wire_old_buffer(req, 0); 6246251213Snp if (rc != 0) 6247251213Snp return (rc); 6248251213Snp 6249251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6250251213Snp if (sb == NULL) 6251251213Snp return (ENOMEM); 6252251213Snp 6253251213Snp buf = malloc(2 * CIM_MALA_SIZE * 5 * sizeof(uint32_t), M_CXGBE, 6254251213Snp M_ZERO | M_WAITOK); 6255251213Snp 6256251213Snp t4_cim_read_ma_la(sc, buf, buf + 5 * CIM_MALA_SIZE); 6257251213Snp p = buf; 6258251213Snp 6259251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) { 6260251213Snp sbuf_printf(sb, "\n%02x%08x%08x%08x%08x", p[4], p[3], p[2], 6261251213Snp p[1], p[0]); 6262251213Snp } 6263251213Snp 6264251213Snp sbuf_printf(sb, "\n\nCnt ID Tag UE Data RDY VLD"); 6265251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) { 6266251213Snp sbuf_printf(sb, "\n%3u %2u %x %u %08x%08x %u %u", 6267251213Snp (p[2] >> 10) & 0xff, (p[2] >> 7) & 7, 6268251213Snp (p[2] >> 3) & 0xf, (p[2] >> 2) & 1, 6269251213Snp (p[1] >> 2) | ((p[2] & 3) << 30), 6270251213Snp (p[0] >> 2) | ((p[1] & 3) << 30), (p[0] >> 1) & 1, 6271251213Snp p[0] & 1); 6272251213Snp } 6273251213Snp 6274251213Snp rc = sbuf_finish(sb); 6275251213Snp sbuf_delete(sb); 6276251213Snp free(buf, M_CXGBE); 6277251213Snp return (rc); 6278251213Snp} 6279251213Snp 6280251213Snpstatic int 6281251213Snpsysctl_cim_pif_la(SYSCTL_HANDLER_ARGS) 6282251213Snp{ 6283251213Snp struct adapter *sc = arg1; 6284251213Snp u_int i; 6285251213Snp struct sbuf *sb; 6286251213Snp uint32_t *buf, *p; 6287251213Snp int rc; 6288251213Snp 6289251213Snp rc = sysctl_wire_old_buffer(req, 0); 6290251213Snp if (rc != 0) 6291251213Snp return (rc); 6292251213Snp 6293251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6294251213Snp if (sb == NULL) 6295251213Snp return (ENOMEM); 6296251213Snp 6297251213Snp buf = malloc(2 * CIM_PIFLA_SIZE * 6 * sizeof(uint32_t), M_CXGBE, 6298251213Snp M_ZERO | M_WAITOK); 6299251213Snp 6300251213Snp t4_cim_read_pif_la(sc, buf, buf + 6 * CIM_PIFLA_SIZE, NULL, NULL); 6301251213Snp p = buf; 6302251213Snp 6303251213Snp sbuf_printf(sb, "Cntl ID DataBE Addr Data"); 6304308304Sjhb for (i = 0; i < CIM_PIFLA_SIZE; i++, p += 6) { 6305251213Snp sbuf_printf(sb, "\n %02x %02x %04x %08x %08x%08x%08x%08x", 6306251213Snp (p[5] >> 22) & 0xff, (p[5] >> 16) & 0x3f, p[5] & 0xffff, 6307251213Snp p[4], p[3], p[2], p[1], p[0]); 6308251213Snp } 6309251213Snp 6310251213Snp sbuf_printf(sb, "\n\nCntl ID Data"); 6311308304Sjhb for (i = 0; i < CIM_PIFLA_SIZE; i++, p += 6) { 6312251213Snp sbuf_printf(sb, "\n %02x %02x %08x%08x%08x%08x", 6313251213Snp (p[4] >> 6) & 0xff, p[4] & 0x3f, p[3], p[2], p[1], p[0]); 6314251213Snp } 6315251213Snp 6316251213Snp rc = sbuf_finish(sb); 6317251213Snp sbuf_delete(sb); 6318251213Snp free(buf, M_CXGBE); 6319251213Snp return (rc); 6320251213Snp} 6321251213Snp 6322251213Snpstatic int 6323247122Snpsysctl_cim_qcfg(SYSCTL_HANDLER_ARGS) 6324247122Snp{ 6325247122Snp struct adapter *sc = arg1; 6326247122Snp struct sbuf *sb; 6327247122Snp int rc, i; 6328248925Snp uint16_t base[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; 6329248925Snp uint16_t size[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; 6330247122Snp uint16_t thres[CIM_NUM_IBQ]; 6331248925Snp uint32_t obq_wr[2 * CIM_NUM_OBQ_T5], *wr = obq_wr; 6332248925Snp uint32_t stat[4 * (CIM_NUM_IBQ + CIM_NUM_OBQ_T5)], *p = stat; 6333248925Snp u_int cim_num_obq, ibq_rdaddr, obq_rdaddr, nq; 6334247122Snp 6335308304Sjhb cim_num_obq = sc->chip_params->cim_num_obq; 6336248925Snp if (is_t4(sc)) { 6337248925Snp ibq_rdaddr = A_UP_IBQ_0_RDADDR; 6338248925Snp obq_rdaddr = A_UP_OBQ_0_REALADDR; 6339248925Snp } else { 6340248925Snp ibq_rdaddr = A_UP_IBQ_0_SHADOW_RDADDR; 6341248925Snp obq_rdaddr = A_UP_OBQ_0_SHADOW_REALADDR; 6342248925Snp } 6343248925Snp nq = CIM_NUM_IBQ + cim_num_obq; 6344248925Snp 6345248925Snp rc = -t4_cim_read(sc, ibq_rdaddr, 4 * nq, stat); 6346247122Snp if (rc == 0) 6347248925Snp rc = -t4_cim_read(sc, obq_rdaddr, 2 * cim_num_obq, obq_wr); 6348247122Snp if (rc != 0) 6349247122Snp return (rc); 6350247122Snp 6351247122Snp t4_read_cimq_cfg(sc, base, size, thres); 6352247122Snp 6353247122Snp rc = sysctl_wire_old_buffer(req, 0); 6354247122Snp if (rc != 0) 6355247122Snp return (rc); 6356247122Snp 6357248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req); 6358247122Snp if (sb == NULL) 6359247122Snp return (ENOMEM); 6360247122Snp 6361309458Sjhb sbuf_printf(sb, 6362309458Sjhb " Queue Base Size Thres RdPtr WrPtr SOP EOP Avail"); 6363247122Snp 6364247122Snp for (i = 0; i < CIM_NUM_IBQ; i++, p += 4) 6365248925Snp sbuf_printf(sb, "\n%7s %5x %5u %5u %6x %4x %4u %4u %5u", 6366247122Snp qname[i], base[i], size[i], thres[i], G_IBQRDADDR(p[0]), 6367247122Snp G_IBQWRADDR(p[1]), G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), 6368247122Snp G_QUEREMFLITS(p[2]) * 16); 6369248925Snp for ( ; i < nq; i++, p += 4, wr += 2) 6370248925Snp sbuf_printf(sb, "\n%7s %5x %5u %12x %4x %4u %4u %5u", qname[i], 6371247122Snp base[i], size[i], G_QUERDADDR(p[0]) & 0x3fff, 6372247122Snp wr[0] - base[i], G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), 6373247122Snp G_QUEREMFLITS(p[2]) * 16); 6374247122Snp 6375247122Snp rc = sbuf_finish(sb); 6376247122Snp sbuf_delete(sb); 6377247122Snp 6378247122Snp return (rc); 6379247122Snp} 6380247122Snp 6381247122Snpstatic int 6382228561Snpsysctl_cpl_stats(SYSCTL_HANDLER_ARGS) 6383228561Snp{ 6384228561Snp struct adapter *sc = arg1; 6385228561Snp struct sbuf *sb; 6386228561Snp int rc; 6387228561Snp struct tp_cpl_stats stats; 6388228561Snp 6389228561Snp rc = sysctl_wire_old_buffer(req, 0); 6390228561Snp if (rc != 0) 6391228561Snp return (rc); 6392228561Snp 6393228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6394228561Snp if (sb == NULL) 6395228561Snp return (ENOMEM); 6396228561Snp 6397308305Sjhb mtx_lock(&sc->reg_lock); 6398353418Snp t4_tp_get_cpl_stats(sc, &stats, 0); 6399308305Sjhb mtx_unlock(&sc->reg_lock); 6400228561Snp 6401308304Sjhb if (sc->chip_params->nchan > 2) { 6402308304Sjhb sbuf_printf(sb, " channel 0 channel 1" 6403308304Sjhb " channel 2 channel 3"); 6404308304Sjhb sbuf_printf(sb, "\nCPL requests: %10u %10u %10u %10u", 6405308304Sjhb stats.req[0], stats.req[1], stats.req[2], stats.req[3]); 6406308304Sjhb sbuf_printf(sb, "\nCPL responses: %10u %10u %10u %10u", 6407308304Sjhb stats.rsp[0], stats.rsp[1], stats.rsp[2], stats.rsp[3]); 6408308304Sjhb } else { 6409308304Sjhb sbuf_printf(sb, " channel 0 channel 1"); 6410308304Sjhb sbuf_printf(sb, "\nCPL requests: %10u %10u", 6411308304Sjhb stats.req[0], stats.req[1]); 6412308304Sjhb sbuf_printf(sb, "\nCPL responses: %10u %10u", 6413308304Sjhb stats.rsp[0], stats.rsp[1]); 6414308304Sjhb } 6415228561Snp 6416228561Snp rc = sbuf_finish(sb); 6417228561Snp sbuf_delete(sb); 6418228561Snp 6419228561Snp return (rc); 6420228561Snp} 6421228561Snp 6422228561Snpstatic int 6423228561Snpsysctl_ddp_stats(SYSCTL_HANDLER_ARGS) 6424228561Snp{ 6425228561Snp struct adapter *sc = arg1; 6426228561Snp struct sbuf *sb; 6427228561Snp int rc; 6428228561Snp struct tp_usm_stats stats; 6429228561Snp 6430228561Snp rc = sysctl_wire_old_buffer(req, 0); 6431228561Snp if (rc != 0) 6432228561Snp return(rc); 6433228561Snp 6434228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6435228561Snp if (sb == NULL) 6436228561Snp return (ENOMEM); 6437228561Snp 6438353418Snp t4_get_usm_stats(sc, &stats, 1); 6439228561Snp 6440228561Snp sbuf_printf(sb, "Frames: %u\n", stats.frames); 6441228561Snp sbuf_printf(sb, "Octets: %ju\n", stats.octets); 6442228561Snp sbuf_printf(sb, "Drops: %u", stats.drops); 6443228561Snp 6444228561Snp rc = sbuf_finish(sb); 6445228561Snp sbuf_delete(sb); 6446228561Snp 6447228561Snp return (rc); 6448228561Snp} 6449228561Snp 6450308305Sjhbstatic const char * const devlog_level_strings[] = { 6451222551Snp [FW_DEVLOG_LEVEL_EMERG] = "EMERG", 6452222551Snp [FW_DEVLOG_LEVEL_CRIT] = "CRIT", 6453222551Snp [FW_DEVLOG_LEVEL_ERR] = "ERR", 6454222551Snp [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", 6455222551Snp [FW_DEVLOG_LEVEL_INFO] = "INFO", 6456222551Snp [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" 6457222551Snp}; 6458222551Snp 6459308305Sjhbstatic const char * const devlog_facility_strings[] = { 6460222551Snp [FW_DEVLOG_FACILITY_CORE] = "CORE", 6461268823Snp [FW_DEVLOG_FACILITY_CF] = "CF", 6462222551Snp [FW_DEVLOG_FACILITY_SCHED] = "SCHED", 6463222551Snp [FW_DEVLOG_FACILITY_TIMER] = "TIMER", 6464222551Snp [FW_DEVLOG_FACILITY_RES] = "RES", 6465222551Snp [FW_DEVLOG_FACILITY_HW] = "HW", 6466222551Snp [FW_DEVLOG_FACILITY_FLR] = "FLR", 6467222551Snp [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", 6468222551Snp [FW_DEVLOG_FACILITY_PHY] = "PHY", 6469222551Snp [FW_DEVLOG_FACILITY_MAC] = "MAC", 6470222551Snp [FW_DEVLOG_FACILITY_PORT] = "PORT", 6471222551Snp [FW_DEVLOG_FACILITY_VI] = "VI", 6472222551Snp [FW_DEVLOG_FACILITY_FILTER] = "FILTER", 6473222551Snp [FW_DEVLOG_FACILITY_ACL] = "ACL", 6474222551Snp [FW_DEVLOG_FACILITY_TM] = "TM", 6475222551Snp [FW_DEVLOG_FACILITY_QFC] = "QFC", 6476222551Snp [FW_DEVLOG_FACILITY_DCB] = "DCB", 6477222551Snp [FW_DEVLOG_FACILITY_ETH] = "ETH", 6478222551Snp [FW_DEVLOG_FACILITY_OFLD] = "OFLD", 6479222551Snp [FW_DEVLOG_FACILITY_RI] = "RI", 6480222551Snp [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", 6481222551Snp [FW_DEVLOG_FACILITY_FCOE] = "FCOE", 6482222551Snp [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", 6483308305Sjhb [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE", 6484308305Sjhb [FW_DEVLOG_FACILITY_CHNET] = "CHNET", 6485222551Snp}; 6486222551Snp 6487222551Snpstatic int 6488222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS) 6489222551Snp{ 6490222551Snp struct adapter *sc = arg1; 6491222551Snp struct devlog_params *dparams = &sc->params.devlog; 6492222551Snp struct fw_devlog_e *buf, *e; 6493308305Sjhb int i, j, rc, nentries, first = 0; 6494222551Snp struct sbuf *sb; 6495222551Snp uint64_t ftstamp = UINT64_MAX; 6496222551Snp 6497308305Sjhb if (dparams->addr == 0) 6498308305Sjhb return (ENXIO); 6499222551Snp 6500222551Snp buf = malloc(dparams->size, M_CXGBE, M_NOWAIT); 6501222551Snp if (buf == NULL) 6502222551Snp return (ENOMEM); 6503222551Snp 6504308305Sjhb rc = read_via_memwin(sc, 1, dparams->addr, (void *)buf, dparams->size); 6505222551Snp if (rc != 0) 6506222551Snp goto done; 6507222551Snp 6508308305Sjhb nentries = dparams->size / sizeof(struct fw_devlog_e); 6509222551Snp for (i = 0; i < nentries; i++) { 6510222551Snp e = &buf[i]; 6511222551Snp 6512222551Snp if (e->timestamp == 0) 6513222551Snp break; /* end */ 6514222551Snp 6515222551Snp e->timestamp = be64toh(e->timestamp); 6516222551Snp e->seqno = be32toh(e->seqno); 6517222551Snp for (j = 0; j < 8; j++) 6518222551Snp e->params[j] = be32toh(e->params[j]); 6519222551Snp 6520222551Snp if (e->timestamp < ftstamp) { 6521222551Snp ftstamp = e->timestamp; 6522222551Snp first = i; 6523222551Snp } 6524222551Snp } 6525222551Snp 6526222551Snp if (buf[first].timestamp == 0) 6527222551Snp goto done; /* nothing in the log */ 6528222551Snp 6529222551Snp rc = sysctl_wire_old_buffer(req, 0); 6530222551Snp if (rc != 0) 6531222551Snp goto done; 6532222551Snp 6533222551Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6534228561Snp if (sb == NULL) { 6535228561Snp rc = ENOMEM; 6536228561Snp goto done; 6537228561Snp } 6538228561Snp sbuf_printf(sb, "%10s %15s %8s %8s %s\n", 6539222551Snp "Seq#", "Tstamp", "Level", "Facility", "Message"); 6540222551Snp 6541222551Snp i = first; 6542222551Snp do { 6543222551Snp e = &buf[i]; 6544222551Snp if (e->timestamp == 0) 6545222551Snp break; /* end */ 6546222551Snp 6547222551Snp sbuf_printf(sb, "%10d %15ju %8s %8s ", 6548222551Snp e->seqno, e->timestamp, 6549240452Snp (e->level < nitems(devlog_level_strings) ? 6550222551Snp devlog_level_strings[e->level] : "UNKNOWN"), 6551240452Snp (e->facility < nitems(devlog_facility_strings) ? 6552222551Snp devlog_facility_strings[e->facility] : "UNKNOWN")); 6553222551Snp sbuf_printf(sb, e->fmt, e->params[0], e->params[1], 6554222551Snp e->params[2], e->params[3], e->params[4], 6555222551Snp e->params[5], e->params[6], e->params[7]); 6556222551Snp 6557222551Snp if (++i == nentries) 6558222551Snp i = 0; 6559222551Snp } while (i != first); 6560222551Snp 6561222551Snp rc = sbuf_finish(sb); 6562222551Snp sbuf_delete(sb); 6563222551Snpdone: 6564222551Snp free(buf, M_CXGBE); 6565222551Snp return (rc); 6566222551Snp} 6567222551Snp 6568228561Snpstatic int 6569228561Snpsysctl_fcoe_stats(SYSCTL_HANDLER_ARGS) 6570228561Snp{ 6571228561Snp struct adapter *sc = arg1; 6572228561Snp struct sbuf *sb; 6573228561Snp int rc; 6574308304Sjhb struct tp_fcoe_stats stats[MAX_NCHAN]; 6575308304Sjhb int i, nchan = sc->chip_params->nchan; 6576228561Snp 6577228561Snp rc = sysctl_wire_old_buffer(req, 0); 6578228561Snp if (rc != 0) 6579228561Snp return (rc); 6580228561Snp 6581228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6582228561Snp if (sb == NULL) 6583228561Snp return (ENOMEM); 6584228561Snp 6585308304Sjhb for (i = 0; i < nchan; i++) 6586353418Snp t4_get_fcoe_stats(sc, i, &stats[i], 1); 6587228561Snp 6588308304Sjhb if (nchan > 2) { 6589308304Sjhb sbuf_printf(sb, " channel 0 channel 1" 6590308304Sjhb " channel 2 channel 3"); 6591308304Sjhb sbuf_printf(sb, "\noctetsDDP: %16ju %16ju %16ju %16ju", 6592308304Sjhb stats[0].octets_ddp, stats[1].octets_ddp, 6593308304Sjhb stats[2].octets_ddp, stats[3].octets_ddp); 6594308304Sjhb sbuf_printf(sb, "\nframesDDP: %16u %16u %16u %16u", 6595308304Sjhb stats[0].frames_ddp, stats[1].frames_ddp, 6596308304Sjhb stats[2].frames_ddp, stats[3].frames_ddp); 6597308304Sjhb sbuf_printf(sb, "\nframesDrop: %16u %16u %16u %16u", 6598308304Sjhb stats[0].frames_drop, stats[1].frames_drop, 6599308304Sjhb stats[2].frames_drop, stats[3].frames_drop); 6600308304Sjhb } else { 6601308304Sjhb sbuf_printf(sb, " channel 0 channel 1"); 6602308304Sjhb sbuf_printf(sb, "\noctetsDDP: %16ju %16ju", 6603308304Sjhb stats[0].octets_ddp, stats[1].octets_ddp); 6604308304Sjhb sbuf_printf(sb, "\nframesDDP: %16u %16u", 6605308304Sjhb stats[0].frames_ddp, stats[1].frames_ddp); 6606308304Sjhb sbuf_printf(sb, "\nframesDrop: %16u %16u", 6607308304Sjhb stats[0].frames_drop, stats[1].frames_drop); 6608308304Sjhb } 6609228561Snp 6610228561Snp rc = sbuf_finish(sb); 6611228561Snp sbuf_delete(sb); 6612228561Snp 6613228561Snp return (rc); 6614228561Snp} 6615228561Snp 6616228561Snpstatic int 6617228561Snpsysctl_hw_sched(SYSCTL_HANDLER_ARGS) 6618228561Snp{ 6619228561Snp struct adapter *sc = arg1; 6620228561Snp struct sbuf *sb; 6621228561Snp int rc, i; 6622228561Snp unsigned int map, kbps, ipg, mode; 6623228561Snp unsigned int pace_tab[NTX_SCHED]; 6624228561Snp 6625228561Snp rc = sysctl_wire_old_buffer(req, 0); 6626228561Snp if (rc != 0) 6627228561Snp return (rc); 6628228561Snp 6629228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6630228561Snp if (sb == NULL) 6631228561Snp return (ENOMEM); 6632228561Snp 6633228561Snp map = t4_read_reg(sc, A_TP_TX_MOD_QUEUE_REQ_MAP); 6634228561Snp mode = G_TIMERMODE(t4_read_reg(sc, A_TP_MOD_CONFIG)); 6635228561Snp t4_read_pace_tbl(sc, pace_tab); 6636228561Snp 6637228561Snp sbuf_printf(sb, "Scheduler Mode Channel Rate (Kbps) " 6638228561Snp "Class IPG (0.1 ns) Flow IPG (us)"); 6639228561Snp 6640228561Snp for (i = 0; i < NTX_SCHED; ++i, map >>= 2) { 6641353418Snp t4_get_tx_sched(sc, i, &kbps, &ipg, 1); 6642228561Snp sbuf_printf(sb, "\n %u %-5s %u ", i, 6643228561Snp (mode & (1 << i)) ? "flow" : "class", map & 3); 6644228561Snp if (kbps) 6645228561Snp sbuf_printf(sb, "%9u ", kbps); 6646228561Snp else 6647228561Snp sbuf_printf(sb, " disabled "); 6648228561Snp 6649228561Snp if (ipg) 6650228561Snp sbuf_printf(sb, "%13u ", ipg); 6651228561Snp else 6652228561Snp sbuf_printf(sb, " disabled "); 6653228561Snp 6654228561Snp if (pace_tab[i]) 6655228561Snp sbuf_printf(sb, "%10u", pace_tab[i]); 6656228561Snp else 6657228561Snp sbuf_printf(sb, " disabled"); 6658228561Snp } 6659228561Snp 6660228561Snp rc = sbuf_finish(sb); 6661228561Snp sbuf_delete(sb); 6662228561Snp 6663228561Snp return (rc); 6664228561Snp} 6665228561Snp 6666228561Snpstatic int 6667228561Snpsysctl_lb_stats(SYSCTL_HANDLER_ARGS) 6668228561Snp{ 6669228561Snp struct adapter *sc = arg1; 6670228561Snp struct sbuf *sb; 6671228561Snp int rc, i, j; 6672228561Snp uint64_t *p0, *p1; 6673228561Snp struct lb_port_stats s[2]; 6674228561Snp static const char *stat_name[] = { 6675228561Snp "OctetsOK:", "FramesOK:", "BcastFrames:", "McastFrames:", 6676228561Snp "UcastFrames:", "ErrorFrames:", "Frames64:", "Frames65To127:", 6677228561Snp "Frames128To255:", "Frames256To511:", "Frames512To1023:", 6678228561Snp "Frames1024To1518:", "Frames1519ToMax:", "FramesDropped:", 6679228561Snp "BG0FramesDropped:", "BG1FramesDropped:", "BG2FramesDropped:", 6680228561Snp "BG3FramesDropped:", "BG0FramesTrunc:", "BG1FramesTrunc:", 6681228561Snp "BG2FramesTrunc:", "BG3FramesTrunc:" 6682228561Snp }; 6683228561Snp 6684228561Snp rc = sysctl_wire_old_buffer(req, 0); 6685228561Snp if (rc != 0) 6686228561Snp return (rc); 6687228561Snp 6688228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6689228561Snp if (sb == NULL) 6690228561Snp return (ENOMEM); 6691228561Snp 6692228561Snp memset(s, 0, sizeof(s)); 6693228561Snp 6694308304Sjhb for (i = 0; i < sc->chip_params->nchan; i += 2) { 6695228561Snp t4_get_lb_stats(sc, i, &s[0]); 6696228561Snp t4_get_lb_stats(sc, i + 1, &s[1]); 6697228561Snp 6698228561Snp p0 = &s[0].octets; 6699228561Snp p1 = &s[1].octets; 6700228561Snp sbuf_printf(sb, "%s Loopback %u" 6701228561Snp " Loopback %u", i == 0 ? "" : "\n", i, i + 1); 6702228561Snp 6703240452Snp for (j = 0; j < nitems(stat_name); j++) 6704228561Snp sbuf_printf(sb, "\n%-17s %20ju %20ju", stat_name[j], 6705228561Snp *p0++, *p1++); 6706228561Snp } 6707228561Snp 6708228561Snp rc = sbuf_finish(sb); 6709228561Snp sbuf_delete(sb); 6710228561Snp 6711228561Snp return (rc); 6712228561Snp} 6713228561Snp 6714253701Snpstatic int 6715253701Snpsysctl_linkdnrc(SYSCTL_HANDLER_ARGS) 6716253701Snp{ 6717253701Snp int rc = 0; 6718253701Snp struct port_info *pi = arg1; 6719311261Snp struct link_config *lc = &pi->link_cfg; 6720253701Snp struct sbuf *sb; 6721253701Snp 6722253701Snp rc = sysctl_wire_old_buffer(req, 0); 6723253701Snp if (rc != 0) 6724253701Snp return(rc); 6725253701Snp sb = sbuf_new_for_sysctl(NULL, NULL, 64, req); 6726253701Snp if (sb == NULL) 6727253701Snp return (ENOMEM); 6728253701Snp 6729311261Snp if (lc->link_ok || lc->link_down_rc == 255) 6730253701Snp sbuf_printf(sb, "n/a"); 6731253701Snp else 6732311261Snp sbuf_printf(sb, "%s", t4_link_down_rc_str(lc->link_down_rc)); 6733253701Snp 6734253701Snp rc = sbuf_finish(sb); 6735253701Snp sbuf_delete(sb); 6736253701Snp 6737253701Snp return (rc); 6738253701Snp} 6739253701Snp 6740228561Snpstruct mem_desc { 6741228561Snp unsigned int base; 6742228561Snp unsigned int limit; 6743228561Snp unsigned int idx; 6744228561Snp}; 6745228561Snp 6746228561Snpstatic int 6747228561Snpmem_desc_cmp(const void *a, const void *b) 6748228561Snp{ 6749228561Snp return ((const struct mem_desc *)a)->base - 6750228561Snp ((const struct mem_desc *)b)->base; 6751228561Snp} 6752228561Snp 6753228561Snpstatic void 6754228561Snpmem_region_show(struct sbuf *sb, const char *name, unsigned int from, 6755228561Snp unsigned int to) 6756228561Snp{ 6757228561Snp unsigned int size; 6758228561Snp 6759308311Sjhb if (from == to) 6760308311Sjhb return; 6761308311Sjhb 6762228561Snp size = to - from + 1; 6763228561Snp if (size == 0) 6764228561Snp return; 6765228561Snp 6766228561Snp /* XXX: need humanize_number(3) in libkern for a more readable 'size' */ 6767228561Snp sbuf_printf(sb, "%-15s %#x-%#x [%u]\n", name, from, to, size); 6768228561Snp} 6769228561Snp 6770228561Snpstatic int 6771228561Snpsysctl_meminfo(SYSCTL_HANDLER_ARGS) 6772228561Snp{ 6773228561Snp struct adapter *sc = arg1; 6774228561Snp struct sbuf *sb; 6775228561Snp int rc, i, n; 6776248925Snp uint32_t lo, hi, used, alloc; 6777248925Snp static const char *memory[] = {"EDC0:", "EDC1:", "MC:", "MC0:", "MC1:"}; 6778228561Snp static const char *region[] = { 6779228561Snp "DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:", 6780228561Snp "Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:", 6781228561Snp "Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:", 6782228561Snp "TDDP region:", "TPT region:", "STAG region:", "RQ region:", 6783248925Snp "RQUDP region:", "PBL region:", "TXPBL region:", 6784248925Snp "DBVFIFO region:", "ULPRX state:", "ULPTX state:", 6785248925Snp "On-chip queues:" 6786228561Snp }; 6787248925Snp struct mem_desc avail[4]; 6788240452Snp struct mem_desc mem[nitems(region) + 3]; /* up to 3 holes */ 6789228561Snp struct mem_desc *md = mem; 6790228561Snp 6791228561Snp rc = sysctl_wire_old_buffer(req, 0); 6792228561Snp if (rc != 0) 6793228561Snp return (rc); 6794228561Snp 6795228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6796228561Snp if (sb == NULL) 6797228561Snp return (ENOMEM); 6798228561Snp 6799240452Snp for (i = 0; i < nitems(mem); i++) { 6800228561Snp mem[i].limit = 0; 6801228561Snp mem[i].idx = i; 6802228561Snp } 6803228561Snp 6804228561Snp /* Find and sort the populated memory ranges */ 6805228561Snp i = 0; 6806228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 6807228561Snp if (lo & F_EDRAM0_ENABLE) { 6808228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 6809228561Snp avail[i].base = G_EDRAM0_BASE(hi) << 20; 6810228561Snp avail[i].limit = avail[i].base + (G_EDRAM0_SIZE(hi) << 20); 6811228561Snp avail[i].idx = 0; 6812228561Snp i++; 6813228561Snp } 6814228561Snp if (lo & F_EDRAM1_ENABLE) { 6815228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 6816228561Snp avail[i].base = G_EDRAM1_BASE(hi) << 20; 6817228561Snp avail[i].limit = avail[i].base + (G_EDRAM1_SIZE(hi) << 20); 6818228561Snp avail[i].idx = 1; 6819228561Snp i++; 6820228561Snp } 6821228561Snp if (lo & F_EXT_MEM_ENABLE) { 6822228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 6823228561Snp avail[i].base = G_EXT_MEM_BASE(hi) << 20; 6824248925Snp avail[i].limit = avail[i].base + 6825248925Snp (G_EXT_MEM_SIZE(hi) << 20); 6826308304Sjhb avail[i].idx = is_t5(sc) ? 3 : 2; /* Call it MC0 for T5 */ 6827228561Snp i++; 6828228561Snp } 6829308304Sjhb if (is_t5(sc) && lo & F_EXT_MEM1_ENABLE) { 6830248925Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 6831248925Snp avail[i].base = G_EXT_MEM1_BASE(hi) << 20; 6832248925Snp avail[i].limit = avail[i].base + 6833248925Snp (G_EXT_MEM1_SIZE(hi) << 20); 6834248925Snp avail[i].idx = 4; 6835248925Snp i++; 6836248925Snp } 6837228561Snp if (!i) /* no memory available */ 6838228561Snp return 0; 6839228561Snp qsort(avail, i, sizeof(struct mem_desc), mem_desc_cmp); 6840228561Snp 6841228561Snp (md++)->base = t4_read_reg(sc, A_SGE_DBQ_CTXT_BADDR); 6842228561Snp (md++)->base = t4_read_reg(sc, A_SGE_IMSG_CTXT_BADDR); 6843228561Snp (md++)->base = t4_read_reg(sc, A_SGE_FLM_CACHE_BADDR); 6844228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 6845228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_BASE); 6846228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TIMER_BASE); 6847228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_RX_FLST_BASE); 6848228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_TX_FLST_BASE); 6849228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_PS_FLST_BASE); 6850228561Snp 6851228561Snp /* the next few have explicit upper bounds */ 6852228561Snp md->base = t4_read_reg(sc, A_TP_PMM_TX_BASE); 6853228561Snp md->limit = md->base - 1 + 6854228561Snp t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE) * 6855228561Snp G_PMTXMAXPAGE(t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE)); 6856228561Snp md++; 6857228561Snp 6858228561Snp md->base = t4_read_reg(sc, A_TP_PMM_RX_BASE); 6859228561Snp md->limit = md->base - 1 + 6860228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) * 6861228561Snp G_PMRXMAXPAGE(t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE)); 6862228561Snp md++; 6863228561Snp 6864228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 6865308311Sjhb if (chip_id(sc) <= CHELSIO_T5) 6866308304Sjhb md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE); 6867308311Sjhb else 6868308304Sjhb md->base = t4_read_reg(sc, A_LE_DB_HASH_TBL_BASE_ADDR); 6869308304Sjhb md->limit = 0; 6870228561Snp } else { 6871228561Snp md->base = 0; 6872240452Snp md->idx = nitems(region); /* hide it */ 6873228561Snp } 6874228561Snp md++; 6875228561Snp 6876228561Snp#define ulp_region(reg) \ 6877228561Snp md->base = t4_read_reg(sc, A_ULP_ ## reg ## _LLIMIT);\ 6878228561Snp (md++)->limit = t4_read_reg(sc, A_ULP_ ## reg ## _ULIMIT) 6879228561Snp 6880228561Snp ulp_region(RX_ISCSI); 6881228561Snp ulp_region(RX_TDDP); 6882228561Snp ulp_region(TX_TPT); 6883228561Snp ulp_region(RX_STAG); 6884228561Snp ulp_region(RX_RQ); 6885228561Snp ulp_region(RX_RQUDP); 6886228561Snp ulp_region(RX_PBL); 6887228561Snp ulp_region(TX_PBL); 6888228561Snp#undef ulp_region 6889228561Snp 6890248925Snp md->base = 0; 6891248925Snp md->idx = nitems(region); 6892308304Sjhb if (!is_t4(sc)) { 6893308304Sjhb uint32_t size = 0; 6894308304Sjhb uint32_t sge_ctrl = t4_read_reg(sc, A_SGE_CONTROL2); 6895308304Sjhb uint32_t fifo_size = t4_read_reg(sc, A_SGE_DBVFIFO_SIZE); 6896308304Sjhb 6897308304Sjhb if (is_t5(sc)) { 6898308304Sjhb if (sge_ctrl & F_VFIFO_ENABLE) 6899308304Sjhb size = G_DBVFIFO_SIZE(fifo_size); 6900308304Sjhb } else 6901308304Sjhb size = G_T6_DBVFIFO_SIZE(fifo_size); 6902308304Sjhb 6903308304Sjhb if (size) { 6904308304Sjhb md->base = G_BASEADDR(t4_read_reg(sc, 6905308304Sjhb A_SGE_DBVFIFO_BADDR)); 6906308304Sjhb md->limit = md->base + (size << 2) - 1; 6907308304Sjhb } 6908248925Snp } 6909248925Snp md++; 6910248925Snp 6911228561Snp md->base = t4_read_reg(sc, A_ULP_RX_CTX_BASE); 6912308304Sjhb md->limit = 0; 6913228561Snp md++; 6914228561Snp md->base = t4_read_reg(sc, A_ULP_TX_ERR_TABLE_BASE); 6915308304Sjhb md->limit = 0; 6916228561Snp md++; 6917228561Snp 6918228561Snp md->base = sc->vres.ocq.start; 6919228561Snp if (sc->vres.ocq.size) 6920228561Snp md->limit = md->base + sc->vres.ocq.size - 1; 6921228561Snp else 6922240452Snp md->idx = nitems(region); /* hide it */ 6923228561Snp md++; 6924228561Snp 6925228561Snp /* add any address-space holes, there can be up to 3 */ 6926228561Snp for (n = 0; n < i - 1; n++) 6927228561Snp if (avail[n].limit < avail[n + 1].base) 6928228561Snp (md++)->base = avail[n].limit; 6929228561Snp if (avail[n].limit) 6930228561Snp (md++)->base = avail[n].limit; 6931228561Snp 6932228561Snp n = md - mem; 6933228561Snp qsort(mem, n, sizeof(struct mem_desc), mem_desc_cmp); 6934228561Snp 6935228561Snp for (lo = 0; lo < i; lo++) 6936228561Snp mem_region_show(sb, memory[avail[lo].idx], avail[lo].base, 6937228561Snp avail[lo].limit - 1); 6938228561Snp 6939228561Snp sbuf_printf(sb, "\n"); 6940228561Snp for (i = 0; i < n; i++) { 6941240452Snp if (mem[i].idx >= nitems(region)) 6942228561Snp continue; /* skip holes */ 6943228561Snp if (!mem[i].limit) 6944228561Snp mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0; 6945228561Snp mem_region_show(sb, region[mem[i].idx], mem[i].base, 6946228561Snp mem[i].limit); 6947228561Snp } 6948228561Snp 6949228561Snp sbuf_printf(sb, "\n"); 6950228561Snp lo = t4_read_reg(sc, A_CIM_SDRAM_BASE_ADDR); 6951228561Snp hi = t4_read_reg(sc, A_CIM_SDRAM_ADDR_SIZE) + lo - 1; 6952228561Snp mem_region_show(sb, "uP RAM:", lo, hi); 6953228561Snp 6954228561Snp lo = t4_read_reg(sc, A_CIM_EXTMEM2_BASE_ADDR); 6955228561Snp hi = t4_read_reg(sc, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1; 6956228561Snp mem_region_show(sb, "uP Extmem2:", lo, hi); 6957228561Snp 6958228561Snp lo = t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE); 6959228561Snp sbuf_printf(sb, "\n%u Rx pages of size %uKiB for %u channels\n", 6960228561Snp G_PMRXMAXPAGE(lo), 6961228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) >> 10, 6962228561Snp (lo & F_PMRXNUMCHN) ? 2 : 1); 6963228561Snp 6964228561Snp lo = t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE); 6965228561Snp hi = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE); 6966228561Snp sbuf_printf(sb, "%u Tx pages of size %u%ciB for %u channels\n", 6967228561Snp G_PMTXMAXPAGE(lo), 6968228561Snp hi >= (1 << 20) ? (hi >> 20) : (hi >> 10), 6969228561Snp hi >= (1 << 20) ? 'M' : 'K', 1 << G_PMTXNUMCHN(lo)); 6970228561Snp sbuf_printf(sb, "%u p-structs\n", 6971228561Snp t4_read_reg(sc, A_TP_CMM_MM_MAX_PSTRUCT)); 6972228561Snp 6973228561Snp for (i = 0; i < 4; i++) { 6974308304Sjhb if (chip_id(sc) > CHELSIO_T5) 6975308304Sjhb lo = t4_read_reg(sc, A_MPS_RX_MAC_BG_PG_CNT0 + i * 4); 6976308304Sjhb else 6977308304Sjhb lo = t4_read_reg(sc, A_MPS_RX_PG_RSV0 + i * 4); 6978308304Sjhb if (is_t5(sc)) { 6979308304Sjhb used = G_T5_USED(lo); 6980308304Sjhb alloc = G_T5_ALLOC(lo); 6981308304Sjhb } else { 6982248925Snp used = G_USED(lo); 6983248925Snp alloc = G_ALLOC(lo); 6984248925Snp } 6985308304Sjhb /* For T6 these are MAC buffer groups */ 6986228561Snp sbuf_printf(sb, "\nPort %d using %u pages out of %u allocated", 6987308304Sjhb i, used, alloc); 6988228561Snp } 6989308304Sjhb for (i = 0; i < sc->chip_params->nchan; i++) { 6990308304Sjhb if (chip_id(sc) > CHELSIO_T5) 6991308304Sjhb lo = t4_read_reg(sc, A_MPS_RX_LPBK_BG_PG_CNT0 + i * 4); 6992308304Sjhb else 6993308304Sjhb lo = t4_read_reg(sc, A_MPS_RX_PG_RSV4 + i * 4); 6994308304Sjhb if (is_t5(sc)) { 6995308304Sjhb used = G_T5_USED(lo); 6996308304Sjhb alloc = G_T5_ALLOC(lo); 6997308304Sjhb } else { 6998248925Snp used = G_USED(lo); 6999248925Snp alloc = G_ALLOC(lo); 7000248925Snp } 7001308304Sjhb /* For T6 these are MAC buffer groups */ 7002228561Snp sbuf_printf(sb, 7003308304Sjhb "\nLoopback %d using %u pages out of %u allocated", 7004308304Sjhb i, used, alloc); 7005228561Snp } 7006228561Snp 7007228561Snp rc = sbuf_finish(sb); 7008228561Snp sbuf_delete(sb); 7009228561Snp 7010228561Snp return (rc); 7011228561Snp} 7012228561Snp 7013251213Snpstatic inline void 7014251213Snptcamxy2valmask(uint64_t x, uint64_t y, uint8_t *addr, uint64_t *mask) 7015251213Snp{ 7016251213Snp *mask = x | y; 7017251213Snp y = htobe64(y); 7018251213Snp memcpy(addr, (char *)&y + 2, ETHER_ADDR_LEN); 7019251213Snp} 7020251213Snp 7021228561Snpstatic int 7022251213Snpsysctl_mps_tcam(SYSCTL_HANDLER_ARGS) 7023251213Snp{ 7024251213Snp struct adapter *sc = arg1; 7025251213Snp struct sbuf *sb; 7026308304Sjhb int rc, i; 7027251213Snp 7028308304Sjhb MPASS(chip_id(sc) <= CHELSIO_T5); 7029308304Sjhb 7030251213Snp rc = sysctl_wire_old_buffer(req, 0); 7031251213Snp if (rc != 0) 7032251213Snp return (rc); 7033251213Snp 7034251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 7035251213Snp if (sb == NULL) 7036251213Snp return (ENOMEM); 7037251213Snp 7038251213Snp sbuf_printf(sb, 7039251213Snp "Idx Ethernet address Mask Vld Ports PF" 7040251213Snp " VF Replication P0 P1 P2 P3 ML"); 7041308304Sjhb for (i = 0; i < sc->chip_params->mps_tcam_size; i++) { 7042251213Snp uint64_t tcamx, tcamy, mask; 7043251213Snp uint32_t cls_lo, cls_hi; 7044251213Snp uint8_t addr[ETHER_ADDR_LEN]; 7045251213Snp 7046251213Snp tcamy = t4_read_reg64(sc, MPS_CLS_TCAM_Y_L(i)); 7047251213Snp tcamx = t4_read_reg64(sc, MPS_CLS_TCAM_X_L(i)); 7048251213Snp if (tcamx & tcamy) 7049251213Snp continue; 7050251213Snp tcamxy2valmask(tcamx, tcamy, addr, &mask); 7051308304Sjhb cls_lo = t4_read_reg(sc, MPS_CLS_SRAM_L(i)); 7052308304Sjhb cls_hi = t4_read_reg(sc, MPS_CLS_SRAM_H(i)); 7053251213Snp sbuf_printf(sb, "\n%3u %02x:%02x:%02x:%02x:%02x:%02x %012jx" 7054251213Snp " %c %#x%4u%4d", i, addr[0], addr[1], addr[2], 7055251213Snp addr[3], addr[4], addr[5], (uintmax_t)mask, 7056251213Snp (cls_lo & F_SRAM_VLD) ? 'Y' : 'N', 7057251213Snp G_PORTMAP(cls_hi), G_PF(cls_lo), 7058251213Snp (cls_lo & F_VF_VALID) ? G_VF(cls_lo) : -1); 7059251213Snp 7060251213Snp if (cls_lo & F_REPLICATE) { 7061251213Snp struct fw_ldst_cmd ldst_cmd; 7062251213Snp 7063251213Snp memset(&ldst_cmd, 0, sizeof(ldst_cmd)); 7064251213Snp ldst_cmd.op_to_addrspace = 7065251213Snp htobe32(V_FW_CMD_OP(FW_LDST_CMD) | 7066251213Snp F_FW_CMD_REQUEST | F_FW_CMD_READ | 7067251213Snp V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MPS)); 7068251213Snp ldst_cmd.cycles_to_len16 = htobe32(FW_LEN16(ldst_cmd)); 7069286895Snp ldst_cmd.u.mps.rplc.fid_idx = 7070251213Snp htobe16(V_FW_LDST_CMD_FID(FW_LDST_MPS_RPLC) | 7071286895Snp V_FW_LDST_CMD_IDX(i)); 7072251213Snp 7073251213Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, 7074251213Snp "t4mps"); 7075251213Snp if (rc) 7076251213Snp break; 7077251213Snp rc = -t4_wr_mbox(sc, sc->mbox, &ldst_cmd, 7078251213Snp sizeof(ldst_cmd), &ldst_cmd); 7079251213Snp end_synchronized_op(sc, 0); 7080251213Snp 7081251213Snp if (rc != 0) { 7082308304Sjhb sbuf_printf(sb, "%36d", rc); 7083251213Snp rc = 0; 7084251213Snp } else { 7085251213Snp sbuf_printf(sb, " %08x %08x %08x %08x", 7086286895Snp be32toh(ldst_cmd.u.mps.rplc.rplc127_96), 7087286895Snp be32toh(ldst_cmd.u.mps.rplc.rplc95_64), 7088286895Snp be32toh(ldst_cmd.u.mps.rplc.rplc63_32), 7089286895Snp be32toh(ldst_cmd.u.mps.rplc.rplc31_0)); 7090251213Snp } 7091251213Snp } else 7092251213Snp sbuf_printf(sb, "%36s", ""); 7093251213Snp 7094251213Snp sbuf_printf(sb, "%4u%3u%3u%3u %#3x", G_SRAM_PRIO0(cls_lo), 7095251213Snp G_SRAM_PRIO1(cls_lo), G_SRAM_PRIO2(cls_lo), 7096251213Snp G_SRAM_PRIO3(cls_lo), (cls_lo >> S_MULTILISTEN0) & 0xf); 7097251213Snp } 7098251213Snp 7099251213Snp if (rc) 7100251213Snp (void) sbuf_finish(sb); 7101251213Snp else 7102251213Snp rc = sbuf_finish(sb); 7103251213Snp sbuf_delete(sb); 7104251213Snp 7105251213Snp return (rc); 7106251213Snp} 7107251213Snp 7108251213Snpstatic int 7109308304Sjhbsysctl_mps_tcam_t6(SYSCTL_HANDLER_ARGS) 7110308304Sjhb{ 7111308304Sjhb struct adapter *sc = arg1; 7112308304Sjhb struct sbuf *sb; 7113308304Sjhb int rc, i; 7114308304Sjhb 7115308304Sjhb MPASS(chip_id(sc) > CHELSIO_T5); 7116308304Sjhb 7117308304Sjhb rc = sysctl_wire_old_buffer(req, 0); 7118308304Sjhb if (rc != 0) 7119308304Sjhb return (rc); 7120308304Sjhb 7121308304Sjhb sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 7122308304Sjhb if (sb == NULL) 7123308304Sjhb return (ENOMEM); 7124308304Sjhb 7125308304Sjhb sbuf_printf(sb, "Idx Ethernet address Mask VNI Mask" 7126308304Sjhb " IVLAN Vld DIP_Hit Lookup Port Vld Ports PF VF" 7127308304Sjhb " Replication" 7128308304Sjhb " P0 P1 P2 P3 ML\n"); 7129308304Sjhb 7130308304Sjhb for (i = 0; i < sc->chip_params->mps_tcam_size; i++) { 7131308304Sjhb uint8_t dip_hit, vlan_vld, lookup_type, port_num; 7132308304Sjhb uint16_t ivlan; 7133308304Sjhb uint64_t tcamx, tcamy, val, mask; 7134308304Sjhb uint32_t cls_lo, cls_hi, ctl, data2, vnix, vniy; 7135308304Sjhb uint8_t addr[ETHER_ADDR_LEN]; 7136308304Sjhb 7137308304Sjhb ctl = V_CTLREQID(1) | V_CTLCMDTYPE(0) | V_CTLXYBITSEL(0); 7138308304Sjhb if (i < 256) 7139308304Sjhb ctl |= V_CTLTCAMINDEX(i) | V_CTLTCAMSEL(0); 7140308304Sjhb else 7141308304Sjhb ctl |= V_CTLTCAMINDEX(i - 256) | V_CTLTCAMSEL(1); 7142308304Sjhb t4_write_reg(sc, A_MPS_CLS_TCAM_DATA2_CTL, ctl); 7143308304Sjhb val = t4_read_reg(sc, A_MPS_CLS_TCAM_RDATA1_REQ_ID1); 7144308304Sjhb tcamy = G_DMACH(val) << 32; 7145308304Sjhb tcamy |= t4_read_reg(sc, A_MPS_CLS_TCAM_RDATA0_REQ_ID1); 7146308304Sjhb data2 = t4_read_reg(sc, A_MPS_CLS_TCAM_RDATA2_REQ_ID1); 7147308304Sjhb lookup_type = G_DATALKPTYPE(data2); 7148308304Sjhb port_num = G_DATAPORTNUM(data2); 7149308304Sjhb if (lookup_type && lookup_type != M_DATALKPTYPE) { 7150308304Sjhb /* Inner header VNI */ 7151308304Sjhb vniy = ((data2 & F_DATAVIDH2) << 23) | 7152308304Sjhb (G_DATAVIDH1(data2) << 16) | G_VIDL(val); 7153308304Sjhb dip_hit = data2 & F_DATADIPHIT; 7154308304Sjhb vlan_vld = 0; 7155308304Sjhb } else { 7156308304Sjhb vniy = 0; 7157308304Sjhb dip_hit = 0; 7158308304Sjhb vlan_vld = data2 & F_DATAVIDH2; 7159308304Sjhb ivlan = G_VIDL(val); 7160308304Sjhb } 7161308304Sjhb 7162308304Sjhb ctl |= V_CTLXYBITSEL(1); 7163308304Sjhb t4_write_reg(sc, A_MPS_CLS_TCAM_DATA2_CTL, ctl); 7164308304Sjhb val = t4_read_reg(sc, A_MPS_CLS_TCAM_RDATA1_REQ_ID1); 7165308304Sjhb tcamx = G_DMACH(val) << 32; 7166308304Sjhb tcamx |= t4_read_reg(sc, A_MPS_CLS_TCAM_RDATA0_REQ_ID1); 7167308304Sjhb data2 = t4_read_reg(sc, A_MPS_CLS_TCAM_RDATA2_REQ_ID1); 7168308304Sjhb if (lookup_type && lookup_type != M_DATALKPTYPE) { 7169308304Sjhb /* Inner header VNI mask */ 7170308304Sjhb vnix = ((data2 & F_DATAVIDH2) << 23) | 7171308304Sjhb (G_DATAVIDH1(data2) << 16) | G_VIDL(val); 7172308304Sjhb } else 7173308304Sjhb vnix = 0; 7174308304Sjhb 7175308304Sjhb if (tcamx & tcamy) 7176308304Sjhb continue; 7177308304Sjhb tcamxy2valmask(tcamx, tcamy, addr, &mask); 7178308304Sjhb 7179308304Sjhb cls_lo = t4_read_reg(sc, MPS_CLS_SRAM_L(i)); 7180308304Sjhb cls_hi = t4_read_reg(sc, MPS_CLS_SRAM_H(i)); 7181308304Sjhb 7182308304Sjhb if (lookup_type && lookup_type != M_DATALKPTYPE) { 7183308304Sjhb sbuf_printf(sb, "\n%3u %02x:%02x:%02x:%02x:%02x:%02x " 7184308304Sjhb "%012jx %06x %06x - - %3c" 7185308304Sjhb " 'I' %4x %3c %#x%4u%4d", i, addr[0], 7186308304Sjhb addr[1], addr[2], addr[3], addr[4], addr[5], 7187308304Sjhb (uintmax_t)mask, vniy, vnix, dip_hit ? 'Y' : 'N', 7188308304Sjhb port_num, cls_lo & F_T6_SRAM_VLD ? 'Y' : 'N', 7189308304Sjhb G_PORTMAP(cls_hi), G_T6_PF(cls_lo), 7190308304Sjhb cls_lo & F_T6_VF_VALID ? G_T6_VF(cls_lo) : -1); 7191308304Sjhb } else { 7192308304Sjhb sbuf_printf(sb, "\n%3u %02x:%02x:%02x:%02x:%02x:%02x " 7193308304Sjhb "%012jx - - ", i, addr[0], addr[1], 7194308304Sjhb addr[2], addr[3], addr[4], addr[5], 7195308304Sjhb (uintmax_t)mask); 7196308304Sjhb 7197308304Sjhb if (vlan_vld) 7198308304Sjhb sbuf_printf(sb, "%4u Y ", ivlan); 7199308304Sjhb else 7200308304Sjhb sbuf_printf(sb, " - N "); 7201308304Sjhb 7202308304Sjhb sbuf_printf(sb, "- %3c %4x %3c %#x%4u%4d", 7203308304Sjhb lookup_type ? 'I' : 'O', port_num, 7204308304Sjhb cls_lo & F_T6_SRAM_VLD ? 'Y' : 'N', 7205308304Sjhb G_PORTMAP(cls_hi), G_T6_PF(cls_lo), 7206308304Sjhb cls_lo & F_T6_VF_VALID ? G_T6_VF(cls_lo) : -1); 7207308304Sjhb } 7208308304Sjhb 7209308304Sjhb 7210308304Sjhb if (cls_lo & F_T6_REPLICATE) { 7211308304Sjhb struct fw_ldst_cmd ldst_cmd; 7212308304Sjhb 7213308304Sjhb memset(&ldst_cmd, 0, sizeof(ldst_cmd)); 7214308304Sjhb ldst_cmd.op_to_addrspace = 7215308304Sjhb htobe32(V_FW_CMD_OP(FW_LDST_CMD) | 7216308304Sjhb F_FW_CMD_REQUEST | F_FW_CMD_READ | 7217308304Sjhb V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MPS)); 7218308304Sjhb ldst_cmd.cycles_to_len16 = htobe32(FW_LEN16(ldst_cmd)); 7219308304Sjhb ldst_cmd.u.mps.rplc.fid_idx = 7220308304Sjhb htobe16(V_FW_LDST_CMD_FID(FW_LDST_MPS_RPLC) | 7221308304Sjhb V_FW_LDST_CMD_IDX(i)); 7222308304Sjhb 7223308304Sjhb rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, 7224308304Sjhb "t6mps"); 7225308304Sjhb if (rc) 7226308304Sjhb break; 7227308304Sjhb rc = -t4_wr_mbox(sc, sc->mbox, &ldst_cmd, 7228308304Sjhb sizeof(ldst_cmd), &ldst_cmd); 7229308304Sjhb end_synchronized_op(sc, 0); 7230308304Sjhb 7231308304Sjhb if (rc != 0) { 7232308304Sjhb sbuf_printf(sb, "%72d", rc); 7233308304Sjhb rc = 0; 7234308304Sjhb } else { 7235308304Sjhb sbuf_printf(sb, " %08x %08x %08x %08x" 7236308304Sjhb " %08x %08x %08x %08x", 7237308304Sjhb be32toh(ldst_cmd.u.mps.rplc.rplc255_224), 7238308304Sjhb be32toh(ldst_cmd.u.mps.rplc.rplc223_192), 7239308304Sjhb be32toh(ldst_cmd.u.mps.rplc.rplc191_160), 7240308304Sjhb be32toh(ldst_cmd.u.mps.rplc.rplc159_128), 7241308304Sjhb be32toh(ldst_cmd.u.mps.rplc.rplc127_96), 7242308304Sjhb be32toh(ldst_cmd.u.mps.rplc.rplc95_64), 7243308304Sjhb be32toh(ldst_cmd.u.mps.rplc.rplc63_32), 7244308304Sjhb be32toh(ldst_cmd.u.mps.rplc.rplc31_0)); 7245308304Sjhb } 7246308304Sjhb } else 7247308304Sjhb sbuf_printf(sb, "%72s", ""); 7248308304Sjhb 7249308304Sjhb sbuf_printf(sb, "%4u%3u%3u%3u %#x", 7250308304Sjhb G_T6_SRAM_PRIO0(cls_lo), G_T6_SRAM_PRIO1(cls_lo), 7251308304Sjhb G_T6_SRAM_PRIO2(cls_lo), G_T6_SRAM_PRIO3(cls_lo), 7252308304Sjhb (cls_lo >> S_T6_MULTILISTEN0) & 0xf); 7253308304Sjhb } 7254308304Sjhb 7255308304Sjhb if (rc) 7256308304Sjhb (void) sbuf_finish(sb); 7257308304Sjhb else 7258308304Sjhb rc = sbuf_finish(sb); 7259308304Sjhb sbuf_delete(sb); 7260308304Sjhb 7261308304Sjhb return (rc); 7262308304Sjhb} 7263308304Sjhb 7264308304Sjhbstatic int 7265228561Snpsysctl_path_mtus(SYSCTL_HANDLER_ARGS) 7266228561Snp{ 7267228561Snp struct adapter *sc = arg1; 7268228561Snp struct sbuf *sb; 7269228561Snp int rc; 7270228561Snp uint16_t mtus[NMTUS]; 7271228561Snp 7272228561Snp rc = sysctl_wire_old_buffer(req, 0); 7273228561Snp if (rc != 0) 7274228561Snp return (rc); 7275228561Snp 7276228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 7277228561Snp if (sb == NULL) 7278228561Snp return (ENOMEM); 7279228561Snp 7280228561Snp t4_read_mtu_tbl(sc, mtus, NULL); 7281228561Snp 7282228561Snp sbuf_printf(sb, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", 7283228561Snp mtus[0], mtus[1], mtus[2], mtus[3], mtus[4], mtus[5], mtus[6], 7284228561Snp mtus[7], mtus[8], mtus[9], mtus[10], mtus[11], mtus[12], mtus[13], 7285228561Snp mtus[14], mtus[15]); 7286228561Snp 7287228561Snp rc = sbuf_finish(sb); 7288228561Snp sbuf_delete(sb); 7289228561Snp 7290228561Snp return (rc); 7291228561Snp} 7292228561Snp 7293228561Snpstatic int 7294228561Snpsysctl_pm_stats(SYSCTL_HANDLER_ARGS) 7295228561Snp{ 7296228561Snp struct adapter *sc = arg1; 7297228561Snp struct sbuf *sb; 7298228561Snp int rc, i; 7299308304Sjhb uint32_t tx_cnt[MAX_PM_NSTATS], rx_cnt[MAX_PM_NSTATS]; 7300308304Sjhb uint64_t tx_cyc[MAX_PM_NSTATS], rx_cyc[MAX_PM_NSTATS]; 7301308304Sjhb static const char *tx_stats[MAX_PM_NSTATS] = { 7302308304Sjhb "Read:", "Write bypass:", "Write mem:", "Bypass + mem:", 7303308304Sjhb "Tx FIFO wait", NULL, "Tx latency" 7304228561Snp }; 7305308304Sjhb static const char *rx_stats[MAX_PM_NSTATS] = { 7306308304Sjhb "Read:", "Write bypass:", "Write mem:", "Flush:", 7307309458Sjhb "Rx FIFO wait", NULL, "Rx latency" 7308259142Snp }; 7309228561Snp 7310228561Snp rc = sysctl_wire_old_buffer(req, 0); 7311228561Snp if (rc != 0) 7312228561Snp return (rc); 7313228561Snp 7314228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 7315228561Snp if (sb == NULL) 7316228561Snp return (ENOMEM); 7317228561Snp 7318308304Sjhb t4_pmtx_get_stats(sc, tx_cnt, tx_cyc); 7319308304Sjhb t4_pmrx_get_stats(sc, rx_cnt, rx_cyc); 7320308304Sjhb 7321259142Snp sbuf_printf(sb, " Tx pcmds Tx bytes"); 7322308304Sjhb for (i = 0; i < 4; i++) { 7323308304Sjhb sbuf_printf(sb, "\n%-13s %10u %20ju", tx_stats[i], tx_cnt[i], 7324308304Sjhb tx_cyc[i]); 7325308304Sjhb } 7326228561Snp 7327259142Snp sbuf_printf(sb, "\n Rx pcmds Rx bytes"); 7328308304Sjhb for (i = 0; i < 4; i++) { 7329308304Sjhb sbuf_printf(sb, "\n%-13s %10u %20ju", rx_stats[i], rx_cnt[i], 7330308304Sjhb rx_cyc[i]); 7331308304Sjhb } 7332228561Snp 7333308304Sjhb if (chip_id(sc) > CHELSIO_T5) { 7334308304Sjhb sbuf_printf(sb, 7335308304Sjhb "\n Total wait Total occupancy"); 7336308304Sjhb sbuf_printf(sb, "\n%-13s %10u %20ju", tx_stats[i], tx_cnt[i], 7337308304Sjhb tx_cyc[i]); 7338308304Sjhb sbuf_printf(sb, "\n%-13s %10u %20ju", rx_stats[i], rx_cnt[i], 7339308304Sjhb rx_cyc[i]); 7340308304Sjhb 7341308304Sjhb i += 2; 7342308304Sjhb MPASS(i < nitems(tx_stats)); 7343308304Sjhb 7344308304Sjhb sbuf_printf(sb, 7345308304Sjhb "\n Reads Total wait"); 7346308304Sjhb sbuf_printf(sb, "\n%-13s %10u %20ju", tx_stats[i], tx_cnt[i], 7347308304Sjhb tx_cyc[i]); 7348308304Sjhb sbuf_printf(sb, "\n%-13s %10u %20ju", rx_stats[i], rx_cnt[i], 7349308304Sjhb rx_cyc[i]); 7350308304Sjhb } 7351308304Sjhb 7352228561Snp rc = sbuf_finish(sb); 7353228561Snp sbuf_delete(sb); 7354228561Snp 7355228561Snp return (rc); 7356228561Snp} 7357228561Snp 7358228561Snpstatic int 7359228561Snpsysctl_rdma_stats(SYSCTL_HANDLER_ARGS) 7360228561Snp{ 7361228561Snp struct adapter *sc = arg1; 7362228561Snp struct sbuf *sb; 7363228561Snp int rc; 7364228561Snp struct tp_rdma_stats stats; 7365228561Snp 7366228561Snp rc = sysctl_wire_old_buffer(req, 0); 7367228561Snp if (rc != 0) 7368228561Snp return (rc); 7369228561Snp 7370228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 7371228561Snp if (sb == NULL) 7372228561Snp return (ENOMEM); 7373228561Snp 7374308305Sjhb mtx_lock(&sc->reg_lock); 7375353418Snp t4_tp_get_rdma_stats(sc, &stats, 0); 7376308305Sjhb mtx_unlock(&sc->reg_lock); 7377308304Sjhb 7378228561Snp sbuf_printf(sb, "NoRQEModDefferals: %u\n", stats.rqe_dfr_mod); 7379228561Snp sbuf_printf(sb, "NoRQEPktDefferals: %u", stats.rqe_dfr_pkt); 7380228561Snp 7381228561Snp rc = sbuf_finish(sb); 7382228561Snp sbuf_delete(sb); 7383228561Snp 7384228561Snp return (rc); 7385228561Snp} 7386228561Snp 7387228561Snpstatic int 7388228561Snpsysctl_tcp_stats(SYSCTL_HANDLER_ARGS) 7389228561Snp{ 7390228561Snp struct adapter *sc = arg1; 7391228561Snp struct sbuf *sb; 7392228561Snp int rc; 7393228561Snp struct tp_tcp_stats v4, v6; 7394228561Snp 7395228561Snp rc = sysctl_wire_old_buffer(req, 0); 7396228561Snp if (rc != 0) 7397228561Snp return (rc); 7398228561Snp 7399228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 7400228561Snp if (sb == NULL) 7401228561Snp return (ENOMEM); 7402228561Snp 7403308305Sjhb mtx_lock(&sc->reg_lock); 7404353418Snp t4_tp_get_tcp_stats(sc, &v4, &v6, 0); 7405308305Sjhb mtx_unlock(&sc->reg_lock); 7406308304Sjhb 7407228561Snp sbuf_printf(sb, 7408228561Snp " IP IPv6\n"); 7409228561Snp sbuf_printf(sb, "OutRsts: %20u %20u\n", 7410308304Sjhb v4.tcp_out_rsts, v6.tcp_out_rsts); 7411228561Snp sbuf_printf(sb, "InSegs: %20ju %20ju\n", 7412308304Sjhb v4.tcp_in_segs, v6.tcp_in_segs); 7413228561Snp sbuf_printf(sb, "OutSegs: %20ju %20ju\n", 7414308304Sjhb v4.tcp_out_segs, v6.tcp_out_segs); 7415228561Snp sbuf_printf(sb, "RetransSegs: %20ju %20ju", 7416308304Sjhb v4.tcp_retrans_segs, v6.tcp_retrans_segs); 7417228561Snp 7418228561Snp rc = sbuf_finish(sb); 7419228561Snp sbuf_delete(sb); 7420228561Snp 7421228561Snp return (rc); 7422228561Snp} 7423228561Snp 7424228561Snpstatic int 7425228561Snpsysctl_tids(SYSCTL_HANDLER_ARGS) 7426228561Snp{ 7427228561Snp struct adapter *sc = arg1; 7428228561Snp struct sbuf *sb; 7429228561Snp int rc; 7430228561Snp struct tid_info *t = &sc->tids; 7431228561Snp 7432228561Snp rc = sysctl_wire_old_buffer(req, 0); 7433228561Snp if (rc != 0) 7434228561Snp return (rc); 7435228561Snp 7436228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 7437228561Snp if (sb == NULL) 7438228561Snp return (ENOMEM); 7439228561Snp 7440228561Snp if (t->natids) { 7441228561Snp sbuf_printf(sb, "ATID range: 0-%u, in use: %u\n", t->natids - 1, 7442228561Snp t->atids_in_use); 7443228561Snp } 7444228561Snp 7445228561Snp if (t->ntids) { 7446311261Snp sbuf_printf(sb, "TID range: "); 7447228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 7448311261Snp uint32_t b, hb; 7449228561Snp 7450311261Snp if (chip_id(sc) <= CHELSIO_T5) { 7451309560Sjhb b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4; 7452311261Snp hb = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4; 7453311261Snp } else { 7454309560Sjhb b = t4_read_reg(sc, A_LE_DB_SRVR_START_INDEX); 7455311261Snp hb = t4_read_reg(sc, A_T6_LE_DB_HASH_TID_BASE); 7456311261Snp } 7457309560Sjhb 7458311261Snp if (b) 7459311261Snp sbuf_printf(sb, "0-%u, ", b - 1); 7460311261Snp sbuf_printf(sb, "%u-%u", hb, t->ntids - 1); 7461228561Snp } else 7462311261Snp sbuf_printf(sb, "0-%u", t->ntids - 1); 7463228561Snp sbuf_printf(sb, ", in use: %u\n", 7464228561Snp atomic_load_acq_int(&t->tids_in_use)); 7465228561Snp } 7466228561Snp 7467228561Snp if (t->nstids) { 7468228561Snp sbuf_printf(sb, "STID range: %u-%u, in use: %u\n", t->stid_base, 7469228561Snp t->stid_base + t->nstids - 1, t->stids_in_use); 7470228561Snp } 7471228561Snp 7472228561Snp if (t->nftids) { 7473228561Snp sbuf_printf(sb, "FTID range: %u-%u\n", t->ftid_base, 7474228561Snp t->ftid_base + t->nftids - 1); 7475228561Snp } 7476228561Snp 7477265426Snp if (t->netids) { 7478265426Snp sbuf_printf(sb, "ETID range: %u-%u\n", t->etid_base, 7479265426Snp t->etid_base + t->netids - 1); 7480265426Snp } 7481265426Snp 7482228561Snp sbuf_printf(sb, "HW TID usage: %u IP users, %u IPv6 users", 7483228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV4), 7484228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV6)); 7485228561Snp 7486228561Snp rc = sbuf_finish(sb); 7487228561Snp sbuf_delete(sb); 7488228561Snp 7489228561Snp return (rc); 7490228561Snp} 7491228561Snp 7492228561Snpstatic int 7493228561Snpsysctl_tp_err_stats(SYSCTL_HANDLER_ARGS) 7494228561Snp{ 7495228561Snp struct adapter *sc = arg1; 7496228561Snp struct sbuf *sb; 7497228561Snp int rc; 7498228561Snp struct tp_err_stats stats; 7499228561Snp 7500228561Snp rc = sysctl_wire_old_buffer(req, 0); 7501228561Snp if (rc != 0) 7502228561Snp return (rc); 7503228561Snp 7504228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 7505228561Snp if (sb == NULL) 7506228561Snp return (ENOMEM); 7507228561Snp 7508308305Sjhb mtx_lock(&sc->reg_lock); 7509353418Snp t4_tp_get_err_stats(sc, &stats, 0); 7510308305Sjhb mtx_unlock(&sc->reg_lock); 7511228561Snp 7512308304Sjhb if (sc->chip_params->nchan > 2) { 7513308304Sjhb sbuf_printf(sb, " channel 0 channel 1" 7514308304Sjhb " channel 2 channel 3\n"); 7515308304Sjhb sbuf_printf(sb, "macInErrs: %10u %10u %10u %10u\n", 7516308304Sjhb stats.mac_in_errs[0], stats.mac_in_errs[1], 7517308304Sjhb stats.mac_in_errs[2], stats.mac_in_errs[3]); 7518308304Sjhb sbuf_printf(sb, "hdrInErrs: %10u %10u %10u %10u\n", 7519308304Sjhb stats.hdr_in_errs[0], stats.hdr_in_errs[1], 7520308304Sjhb stats.hdr_in_errs[2], stats.hdr_in_errs[3]); 7521308304Sjhb sbuf_printf(sb, "tcpInErrs: %10u %10u %10u %10u\n", 7522308304Sjhb stats.tcp_in_errs[0], stats.tcp_in_errs[1], 7523308304Sjhb stats.tcp_in_errs[2], stats.tcp_in_errs[3]); 7524308304Sjhb sbuf_printf(sb, "tcp6InErrs: %10u %10u %10u %10u\n", 7525308304Sjhb stats.tcp6_in_errs[0], stats.tcp6_in_errs[1], 7526308304Sjhb stats.tcp6_in_errs[2], stats.tcp6_in_errs[3]); 7527308304Sjhb sbuf_printf(sb, "tnlCongDrops: %10u %10u %10u %10u\n", 7528308304Sjhb stats.tnl_cong_drops[0], stats.tnl_cong_drops[1], 7529308304Sjhb stats.tnl_cong_drops[2], stats.tnl_cong_drops[3]); 7530308304Sjhb sbuf_printf(sb, "tnlTxDrops: %10u %10u %10u %10u\n", 7531308304Sjhb stats.tnl_tx_drops[0], stats.tnl_tx_drops[1], 7532308304Sjhb stats.tnl_tx_drops[2], stats.tnl_tx_drops[3]); 7533308304Sjhb sbuf_printf(sb, "ofldVlanDrops: %10u %10u %10u %10u\n", 7534308304Sjhb stats.ofld_vlan_drops[0], stats.ofld_vlan_drops[1], 7535308304Sjhb stats.ofld_vlan_drops[2], stats.ofld_vlan_drops[3]); 7536308304Sjhb sbuf_printf(sb, "ofldChanDrops: %10u %10u %10u %10u\n\n", 7537308304Sjhb stats.ofld_chan_drops[0], stats.ofld_chan_drops[1], 7538308304Sjhb stats.ofld_chan_drops[2], stats.ofld_chan_drops[3]); 7539308304Sjhb } else { 7540308304Sjhb sbuf_printf(sb, " channel 0 channel 1\n"); 7541308304Sjhb sbuf_printf(sb, "macInErrs: %10u %10u\n", 7542308304Sjhb stats.mac_in_errs[0], stats.mac_in_errs[1]); 7543308304Sjhb sbuf_printf(sb, "hdrInErrs: %10u %10u\n", 7544308304Sjhb stats.hdr_in_errs[0], stats.hdr_in_errs[1]); 7545308304Sjhb sbuf_printf(sb, "tcpInErrs: %10u %10u\n", 7546308304Sjhb stats.tcp_in_errs[0], stats.tcp_in_errs[1]); 7547308304Sjhb sbuf_printf(sb, "tcp6InErrs: %10u %10u\n", 7548308304Sjhb stats.tcp6_in_errs[0], stats.tcp6_in_errs[1]); 7549308304Sjhb sbuf_printf(sb, "tnlCongDrops: %10u %10u\n", 7550308304Sjhb stats.tnl_cong_drops[0], stats.tnl_cong_drops[1]); 7551308304Sjhb sbuf_printf(sb, "tnlTxDrops: %10u %10u\n", 7552308304Sjhb stats.tnl_tx_drops[0], stats.tnl_tx_drops[1]); 7553308304Sjhb sbuf_printf(sb, "ofldVlanDrops: %10u %10u\n", 7554308304Sjhb stats.ofld_vlan_drops[0], stats.ofld_vlan_drops[1]); 7555308304Sjhb sbuf_printf(sb, "ofldChanDrops: %10u %10u\n\n", 7556308304Sjhb stats.ofld_chan_drops[0], stats.ofld_chan_drops[1]); 7557308304Sjhb } 7558308304Sjhb 7559228561Snp sbuf_printf(sb, "ofldNoNeigh: %u\nofldCongDefer: %u", 7560308304Sjhb stats.ofld_no_neigh, stats.ofld_cong_defer); 7561228561Snp 7562228561Snp rc = sbuf_finish(sb); 7563228561Snp sbuf_delete(sb); 7564228561Snp 7565228561Snp return (rc); 7566228561Snp} 7567228561Snp 7568308311Sjhbstatic int 7569308311Sjhbsysctl_tp_la_mask(SYSCTL_HANDLER_ARGS) 7570308311Sjhb{ 7571308311Sjhb struct adapter *sc = arg1; 7572308311Sjhb struct tp_params *tpp = &sc->params.tp; 7573308311Sjhb u_int mask; 7574308311Sjhb int rc; 7575308311Sjhb 7576308311Sjhb mask = tpp->la_mask >> 16; 7577308311Sjhb rc = sysctl_handle_int(oidp, &mask, 0, req); 7578308311Sjhb if (rc != 0 || req->newptr == NULL) 7579308311Sjhb return (rc); 7580308311Sjhb if (mask > 0xffff) 7581308311Sjhb return (EINVAL); 7582308311Sjhb tpp->la_mask = mask << 16; 7583308311Sjhb t4_set_reg_field(sc, A_TP_DBG_LA_CONFIG, 0xffff0000U, tpp->la_mask); 7584308311Sjhb 7585308311Sjhb return (0); 7586308311Sjhb} 7587308311Sjhb 7588251213Snpstruct field_desc { 7589251213Snp const char *name; 7590251213Snp u_int start; 7591251213Snp u_int width; 7592251213Snp}; 7593251213Snp 7594251213Snpstatic void 7595251213Snpfield_desc_show(struct sbuf *sb, uint64_t v, const struct field_desc *f) 7596251213Snp{ 7597251213Snp char buf[32]; 7598251213Snp int line_size = 0; 7599251213Snp 7600251213Snp while (f->name) { 7601251213Snp uint64_t mask = (1ULL << f->width) - 1; 7602251213Snp int len = snprintf(buf, sizeof(buf), "%s: %ju", f->name, 7603251213Snp ((uintmax_t)v >> f->start) & mask); 7604251213Snp 7605251213Snp if (line_size + len >= 79) { 7606251213Snp line_size = 8; 7607251213Snp sbuf_printf(sb, "\n "); 7608251213Snp } 7609251213Snp sbuf_printf(sb, "%s ", buf); 7610251213Snp line_size += len + 1; 7611251213Snp f++; 7612251213Snp } 7613251213Snp sbuf_printf(sb, "\n"); 7614251213Snp} 7615251213Snp 7616308304Sjhbstatic const struct field_desc tp_la0[] = { 7617251213Snp { "RcfOpCodeOut", 60, 4 }, 7618251213Snp { "State", 56, 4 }, 7619251213Snp { "WcfState", 52, 4 }, 7620251213Snp { "RcfOpcSrcOut", 50, 2 }, 7621251213Snp { "CRxError", 49, 1 }, 7622251213Snp { "ERxError", 48, 1 }, 7623251213Snp { "SanityFailed", 47, 1 }, 7624251213Snp { "SpuriousMsg", 46, 1 }, 7625251213Snp { "FlushInputMsg", 45, 1 }, 7626251213Snp { "FlushInputCpl", 44, 1 }, 7627251213Snp { "RssUpBit", 43, 1 }, 7628251213Snp { "RssFilterHit", 42, 1 }, 7629251213Snp { "Tid", 32, 10 }, 7630251213Snp { "InitTcb", 31, 1 }, 7631251213Snp { "LineNumber", 24, 7 }, 7632251213Snp { "Emsg", 23, 1 }, 7633251213Snp { "EdataOut", 22, 1 }, 7634251213Snp { "Cmsg", 21, 1 }, 7635251213Snp { "CdataOut", 20, 1 }, 7636251213Snp { "EreadPdu", 19, 1 }, 7637251213Snp { "CreadPdu", 18, 1 }, 7638251213Snp { "TunnelPkt", 17, 1 }, 7639251213Snp { "RcfPeerFin", 16, 1 }, 7640251213Snp { "RcfReasonOut", 12, 4 }, 7641251213Snp { "TxCchannel", 10, 2 }, 7642251213Snp { "RcfTxChannel", 8, 2 }, 7643251213Snp { "RxEchannel", 6, 2 }, 7644251213Snp { "RcfRxChannel", 5, 1 }, 7645251213Snp { "RcfDataOutSrdy", 4, 1 }, 7646251213Snp { "RxDvld", 3, 1 }, 7647251213Snp { "RxOoDvld", 2, 1 }, 7648251213Snp { "RxCongestion", 1, 1 }, 7649251213Snp { "TxCongestion", 0, 1 }, 7650251213Snp { NULL } 7651251213Snp}; 7652251213Snp 7653308304Sjhbstatic const struct field_desc tp_la1[] = { 7654251213Snp { "CplCmdIn", 56, 8 }, 7655251213Snp { "CplCmdOut", 48, 8 }, 7656251213Snp { "ESynOut", 47, 1 }, 7657251213Snp { "EAckOut", 46, 1 }, 7658251213Snp { "EFinOut", 45, 1 }, 7659251213Snp { "ERstOut", 44, 1 }, 7660251213Snp { "SynIn", 43, 1 }, 7661251213Snp { "AckIn", 42, 1 }, 7662251213Snp { "FinIn", 41, 1 }, 7663251213Snp { "RstIn", 40, 1 }, 7664251213Snp { "DataIn", 39, 1 }, 7665251213Snp { "DataInVld", 38, 1 }, 7666251213Snp { "PadIn", 37, 1 }, 7667251213Snp { "RxBufEmpty", 36, 1 }, 7668251213Snp { "RxDdp", 35, 1 }, 7669251213Snp { "RxFbCongestion", 34, 1 }, 7670251213Snp { "TxFbCongestion", 33, 1 }, 7671251213Snp { "TxPktSumSrdy", 32, 1 }, 7672251213Snp { "RcfUlpType", 28, 4 }, 7673251213Snp { "Eread", 27, 1 }, 7674251213Snp { "Ebypass", 26, 1 }, 7675251213Snp { "Esave", 25, 1 }, 7676251213Snp { "Static0", 24, 1 }, 7677251213Snp { "Cread", 23, 1 }, 7678251213Snp { "Cbypass", 22, 1 }, 7679251213Snp { "Csave", 21, 1 }, 7680251213Snp { "CPktOut", 20, 1 }, 7681251213Snp { "RxPagePoolFull", 18, 2 }, 7682251213Snp { "RxLpbkPkt", 17, 1 }, 7683251213Snp { "TxLpbkPkt", 16, 1 }, 7684251213Snp { "RxVfValid", 15, 1 }, 7685251213Snp { "SynLearned", 14, 1 }, 7686251213Snp { "SetDelEntry", 13, 1 }, 7687251213Snp { "SetInvEntry", 12, 1 }, 7688251213Snp { "CpcmdDvld", 11, 1 }, 7689251213Snp { "CpcmdSave", 10, 1 }, 7690251213Snp { "RxPstructsFull", 8, 2 }, 7691251213Snp { "EpcmdDvld", 7, 1 }, 7692251213Snp { "EpcmdFlush", 6, 1 }, 7693251213Snp { "EpcmdTrimPrefix", 5, 1 }, 7694251213Snp { "EpcmdTrimPostfix", 4, 1 }, 7695251213Snp { "ERssIp4Pkt", 3, 1 }, 7696251213Snp { "ERssIp6Pkt", 2, 1 }, 7697251213Snp { "ERssTcpUdpPkt", 1, 1 }, 7698251213Snp { "ERssFceFipPkt", 0, 1 }, 7699251213Snp { NULL } 7700251213Snp}; 7701251213Snp 7702308304Sjhbstatic const struct field_desc tp_la2[] = { 7703251213Snp { "CplCmdIn", 56, 8 }, 7704251213Snp { "MpsVfVld", 55, 1 }, 7705251213Snp { "MpsPf", 52, 3 }, 7706251213Snp { "MpsVf", 44, 8 }, 7707251213Snp { "SynIn", 43, 1 }, 7708251213Snp { "AckIn", 42, 1 }, 7709251213Snp { "FinIn", 41, 1 }, 7710251213Snp { "RstIn", 40, 1 }, 7711251213Snp { "DataIn", 39, 1 }, 7712251213Snp { "DataInVld", 38, 1 }, 7713251213Snp { "PadIn", 37, 1 }, 7714251213Snp { "RxBufEmpty", 36, 1 }, 7715251213Snp { "RxDdp", 35, 1 }, 7716251213Snp { "RxFbCongestion", 34, 1 }, 7717251213Snp { "TxFbCongestion", 33, 1 }, 7718251213Snp { "TxPktSumSrdy", 32, 1 }, 7719251213Snp { "RcfUlpType", 28, 4 }, 7720251213Snp { "Eread", 27, 1 }, 7721251213Snp { "Ebypass", 26, 1 }, 7722251213Snp { "Esave", 25, 1 }, 7723251213Snp { "Static0", 24, 1 }, 7724251213Snp { "Cread", 23, 1 }, 7725251213Snp { "Cbypass", 22, 1 }, 7726251213Snp { "Csave", 21, 1 }, 7727251213Snp { "CPktOut", 20, 1 }, 7728251213Snp { "RxPagePoolFull", 18, 2 }, 7729251213Snp { "RxLpbkPkt", 17, 1 }, 7730251213Snp { "TxLpbkPkt", 16, 1 }, 7731251213Snp { "RxVfValid", 15, 1 }, 7732251213Snp { "SynLearned", 14, 1 }, 7733251213Snp { "SetDelEntry", 13, 1 }, 7734251213Snp { "SetInvEntry", 12, 1 }, 7735251213Snp { "CpcmdDvld", 11, 1 }, 7736251213Snp { "CpcmdSave", 10, 1 }, 7737251213Snp { "RxPstructsFull", 8, 2 }, 7738251213Snp { "EpcmdDvld", 7, 1 }, 7739251213Snp { "EpcmdFlush", 6, 1 }, 7740251213Snp { "EpcmdTrimPrefix", 5, 1 }, 7741251213Snp { "EpcmdTrimPostfix", 4, 1 }, 7742251213Snp { "ERssIp4Pkt", 3, 1 }, 7743251213Snp { "ERssIp6Pkt", 2, 1 }, 7744251213Snp { "ERssTcpUdpPkt", 1, 1 }, 7745251213Snp { "ERssFceFipPkt", 0, 1 }, 7746251213Snp { NULL } 7747251213Snp}; 7748251213Snp 7749251213Snpstatic void 7750251213Snptp_la_show(struct sbuf *sb, uint64_t *p, int idx) 7751251213Snp{ 7752251213Snp 7753251213Snp field_desc_show(sb, *p, tp_la0); 7754251213Snp} 7755251213Snp 7756251213Snpstatic void 7757251213Snptp_la_show2(struct sbuf *sb, uint64_t *p, int idx) 7758251213Snp{ 7759251213Snp 7760251213Snp if (idx) 7761251213Snp sbuf_printf(sb, "\n"); 7762251213Snp field_desc_show(sb, p[0], tp_la0); 7763251213Snp if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) 7764251213Snp field_desc_show(sb, p[1], tp_la0); 7765251213Snp} 7766251213Snp 7767251213Snpstatic void 7768251213Snptp_la_show3(struct sbuf *sb, uint64_t *p, int idx) 7769251213Snp{ 7770251213Snp 7771251213Snp if (idx) 7772251213Snp sbuf_printf(sb, "\n"); 7773251213Snp field_desc_show(sb, p[0], tp_la0); 7774251213Snp if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) 7775251213Snp field_desc_show(sb, p[1], (p[0] & (1 << 17)) ? tp_la2 : tp_la1); 7776251213Snp} 7777251213Snp 7778228561Snpstatic int 7779251213Snpsysctl_tp_la(SYSCTL_HANDLER_ARGS) 7780251213Snp{ 7781251213Snp struct adapter *sc = arg1; 7782251213Snp struct sbuf *sb; 7783251213Snp uint64_t *buf, *p; 7784251213Snp int rc; 7785251213Snp u_int i, inc; 7786251213Snp void (*show_func)(struct sbuf *, uint64_t *, int); 7787251213Snp 7788251213Snp rc = sysctl_wire_old_buffer(req, 0); 7789251213Snp if (rc != 0) 7790251213Snp return (rc); 7791251213Snp 7792251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 7793251213Snp if (sb == NULL) 7794251213Snp return (ENOMEM); 7795251213Snp 7796251213Snp buf = malloc(TPLA_SIZE * sizeof(uint64_t), M_CXGBE, M_ZERO | M_WAITOK); 7797251213Snp 7798251213Snp t4_tp_read_la(sc, buf, NULL); 7799251213Snp p = buf; 7800251213Snp 7801251213Snp switch (G_DBGLAMODE(t4_read_reg(sc, A_TP_DBG_LA_CONFIG))) { 7802251213Snp case 2: 7803251213Snp inc = 2; 7804251213Snp show_func = tp_la_show2; 7805251213Snp break; 7806251213Snp case 3: 7807251213Snp inc = 2; 7808251213Snp show_func = tp_la_show3; 7809251213Snp break; 7810251213Snp default: 7811251213Snp inc = 1; 7812251213Snp show_func = tp_la_show; 7813251213Snp } 7814251213Snp 7815251213Snp for (i = 0; i < TPLA_SIZE / inc; i++, p += inc) 7816251213Snp (*show_func)(sb, p, i); 7817251213Snp 7818251213Snp rc = sbuf_finish(sb); 7819251213Snp sbuf_delete(sb); 7820251213Snp free(buf, M_CXGBE); 7821251213Snp return (rc); 7822251213Snp} 7823251213Snp 7824251213Snpstatic int 7825228561Snpsysctl_tx_rate(SYSCTL_HANDLER_ARGS) 7826228561Snp{ 7827228561Snp struct adapter *sc = arg1; 7828228561Snp struct sbuf *sb; 7829228561Snp int rc; 7830308304Sjhb u64 nrate[MAX_NCHAN], orate[MAX_NCHAN]; 7831228561Snp 7832228561Snp rc = sysctl_wire_old_buffer(req, 0); 7833228561Snp if (rc != 0) 7834228561Snp return (rc); 7835228561Snp 7836228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 7837228561Snp if (sb == NULL) 7838228561Snp return (ENOMEM); 7839228561Snp 7840228561Snp t4_get_chan_txrate(sc, nrate, orate); 7841228561Snp 7842308304Sjhb if (sc->chip_params->nchan > 2) { 7843308304Sjhb sbuf_printf(sb, " channel 0 channel 1" 7844308304Sjhb " channel 2 channel 3\n"); 7845308304Sjhb sbuf_printf(sb, "NIC B/s: %10ju %10ju %10ju %10ju\n", 7846308304Sjhb nrate[0], nrate[1], nrate[2], nrate[3]); 7847308304Sjhb sbuf_printf(sb, "Offload B/s: %10ju %10ju %10ju %10ju", 7848308304Sjhb orate[0], orate[1], orate[2], orate[3]); 7849308304Sjhb } else { 7850308304Sjhb sbuf_printf(sb, " channel 0 channel 1\n"); 7851308304Sjhb sbuf_printf(sb, "NIC B/s: %10ju %10ju\n", 7852308304Sjhb nrate[0], nrate[1]); 7853308304Sjhb sbuf_printf(sb, "Offload B/s: %10ju %10ju", 7854308304Sjhb orate[0], orate[1]); 7855308304Sjhb } 7856308304Sjhb 7857228561Snp rc = sbuf_finish(sb); 7858228561Snp sbuf_delete(sb); 7859228561Snp 7860228561Snp return (rc); 7861228561Snp} 7862248925Snp 7863248925Snpstatic int 7864251213Snpsysctl_ulprx_la(SYSCTL_HANDLER_ARGS) 7865251213Snp{ 7866251213Snp struct adapter *sc = arg1; 7867251213Snp struct sbuf *sb; 7868251213Snp uint32_t *buf, *p; 7869251213Snp int rc, i; 7870251213Snp 7871251213Snp rc = sysctl_wire_old_buffer(req, 0); 7872251213Snp if (rc != 0) 7873251213Snp return (rc); 7874251213Snp 7875251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 7876251213Snp if (sb == NULL) 7877251213Snp return (ENOMEM); 7878251213Snp 7879251213Snp buf = malloc(ULPRX_LA_SIZE * 8 * sizeof(uint32_t), M_CXGBE, 7880251213Snp M_ZERO | M_WAITOK); 7881251213Snp 7882251213Snp t4_ulprx_read_la(sc, buf); 7883251213Snp p = buf; 7884251213Snp 7885251213Snp sbuf_printf(sb, " Pcmd Type Message" 7886251213Snp " Data"); 7887251213Snp for (i = 0; i < ULPRX_LA_SIZE; i++, p += 8) { 7888251213Snp sbuf_printf(sb, "\n%08x%08x %4x %08x %08x%08x%08x%08x", 7889251213Snp p[1], p[0], p[2], p[3], p[7], p[6], p[5], p[4]); 7890251213Snp } 7891251213Snp 7892251213Snp rc = sbuf_finish(sb); 7893251213Snp sbuf_delete(sb); 7894251213Snp free(buf, M_CXGBE); 7895251213Snp return (rc); 7896251213Snp} 7897251213Snp 7898251213Snpstatic int 7899249392Snpsysctl_wcwr_stats(SYSCTL_HANDLER_ARGS) 7900248925Snp{ 7901248925Snp struct adapter *sc = arg1; 7902248925Snp struct sbuf *sb; 7903248925Snp int rc, v; 7904248925Snp 7905309560Sjhb MPASS(chip_id(sc) >= CHELSIO_T5); 7906309560Sjhb 7907248925Snp rc = sysctl_wire_old_buffer(req, 0); 7908248925Snp if (rc != 0) 7909248925Snp return (rc); 7910248925Snp 7911248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 7912248925Snp if (sb == NULL) 7913248925Snp return (ENOMEM); 7914248925Snp 7915248925Snp v = t4_read_reg(sc, A_SGE_STAT_CFG); 7916248925Snp if (G_STATSOURCE_T5(v) == 7) { 7917309560Sjhb int mode; 7918309560Sjhb 7919309560Sjhb mode = is_t5(sc) ? G_STATMODE(v) : G_T6_STATMODE(v); 7920309560Sjhb if (mode == 0) { 7921249383Snp sbuf_printf(sb, "total %d, incomplete %d", 7922248925Snp t4_read_reg(sc, A_SGE_STAT_TOTAL), 7923248925Snp t4_read_reg(sc, A_SGE_STAT_MATCH)); 7924309560Sjhb } else if (mode == 1) { 7925249383Snp sbuf_printf(sb, "total %d, data overflow %d", 7926248925Snp t4_read_reg(sc, A_SGE_STAT_TOTAL), 7927248925Snp t4_read_reg(sc, A_SGE_STAT_MATCH)); 7928309560Sjhb } else { 7929309560Sjhb sbuf_printf(sb, "unknown mode %d", mode); 7930248925Snp } 7931248925Snp } 7932248925Snp rc = sbuf_finish(sb); 7933248925Snp sbuf_delete(sb); 7934248925Snp 7935248925Snp return (rc); 7936248925Snp} 7937308321Sjhb 7938308321Sjhbstatic int 7939308321Sjhbsysctl_tc_params(SYSCTL_HANDLER_ARGS) 7940308321Sjhb{ 7941308321Sjhb struct adapter *sc = arg1; 7942318851Snp struct tx_cl_rl_params tc; 7943308321Sjhb struct sbuf *sb; 7944318851Snp int i, rc, port_id, mbps, gbps; 7945308321Sjhb 7946308321Sjhb rc = sysctl_wire_old_buffer(req, 0); 7947308321Sjhb if (rc != 0) 7948308321Sjhb return (rc); 7949308321Sjhb 7950308321Sjhb sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 7951308321Sjhb if (sb == NULL) 7952308321Sjhb return (ENOMEM); 7953308321Sjhb 7954308321Sjhb port_id = arg2 >> 16; 7955308321Sjhb MPASS(port_id < sc->params.nports); 7956308321Sjhb MPASS(sc->port[port_id] != NULL); 7957308321Sjhb i = arg2 & 0xffff; 7958308321Sjhb MPASS(i < sc->chip_params->nsched_cls); 7959308321Sjhb 7960318851Snp mtx_lock(&sc->tc_lock); 7961318851Snp tc = sc->port[port_id]->sched_params->cl_rl[i]; 7962318851Snp mtx_unlock(&sc->tc_lock); 7963308321Sjhb 7964318851Snp if (tc.flags & TX_CLRL_ERROR) { 7965318851Snp sbuf_printf(sb, "error"); 7966308321Sjhb goto done; 7967308321Sjhb } 7968308321Sjhb 7969318851Snp if (tc.ratemode == SCHED_CLASS_RATEMODE_REL) { 7970308321Sjhb /* XXX: top speed or actual link speed? */ 7971308321Sjhb gbps = port_top_speed(sc->port[port_id]); 7972318851Snp sbuf_printf(sb, " %u%% of %uGbps", tc.maxrate, gbps); 7973318851Snp } else if (tc.ratemode == SCHED_CLASS_RATEMODE_ABS) { 7974318851Snp switch (tc.rateunit) { 7975308321Sjhb case SCHED_CLASS_RATEUNIT_BITS: 7976318851Snp mbps = tc.maxrate / 1000; 7977318851Snp gbps = tc.maxrate / 1000000; 7978318851Snp if (tc.maxrate == gbps * 1000000) 7979308321Sjhb sbuf_printf(sb, " %uGbps", gbps); 7980318851Snp else if (tc.maxrate == mbps * 1000) 7981308321Sjhb sbuf_printf(sb, " %uMbps", mbps); 7982308321Sjhb else 7983318851Snp sbuf_printf(sb, " %uKbps", tc.maxrate); 7984308321Sjhb break; 7985308321Sjhb case SCHED_CLASS_RATEUNIT_PKTS: 7986318851Snp sbuf_printf(sb, " %upps", tc.maxrate); 7987308321Sjhb break; 7988308321Sjhb default: 7989308321Sjhb rc = ENXIO; 7990308321Sjhb goto done; 7991308321Sjhb } 7992308321Sjhb } 7993308321Sjhb 7994318851Snp switch (tc.mode) { 7995308321Sjhb case SCHED_CLASS_MODE_CLASS: 7996308321Sjhb sbuf_printf(sb, " aggregate"); 7997308321Sjhb break; 7998308321Sjhb case SCHED_CLASS_MODE_FLOW: 7999308321Sjhb sbuf_printf(sb, " per-flow"); 8000308321Sjhb break; 8001308321Sjhb default: 8002308321Sjhb rc = ENXIO; 8003308321Sjhb goto done; 8004308321Sjhb } 8005308321Sjhb 8006308321Sjhbdone: 8007308321Sjhb if (rc == 0) 8008308321Sjhb rc = sbuf_finish(sb); 8009308321Sjhb sbuf_delete(sb); 8010308321Sjhb 8011308321Sjhb return (rc); 8012308321Sjhb} 8013231115Snp#endif 8014228561Snp 8015308311Sjhb#ifdef TCP_OFFLOAD 8016308311Sjhbstatic void 8017308311Sjhbunit_conv(char *buf, size_t len, u_int val, u_int factor) 8018308311Sjhb{ 8019308311Sjhb u_int rem = val % factor; 8020308311Sjhb 8021308311Sjhb if (rem == 0) 8022308311Sjhb snprintf(buf, len, "%u", val / factor); 8023308311Sjhb else { 8024308311Sjhb while (rem % 10 == 0) 8025308311Sjhb rem /= 10; 8026308311Sjhb snprintf(buf, len, "%u.%u", val / factor, rem); 8027308311Sjhb } 8028308311Sjhb} 8029308311Sjhb 8030308311Sjhbstatic int 8031308311Sjhbsysctl_tp_tick(SYSCTL_HANDLER_ARGS) 8032308311Sjhb{ 8033308311Sjhb struct adapter *sc = arg1; 8034308311Sjhb char buf[16]; 8035308311Sjhb u_int res, re; 8036308311Sjhb u_int cclk_ps = 1000000000 / sc->params.vpd.cclk; 8037308311Sjhb 8038308311Sjhb res = t4_read_reg(sc, A_TP_TIMER_RESOLUTION); 8039308311Sjhb switch (arg2) { 8040308311Sjhb case 0: 8041308311Sjhb /* timer_tick */ 8042308311Sjhb re = G_TIMERRESOLUTION(res); 8043308311Sjhb break; 8044308311Sjhb case 1: 8045308311Sjhb /* TCP timestamp tick */ 8046308311Sjhb re = G_TIMESTAMPRESOLUTION(res); 8047308311Sjhb break; 8048308311Sjhb case 2: 8049308311Sjhb /* DACK tick */ 8050308311Sjhb re = G_DELAYEDACKRESOLUTION(res); 8051308311Sjhb break; 8052308311Sjhb default: 8053308311Sjhb return (EDOOFUS); 8054308311Sjhb } 8055308311Sjhb 8056308311Sjhb unit_conv(buf, sizeof(buf), (cclk_ps << re), 1000000); 8057308311Sjhb 8058308311Sjhb return (sysctl_handle_string(oidp, buf, sizeof(buf), req)); 8059308311Sjhb} 8060308311Sjhb 8061308311Sjhbstatic int 8062308311Sjhbsysctl_tp_dack_timer(SYSCTL_HANDLER_ARGS) 8063308311Sjhb{ 8064308311Sjhb struct adapter *sc = arg1; 8065308311Sjhb u_int res, dack_re, v; 8066308311Sjhb u_int cclk_ps = 1000000000 / sc->params.vpd.cclk; 8067308311Sjhb 8068308311Sjhb res = t4_read_reg(sc, A_TP_TIMER_RESOLUTION); 8069308311Sjhb dack_re = G_DELAYEDACKRESOLUTION(res); 8070308311Sjhb v = ((cclk_ps << dack_re) / 1000000) * t4_read_reg(sc, A_TP_DACK_TIMER); 8071308311Sjhb 8072308311Sjhb return (sysctl_handle_int(oidp, &v, 0, req)); 8073308311Sjhb} 8074308311Sjhb 8075308311Sjhbstatic int 8076308311Sjhbsysctl_tp_timer(SYSCTL_HANDLER_ARGS) 8077308311Sjhb{ 8078308311Sjhb struct adapter *sc = arg1; 8079308311Sjhb int reg = arg2; 8080308311Sjhb u_int tre; 8081308311Sjhb u_long tp_tick_us, v; 8082308311Sjhb u_int cclk_ps = 1000000000 / sc->params.vpd.cclk; 8083308311Sjhb 8084308311Sjhb MPASS(reg == A_TP_RXT_MIN || reg == A_TP_RXT_MAX || 8085316123Snp reg == A_TP_PERS_MIN || reg == A_TP_PERS_MAX || 8086316123Snp reg == A_TP_KEEP_IDLE || reg == A_TP_KEEP_INTVL || 8087316123Snp reg == A_TP_INIT_SRTT || reg == A_TP_FINWAIT2_TIMER); 8088308311Sjhb 8089308311Sjhb tre = G_TIMERRESOLUTION(t4_read_reg(sc, A_TP_TIMER_RESOLUTION)); 8090308311Sjhb tp_tick_us = (cclk_ps << tre) / 1000000; 8091308311Sjhb 8092308311Sjhb if (reg == A_TP_INIT_SRTT) 8093308311Sjhb v = tp_tick_us * G_INITSRTT(t4_read_reg(sc, reg)); 8094308311Sjhb else 8095308311Sjhb v = tp_tick_us * t4_read_reg(sc, reg); 8096308311Sjhb 8097308311Sjhb return (sysctl_handle_long(oidp, &v, 0, req)); 8098308311Sjhb} 8099308311Sjhb#endif 8100308311Sjhb 8101221474Snpstatic uint32_t 8102308304Sjhbfconf_iconf_to_mode(uint32_t fconf, uint32_t iconf) 8103221474Snp{ 8104221474Snp uint32_t mode; 8105221474Snp 8106221474Snp mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR | 8107221474Snp T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT; 8108221474Snp 8109221474Snp if (fconf & F_FRAGMENTATION) 8110221474Snp mode |= T4_FILTER_IP_FRAGMENT; 8111221474Snp 8112221474Snp if (fconf & F_MPSHITTYPE) 8113221474Snp mode |= T4_FILTER_MPS_HIT_TYPE; 8114221474Snp 8115221474Snp if (fconf & F_MACMATCH) 8116221474Snp mode |= T4_FILTER_MAC_IDX; 8117221474Snp 8118221474Snp if (fconf & F_ETHERTYPE) 8119221474Snp mode |= T4_FILTER_ETH_TYPE; 8120221474Snp 8121221474Snp if (fconf & F_PROTOCOL) 8122221474Snp mode |= T4_FILTER_IP_PROTO; 8123221474Snp 8124221474Snp if (fconf & F_TOS) 8125221474Snp mode |= T4_FILTER_IP_TOS; 8126221474Snp 8127221474Snp if (fconf & F_VLAN) 8128228561Snp mode |= T4_FILTER_VLAN; 8129221474Snp 8130308304Sjhb if (fconf & F_VNIC_ID) { 8131228561Snp mode |= T4_FILTER_VNIC; 8132308304Sjhb if (iconf & F_VNIC) 8133308304Sjhb mode |= T4_FILTER_IC_VNIC; 8134308304Sjhb } 8135221474Snp 8136221474Snp if (fconf & F_PORT) 8137221474Snp mode |= T4_FILTER_PORT; 8138221474Snp 8139221474Snp if (fconf & F_FCOE) 8140221474Snp mode |= T4_FILTER_FCoE; 8141221474Snp 8142221474Snp return (mode); 8143221474Snp} 8144221474Snp 8145221474Snpstatic uint32_t 8146221474Snpmode_to_fconf(uint32_t mode) 8147221474Snp{ 8148221474Snp uint32_t fconf = 0; 8149221474Snp 8150221474Snp if (mode & T4_FILTER_IP_FRAGMENT) 8151221474Snp fconf |= F_FRAGMENTATION; 8152221474Snp 8153221474Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 8154221474Snp fconf |= F_MPSHITTYPE; 8155221474Snp 8156221474Snp if (mode & T4_FILTER_MAC_IDX) 8157221474Snp fconf |= F_MACMATCH; 8158221474Snp 8159221474Snp if (mode & T4_FILTER_ETH_TYPE) 8160221474Snp fconf |= F_ETHERTYPE; 8161221474Snp 8162221474Snp if (mode & T4_FILTER_IP_PROTO) 8163221474Snp fconf |= F_PROTOCOL; 8164221474Snp 8165221474Snp if (mode & T4_FILTER_IP_TOS) 8166221474Snp fconf |= F_TOS; 8167221474Snp 8168228561Snp if (mode & T4_FILTER_VLAN) 8169221474Snp fconf |= F_VLAN; 8170221474Snp 8171228561Snp if (mode & T4_FILTER_VNIC) 8172221474Snp fconf |= F_VNIC_ID; 8173221474Snp 8174221474Snp if (mode & T4_FILTER_PORT) 8175221474Snp fconf |= F_PORT; 8176221474Snp 8177221474Snp if (mode & T4_FILTER_FCoE) 8178221474Snp fconf |= F_FCOE; 8179221474Snp 8180221474Snp return (fconf); 8181221474Snp} 8182221474Snp 8183221474Snpstatic uint32_t 8184308304Sjhbmode_to_iconf(uint32_t mode) 8185221474Snp{ 8186308304Sjhb 8187308304Sjhb if (mode & T4_FILTER_IC_VNIC) 8188308304Sjhb return (F_VNIC); 8189308304Sjhb return (0); 8190308304Sjhb} 8191308304Sjhb 8192308304Sjhbstatic int check_fspec_against_fconf_iconf(struct adapter *sc, 8193308304Sjhb struct t4_filter_specification *fs) 8194308304Sjhb{ 8195308304Sjhb struct tp_params *tpp = &sc->params.tp; 8196221474Snp uint32_t fconf = 0; 8197221474Snp 8198221474Snp if (fs->val.frag || fs->mask.frag) 8199221474Snp fconf |= F_FRAGMENTATION; 8200221474Snp 8201221474Snp if (fs->val.matchtype || fs->mask.matchtype) 8202221474Snp fconf |= F_MPSHITTYPE; 8203221474Snp 8204221474Snp if (fs->val.macidx || fs->mask.macidx) 8205221474Snp fconf |= F_MACMATCH; 8206221474Snp 8207221474Snp if (fs->val.ethtype || fs->mask.ethtype) 8208221474Snp fconf |= F_ETHERTYPE; 8209221474Snp 8210221474Snp if (fs->val.proto || fs->mask.proto) 8211221474Snp fconf |= F_PROTOCOL; 8212221474Snp 8213221474Snp if (fs->val.tos || fs->mask.tos) 8214221474Snp fconf |= F_TOS; 8215221474Snp 8216228561Snp if (fs->val.vlan_vld || fs->mask.vlan_vld) 8217221474Snp fconf |= F_VLAN; 8218221474Snp 8219308304Sjhb if (fs->val.ovlan_vld || fs->mask.ovlan_vld) { 8220221474Snp fconf |= F_VNIC_ID; 8221308304Sjhb if (tpp->ingress_config & F_VNIC) 8222308304Sjhb return (EINVAL); 8223308304Sjhb } 8224221474Snp 8225308304Sjhb if (fs->val.pfvf_vld || fs->mask.pfvf_vld) { 8226308304Sjhb fconf |= F_VNIC_ID; 8227308304Sjhb if ((tpp->ingress_config & F_VNIC) == 0) 8228308304Sjhb return (EINVAL); 8229308304Sjhb } 8230308304Sjhb 8231221474Snp if (fs->val.iport || fs->mask.iport) 8232221474Snp fconf |= F_PORT; 8233221474Snp 8234221474Snp if (fs->val.fcoe || fs->mask.fcoe) 8235221474Snp fconf |= F_FCOE; 8236221474Snp 8237308304Sjhb if ((tpp->vlan_pri_map | fconf) != tpp->vlan_pri_map) 8238308304Sjhb return (E2BIG); 8239308304Sjhb 8240308304Sjhb return (0); 8241221474Snp} 8242221474Snp 8243221474Snpstatic int 8244221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode) 8245221474Snp{ 8246308304Sjhb struct tp_params *tpp = &sc->params.tp; 8247221474Snp 8248308304Sjhb /* 8249308304Sjhb * We trust the cached values of the relevant TP registers. This means 8250308304Sjhb * things work reliably only if writes to those registers are always via 8251308304Sjhb * t4_set_filter_mode. 8252308304Sjhb */ 8253308304Sjhb *mode = fconf_iconf_to_mode(tpp->vlan_pri_map, tpp->ingress_config); 8254245274Snp 8255221474Snp return (0); 8256221474Snp} 8257221474Snp 8258221474Snpstatic int 8259221474Snpset_filter_mode(struct adapter *sc, uint32_t mode) 8260221474Snp{ 8261308304Sjhb struct tp_params *tpp = &sc->params.tp; 8262308304Sjhb uint32_t fconf, iconf; 8263221474Snp int rc; 8264221474Snp 8265308304Sjhb iconf = mode_to_iconf(mode); 8266308304Sjhb if ((iconf ^ tpp->ingress_config) & F_VNIC) { 8267308304Sjhb /* 8268308304Sjhb * For now we just complain if A_TP_INGRESS_CONFIG is not 8269308304Sjhb * already set to the correct value for the requested filter 8270308304Sjhb * mode. It's not clear if it's safe to write to this register 8271308304Sjhb * on the fly. (And we trust the cached value of the register). 8272308304Sjhb */ 8273308304Sjhb return (EBUSY); 8274308304Sjhb } 8275308304Sjhb 8276221474Snp fconf = mode_to_fconf(mode); 8277221474Snp 8278245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 8279245274Snp "t4setfm"); 8280245274Snp if (rc) 8281245274Snp return (rc); 8282221474Snp 8283221474Snp if (sc->tids.ftids_in_use > 0) { 8284221474Snp rc = EBUSY; 8285221474Snp goto done; 8286221474Snp } 8287221474Snp 8288237263Snp#ifdef TCP_OFFLOAD 8289284089Snp if (uld_active(sc, ULD_TOM)) { 8290228561Snp rc = EBUSY; 8291228561Snp goto done; 8292228561Snp } 8293228561Snp#endif 8294228561Snp 8295353418Snp rc = -t4_set_filter_mode(sc, fconf, true); 8296221474Snpdone: 8297245274Snp end_synchronized_op(sc, LOCK_HELD); 8298221474Snp return (rc); 8299221474Snp} 8300221474Snp 8301222552Snpstatic inline uint64_t 8302222552Snpget_filter_hits(struct adapter *sc, uint32_t fid) 8303222552Snp{ 8304308305Sjhb uint32_t tcb_addr; 8305222552Snp 8306308305Sjhb tcb_addr = t4_read_reg(sc, A_TP_CMM_TCB_BASE) + 8307308305Sjhb (fid + sc->tids.ftid_base) * TCB_SIZE; 8308308304Sjhb 8309251358Snp if (is_t4(sc)) { 8310308305Sjhb uint64_t hits; 8311308305Sjhb 8312308305Sjhb read_via_memwin(sc, 0, tcb_addr + 16, (uint32_t *)&hits, 8); 8313308305Sjhb return (be64toh(hits)); 8314251358Snp } else { 8315308305Sjhb uint32_t hits; 8316308305Sjhb 8317308305Sjhb read_via_memwin(sc, 0, tcb_addr + 24, &hits, 4); 8318308305Sjhb return (be32toh(hits)); 8319251358Snp } 8320222552Snp} 8321222552Snp 8322221474Snpstatic int 8323221474Snpget_filter(struct adapter *sc, struct t4_filter *t) 8324221474Snp{ 8325245274Snp int i, rc, nfilters = sc->tids.nftids; 8326221474Snp struct filter_entry *f; 8327221474Snp 8328245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 8329245274Snp "t4getf"); 8330245274Snp if (rc) 8331245274Snp return (rc); 8332221474Snp 8333221474Snp if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL || 8334221474Snp t->idx >= nfilters) { 8335221474Snp t->idx = 0xffffffff; 8336245274Snp goto done; 8337221474Snp } 8338221474Snp 8339221474Snp f = &sc->tids.ftid_tab[t->idx]; 8340221474Snp for (i = t->idx; i < nfilters; i++, f++) { 8341221474Snp if (f->valid) { 8342221474Snp t->idx = i; 8343222509Snp t->l2tidx = f->l2t ? f->l2t->idx : 0; 8344222509Snp t->smtidx = f->smtidx; 8345222552Snp if (f->fs.hitcnts) 8346222552Snp t->hits = get_filter_hits(sc, t->idx); 8347222552Snp else 8348222552Snp t->hits = UINT64_MAX; 8349221474Snp t->fs = f->fs; 8350221474Snp 8351245274Snp goto done; 8352221474Snp } 8353221474Snp } 8354221474Snp 8355221474Snp t->idx = 0xffffffff; 8356245274Snpdone: 8357245274Snp end_synchronized_op(sc, LOCK_HELD); 8358221474Snp return (0); 8359221474Snp} 8360221474Snp 8361221474Snpstatic int 8362221474Snpset_filter(struct adapter *sc, struct t4_filter *t) 8363221474Snp{ 8364221474Snp unsigned int nfilters, nports; 8365221474Snp struct filter_entry *f; 8366245274Snp int i, rc; 8367221474Snp 8368245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setf"); 8369245274Snp if (rc) 8370245274Snp return (rc); 8371221474Snp 8372221474Snp nfilters = sc->tids.nftids; 8373221474Snp nports = sc->params.nports; 8374221474Snp 8375245274Snp if (nfilters == 0) { 8376245274Snp rc = ENOTSUP; 8377245274Snp goto done; 8378245274Snp } 8379221474Snp 8380245274Snp if (t->idx >= nfilters) { 8381245274Snp rc = EINVAL; 8382245274Snp goto done; 8383245274Snp } 8384221474Snp 8385308304Sjhb /* Validate against the global filter mode and ingress config */ 8386308304Sjhb rc = check_fspec_against_fconf_iconf(sc, &t->fs); 8387308304Sjhb if (rc != 0) 8388245274Snp goto done; 8389221474Snp 8390245274Snp if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) { 8391245274Snp rc = EINVAL; 8392245274Snp goto done; 8393245274Snp } 8394221474Snp 8395245274Snp if (t->fs.val.iport >= nports) { 8396245274Snp rc = EINVAL; 8397245274Snp goto done; 8398245274Snp } 8399221474Snp 8400221474Snp /* Can't specify an iq if not steering to it */ 8401245274Snp if (!t->fs.dirsteer && t->fs.iq) { 8402245274Snp rc = EINVAL; 8403245274Snp goto done; 8404245274Snp } 8405221474Snp 8406221474Snp /* IPv6 filter idx must be 4 aligned */ 8407221474Snp if (t->fs.type == 1 && 8408245274Snp ((t->idx & 0x3) || t->idx + 4 >= nfilters)) { 8409245274Snp rc = EINVAL; 8410245274Snp goto done; 8411245274Snp } 8412221474Snp 8413309459Sjhb if (!(sc->flags & FULL_INIT_DONE) && 8414309459Sjhb ((rc = adapter_full_init(sc)) != 0)) 8415309459Sjhb goto done; 8416309459Sjhb 8417221474Snp if (sc->tids.ftid_tab == NULL) { 8418221474Snp KASSERT(sc->tids.ftids_in_use == 0, 8419221474Snp ("%s: no memory allocated but filters_in_use > 0", 8420221474Snp __func__)); 8421221474Snp 8422221474Snp sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) * 8423221474Snp nfilters, M_CXGBE, M_NOWAIT | M_ZERO); 8424245274Snp if (sc->tids.ftid_tab == NULL) { 8425245274Snp rc = ENOMEM; 8426245274Snp goto done; 8427245274Snp } 8428245274Snp mtx_init(&sc->tids.ftid_lock, "T4 filters", 0, MTX_DEF); 8429221474Snp } 8430221474Snp 8431221474Snp for (i = 0; i < 4; i++) { 8432221474Snp f = &sc->tids.ftid_tab[t->idx + i]; 8433221474Snp 8434245274Snp if (f->pending || f->valid) { 8435245274Snp rc = EBUSY; 8436245274Snp goto done; 8437245274Snp } 8438245274Snp if (f->locked) { 8439245274Snp rc = EPERM; 8440245274Snp goto done; 8441245274Snp } 8442221474Snp 8443221474Snp if (t->fs.type == 0) 8444221474Snp break; 8445221474Snp } 8446221474Snp 8447221474Snp f = &sc->tids.ftid_tab[t->idx]; 8448221474Snp f->fs = t->fs; 8449221474Snp 8450245274Snp rc = set_filter_wr(sc, t->idx); 8451245274Snpdone: 8452245274Snp end_synchronized_op(sc, 0); 8453245274Snp 8454245274Snp if (rc == 0) { 8455245274Snp mtx_lock(&sc->tids.ftid_lock); 8456245274Snp for (;;) { 8457245274Snp if (f->pending == 0) { 8458245274Snp rc = f->valid ? 0 : EIO; 8459245274Snp break; 8460245274Snp } 8461245274Snp 8462245274Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 8463245274Snp PCATCH, "t4setfw", 0)) { 8464245274Snp rc = EINPROGRESS; 8465245274Snp break; 8466245274Snp } 8467245274Snp } 8468245274Snp mtx_unlock(&sc->tids.ftid_lock); 8469245274Snp } 8470245274Snp return (rc); 8471221474Snp} 8472221474Snp 8473221474Snpstatic int 8474221474Snpdel_filter(struct adapter *sc, struct t4_filter *t) 8475221474Snp{ 8476221474Snp unsigned int nfilters; 8477221474Snp struct filter_entry *f; 8478245274Snp int rc; 8479221474Snp 8480245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4delf"); 8481245274Snp if (rc) 8482245274Snp return (rc); 8483221474Snp 8484221474Snp nfilters = sc->tids.nftids; 8485221474Snp 8486245274Snp if (nfilters == 0) { 8487245274Snp rc = ENOTSUP; 8488245274Snp goto done; 8489245274Snp } 8490221474Snp 8491221474Snp if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 || 8492245274Snp t->idx >= nfilters) { 8493245274Snp rc = EINVAL; 8494245274Snp goto done; 8495245274Snp } 8496221474Snp 8497245274Snp if (!(sc->flags & FULL_INIT_DONE)) { 8498245274Snp rc = EAGAIN; 8499245274Snp goto done; 8500245274Snp } 8501221474Snp 8502221474Snp f = &sc->tids.ftid_tab[t->idx]; 8503221474Snp 8504245274Snp if (f->pending) { 8505245274Snp rc = EBUSY; 8506245274Snp goto done; 8507245274Snp } 8508245274Snp if (f->locked) { 8509245274Snp rc = EPERM; 8510245274Snp goto done; 8511245274Snp } 8512221474Snp 8513221474Snp if (f->valid) { 8514221474Snp t->fs = f->fs; /* extra info for the caller */ 8515245274Snp rc = del_filter_wr(sc, t->idx); 8516221474Snp } 8517221474Snp 8518245274Snpdone: 8519245274Snp end_synchronized_op(sc, 0); 8520245274Snp 8521245274Snp if (rc == 0) { 8522245274Snp mtx_lock(&sc->tids.ftid_lock); 8523245274Snp for (;;) { 8524245274Snp if (f->pending == 0) { 8525245274Snp rc = f->valid ? EIO : 0; 8526245274Snp break; 8527245274Snp } 8528245274Snp 8529245274Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 8530245274Snp PCATCH, "t4delfw", 0)) { 8531245274Snp rc = EINPROGRESS; 8532245274Snp break; 8533245274Snp } 8534245274Snp } 8535245274Snp mtx_unlock(&sc->tids.ftid_lock); 8536245274Snp } 8537245274Snp 8538245274Snp return (rc); 8539221474Snp} 8540221474Snp 8541221474Snpstatic void 8542222509Snpclear_filter(struct filter_entry *f) 8543221474Snp{ 8544222509Snp if (f->l2t) 8545222509Snp t4_l2t_release(f->l2t); 8546222509Snp 8547221474Snp bzero(f, sizeof (*f)); 8548221474Snp} 8549221474Snp 8550221474Snpstatic int 8551221474Snpset_filter_wr(struct adapter *sc, int fidx) 8552221474Snp{ 8553221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 8554221474Snp struct fw_filter_wr *fwr; 8555308304Sjhb unsigned int ftid, vnic_vld, vnic_vld_mask; 8556284052Snp struct wrq_cookie cookie; 8557221474Snp 8558245274Snp ASSERT_SYNCHRONIZED_OP(sc); 8559221474Snp 8560222509Snp if (f->fs.newdmac || f->fs.newvlan) { 8561222509Snp /* This filter needs an L2T entry; allocate one. */ 8562222509Snp f->l2t = t4_l2t_alloc_switching(sc->l2t); 8563222509Snp if (f->l2t == NULL) 8564222509Snp return (EAGAIN); 8565222509Snp if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport, 8566222509Snp f->fs.dmac)) { 8567222509Snp t4_l2t_release(f->l2t); 8568222509Snp f->l2t = NULL; 8569222509Snp return (ENOMEM); 8570222509Snp } 8571222509Snp } 8572221474Snp 8573308304Sjhb /* Already validated against fconf, iconf */ 8574308304Sjhb MPASS((f->fs.val.pfvf_vld & f->fs.val.ovlan_vld) == 0); 8575308304Sjhb MPASS((f->fs.mask.pfvf_vld & f->fs.mask.ovlan_vld) == 0); 8576308304Sjhb if (f->fs.val.pfvf_vld || f->fs.val.ovlan_vld) 8577308304Sjhb vnic_vld = 1; 8578308304Sjhb else 8579308304Sjhb vnic_vld = 0; 8580308304Sjhb if (f->fs.mask.pfvf_vld || f->fs.mask.ovlan_vld) 8581308304Sjhb vnic_vld_mask = 1; 8582308304Sjhb else 8583308304Sjhb vnic_vld_mask = 0; 8584308304Sjhb 8585221474Snp ftid = sc->tids.ftid_base + fidx; 8586221474Snp 8587284052Snp fwr = start_wrq_wr(&sc->sge.mgmtq, howmany(sizeof(*fwr), 16), &cookie); 8588284052Snp if (fwr == NULL) 8589221474Snp return (ENOMEM); 8590284052Snp bzero(fwr, sizeof(*fwr)); 8591221474Snp 8592221474Snp fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR)); 8593221474Snp fwr->len16_pkd = htobe32(FW_LEN16(*fwr)); 8594221474Snp fwr->tid_to_iq = 8595221474Snp htobe32(V_FW_FILTER_WR_TID(ftid) | 8596221474Snp V_FW_FILTER_WR_RQTYPE(f->fs.type) | 8597221474Snp V_FW_FILTER_WR_NOREPLY(0) | 8598221474Snp V_FW_FILTER_WR_IQ(f->fs.iq)); 8599221474Snp fwr->del_filter_to_l2tix = 8600221474Snp htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) | 8601221474Snp V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) | 8602221474Snp V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) | 8603221474Snp V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) | 8604221474Snp V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) | 8605221474Snp V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) | 8606221474Snp V_FW_FILTER_WR_DMAC(f->fs.newdmac) | 8607221474Snp V_FW_FILTER_WR_SMAC(f->fs.newsmac) | 8608221474Snp V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT || 8609221474Snp f->fs.newvlan == VLAN_REWRITE) | 8610221474Snp V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE || 8611221474Snp f->fs.newvlan == VLAN_REWRITE) | 8612221474Snp V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) | 8613221474Snp V_FW_FILTER_WR_TXCHAN(f->fs.eport) | 8614221474Snp V_FW_FILTER_WR_PRIO(f->fs.prio) | 8615222509Snp V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0)); 8616221474Snp fwr->ethtype = htobe16(f->fs.val.ethtype); 8617221474Snp fwr->ethtypem = htobe16(f->fs.mask.ethtype); 8618221474Snp fwr->frag_to_ovlan_vldm = 8619221474Snp (V_FW_FILTER_WR_FRAG(f->fs.val.frag) | 8620221474Snp V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) | 8621228561Snp V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) | 8622308304Sjhb V_FW_FILTER_WR_OVLAN_VLD(vnic_vld) | 8623228561Snp V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) | 8624308304Sjhb V_FW_FILTER_WR_OVLAN_VLDM(vnic_vld_mask)); 8625221474Snp fwr->smac_sel = 0; 8626221474Snp fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) | 8627228561Snp V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id)); 8628221474Snp fwr->maci_to_matchtypem = 8629221474Snp htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) | 8630221474Snp V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) | 8631221474Snp V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) | 8632221474Snp V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) | 8633221474Snp V_FW_FILTER_WR_PORT(f->fs.val.iport) | 8634221474Snp V_FW_FILTER_WR_PORTM(f->fs.mask.iport) | 8635221474Snp V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) | 8636221474Snp V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype)); 8637221474Snp fwr->ptcl = f->fs.val.proto; 8638221474Snp fwr->ptclm = f->fs.mask.proto; 8639221474Snp fwr->ttyp = f->fs.val.tos; 8640221474Snp fwr->ttypm = f->fs.mask.tos; 8641228561Snp fwr->ivlan = htobe16(f->fs.val.vlan); 8642228561Snp fwr->ivlanm = htobe16(f->fs.mask.vlan); 8643228561Snp fwr->ovlan = htobe16(f->fs.val.vnic); 8644228561Snp fwr->ovlanm = htobe16(f->fs.mask.vnic); 8645221474Snp bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip)); 8646221474Snp bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm)); 8647221474Snp bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip)); 8648221474Snp bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm)); 8649221474Snp fwr->lp = htobe16(f->fs.val.dport); 8650221474Snp fwr->lpm = htobe16(f->fs.mask.dport); 8651221474Snp fwr->fp = htobe16(f->fs.val.sport); 8652221474Snp fwr->fpm = htobe16(f->fs.mask.sport); 8653221474Snp if (f->fs.newsmac) 8654221474Snp bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma)); 8655221474Snp 8656221474Snp f->pending = 1; 8657221474Snp sc->tids.ftids_in_use++; 8658228561Snp 8659284052Snp commit_wrq_wr(&sc->sge.mgmtq, fwr, &cookie); 8660228561Snp return (0); 8661221474Snp} 8662221474Snp 8663221474Snpstatic int 8664221474Snpdel_filter_wr(struct adapter *sc, int fidx) 8665221474Snp{ 8666221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 8667221474Snp struct fw_filter_wr *fwr; 8668228561Snp unsigned int ftid; 8669284052Snp struct wrq_cookie cookie; 8670221474Snp 8671221474Snp ftid = sc->tids.ftid_base + fidx; 8672221474Snp 8673284052Snp fwr = start_wrq_wr(&sc->sge.mgmtq, howmany(sizeof(*fwr), 16), &cookie); 8674284052Snp if (fwr == NULL) 8675221474Snp return (ENOMEM); 8676221474Snp bzero(fwr, sizeof (*fwr)); 8677221474Snp 8678228561Snp t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id); 8679221474Snp 8680221474Snp f->pending = 1; 8681284052Snp commit_wrq_wr(&sc->sge.mgmtq, fwr, &cookie); 8682228561Snp return (0); 8683221474Snp} 8684221474Snp 8685239338Snpint 8686239338Snpt4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 8687221474Snp{ 8688228561Snp struct adapter *sc = iq->adapter; 8689228561Snp const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1); 8690221474Snp unsigned int idx = GET_TID(rpl); 8691265426Snp unsigned int rc; 8692265426Snp struct filter_entry *f; 8693221474Snp 8694228561Snp KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__, 8695228561Snp rss->opcode)); 8696309442Sjhb MPASS(iq == &sc->sge.fwq); 8697309442Sjhb MPASS(is_ftid(sc, idx)); 8698228561Snp 8699309442Sjhb idx -= sc->tids.ftid_base; 8700309442Sjhb f = &sc->tids.ftid_tab[idx]; 8701309442Sjhb rc = G_COOKIE(rpl->cookie); 8702221474Snp 8703309442Sjhb mtx_lock(&sc->tids.ftid_lock); 8704309442Sjhb if (rc == FW_FILTER_WR_FLT_ADDED) { 8705309442Sjhb KASSERT(f->pending, ("%s: filter[%u] isn't pending.", 8706309442Sjhb __func__, idx)); 8707309442Sjhb f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff; 8708309442Sjhb f->pending = 0; /* asynchronous setup completed */ 8709309442Sjhb f->valid = 1; 8710309442Sjhb } else { 8711309442Sjhb if (rc != FW_FILTER_WR_FLT_DELETED) { 8712309442Sjhb /* Add or delete failed, display an error */ 8713309442Sjhb log(LOG_ERR, 8714309442Sjhb "filter %u setup failed with error %u\n", 8715309442Sjhb idx, rc); 8716309442Sjhb } 8717265426Snp 8718309442Sjhb clear_filter(f); 8719309442Sjhb sc->tids.ftids_in_use--; 8720221474Snp } 8721309442Sjhb wakeup(&sc->tids.ftid_tab); 8722309442Sjhb mtx_unlock(&sc->tids.ftid_lock); 8723228561Snp 8724228561Snp return (0); 8725221474Snp} 8726221474Snp 8727222973Snpstatic int 8728309442Sjhbset_tcb_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 8729309442Sjhb{ 8730309442Sjhb 8731309442Sjhb MPASS(iq->set_tcb_rpl != NULL); 8732309442Sjhb return (iq->set_tcb_rpl(iq, rss, m)); 8733309442Sjhb} 8734309442Sjhb 8735309442Sjhbstatic int 8736309442Sjhbl2t_write_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 8737309442Sjhb{ 8738309442Sjhb 8739309442Sjhb MPASS(iq->l2t_write_rpl != NULL); 8740309442Sjhb return (iq->l2t_write_rpl(iq, rss, m)); 8741309442Sjhb} 8742309442Sjhb 8743309442Sjhbstatic int 8744222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt) 8745222973Snp{ 8746245274Snp int rc; 8747222973Snp 8748222973Snp if (cntxt->cid > M_CTXTQID) 8749245274Snp return (EINVAL); 8750222973Snp 8751222973Snp if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS && 8752222973Snp cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM) 8753245274Snp return (EINVAL); 8754222973Snp 8755246575Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ctxt"); 8756246575Snp if (rc) 8757246575Snp return (rc); 8758246575Snp 8759222973Snp if (sc->flags & FW_OK) { 8760246575Snp rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id, 8761246575Snp &cntxt->data[0]); 8762246575Snp if (rc == 0) 8763246575Snp goto done; 8764222973Snp } 8765222973Snp 8766245274Snp /* 8767245274Snp * Read via firmware failed or wasn't even attempted. Read directly via 8768245274Snp * the backdoor. 8769245274Snp */ 8770246575Snp rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id, &cntxt->data[0]); 8771246575Snpdone: 8772246575Snp end_synchronized_op(sc, 0); 8773245274Snp return (rc); 8774245274Snp} 8775222973Snp 8776245274Snpstatic int 8777245274Snpload_fw(struct adapter *sc, struct t4_data *fw) 8778245274Snp{ 8779245274Snp int rc; 8780245274Snp uint8_t *fw_data; 8781245274Snp 8782245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ldfw"); 8783245274Snp if (rc) 8784245274Snp return (rc); 8785245274Snp 8786245274Snp if (sc->flags & FULL_INIT_DONE) { 8787245274Snp rc = EBUSY; 8788245274Snp goto done; 8789222973Snp } 8790222973Snp 8791245274Snp fw_data = malloc(fw->len, M_CXGBE, M_WAITOK); 8792245274Snp if (fw_data == NULL) { 8793245274Snp rc = ENOMEM; 8794245274Snp goto done; 8795245274Snp } 8796245274Snp 8797245274Snp rc = copyin(fw->data, fw_data, fw->len); 8798245274Snp if (rc == 0) 8799245274Snp rc = -t4_load_fw(sc, fw_data, fw->len); 8800245274Snp 8801245274Snp free(fw_data, M_CXGBE); 8802245274Snpdone: 8803245274Snp end_synchronized_op(sc, 0); 8804222973Snp return (rc); 8805222973Snp} 8806222973Snp 8807309569Sjhbstatic int 8808309569Sjhbload_cfg(struct adapter *sc, struct t4_data *cfg) 8809309569Sjhb{ 8810309569Sjhb int rc; 8811309569Sjhb uint8_t *cfg_data = NULL; 8812309569Sjhb 8813309569Sjhb rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ldcf"); 8814309569Sjhb if (rc) 8815309569Sjhb return (rc); 8816309569Sjhb 8817309569Sjhb if (cfg->len == 0) { 8818309569Sjhb /* clear */ 8819309569Sjhb rc = -t4_load_cfg(sc, NULL, 0); 8820309569Sjhb goto done; 8821309569Sjhb } 8822309569Sjhb 8823309569Sjhb cfg_data = malloc(cfg->len, M_CXGBE, M_WAITOK); 8824309569Sjhb if (cfg_data == NULL) { 8825309569Sjhb rc = ENOMEM; 8826309569Sjhb goto done; 8827309569Sjhb } 8828309569Sjhb 8829309569Sjhb rc = copyin(cfg->data, cfg_data, cfg->len); 8830309569Sjhb if (rc == 0) 8831309569Sjhb rc = -t4_load_cfg(sc, cfg_data, cfg->len); 8832309569Sjhb 8833309569Sjhb free(cfg_data, M_CXGBE); 8834309569Sjhbdone: 8835309569Sjhb end_synchronized_op(sc, 0); 8836309569Sjhb return (rc); 8837309569Sjhb} 8838309569Sjhb 8839308305Sjhb#define MAX_READ_BUF_SIZE (128 * 1024) 8840228561Snpstatic int 8841248925Snpread_card_mem(struct adapter *sc, int win, struct t4_mem_range *mr) 8842228561Snp{ 8843308305Sjhb uint32_t addr, remaining, n; 8844308305Sjhb uint32_t *buf; 8845228561Snp int rc; 8846248925Snp uint8_t *dst; 8847228561Snp 8848248925Snp rc = validate_mem_range(sc, mr->addr, mr->len); 8849248925Snp if (rc != 0) 8850248925Snp return (rc); 8851228561Snp 8852308305Sjhb buf = malloc(min(mr->len, MAX_READ_BUF_SIZE), M_CXGBE, M_WAITOK); 8853248925Snp addr = mr->addr; 8854228561Snp remaining = mr->len; 8855248925Snp dst = (void *)mr->data; 8856228561Snp 8857228561Snp while (remaining) { 8858308305Sjhb n = min(remaining, MAX_READ_BUF_SIZE); 8859308305Sjhb read_via_memwin(sc, 2, addr, buf, n); 8860228561Snp 8861248925Snp rc = copyout(buf, dst, n); 8862248925Snp if (rc != 0) 8863248925Snp break; 8864228561Snp 8865248925Snp dst += n; 8866248925Snp remaining -= n; 8867248925Snp addr += n; 8868228561Snp } 8869228561Snp 8870228561Snp free(buf, M_CXGBE); 8871228561Snp return (rc); 8872228561Snp} 8873308305Sjhb#undef MAX_READ_BUF_SIZE 8874228561Snp 8875241399Snpstatic int 8876241399Snpread_i2c(struct adapter *sc, struct t4_i2c_data *i2cd) 8877241399Snp{ 8878241399Snp int rc; 8879241399Snp 8880241399Snp if (i2cd->len == 0 || i2cd->port_id >= sc->params.nports) 8881241399Snp return (EINVAL); 8882241399Snp 8883269082Snp if (i2cd->len > sizeof(i2cd->data)) 8884269082Snp return (EFBIG); 8885241399Snp 8886245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4i2crd"); 8887245274Snp if (rc) 8888245274Snp return (rc); 8889241399Snp rc = -t4_i2c_rd(sc, sc->mbox, i2cd->port_id, i2cd->dev_addr, 8890269082Snp i2cd->offset, i2cd->len, &i2cd->data[0]); 8891245274Snp end_synchronized_op(sc, 0); 8892241399Snp 8893241399Snp return (rc); 8894241399Snp} 8895241399Snp 8896309447Sjhbint 8897218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap) 8898218792Snp{ 8899222102Snp int i; 8900218792Snp 8901222102Snp return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0); 8902218792Snp} 8903218792Snp 8904218792Snpint 8905218792Snpt4_os_pci_save_state(struct adapter *sc) 8906218792Snp{ 8907218792Snp device_t dev; 8908218792Snp struct pci_devinfo *dinfo; 8909218792Snp 8910218792Snp dev = sc->dev; 8911218792Snp dinfo = device_get_ivars(dev); 8912218792Snp 8913218792Snp pci_cfg_save(dev, dinfo, 0); 8914218792Snp return (0); 8915218792Snp} 8916218792Snp 8917218792Snpint 8918218792Snpt4_os_pci_restore_state(struct adapter *sc) 8919218792Snp{ 8920218792Snp device_t dev; 8921218792Snp struct pci_devinfo *dinfo; 8922218792Snp 8923218792Snp dev = sc->dev; 8924218792Snp dinfo = device_get_ivars(dev); 8925218792Snp 8926218792Snp pci_cfg_restore(dev, dinfo); 8927218792Snp return (0); 8928218792Snp} 8929219299Snp 8930218792Snpvoid 8931353418Snpt4_os_portmod_changed(struct port_info *pi) 8932218792Snp{ 8933353418Snp struct adapter *sc = pi->adapter; 8934308154Sjhb struct vi_info *vi; 8935308154Sjhb struct ifnet *ifp; 8936218792Snp static const char *mod_str[] = { 8937220232Snp NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM" 8938218792Snp }; 8939218792Snp 8940353418Snp MPASS((pi->flags & FIXED_IFMEDIA) == 0); 8941353418Snp 8942353418Snp vi = &pi->vi[0]; 8943353418Snp if (begin_synchronized_op(sc, vi, HOLD_LOCK, "t4mod") == 0) { 8944353418Snp PORT_LOCK(pi); 8945353418Snp build_medialist(pi, &pi->media); 8946353418Snp apply_l1cfg(pi); 8947353418Snp PORT_UNLOCK(pi); 8948353418Snp end_synchronized_op(sc, LOCK_HELD); 8949308154Sjhb } 8950281207Snp 8951353418Snp ifp = vi->ifp; 8952218792Snp if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 8953308154Sjhb if_printf(ifp, "transceiver unplugged.\n"); 8954220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) 8955308154Sjhb if_printf(ifp, "unknown transceiver inserted.\n"); 8956220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) 8957308154Sjhb if_printf(ifp, "unsupported transceiver inserted.\n"); 8958240452Snp else if (pi->mod_type > 0 && pi->mod_type < nitems(mod_str)) { 8959353418Snp if_printf(ifp, "%dGbps %s transceiver inserted.\n", 8960353418Snp port_top_speed(pi), mod_str[pi->mod_type]); 8961219299Snp } else { 8962308154Sjhb if_printf(ifp, "transceiver (type %d) inserted.\n", 8963219299Snp pi->mod_type); 8964219299Snp } 8965218792Snp} 8966218792Snp 8967218792Snpvoid 8968353418Snpt4_os_link_changed(struct port_info *pi) 8969218792Snp{ 8970308154Sjhb struct vi_info *vi; 8971308154Sjhb struct ifnet *ifp; 8972353418Snp struct link_config *lc; 8973308154Sjhb int v; 8974218792Snp 8975353418Snp PORT_LOCK_ASSERT_OWNED(pi); 8976353418Snp 8977308154Sjhb for_each_vi(pi, v, vi) { 8978308154Sjhb ifp = vi->ifp; 8979308154Sjhb if (ifp == NULL) 8980308154Sjhb continue; 8981308154Sjhb 8982353418Snp lc = &pi->link_cfg; 8983353418Snp if (lc->link_ok) { 8984353418Snp ifp->if_baudrate = IF_Mbps(lc->speed); 8985308154Sjhb if_link_state_change(ifp, LINK_STATE_UP); 8986308154Sjhb } else { 8987308154Sjhb if_link_state_change(ifp, LINK_STATE_DOWN); 8988308154Sjhb } 8989308154Sjhb } 8990218792Snp} 8991218792Snp 8992228561Snpvoid 8993228561Snpt4_iterate(void (*func)(struct adapter *, void *), void *arg) 8994228561Snp{ 8995228561Snp struct adapter *sc; 8996228561Snp 8997255006Snp sx_slock(&t4_list_lock); 8998228561Snp SLIST_FOREACH(sc, &t4_list, link) { 8999228561Snp /* 9000228561Snp * func should not make any assumptions about what state sc is 9001228561Snp * in - the only guarantee is that sc->sc_lock is a valid lock. 9002228561Snp */ 9003228561Snp func(sc, arg); 9004228561Snp } 9005255006Snp sx_sunlock(&t4_list_lock); 9006228561Snp} 9007228561Snp 9008218792Snpstatic int 9009218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag, 9010218792Snp struct thread *td) 9011218792Snp{ 9012218792Snp int rc; 9013218792Snp struct adapter *sc = dev->si_drv1; 9014218792Snp 9015218792Snp rc = priv_check(td, PRIV_DRIVER); 9016218792Snp if (rc != 0) 9017218792Snp return (rc); 9018218792Snp 9019218792Snp switch (cmd) { 9020220410Snp case CHELSIO_T4_GETREG: { 9021220410Snp struct t4_reg *edata = (struct t4_reg *)data; 9022220410Snp 9023218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 9024218792Snp return (EFAULT); 9025220410Snp 9026220410Snp if (edata->size == 4) 9027220410Snp edata->val = t4_read_reg(sc, edata->addr); 9028220410Snp else if (edata->size == 8) 9029220410Snp edata->val = t4_read_reg64(sc, edata->addr); 9030220410Snp else 9031220410Snp return (EINVAL); 9032220410Snp 9033218792Snp break; 9034218792Snp } 9035220410Snp case CHELSIO_T4_SETREG: { 9036220410Snp struct t4_reg *edata = (struct t4_reg *)data; 9037220410Snp 9038218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 9039218792Snp return (EFAULT); 9040220410Snp 9041220410Snp if (edata->size == 4) { 9042220410Snp if (edata->val & 0xffffffff00000000) 9043220410Snp return (EINVAL); 9044220410Snp t4_write_reg(sc, edata->addr, (uint32_t) edata->val); 9045220410Snp } else if (edata->size == 8) 9046220410Snp t4_write_reg64(sc, edata->addr, edata->val); 9047220410Snp else 9048220410Snp return (EINVAL); 9049218792Snp break; 9050218792Snp } 9051218792Snp case CHELSIO_T4_REGDUMP: { 9052218792Snp struct t4_regdump *regs = (struct t4_regdump *)data; 9053309447Sjhb int reglen = t4_get_regs_len(sc); 9054218792Snp uint8_t *buf; 9055218792Snp 9056218792Snp if (regs->len < reglen) { 9057218792Snp regs->len = reglen; /* hint to the caller */ 9058218792Snp return (ENOBUFS); 9059218792Snp } 9060218792Snp 9061218792Snp regs->len = reglen; 9062218792Snp buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO); 9063308304Sjhb get_regs(sc, regs, buf); 9064218792Snp rc = copyout(buf, regs->data, reglen); 9065218792Snp free(buf, M_CXGBE); 9066218792Snp break; 9067218792Snp } 9068221474Snp case CHELSIO_T4_GET_FILTER_MODE: 9069221474Snp rc = get_filter_mode(sc, (uint32_t *)data); 9070221474Snp break; 9071221474Snp case CHELSIO_T4_SET_FILTER_MODE: 9072221474Snp rc = set_filter_mode(sc, *(uint32_t *)data); 9073221474Snp break; 9074221474Snp case CHELSIO_T4_GET_FILTER: 9075221474Snp rc = get_filter(sc, (struct t4_filter *)data); 9076221474Snp break; 9077221474Snp case CHELSIO_T4_SET_FILTER: 9078221474Snp rc = set_filter(sc, (struct t4_filter *)data); 9079221474Snp break; 9080221474Snp case CHELSIO_T4_DEL_FILTER: 9081221474Snp rc = del_filter(sc, (struct t4_filter *)data); 9082221474Snp break; 9083222973Snp case CHELSIO_T4_GET_SGE_CONTEXT: 9084222973Snp rc = get_sge_context(sc, (struct t4_sge_context *)data); 9085222973Snp break; 9086245274Snp case CHELSIO_T4_LOAD_FW: 9087245274Snp rc = load_fw(sc, (struct t4_data *)data); 9088228561Snp break; 9089228561Snp case CHELSIO_T4_GET_MEM: 9090248925Snp rc = read_card_mem(sc, 2, (struct t4_mem_range *)data); 9091228561Snp break; 9092241399Snp case CHELSIO_T4_GET_I2C: 9093241399Snp rc = read_i2c(sc, (struct t4_i2c_data *)data); 9094241399Snp break; 9095241409Snp case CHELSIO_T4_CLEAR_STATS: { 9096308154Sjhb int i, v; 9097241409Snp u_int port_id = *(uint32_t *)data; 9098245518Snp struct port_info *pi; 9099308154Sjhb struct vi_info *vi; 9100241409Snp 9101241409Snp if (port_id >= sc->params.nports) 9102241409Snp return (EINVAL); 9103265410Snp pi = sc->port[port_id]; 9104309559Sjhb if (pi == NULL) 9105309559Sjhb return (EIO); 9106241409Snp 9107245518Snp /* MAC stats */ 9108265410Snp t4_clr_port_stats(sc, pi->tx_chan); 9109284052Snp pi->tx_parse_error = 0; 9110308305Sjhb mtx_lock(&sc->reg_lock); 9111308154Sjhb for_each_vi(pi, v, vi) { 9112308154Sjhb if (vi->flags & VI_INIT_DONE) 9113308154Sjhb t4_clr_vi_stats(sc, vi->viid); 9114308154Sjhb } 9115308305Sjhb mtx_unlock(&sc->reg_lock); 9116245518Snp 9117308154Sjhb /* 9118308154Sjhb * Since this command accepts a port, clear stats for 9119308154Sjhb * all VIs on this port. 9120308154Sjhb */ 9121308154Sjhb for_each_vi(pi, v, vi) { 9122308154Sjhb if (vi->flags & VI_INIT_DONE) { 9123308154Sjhb struct sge_rxq *rxq; 9124308154Sjhb struct sge_txq *txq; 9125308154Sjhb struct sge_wrq *wrq; 9126245518Snp 9127308154Sjhb for_each_rxq(vi, i, rxq) { 9128245518Snp#if defined(INET) || defined(INET6) 9129308154Sjhb rxq->lro.lro_queued = 0; 9130308154Sjhb rxq->lro.lro_flushed = 0; 9131245518Snp#endif 9132308154Sjhb rxq->rxcsum = 0; 9133308154Sjhb rxq->vlan_extraction = 0; 9134308154Sjhb } 9135245518Snp 9136308154Sjhb for_each_txq(vi, i, txq) { 9137308154Sjhb txq->txcsum = 0; 9138308154Sjhb txq->tso_wrs = 0; 9139308154Sjhb txq->vlan_insertion = 0; 9140308154Sjhb txq->imm_wrs = 0; 9141308154Sjhb txq->sgl_wrs = 0; 9142308154Sjhb txq->txpkt_wrs = 0; 9143308154Sjhb txq->txpkts0_wrs = 0; 9144308154Sjhb txq->txpkts1_wrs = 0; 9145308154Sjhb txq->txpkts0_pkts = 0; 9146308154Sjhb txq->txpkts1_pkts = 0; 9147308154Sjhb mp_ring_reset_stats(txq->r); 9148308154Sjhb } 9149245518Snp 9150245518Snp#ifdef TCP_OFFLOAD 9151308154Sjhb /* nothing to clear for each ofld_rxq */ 9152245518Snp 9153308154Sjhb for_each_ofld_txq(vi, i, wrq) { 9154308154Sjhb wrq->tx_wrs_direct = 0; 9155308154Sjhb wrq->tx_wrs_copied = 0; 9156308154Sjhb } 9157308154Sjhb#endif 9158308154Sjhb 9159308154Sjhb if (IS_MAIN_VI(vi)) { 9160308154Sjhb wrq = &sc->sge.ctrlq[pi->port_id]; 9161308154Sjhb wrq->tx_wrs_direct = 0; 9162308154Sjhb wrq->tx_wrs_copied = 0; 9163308154Sjhb } 9164245518Snp } 9165245518Snp } 9166241409Snp break; 9167241409Snp } 9168259142Snp case CHELSIO_T4_SCHED_CLASS: 9169309447Sjhb rc = t4_set_sched_class(sc, (struct t4_sched_params *)data); 9170259142Snp break; 9171259142Snp case CHELSIO_T4_SCHED_QUEUE: 9172309447Sjhb rc = t4_set_sched_queue(sc, (struct t4_sched_queue *)data); 9173259142Snp break; 9174253691Snp case CHELSIO_T4_GET_TRACER: 9175253691Snp rc = t4_get_tracer(sc, (struct t4_tracer *)data); 9176253691Snp break; 9177253691Snp case CHELSIO_T4_SET_TRACER: 9178253691Snp rc = t4_set_tracer(sc, (struct t4_tracer *)data); 9179253691Snp break; 9180309569Sjhb case CHELSIO_T4_LOAD_CFG: 9181309569Sjhb rc = load_cfg(sc, (struct t4_data *)data); 9182309569Sjhb break; 9183218792Snp default: 9184309447Sjhb rc = ENOTTY; 9185218792Snp } 9186218792Snp 9187218792Snp return (rc); 9188218792Snp} 9189218792Snp 9190308304Sjhbvoid 9191308304Sjhbt4_db_full(struct adapter *sc) 9192308304Sjhb{ 9193308304Sjhb 9194308304Sjhb CXGBE_UNIMPLEMENTED(__func__); 9195308304Sjhb} 9196308304Sjhb 9197308304Sjhbvoid 9198308304Sjhbt4_db_dropped(struct adapter *sc) 9199308304Sjhb{ 9200308304Sjhb 9201308304Sjhb CXGBE_UNIMPLEMENTED(__func__); 9202308304Sjhb} 9203308304Sjhb 9204237263Snp#ifdef TCP_OFFLOAD 9205270297Snpvoid 9206309440Sjhbt4_iscsi_init(struct adapter *sc, u_int tag_mask, const u_int *pgsz_order) 9207270297Snp{ 9208270297Snp 9209270297Snp t4_write_reg(sc, A_ULP_RX_ISCSI_TAGMASK, tag_mask); 9210270297Snp t4_write_reg(sc, A_ULP_RX_ISCSI_PSZ, V_HPZ0(pgsz_order[0]) | 9211270297Snp V_HPZ1(pgsz_order[1]) | V_HPZ2(pgsz_order[2]) | 9212270297Snp V_HPZ3(pgsz_order[3])); 9213270297Snp} 9214270297Snp 9215219392Snpstatic int 9216308154Sjhbtoe_capability(struct vi_info *vi, int enable) 9217228561Snp{ 9218228561Snp int rc; 9219308154Sjhb struct port_info *pi = vi->pi; 9220228561Snp struct adapter *sc = pi->adapter; 9221228561Snp 9222245274Snp ASSERT_SYNCHRONIZED_OP(sc); 9223228561Snp 9224228561Snp if (!is_offload(sc)) 9225228561Snp return (ENODEV); 9226228561Snp 9227228561Snp if (enable) { 9228308154Sjhb if ((vi->ifp->if_capenable & IFCAP_TOE) != 0) { 9229308154Sjhb /* TOE is already enabled. */ 9230308154Sjhb return (0); 9231308154Sjhb } 9232308154Sjhb 9233281248Snp /* 9234281248Snp * We need the port's queues around so that we're able to send 9235281248Snp * and receive CPLs to/from the TOE even if the ifnet for this 9236281248Snp * port has never been UP'd administratively. 9237281248Snp */ 9238308154Sjhb if (!(vi->flags & VI_INIT_DONE)) { 9239308154Sjhb rc = vi_full_init(vi); 9240245274Snp if (rc) 9241245274Snp return (rc); 9242237263Snp } 9243308154Sjhb if (!(pi->vi[0].flags & VI_INIT_DONE)) { 9244308154Sjhb rc = vi_full_init(&pi->vi[0]); 9245308154Sjhb if (rc) 9246308154Sjhb return (rc); 9247308154Sjhb } 9248237263Snp 9249308154Sjhb if (isset(&sc->offload_map, pi->port_id)) { 9250308154Sjhb /* TOE is enabled on another VI of this port. */ 9251308154Sjhb pi->uld_vis++; 9252228561Snp return (0); 9253308154Sjhb } 9254228561Snp 9255284089Snp if (!uld_active(sc, ULD_TOM)) { 9256237263Snp rc = t4_activate_uld(sc, ULD_TOM); 9257237263Snp if (rc == EAGAIN) { 9258237263Snp log(LOG_WARNING, 9259237263Snp "You must kldload t4_tom.ko before trying " 9260237263Snp "to enable TOE on a cxgbe interface.\n"); 9261237263Snp } 9262228561Snp if (rc != 0) 9263228561Snp return (rc); 9264237263Snp KASSERT(sc->tom_softc != NULL, 9265237263Snp ("%s: TOM activated but softc NULL", __func__)); 9266284089Snp KASSERT(uld_active(sc, ULD_TOM), 9267237263Snp ("%s: TOM activated but flag not set", __func__)); 9268228561Snp } 9269228561Snp 9270284089Snp /* Activate iWARP and iSCSI too, if the modules are loaded. */ 9271284089Snp if (!uld_active(sc, ULD_IWARP)) 9272284089Snp (void) t4_activate_uld(sc, ULD_IWARP); 9273284089Snp if (!uld_active(sc, ULD_ISCSI)) 9274284089Snp (void) t4_activate_uld(sc, ULD_ISCSI); 9275284089Snp 9276308154Sjhb pi->uld_vis++; 9277228561Snp setbit(&sc->offload_map, pi->port_id); 9278228561Snp } else { 9279308154Sjhb pi->uld_vis--; 9280308154Sjhb 9281308154Sjhb if (!isset(&sc->offload_map, pi->port_id) || pi->uld_vis > 0) 9282228561Snp return (0); 9283228561Snp 9284284089Snp KASSERT(uld_active(sc, ULD_TOM), 9285237263Snp ("%s: TOM never initialized?", __func__)); 9286228561Snp clrbit(&sc->offload_map, pi->port_id); 9287228561Snp } 9288228561Snp 9289228561Snp return (0); 9290228561Snp} 9291228561Snp 9292228561Snp/* 9293228561Snp * Add an upper layer driver to the global list. 9294228561Snp */ 9295228561Snpint 9296228561Snpt4_register_uld(struct uld_info *ui) 9297228561Snp{ 9298228561Snp int rc = 0; 9299228561Snp struct uld_info *u; 9300228561Snp 9301255006Snp sx_xlock(&t4_uld_list_lock); 9302228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 9303228561Snp if (u->uld_id == ui->uld_id) { 9304228561Snp rc = EEXIST; 9305228561Snp goto done; 9306228561Snp } 9307228561Snp } 9308228561Snp 9309228561Snp SLIST_INSERT_HEAD(&t4_uld_list, ui, link); 9310228561Snp ui->refcount = 0; 9311228561Snpdone: 9312255006Snp sx_xunlock(&t4_uld_list_lock); 9313228561Snp return (rc); 9314228561Snp} 9315228561Snp 9316228561Snpint 9317228561Snpt4_unregister_uld(struct uld_info *ui) 9318228561Snp{ 9319228561Snp int rc = EINVAL; 9320228561Snp struct uld_info *u; 9321228561Snp 9322255006Snp sx_xlock(&t4_uld_list_lock); 9323228561Snp 9324228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 9325228561Snp if (u == ui) { 9326228561Snp if (ui->refcount > 0) { 9327228561Snp rc = EBUSY; 9328228561Snp goto done; 9329228561Snp } 9330228561Snp 9331228561Snp SLIST_REMOVE(&t4_uld_list, ui, uld_info, link); 9332228561Snp rc = 0; 9333228561Snp goto done; 9334228561Snp } 9335228561Snp } 9336228561Snpdone: 9337255006Snp sx_xunlock(&t4_uld_list_lock); 9338228561Snp return (rc); 9339228561Snp} 9340228561Snp 9341237263Snpint 9342237263Snpt4_activate_uld(struct adapter *sc, int id) 9343228561Snp{ 9344284089Snp int rc; 9345228561Snp struct uld_info *ui; 9346228561Snp 9347245274Snp ASSERT_SYNCHRONIZED_OP(sc); 9348245274Snp 9349284089Snp if (id < 0 || id > ULD_MAX) 9350284089Snp return (EINVAL); 9351284089Snp rc = EAGAIN; /* kldoad the module with this ULD and try again. */ 9352284089Snp 9353255006Snp sx_slock(&t4_uld_list_lock); 9354228561Snp 9355228561Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 9356228561Snp if (ui->uld_id == id) { 9357282367Snp if (!(sc->flags & FULL_INIT_DONE)) { 9358282367Snp rc = adapter_full_init(sc); 9359282367Snp if (rc != 0) 9360284089Snp break; 9361282367Snp } 9362282367Snp 9363237263Snp rc = ui->activate(sc); 9364284089Snp if (rc == 0) { 9365284089Snp setbit(&sc->active_ulds, id); 9366228561Snp ui->refcount++; 9367284089Snp } 9368284089Snp break; 9369228561Snp } 9370228561Snp } 9371284089Snp 9372255006Snp sx_sunlock(&t4_uld_list_lock); 9373228561Snp 9374228561Snp return (rc); 9375228561Snp} 9376228561Snp 9377237263Snpint 9378237263Snpt4_deactivate_uld(struct adapter *sc, int id) 9379228561Snp{ 9380284089Snp int rc; 9381237263Snp struct uld_info *ui; 9382228561Snp 9383245274Snp ASSERT_SYNCHRONIZED_OP(sc); 9384245274Snp 9385284089Snp if (id < 0 || id > ULD_MAX) 9386284089Snp return (EINVAL); 9387284089Snp rc = ENXIO; 9388284089Snp 9389255006Snp sx_slock(&t4_uld_list_lock); 9390228561Snp 9391237263Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 9392237263Snp if (ui->uld_id == id) { 9393237263Snp rc = ui->deactivate(sc); 9394284089Snp if (rc == 0) { 9395284089Snp clrbit(&sc->active_ulds, id); 9396237263Snp ui->refcount--; 9397284089Snp } 9398284089Snp break; 9399237263Snp } 9400228561Snp } 9401284089Snp 9402255006Snp sx_sunlock(&t4_uld_list_lock); 9403228561Snp 9404228561Snp return (rc); 9405228561Snp} 9406284089Snp 9407284089Snpint 9408284089Snpuld_active(struct adapter *sc, int uld_id) 9409284089Snp{ 9410284089Snp 9411284089Snp MPASS(uld_id >= 0 && uld_id <= ULD_MAX); 9412284089Snp 9413284089Snp return (isset(&sc->active_ulds, uld_id)); 9414284089Snp} 9415228561Snp#endif 9416228561Snp 9417228561Snp/* 9418318809Snp * t = ptr to tunable. 9419318809Snp * nc = number of CPUs. 9420318809Snp * c = compiled in default for that tunable. 9421318809Snp */ 9422318809Snpstatic void 9423318809Snpcalculate_nqueues(int *t, int nc, const int c) 9424318809Snp{ 9425318809Snp int nq; 9426318809Snp 9427318809Snp if (*t > 0) 9428318809Snp return; 9429318809Snp nq = *t < 0 ? -*t : c; 9430318809Snp *t = min(nc, nq); 9431318809Snp} 9432318809Snp 9433318809Snp/* 9434228561Snp * Come up with reasonable defaults for some of the tunables, provided they're 9435228561Snp * not set by the user (in which case we'll use the values as is). 9436228561Snp */ 9437228561Snpstatic void 9438228561Snptweak_tunables(void) 9439228561Snp{ 9440228561Snp int nc = mp_ncpus; /* our snapshot of the number of CPUs */ 9441228561Snp 9442308153Sjhb if (t4_ntxq10g < 1) { 9443308153Sjhb#ifdef RSS 9444308153Sjhb t4_ntxq10g = rss_getnumbuckets(); 9445308153Sjhb#else 9446318809Snp calculate_nqueues(&t4_ntxq10g, nc, NTXQ_10G); 9447308153Sjhb#endif 9448308153Sjhb } 9449228561Snp 9450308153Sjhb if (t4_ntxq1g < 1) { 9451308153Sjhb#ifdef RSS 9452308153Sjhb /* XXX: way too many for 1GbE? */ 9453308153Sjhb t4_ntxq1g = rss_getnumbuckets(); 9454308153Sjhb#else 9455318809Snp calculate_nqueues(&t4_ntxq1g, nc, NTXQ_1G); 9456308153Sjhb#endif 9457308153Sjhb } 9458228561Snp 9459318809Snp calculate_nqueues(&t4_ntxq_vi, nc, NTXQ_VI); 9460308154Sjhb 9461308153Sjhb if (t4_nrxq10g < 1) { 9462308153Sjhb#ifdef RSS 9463308153Sjhb t4_nrxq10g = rss_getnumbuckets(); 9464308153Sjhb#else 9465318809Snp calculate_nqueues(&t4_nrxq10g, nc, NRXQ_10G); 9466308153Sjhb#endif 9467308153Sjhb } 9468228561Snp 9469308153Sjhb if (t4_nrxq1g < 1) { 9470308153Sjhb#ifdef RSS 9471308153Sjhb /* XXX: way too many for 1GbE? */ 9472308153Sjhb t4_nrxq1g = rss_getnumbuckets(); 9473308153Sjhb#else 9474318809Snp calculate_nqueues(&t4_nrxq1g, nc, NRXQ_1G); 9475308153Sjhb#endif 9476308153Sjhb } 9477228561Snp 9478318809Snp calculate_nqueues(&t4_nrxq_vi, nc, NRXQ_VI); 9479308154Sjhb 9480237263Snp#ifdef TCP_OFFLOAD 9481318809Snp calculate_nqueues(&t4_nofldtxq10g, nc, NOFLDTXQ_10G); 9482318809Snp calculate_nqueues(&t4_nofldtxq1g, nc, NOFLDTXQ_1G); 9483318809Snp calculate_nqueues(&t4_nofldtxq_vi, nc, NOFLDTXQ_VI); 9484318809Snp calculate_nqueues(&t4_nofldrxq10g, nc, NOFLDRXQ_10G); 9485318809Snp calculate_nqueues(&t4_nofldrxq1g, nc, NOFLDRXQ_1G); 9486318809Snp calculate_nqueues(&t4_nofldrxq_vi, nc, NOFLDRXQ_VI); 9487228561Snp 9488238028Snp if (t4_toecaps_allowed == -1) 9489238028Snp t4_toecaps_allowed = FW_CAPS_CONFIG_TOE; 9490308313Sjhb 9491308313Sjhb if (t4_rdmacaps_allowed == -1) { 9492308313Sjhb t4_rdmacaps_allowed = FW_CAPS_CONFIG_RDMA_RDDP | 9493308313Sjhb FW_CAPS_CONFIG_RDMA_RDMAC; 9494308313Sjhb } 9495308313Sjhb 9496308313Sjhb if (t4_iscsicaps_allowed == -1) { 9497308313Sjhb t4_iscsicaps_allowed = FW_CAPS_CONFIG_ISCSI_INITIATOR_PDU | 9498308313Sjhb FW_CAPS_CONFIG_ISCSI_TARGET_PDU | 9499308313Sjhb FW_CAPS_CONFIG_ISCSI_T10DIF; 9500308313Sjhb } 9501238028Snp#else 9502238028Snp if (t4_toecaps_allowed == -1) 9503238028Snp t4_toecaps_allowed = 0; 9504308313Sjhb 9505308313Sjhb if (t4_rdmacaps_allowed == -1) 9506308313Sjhb t4_rdmacaps_allowed = 0; 9507308313Sjhb 9508308313Sjhb if (t4_iscsicaps_allowed == -1) 9509308313Sjhb t4_iscsicaps_allowed = 0; 9510228561Snp#endif 9511228561Snp 9512270297Snp#ifdef DEV_NETMAP 9513318809Snp calculate_nqueues(&t4_nnmtxq_vi, nc, NNMTXQ_VI); 9514318809Snp calculate_nqueues(&t4_nnmrxq_vi, nc, NNMRXQ_VI); 9515270297Snp#endif 9516270297Snp 9517228561Snp if (t4_tmr_idx_10g < 0 || t4_tmr_idx_10g >= SGE_NTIMERS) 9518228561Snp t4_tmr_idx_10g = TMR_IDX_10G; 9519228561Snp 9520228561Snp if (t4_pktc_idx_10g < -1 || t4_pktc_idx_10g >= SGE_NCOUNTERS) 9521228561Snp t4_pktc_idx_10g = PKTC_IDX_10G; 9522228561Snp 9523228561Snp if (t4_tmr_idx_1g < 0 || t4_tmr_idx_1g >= SGE_NTIMERS) 9524228561Snp t4_tmr_idx_1g = TMR_IDX_1G; 9525228561Snp 9526228561Snp if (t4_pktc_idx_1g < -1 || t4_pktc_idx_1g >= SGE_NCOUNTERS) 9527228561Snp t4_pktc_idx_1g = PKTC_IDX_1G; 9528228561Snp 9529228561Snp if (t4_qsize_txq < 128) 9530228561Snp t4_qsize_txq = 128; 9531228561Snp 9532228561Snp if (t4_qsize_rxq < 128) 9533228561Snp t4_qsize_rxq = 128; 9534228561Snp while (t4_qsize_rxq & 7) 9535228561Snp t4_qsize_rxq++; 9536228561Snp 9537228561Snp t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX; 9538228561Snp} 9539228561Snp 9540308318Sjhb#ifdef DDB 9541308318Sjhbstatic void 9542308318Sjhbt4_dump_tcb(struct adapter *sc, int tid) 9543308318Sjhb{ 9544308318Sjhb uint32_t base, i, j, off, pf, reg, save, tcb_addr, win_pos; 9545308318Sjhb 9546308318Sjhb reg = PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2); 9547308318Sjhb save = t4_read_reg(sc, reg); 9548308318Sjhb base = sc->memwin[2].mw_base; 9549308318Sjhb 9550308318Sjhb /* Dump TCB for the tid */ 9551308318Sjhb tcb_addr = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 9552308318Sjhb tcb_addr += tid * TCB_SIZE; 9553308318Sjhb 9554308318Sjhb if (is_t4(sc)) { 9555308318Sjhb pf = 0; 9556308318Sjhb win_pos = tcb_addr & ~0xf; /* start must be 16B aligned */ 9557308318Sjhb } else { 9558308318Sjhb pf = V_PFNUM(sc->pf); 9559308318Sjhb win_pos = tcb_addr & ~0x7f; /* start must be 128B aligned */ 9560308318Sjhb } 9561308318Sjhb t4_write_reg(sc, reg, win_pos | pf); 9562308318Sjhb t4_read_reg(sc, reg); 9563308318Sjhb 9564308318Sjhb off = tcb_addr - win_pos; 9565308318Sjhb for (i = 0; i < 4; i++) { 9566308318Sjhb uint32_t buf[8]; 9567308318Sjhb for (j = 0; j < 8; j++, off += 4) 9568308318Sjhb buf[j] = htonl(t4_read_reg(sc, base + off)); 9569308318Sjhb 9570308318Sjhb db_printf("%08x %08x %08x %08x %08x %08x %08x %08x\n", 9571308318Sjhb buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], 9572308318Sjhb buf[7]); 9573308318Sjhb } 9574308318Sjhb 9575308318Sjhb t4_write_reg(sc, reg, save); 9576308318Sjhb t4_read_reg(sc, reg); 9577308318Sjhb} 9578308318Sjhb 9579308318Sjhbstatic void 9580308318Sjhbt4_dump_devlog(struct adapter *sc) 9581308318Sjhb{ 9582308318Sjhb struct devlog_params *dparams = &sc->params.devlog; 9583308318Sjhb struct fw_devlog_e e; 9584308318Sjhb int i, first, j, m, nentries, rc; 9585308318Sjhb uint64_t ftstamp = UINT64_MAX; 9586308318Sjhb 9587308318Sjhb if (dparams->start == 0) { 9588308318Sjhb db_printf("devlog params not valid\n"); 9589308318Sjhb return; 9590308318Sjhb } 9591308318Sjhb 9592308318Sjhb nentries = dparams->size / sizeof(struct fw_devlog_e); 9593308318Sjhb m = fwmtype_to_hwmtype(dparams->memtype); 9594308318Sjhb 9595308318Sjhb /* Find the first entry. */ 9596308318Sjhb first = -1; 9597308318Sjhb for (i = 0; i < nentries && !db_pager_quit; i++) { 9598308318Sjhb rc = -t4_mem_read(sc, m, dparams->start + i * sizeof(e), 9599308318Sjhb sizeof(e), (void *)&e); 9600308318Sjhb if (rc != 0) 9601308318Sjhb break; 9602308318Sjhb 9603308318Sjhb if (e.timestamp == 0) 9604308318Sjhb break; 9605308318Sjhb 9606308318Sjhb e.timestamp = be64toh(e.timestamp); 9607308318Sjhb if (e.timestamp < ftstamp) { 9608308318Sjhb ftstamp = e.timestamp; 9609308318Sjhb first = i; 9610308318Sjhb } 9611308318Sjhb } 9612308318Sjhb 9613308318Sjhb if (first == -1) 9614308318Sjhb return; 9615308318Sjhb 9616308318Sjhb i = first; 9617308318Sjhb do { 9618308318Sjhb rc = -t4_mem_read(sc, m, dparams->start + i * sizeof(e), 9619308318Sjhb sizeof(e), (void *)&e); 9620308318Sjhb if (rc != 0) 9621308318Sjhb return; 9622308318Sjhb 9623308318Sjhb if (e.timestamp == 0) 9624308318Sjhb return; 9625308318Sjhb 9626308318Sjhb e.timestamp = be64toh(e.timestamp); 9627308318Sjhb e.seqno = be32toh(e.seqno); 9628308318Sjhb for (j = 0; j < 8; j++) 9629308318Sjhb e.params[j] = be32toh(e.params[j]); 9630308318Sjhb 9631308318Sjhb db_printf("%10d %15ju %8s %8s ", 9632308318Sjhb e.seqno, e.timestamp, 9633308318Sjhb (e.level < nitems(devlog_level_strings) ? 9634308318Sjhb devlog_level_strings[e.level] : "UNKNOWN"), 9635308318Sjhb (e.facility < nitems(devlog_facility_strings) ? 9636308318Sjhb devlog_facility_strings[e.facility] : "UNKNOWN")); 9637308318Sjhb db_printf(e.fmt, e.params[0], e.params[1], e.params[2], 9638308318Sjhb e.params[3], e.params[4], e.params[5], e.params[6], 9639308318Sjhb e.params[7]); 9640308318Sjhb 9641308318Sjhb if (++i == nentries) 9642308318Sjhb i = 0; 9643308318Sjhb } while (i != first && !db_pager_quit); 9644308318Sjhb} 9645308318Sjhb 9646308318Sjhbstatic struct command_table db_t4_table = LIST_HEAD_INITIALIZER(db_t4_table); 9647308318Sjhb_DB_SET(_show, t4, NULL, db_show_table, 0, &db_t4_table); 9648308318Sjhb 9649308318SjhbDB_FUNC(devlog, db_show_devlog, db_t4_table, CS_OWN, NULL) 9650308318Sjhb{ 9651308318Sjhb device_t dev; 9652308318Sjhb int t; 9653308318Sjhb bool valid; 9654308318Sjhb 9655308318Sjhb valid = false; 9656308318Sjhb t = db_read_token(); 9657308318Sjhb if (t == tIDENT) { 9658308318Sjhb dev = device_lookup_by_name(db_tok_string); 9659308318Sjhb valid = true; 9660308318Sjhb } 9661308318Sjhb db_skip_to_eol(); 9662308318Sjhb if (!valid) { 9663308318Sjhb db_printf("usage: show t4 devlog <nexus>\n"); 9664308318Sjhb return; 9665308318Sjhb } 9666308318Sjhb 9667308318Sjhb if (dev == NULL) { 9668308318Sjhb db_printf("device not found\n"); 9669308318Sjhb return; 9670308318Sjhb } 9671308318Sjhb 9672308318Sjhb t4_dump_devlog(device_get_softc(dev)); 9673308318Sjhb} 9674308318Sjhb 9675308318SjhbDB_FUNC(tcb, db_show_t4tcb, db_t4_table, CS_OWN, NULL) 9676308318Sjhb{ 9677308318Sjhb device_t dev; 9678308318Sjhb int radix, tid, t; 9679308318Sjhb bool valid; 9680308318Sjhb 9681308318Sjhb valid = false; 9682308318Sjhb radix = db_radix; 9683308318Sjhb db_radix = 10; 9684308318Sjhb t = db_read_token(); 9685308318Sjhb if (t == tIDENT) { 9686308318Sjhb dev = device_lookup_by_name(db_tok_string); 9687308318Sjhb t = db_read_token(); 9688308318Sjhb if (t == tNUMBER) { 9689308318Sjhb tid = db_tok_number; 9690308318Sjhb valid = true; 9691308318Sjhb } 9692308318Sjhb } 9693308318Sjhb db_radix = radix; 9694308318Sjhb db_skip_to_eol(); 9695308318Sjhb if (!valid) { 9696308318Sjhb db_printf("usage: show t4 tcb <nexus> <tid>\n"); 9697308318Sjhb return; 9698308318Sjhb } 9699308318Sjhb 9700308318Sjhb if (dev == NULL) { 9701308318Sjhb db_printf("device not found\n"); 9702308318Sjhb return; 9703308318Sjhb } 9704308318Sjhb if (tid < 0) { 9705308318Sjhb db_printf("invalid tid\n"); 9706308318Sjhb return; 9707308318Sjhb } 9708308318Sjhb 9709308318Sjhb t4_dump_tcb(device_get_softc(dev), tid); 9710308318Sjhb} 9711308318Sjhb#endif 9712308318Sjhb 9713269356Snpstatic struct sx mlu; /* mod load unload */ 9714269356SnpSX_SYSINIT(cxgbe_mlu, &mlu, "cxgbe mod load/unload"); 9715269356Snp 9716228561Snpstatic int 9717249370Snpmod_event(module_t mod, int cmd, void *arg) 9718219392Snp{ 9719228561Snp int rc = 0; 9720249370Snp static int loaded = 0; 9721219392Snp 9722228561Snp switch (cmd) { 9723228561Snp case MOD_LOAD: 9724269356Snp sx_xlock(&mlu); 9725269356Snp if (loaded++ == 0) { 9726269356Snp t4_sge_modload(); 9727309442Sjhb t4_register_cpl_handler(CPL_SET_TCB_RPL, set_tcb_rpl); 9728309442Sjhb t4_register_cpl_handler(CPL_L2T_WRITE_RPL, l2t_write_rpl); 9729309442Sjhb t4_register_cpl_handler(CPL_TRACE_PKT, t4_trace_pkt); 9730309442Sjhb t4_register_cpl_handler(CPL_T5_TRACE_PKT, t5_trace_pkt); 9731269356Snp sx_init(&t4_list_lock, "T4/T5 adapters"); 9732269356Snp SLIST_INIT(&t4_list); 9733237263Snp#ifdef TCP_OFFLOAD 9734269356Snp sx_init(&t4_uld_list_lock, "T4/T5 ULDs"); 9735269356Snp SLIST_INIT(&t4_uld_list); 9736228561Snp#endif 9737269356Snp t4_tracer_modload(); 9738269356Snp tweak_tunables(); 9739269356Snp } 9740269356Snp sx_xunlock(&mlu); 9741228561Snp break; 9742219392Snp 9743228561Snp case MOD_UNLOAD: 9744269356Snp sx_xlock(&mlu); 9745269356Snp if (--loaded == 0) { 9746269356Snp int tries; 9747269356Snp 9748269356Snp sx_slock(&t4_list_lock); 9749269356Snp if (!SLIST_EMPTY(&t4_list)) { 9750269356Snp rc = EBUSY; 9751269356Snp sx_sunlock(&t4_list_lock); 9752269356Snp goto done_unload; 9753269356Snp } 9754237263Snp#ifdef TCP_OFFLOAD 9755269356Snp sx_slock(&t4_uld_list_lock); 9756269356Snp if (!SLIST_EMPTY(&t4_uld_list)) { 9757269356Snp rc = EBUSY; 9758269356Snp sx_sunlock(&t4_uld_list_lock); 9759269356Snp sx_sunlock(&t4_list_lock); 9760269356Snp goto done_unload; 9761269356Snp } 9762269356Snp#endif 9763269356Snp tries = 0; 9764269356Snp while (tries++ < 5 && t4_sge_extfree_refs() != 0) { 9765269356Snp uprintf("%ju clusters with custom free routine " 9766269356Snp "still is use.\n", t4_sge_extfree_refs()); 9767269356Snp pause("t4unload", 2 * hz); 9768269356Snp } 9769269356Snp#ifdef TCP_OFFLOAD 9770255006Snp sx_sunlock(&t4_uld_list_lock); 9771228561Snp#endif 9772255006Snp sx_sunlock(&t4_list_lock); 9773269356Snp 9774269356Snp if (t4_sge_extfree_refs() == 0) { 9775269356Snp t4_tracer_modunload(); 9776269356Snp#ifdef TCP_OFFLOAD 9777269356Snp sx_destroy(&t4_uld_list_lock); 9778269356Snp#endif 9779269356Snp sx_destroy(&t4_list_lock); 9780269356Snp t4_sge_modunload(); 9781269356Snp loaded = 0; 9782269356Snp } else { 9783269356Snp rc = EBUSY; 9784269356Snp loaded++; /* undo earlier decrement */ 9785269356Snp } 9786228561Snp } 9787269356Snpdone_unload: 9788269356Snp sx_xunlock(&mlu); 9789228561Snp break; 9790228561Snp } 9791228561Snp 9792228561Snp return (rc); 9793219392Snp} 9794219392Snp 9795309560Sjhbstatic devclass_t t4_devclass, t5_devclass, t6_devclass; 9796309560Sjhbstatic devclass_t cxgbe_devclass, cxl_devclass, cc_devclass; 9797309560Sjhbstatic devclass_t vcxgbe_devclass, vcxl_devclass, vcc_devclass; 9798218792Snp 9799249370SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, mod_event, 0); 9800218792SnpMODULE_VERSION(t4nex, 1); 9801250697SkibMODULE_DEPEND(t4nex, firmware, 1, 1, 1); 9802218792Snp 9803249370SnpDRIVER_MODULE(t5nex, pci, t5_driver, t5_devclass, mod_event, 0); 9804248925SnpMODULE_VERSION(t5nex, 1); 9805250697SkibMODULE_DEPEND(t5nex, firmware, 1, 1, 1); 9806248925Snp 9807309560SjhbDRIVER_MODULE(t6nex, pci, t6_driver, t6_devclass, mod_event, 0); 9808309560SjhbMODULE_VERSION(t6nex, 1); 9809309560SjhbMODULE_DEPEND(t6nex, firmware, 1, 1, 1); 9810309560Sjhb#ifdef DEV_NETMAP 9811309560SjhbMODULE_DEPEND(t6nex, netmap, 1, 1, 1); 9812309560Sjhb#endif /* DEV_NETMAP */ 9813309560Sjhb 9814218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0); 9815218792SnpMODULE_VERSION(cxgbe, 1); 9816248925Snp 9817248925SnpDRIVER_MODULE(cxl, t5nex, cxl_driver, cxl_devclass, 0, 0); 9818248925SnpMODULE_VERSION(cxl, 1); 9819308154Sjhb 9820309560SjhbDRIVER_MODULE(cc, t6nex, cc_driver, cc_devclass, 0, 0); 9821309560SjhbMODULE_VERSION(cc, 1); 9822309560Sjhb 9823308154SjhbDRIVER_MODULE(vcxgbe, cxgbe, vcxgbe_driver, vcxgbe_devclass, 0, 0); 9824308154SjhbMODULE_VERSION(vcxgbe, 1); 9825308154Sjhb 9826308154SjhbDRIVER_MODULE(vcxl, cxl, vcxl_driver, vcxl_devclass, 0, 0); 9827308154SjhbMODULE_VERSION(vcxl, 1); 9828309560Sjhb 9829309560SjhbDRIVER_MODULE(vcc, cc, vcc_driver, vcc_devclass, 0, 0); 9830309560SjhbMODULE_VERSION(vcc, 1); 9831