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$"); 30218792Snp 31218792Snp#include "opt_inet.h" 32237925Snp#include "opt_inet6.h" 33218792Snp 34218792Snp#include <sys/param.h> 35218792Snp#include <sys/conf.h> 36218792Snp#include <sys/priv.h> 37218792Snp#include <sys/kernel.h> 38218792Snp#include <sys/bus.h> 39218792Snp#include <sys/module.h> 40219286Snp#include <sys/malloc.h> 41219286Snp#include <sys/queue.h> 42219286Snp#include <sys/taskqueue.h> 43218792Snp#include <sys/pciio.h> 44218792Snp#include <dev/pci/pcireg.h> 45218792Snp#include <dev/pci/pcivar.h> 46218792Snp#include <dev/pci/pci_private.h> 47218792Snp#include <sys/firmware.h> 48219436Snp#include <sys/sbuf.h> 49218792Snp#include <sys/smp.h> 50218792Snp#include <sys/socket.h> 51218792Snp#include <sys/sockio.h> 52218792Snp#include <sys/sysctl.h> 53218792Snp#include <net/ethernet.h> 54218792Snp#include <net/if.h> 55218792Snp#include <net/if_types.h> 56218792Snp#include <net/if_dl.h> 57222003Snp#include <net/if_vlan_var.h> 58252495Snp#if defined(__i386__) || defined(__amd64__) 59252495Snp#include <vm/vm.h> 60252495Snp#include <vm/pmap.h> 61252495Snp#endif 62218792Snp 63218792Snp#include "common/common.h" 64221474Snp#include "common/t4_msg.h" 65218792Snp#include "common/t4_regs.h" 66218792Snp#include "common/t4_regs_values.h" 67218792Snp#include "t4_ioctl.h" 68222509Snp#include "t4_l2t.h" 69218792Snp 70218792Snp/* T4 bus driver interface */ 71218792Snpstatic int t4_probe(device_t); 72218792Snpstatic int t4_attach(device_t); 73218792Snpstatic int t4_detach(device_t); 74218792Snpstatic device_method_t t4_methods[] = { 75218792Snp DEVMETHOD(device_probe, t4_probe), 76218792Snp DEVMETHOD(device_attach, t4_attach), 77218792Snp DEVMETHOD(device_detach, t4_detach), 78218792Snp 79229093Shselasky DEVMETHOD_END 80218792Snp}; 81218792Snpstatic driver_t t4_driver = { 82218792Snp "t4nex", 83218792Snp t4_methods, 84218792Snp sizeof(struct adapter) 85218792Snp}; 86218792Snp 87218792Snp 88218792Snp/* T4 port (cxgbe) interface */ 89218792Snpstatic int cxgbe_probe(device_t); 90218792Snpstatic int cxgbe_attach(device_t); 91218792Snpstatic int cxgbe_detach(device_t); 92218792Snpstatic device_method_t cxgbe_methods[] = { 93218792Snp DEVMETHOD(device_probe, cxgbe_probe), 94218792Snp DEVMETHOD(device_attach, cxgbe_attach), 95218792Snp DEVMETHOD(device_detach, cxgbe_detach), 96218792Snp { 0, 0 } 97218792Snp}; 98218792Snpstatic driver_t cxgbe_driver = { 99218792Snp "cxgbe", 100218792Snp cxgbe_methods, 101218792Snp sizeof(struct port_info) 102218792Snp}; 103218792Snp 104218792Snpstatic d_ioctl_t t4_ioctl; 105218792Snpstatic d_open_t t4_open; 106218792Snpstatic d_close_t t4_close; 107218792Snp 108218792Snpstatic struct cdevsw t4_cdevsw = { 109218792Snp .d_version = D_VERSION, 110218792Snp .d_flags = 0, 111218792Snp .d_open = t4_open, 112218792Snp .d_close = t4_close, 113218792Snp .d_ioctl = t4_ioctl, 114218792Snp .d_name = "t4nex", 115218792Snp}; 116218792Snp 117252495Snp/* T5 bus driver interface */ 118252495Snpstatic int t5_probe(device_t); 119252495Snpstatic device_method_t t5_methods[] = { 120252495Snp DEVMETHOD(device_probe, t5_probe), 121252495Snp DEVMETHOD(device_attach, t4_attach), 122252495Snp DEVMETHOD(device_detach, t4_detach), 123252495Snp 124252495Snp DEVMETHOD_END 125252495Snp}; 126252495Snpstatic driver_t t5_driver = { 127252495Snp "t5nex", 128252495Snp t5_methods, 129252495Snp sizeof(struct adapter) 130252495Snp}; 131252495Snp 132252495Snp 133252495Snp/* T5 port (cxl) interface */ 134252495Snpstatic driver_t cxl_driver = { 135252495Snp "cxl", 136252495Snp cxgbe_methods, 137252495Snp sizeof(struct port_info) 138252495Snp}; 139252495Snp 140252495Snpstatic struct cdevsw t5_cdevsw = { 141252495Snp .d_version = D_VERSION, 142252495Snp .d_flags = 0, 143252495Snp .d_open = t4_open, 144252495Snp .d_close = t4_close, 145252495Snp .d_ioctl = t4_ioctl, 146252495Snp .d_name = "t5nex", 147252495Snp}; 148252495Snp 149218792Snp/* ifnet + media interface */ 150218792Snpstatic void cxgbe_init(void *); 151218792Snpstatic int cxgbe_ioctl(struct ifnet *, unsigned long, caddr_t); 152218792Snpstatic int cxgbe_transmit(struct ifnet *, struct mbuf *); 153218792Snpstatic void cxgbe_qflush(struct ifnet *); 154218792Snpstatic int cxgbe_media_change(struct ifnet *); 155218792Snpstatic void cxgbe_media_status(struct ifnet *, struct ifmediareq *); 156218792Snp 157252495SnpMALLOC_DEFINE(M_CXGBE, "cxgbe", "Chelsio T4/T5 Ethernet driver and services"); 158218792Snp 159237920Snp/* 160237920Snp * Correct lock order when you need to acquire multiple locks is t4_list_lock, 161237920Snp * then ADAPTER_LOCK, then t4_uld_list_lock. 162237920Snp */ 163231093Snpstatic struct mtx t4_list_lock; 164231093Snpstatic SLIST_HEAD(, adapter) t4_list; 165237920Snp#ifdef TCP_OFFLOAD 166231093Snpstatic struct mtx t4_uld_list_lock; 167231093Snpstatic SLIST_HEAD(, uld_info) t4_uld_list; 168231093Snp#endif 169218792Snp 170218792Snp/* 171231093Snp * Tunables. See tweak_tunables() too. 172252495Snp * 173252495Snp * Each tunable is set to a default value here if it's known at compile-time. 174252495Snp * Otherwise it is set to -1 as an indication to tweak_tunables() that it should 175252495Snp * provide a reasonable default when the driver is loaded. 176252495Snp * 177252495Snp * Tunables applicable to both T4 and T5 are under hw.cxgbe. Those specific to 178252495Snp * T5 are under hw.cxl. 179218792Snp */ 180218792Snp 181218792Snp/* 182231093Snp * Number of queues for tx and rx, 10G and 1G, NIC and offload. 183218792Snp */ 184231093Snp#define NTXQ_10G 16 185231093Snpstatic int t4_ntxq10g = -1; 186231093SnpTUNABLE_INT("hw.cxgbe.ntxq10g", &t4_ntxq10g); 187218792Snp 188231093Snp#define NRXQ_10G 8 189231093Snpstatic int t4_nrxq10g = -1; 190231093SnpTUNABLE_INT("hw.cxgbe.nrxq10g", &t4_nrxq10g); 191218792Snp 192231093Snp#define NTXQ_1G 4 193231093Snpstatic int t4_ntxq1g = -1; 194231093SnpTUNABLE_INT("hw.cxgbe.ntxq1g", &t4_ntxq1g); 195218792Snp 196231093Snp#define NRXQ_1G 2 197231093Snpstatic int t4_nrxq1g = -1; 198231093SnpTUNABLE_INT("hw.cxgbe.nrxq1g", &t4_nrxq1g); 199218792Snp 200265582Snpstatic int t4_rsrv_noflowq = 0; 201265582SnpTUNABLE_INT("hw.cxgbe.rsrv_noflowq", &t4_rsrv_noflowq); 202265582Snp 203237920Snp#ifdef TCP_OFFLOAD 204231093Snp#define NOFLDTXQ_10G 8 205231093Snpstatic int t4_nofldtxq10g = -1; 206231093SnpTUNABLE_INT("hw.cxgbe.nofldtxq10g", &t4_nofldtxq10g); 207231093Snp 208231093Snp#define NOFLDRXQ_10G 2 209231093Snpstatic int t4_nofldrxq10g = -1; 210231093SnpTUNABLE_INT("hw.cxgbe.nofldrxq10g", &t4_nofldrxq10g); 211231093Snp 212231093Snp#define NOFLDTXQ_1G 2 213231093Snpstatic int t4_nofldtxq1g = -1; 214231093SnpTUNABLE_INT("hw.cxgbe.nofldtxq1g", &t4_nofldtxq1g); 215231093Snp 216231093Snp#define NOFLDRXQ_1G 1 217231093Snpstatic int t4_nofldrxq1g = -1; 218231093SnpTUNABLE_INT("hw.cxgbe.nofldrxq1g", &t4_nofldrxq1g); 219231093Snp#endif 220231093Snp 221218792Snp/* 222218792Snp * Holdoff parameters for 10G and 1G ports. 223218792Snp */ 224231093Snp#define TMR_IDX_10G 1 225231093Snpstatic int t4_tmr_idx_10g = TMR_IDX_10G; 226231093SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_10G", &t4_tmr_idx_10g); 227218792Snp 228237916Snp#define PKTC_IDX_10G (-1) 229231093Snpstatic int t4_pktc_idx_10g = PKTC_IDX_10G; 230231093SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_10G", &t4_pktc_idx_10g); 231218792Snp 232231093Snp#define TMR_IDX_1G 1 233231093Snpstatic int t4_tmr_idx_1g = TMR_IDX_1G; 234231093SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_1G", &t4_tmr_idx_1g); 235218792Snp 236237916Snp#define PKTC_IDX_1G (-1) 237231093Snpstatic int t4_pktc_idx_1g = PKTC_IDX_1G; 238231093SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_1G", &t4_pktc_idx_1g); 239218792Snp 240218792Snp/* 241218792Snp * Size (# of entries) of each tx and rx queue. 242218792Snp */ 243231093Snpstatic unsigned int t4_qsize_txq = TX_EQ_QSIZE; 244231093SnpTUNABLE_INT("hw.cxgbe.qsize_txq", &t4_qsize_txq); 245218792Snp 246231093Snpstatic unsigned int t4_qsize_rxq = RX_IQ_QSIZE; 247231093SnpTUNABLE_INT("hw.cxgbe.qsize_rxq", &t4_qsize_rxq); 248218792Snp 249218792Snp/* 250231093Snp * Interrupt types allowed (bits 0, 1, 2 = INTx, MSI, MSI-X respectively). 251218792Snp */ 252231093Snpstatic int t4_intr_types = INTR_MSIX | INTR_MSI | INTR_INTX; 253231093SnpTUNABLE_INT("hw.cxgbe.interrupt_types", &t4_intr_types); 254218792Snp 255218792Snp/* 256231093Snp * Configuration file. 257218792Snp */ 258252495Snp#define DEFAULT_CF "default" 259252495Snp#define FLASH_CF "flash" 260252495Snp#define UWIRE_CF "uwire" 261252495Snp#define FPGA_CF "fpga" 262252495Snpstatic char t4_cfg_file[32] = DEFAULT_CF; 263231093SnpTUNABLE_STR("hw.cxgbe.config_file", t4_cfg_file, sizeof(t4_cfg_file)); 264218792Snp 265231093Snp/* 266247434Snp * Firmware auto-install by driver during attach (0, 1, 2 = prohibited, allowed, 267247434Snp * encouraged respectively). 268247434Snp */ 269247434Snpstatic unsigned int t4_fw_install = 1; 270247434SnpTUNABLE_INT("hw.cxgbe.fw_install", &t4_fw_install); 271247434Snp 272247434Snp/* 273231093Snp * ASIC features that will be used. Disable the ones you don't want so that the 274231093Snp * chip resources aren't wasted on features that will not be used. 275231093Snp */ 276231093Snpstatic int t4_linkcaps_allowed = 0; /* No DCBX, PPP, etc. by default */ 277231093SnpTUNABLE_INT("hw.cxgbe.linkcaps_allowed", &t4_linkcaps_allowed); 278221474Snp 279231093Snpstatic int t4_niccaps_allowed = FW_CAPS_CONFIG_NIC; 280231093SnpTUNABLE_INT("hw.cxgbe.niccaps_allowed", &t4_niccaps_allowed); 281231093Snp 282238037Snpstatic int t4_toecaps_allowed = -1; 283231093SnpTUNABLE_INT("hw.cxgbe.toecaps_allowed", &t4_toecaps_allowed); 284231093Snp 285231093Snpstatic int t4_rdmacaps_allowed = 0; 286231093SnpTUNABLE_INT("hw.cxgbe.rdmacaps_allowed", &t4_rdmacaps_allowed); 287231093Snp 288231093Snpstatic int t4_iscsicaps_allowed = 0; 289231093SnpTUNABLE_INT("hw.cxgbe.iscsicaps_allowed", &t4_iscsicaps_allowed); 290231093Snp 291231093Snpstatic int t4_fcoecaps_allowed = 0; 292231093SnpTUNABLE_INT("hw.cxgbe.fcoecaps_allowed", &t4_fcoecaps_allowed); 293231093Snp 294252495Snpstatic int t5_write_combine = 0; 295252495SnpTUNABLE_INT("hw.cxl.write_combine", &t5_write_combine); 296252495Snp 297218792Snpstruct intrs_and_queues { 298219944Snp int intr_type; /* INTx, MSI, or MSI-X */ 299218792Snp int nirq; /* Number of vectors */ 300231093Snp int intr_flags; 301218792Snp int ntxq10g; /* # of NIC txq's for each 10G port */ 302218792Snp int nrxq10g; /* # of NIC rxq's for each 10G port */ 303218792Snp int ntxq1g; /* # of NIC txq's for each 1G port */ 304218792Snp int nrxq1g; /* # of NIC rxq's for each 1G port */ 305265582Snp int rsrv_noflowq; /* Flag whether to reserve queue 0 */ 306237920Snp#ifdef TCP_OFFLOAD 307231093Snp int nofldtxq10g; /* # of TOE txq's for each 10G port */ 308231093Snp int nofldrxq10g; /* # of TOE rxq's for each 10G port */ 309231093Snp int nofldtxq1g; /* # of TOE txq's for each 1G port */ 310231093Snp int nofldrxq1g; /* # of TOE rxq's for each 1G port */ 311231093Snp#endif 312218792Snp}; 313218792Snp 314221474Snpstruct filter_entry { 315221474Snp uint32_t valid:1; /* filter allocated and valid */ 316221474Snp uint32_t locked:1; /* filter is administratively locked */ 317221474Snp uint32_t pending:1; /* filter action is pending firmware reply */ 318221474Snp uint32_t smtidx:8; /* Source MAC Table index for smac */ 319222509Snp struct l2t_entry *l2t; /* Layer Two Table entry for dmac */ 320221474Snp 321221474Snp struct t4_filter_specification fs; 322221474Snp}; 323221474Snp 324218792Snpenum { 325218792Snp XGMAC_MTU = (1 << 0), 326218792Snp XGMAC_PROMISC = (1 << 1), 327218792Snp XGMAC_ALLMULTI = (1 << 2), 328218792Snp XGMAC_VLANEX = (1 << 3), 329218792Snp XGMAC_UCADDR = (1 << 4), 330218792Snp XGMAC_MCADDRS = (1 << 5), 331218792Snp 332218792Snp XGMAC_ALL = 0xffff 333218792Snp}; 334218792Snp 335252495Snpstatic int map_bars_0_and_4(struct adapter *); 336252495Snpstatic int map_bar_2(struct adapter *); 337218792Snpstatic void setup_memwin(struct adapter *); 338252495Snpstatic int validate_mem_range(struct adapter *, uint32_t, int); 339265483Snpstatic int fwmtype_to_hwmtype(int); 340252495Snpstatic int validate_mt_off_len(struct adapter *, int, uint32_t, int, 341252495Snp uint32_t *); 342252495Snpstatic void memwin_info(struct adapter *, int, uint32_t *, uint32_t *); 343252495Snpstatic uint32_t position_memwin(struct adapter *, int, uint32_t); 344218792Snpstatic int cfg_itype_and_nqueues(struct adapter *, int, int, 345218792Snp struct intrs_and_queues *); 346218792Snpstatic int prep_firmware(struct adapter *); 347252495Snpstatic int partition_resources(struct adapter *, const struct firmware *, 348252495Snp const char *); 349231093Snpstatic int get_params__pre_init(struct adapter *); 350231093Snpstatic int get_params__post_init(struct adapter *); 351247434Snpstatic int set_params__post_init(struct adapter *); 352218792Snpstatic void t4_set_desc(struct adapter *); 353218792Snpstatic void build_medialist(struct port_info *); 354218792Snpstatic int update_mac_settings(struct port_info *, int); 355218792Snpstatic int cxgbe_init_synchronized(struct port_info *); 356218792Snpstatic int cxgbe_uninit_synchronized(struct port_info *); 357241467Snpstatic int setup_intr_handlers(struct adapter *); 358231093Snpstatic int adapter_full_init(struct adapter *); 359231093Snpstatic int adapter_full_uninit(struct adapter *); 360231093Snpstatic int port_full_init(struct port_info *); 361231093Snpstatic int port_full_uninit(struct port_info *); 362231093Snpstatic void quiesce_eq(struct adapter *, struct sge_eq *); 363231093Snpstatic void quiesce_iq(struct adapter *, struct sge_iq *); 364231093Snpstatic void quiesce_fl(struct adapter *, struct sge_fl *); 365218792Snpstatic int t4_alloc_irq(struct adapter *, struct irq *, int rid, 366231093Snp driver_intr_t *, void *, char *); 367218792Snpstatic int t4_free_irq(struct adapter *, struct irq *); 368218792Snpstatic void reg_block_dump(struct adapter *, uint8_t *, unsigned int, 369218792Snp unsigned int); 370218792Snpstatic void t4_get_regs(struct adapter *, struct t4_regdump *, uint8_t *); 371218792Snpstatic void cxgbe_tick(void *); 372237920Snpstatic void cxgbe_vlan_config(void *, struct ifnet *, uint16_t); 373231093Snpstatic int cpl_not_handled(struct sge_iq *, const struct rss_header *, 374231093Snp struct mbuf *); 375237920Snpstatic int an_not_handled(struct sge_iq *, const struct rsp_ctrl *); 376240169Snpstatic int fw_msg_not_handled(struct adapter *, const __be64 *); 377218792Snpstatic int t4_sysctls(struct adapter *); 378218792Snpstatic int cxgbe_sysctls(struct port_info *); 379219436Snpstatic int sysctl_int_array(SYSCTL_HANDLER_ARGS); 380231093Snpstatic int sysctl_bitfield(SYSCTL_HANDLER_ARGS); 381252814Snpstatic int sysctl_btphy(SYSCTL_HANDLER_ARGS); 382265582Snpstatic int sysctl_noflowq(SYSCTL_HANDLER_ARGS); 383218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS); 384218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS); 385218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS); 386218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS); 387218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS); 388265478Snpstatic int sysctl_temperature(SYSCTL_HANDLER_ARGS); 389231593Snp#ifdef SBUF_DRAIN 390231093Snpstatic int sysctl_cctrl(SYSCTL_HANDLER_ARGS); 391247434Snpstatic int sysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS); 392247434Snpstatic int sysctl_cim_la(SYSCTL_HANDLER_ARGS); 393252495Snpstatic int sysctl_cim_ma_la(SYSCTL_HANDLER_ARGS); 394252495Snpstatic int sysctl_cim_pif_la(SYSCTL_HANDLER_ARGS); 395247434Snpstatic int sysctl_cim_qcfg(SYSCTL_HANDLER_ARGS); 396231093Snpstatic int sysctl_cpl_stats(SYSCTL_HANDLER_ARGS); 397231093Snpstatic int sysctl_ddp_stats(SYSCTL_HANDLER_ARGS); 398222551Snpstatic int sysctl_devlog(SYSCTL_HANDLER_ARGS); 399231093Snpstatic int sysctl_fcoe_stats(SYSCTL_HANDLER_ARGS); 400231093Snpstatic int sysctl_hw_sched(SYSCTL_HANDLER_ARGS); 401231093Snpstatic int sysctl_lb_stats(SYSCTL_HANDLER_ARGS); 402265478Snpstatic int sysctl_linkdnrc(SYSCTL_HANDLER_ARGS); 403231093Snpstatic int sysctl_meminfo(SYSCTL_HANDLER_ARGS); 404252495Snpstatic int sysctl_mps_tcam(SYSCTL_HANDLER_ARGS); 405231093Snpstatic int sysctl_path_mtus(SYSCTL_HANDLER_ARGS); 406231093Snpstatic int sysctl_pm_stats(SYSCTL_HANDLER_ARGS); 407231093Snpstatic int sysctl_rdma_stats(SYSCTL_HANDLER_ARGS); 408231093Snpstatic int sysctl_tcp_stats(SYSCTL_HANDLER_ARGS); 409231093Snpstatic int sysctl_tids(SYSCTL_HANDLER_ARGS); 410231093Snpstatic int sysctl_tp_err_stats(SYSCTL_HANDLER_ARGS); 411252495Snpstatic int sysctl_tp_la(SYSCTL_HANDLER_ARGS); 412231093Snpstatic int sysctl_tx_rate(SYSCTL_HANDLER_ARGS); 413252495Snpstatic int sysctl_ulprx_la(SYSCTL_HANDLER_ARGS); 414252495Snpstatic int sysctl_wcwr_stats(SYSCTL_HANDLER_ARGS); 415231593Snp#endif 416219286Snpstatic inline void txq_start(struct ifnet *, struct sge_txq *); 417221474Snpstatic uint32_t fconf_to_mode(uint32_t); 418221474Snpstatic uint32_t mode_to_fconf(uint32_t); 419221474Snpstatic uint32_t fspec_to_fconf(struct t4_filter_specification *); 420221474Snpstatic int get_filter_mode(struct adapter *, uint32_t *); 421221474Snpstatic int set_filter_mode(struct adapter *, uint32_t); 422222552Snpstatic inline uint64_t get_filter_hits(struct adapter *, uint32_t); 423221474Snpstatic int get_filter(struct adapter *, struct t4_filter *); 424221474Snpstatic int set_filter(struct adapter *, struct t4_filter *); 425221474Snpstatic int del_filter(struct adapter *, struct t4_filter *); 426222509Snpstatic void clear_filter(struct filter_entry *); 427221474Snpstatic int set_filter_wr(struct adapter *, int); 428221474Snpstatic int del_filter_wr(struct adapter *, int); 429222973Snpstatic int get_sge_context(struct adapter *, struct t4_sge_context *); 430247434Snpstatic int load_fw(struct adapter *, struct t4_data *); 431252495Snpstatic int read_card_mem(struct adapter *, int, struct t4_mem_range *); 432241573Snpstatic int read_i2c(struct adapter *, struct t4_i2c_data *); 433265552Snpstatic int set_sched_class(struct adapter *, struct t4_sched_params *); 434265552Snpstatic int set_sched_queue(struct adapter *, struct t4_sched_queue *); 435237920Snp#ifdef TCP_OFFLOAD 436231093Snpstatic int toe_capability(struct port_info *, int); 437231093Snp#endif 438252495Snpstatic int mod_event(module_t, int, void *); 439218792Snp 440252495Snpstruct { 441218792Snp uint16_t device; 442218792Snp char *desc; 443218792Snp} t4_pciids[] = { 444237925Snp {0xa000, "Chelsio Terminator 4 FPGA"}, 445237925Snp {0x4400, "Chelsio T440-dbg"}, 446237925Snp {0x4401, "Chelsio T420-CR"}, 447237925Snp {0x4402, "Chelsio T422-CR"}, 448237925Snp {0x4403, "Chelsio T440-CR"}, 449237925Snp {0x4404, "Chelsio T420-BCH"}, 450237925Snp {0x4405, "Chelsio T440-BCH"}, 451237925Snp {0x4406, "Chelsio T440-CH"}, 452237925Snp {0x4407, "Chelsio T420-SO"}, 453237925Snp {0x4408, "Chelsio T420-CX"}, 454237925Snp {0x4409, "Chelsio T420-BT"}, 455237925Snp {0x440a, "Chelsio T404-BT"}, 456245145Snp {0x440e, "Chelsio T440-LP-CR"}, 457252495Snp}, t5_pciids[] = { 458252495Snp {0xb000, "Chelsio Terminator 5 FPGA"}, 459252495Snp {0x5400, "Chelsio T580-dbg"}, 460253776Snp {0x5401, "Chelsio T520-CR"}, /* 2 x 10G */ 461253776Snp {0x5402, "Chelsio T522-CR"}, /* 2 x 10G, 2 X 1G */ 462253776Snp {0x5403, "Chelsio T540-CR"}, /* 4 x 10G */ 463253776Snp {0x5407, "Chelsio T520-SO"}, /* 2 x 10G, nomem */ 464253776Snp {0x5409, "Chelsio T520-BT"}, /* 2 x 10GBaseT */ 465253776Snp {0x540a, "Chelsio T504-BT"}, /* 4 x 1G */ 466253776Snp {0x540d, "Chelsio T580-CR"}, /* 2 x 40G */ 467253776Snp {0x540e, "Chelsio T540-LP-CR"}, /* 4 x 10G */ 468252495Snp {0x5410, "Chelsio T580-LP-CR"}, /* 2 x 40G */ 469253776Snp {0x5411, "Chelsio T520-LL-CR"}, /* 2 x 10G */ 470253776Snp {0x5412, "Chelsio T560-CR"}, /* 1 x 40G, 2 x 10G */ 471253776Snp {0x5414, "Chelsio T580-LP-SO-CR"}, /* 2 x 40G, nomem */ 472252495Snp#ifdef notyet 473252495Snp {0x5404, "Chelsio T520-BCH"}, 474252495Snp {0x5405, "Chelsio T540-BCH"}, 475252495Snp {0x5406, "Chelsio T540-CH"}, 476253776Snp {0x5408, "Chelsio T520-CX"}, 477252495Snp {0x540b, "Chelsio B520-SR"}, 478252495Snp {0x540c, "Chelsio B504-BT"}, 479252495Snp {0x540f, "Chelsio Amsterdam"}, 480253776Snp {0x5413, "Chelsio T580-CHR"}, 481252495Snp#endif 482218792Snp}; 483218792Snp 484237920Snp#ifdef TCP_OFFLOAD 485237920Snp/* 486237920Snp * service_iq() has an iq and needs the fl. Offset of fl from the iq should be 487237920Snp * exactly the same for both rxq and ofld_rxq. 488237920Snp */ 489237920SnpCTASSERT(offsetof(struct sge_ofld_rxq, iq) == offsetof(struct sge_rxq, iq)); 490231093SnpCTASSERT(offsetof(struct sge_ofld_rxq, fl) == offsetof(struct sge_rxq, fl)); 491231093Snp#endif 492231093Snp 493240169Snp/* No easy way to include t4_msg.h before adapter.h so we check this way */ 494241467SnpCTASSERT(nitems(((struct adapter *)0)->cpl_handler) == NUM_CPL_CMDS); 495241467SnpCTASSERT(nitems(((struct adapter *)0)->fw_msg_handler) == NUM_FW6_TYPES); 496240169Snp 497265582SnpCTASSERT(sizeof(struct cluster_metadata) <= CL_METADATA_SIZE); 498265582Snp 499218792Snpstatic int 500218792Snpt4_probe(device_t dev) 501218792Snp{ 502218792Snp int i; 503218792Snp uint16_t v = pci_get_vendor(dev); 504218792Snp uint16_t d = pci_get_device(dev); 505237925Snp uint8_t f = pci_get_function(dev); 506218792Snp 507218792Snp if (v != PCI_VENDOR_ID_CHELSIO) 508218792Snp return (ENXIO); 509218792Snp 510237925Snp /* Attach only to PF0 of the FPGA */ 511237925Snp if (d == 0xa000 && f != 0) 512237925Snp return (ENXIO); 513237925Snp 514241467Snp for (i = 0; i < nitems(t4_pciids); i++) { 515237925Snp if (d == t4_pciids[i].device) { 516218792Snp device_set_desc(dev, t4_pciids[i].desc); 517218792Snp return (BUS_PROBE_DEFAULT); 518218792Snp } 519218792Snp } 520218792Snp 521218792Snp return (ENXIO); 522218792Snp} 523218792Snp 524218792Snpstatic int 525252495Snpt5_probe(device_t dev) 526252495Snp{ 527252495Snp int i; 528252495Snp uint16_t v = pci_get_vendor(dev); 529252495Snp uint16_t d = pci_get_device(dev); 530252495Snp uint8_t f = pci_get_function(dev); 531252495Snp 532252495Snp if (v != PCI_VENDOR_ID_CHELSIO) 533252495Snp return (ENXIO); 534252495Snp 535252495Snp /* Attach only to PF0 of the FPGA */ 536252495Snp if (d == 0xb000 && f != 0) 537252495Snp return (ENXIO); 538252495Snp 539252495Snp for (i = 0; i < nitems(t5_pciids); i++) { 540252495Snp if (d == t5_pciids[i].device) { 541252495Snp device_set_desc(dev, t5_pciids[i].desc); 542252495Snp return (BUS_PROBE_DEFAULT); 543252495Snp } 544252495Snp } 545252495Snp 546252495Snp return (ENXIO); 547252495Snp} 548252495Snp 549252495Snpstatic int 550218792Snpt4_attach(device_t dev) 551218792Snp{ 552218792Snp struct adapter *sc; 553218792Snp int rc = 0, i, n10g, n1g, rqidx, tqidx; 554218792Snp struct intrs_and_queues iaq; 555218792Snp struct sge *s; 556237920Snp#ifdef TCP_OFFLOAD 557231093Snp int ofld_rqidx, ofld_tqidx; 558231093Snp#endif 559218792Snp 560218792Snp sc = device_get_softc(dev); 561218792Snp sc->dev = dev; 562218792Snp 563218792Snp pci_enable_busmaster(dev); 564222085Snp if (pci_find_cap(dev, PCIY_EXPRESS, &i) == 0) { 565231093Snp uint32_t v; 566231093Snp 567222085Snp pci_set_max_read_req(dev, 4096); 568242015Sgavin v = pci_read_config(dev, i + PCIER_DEVICE_CTL, 2); 569242015Sgavin v |= PCIEM_CTL_RELAXED_ORD_ENABLE; 570242015Sgavin pci_write_config(dev, i + PCIER_DEVICE_CTL, v, 2); 571222085Snp } 572222085Snp 573218792Snp snprintf(sc->lockname, sizeof(sc->lockname), "%s", 574218792Snp device_get_nameunit(dev)); 575218792Snp mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF); 576231093Snp mtx_lock(&t4_list_lock); 577231093Snp SLIST_INSERT_HEAD(&t4_list, sc, link); 578231093Snp mtx_unlock(&t4_list_lock); 579218792Snp 580231093Snp mtx_init(&sc->sfl_lock, "starving freelists", 0, MTX_DEF); 581231093Snp TAILQ_INIT(&sc->sfl); 582231093Snp callout_init(&sc->sfl_callout, CALLOUT_MPSAFE); 583231093Snp 584252495Snp rc = map_bars_0_and_4(sc); 585218792Snp if (rc != 0) 586218792Snp goto done; /* error message displayed already */ 587218792Snp 588237925Snp /* 589237925Snp * This is the real PF# to which we're attaching. Works from within PCI 590237925Snp * passthrough environments too, where pci_get_function() could return a 591237925Snp * different PF# depending on the passthrough configuration. We need to 592237925Snp * use the real PF# in all our communication with the firmware. 593237925Snp */ 594237925Snp sc->pf = G_SOURCEPF(t4_read_reg(sc, A_PL_WHOAMI)); 595237925Snp sc->mbox = sc->pf; 596237925Snp 597218792Snp memset(sc->chan_map, 0xff, sizeof(sc->chan_map)); 598237920Snp sc->an_handler = an_not_handled; 599241467Snp for (i = 0; i < nitems(sc->cpl_handler); i++) 600231093Snp sc->cpl_handler[i] = cpl_not_handled; 601241467Snp for (i = 0; i < nitems(sc->fw_msg_handler); i++) 602240169Snp sc->fw_msg_handler[i] = fw_msg_not_handled; 603240169Snp t4_register_cpl_handler(sc, CPL_SET_TCB_RPL, t4_filter_rpl); 604252495Snp t4_init_sge_cpl_handlers(sc); 605218792Snp 606218792Snp /* Prepare the adapter for operation */ 607218792Snp rc = -t4_prep_adapter(sc); 608218792Snp if (rc != 0) { 609218792Snp device_printf(dev, "failed to prepare adapter: %d.\n", rc); 610218792Snp goto done; 611218792Snp } 612218792Snp 613231093Snp /* 614231093Snp * Do this really early, with the memory windows set up even before the 615231093Snp * character device. The userland tool's register i/o and mem read 616231093Snp * will work even in "recovery mode". 617231093Snp */ 618231093Snp setup_memwin(sc); 619252495Snp sc->cdev = make_dev(is_t4(sc) ? &t4_cdevsw : &t5_cdevsw, 620252495Snp device_get_unit(dev), UID_ROOT, GID_WHEEL, 0600, "%s", 621252495Snp device_get_nameunit(dev)); 622252495Snp if (sc->cdev == NULL) 623252495Snp device_printf(dev, "failed to create nexus char device.\n"); 624252495Snp else 625252495Snp sc->cdev->si_drv1 = sc; 626218792Snp 627231093Snp /* Go no further if recovery mode has been requested. */ 628231093Snp if (TUNABLE_INT_FETCH("hw.cxgbe.sos", &i) && i != 0) { 629231093Snp device_printf(dev, "recovery mode.\n"); 630231093Snp goto done; 631231093Snp } 632231093Snp 633218792Snp /* Prepare the firmware for operation */ 634218792Snp rc = prep_firmware(sc); 635218792Snp if (rc != 0) 636218792Snp goto done; /* error message displayed already */ 637218792Snp 638252495Snp rc = get_params__post_init(sc); 639231093Snp if (rc != 0) 640231093Snp goto done; /* error message displayed already */ 641222551Snp 642252495Snp rc = set_params__post_init(sc); 643231093Snp if (rc != 0) 644231093Snp goto done; /* error message displayed already */ 645218792Snp 646252495Snp rc = map_bar_2(sc); 647231093Snp if (rc != 0) 648231093Snp goto done; /* error message displayed already */ 649218792Snp 650218792Snp rc = t4_create_dma_tag(sc); 651218792Snp if (rc != 0) 652218792Snp goto done; /* error message displayed already */ 653218792Snp 654218792Snp /* 655218792Snp * First pass over all the ports - allocate VIs and initialize some 656218792Snp * basic parameters like mac address, port type, etc. We also figure 657218792Snp * out whether a port is 10G or 1G and use that information when 658218792Snp * calculating how many interrupts to attempt to allocate. 659218792Snp */ 660218792Snp n10g = n1g = 0; 661218792Snp for_each_port(sc, i) { 662218792Snp struct port_info *pi; 663218792Snp 664218792Snp pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK); 665218792Snp sc->port[i] = pi; 666218792Snp 667218792Snp /* These must be set before t4_port_init */ 668218792Snp pi->adapter = sc; 669218792Snp pi->port_id = i; 670218792Snp 671218792Snp /* Allocate the vi and initialize parameters like mac addr */ 672218792Snp rc = -t4_port_init(pi, sc->mbox, sc->pf, 0); 673218792Snp if (rc != 0) { 674218792Snp device_printf(dev, "unable to initialize port %d: %d\n", 675218792Snp i, rc); 676218792Snp free(pi, M_CXGBE); 677222510Snp sc->port[i] = NULL; 678222510Snp goto done; 679218792Snp } 680218792Snp 681218792Snp snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d", 682218792Snp device_get_nameunit(dev), i); 683218792Snp mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF); 684218792Snp 685252495Snp if (is_10G_port(pi) || is_40G_port(pi)) { 686218792Snp n10g++; 687231093Snp pi->tmr_idx = t4_tmr_idx_10g; 688231093Snp pi->pktc_idx = t4_pktc_idx_10g; 689218792Snp } else { 690218792Snp n1g++; 691231093Snp pi->tmr_idx = t4_tmr_idx_1g; 692231093Snp pi->pktc_idx = t4_pktc_idx_1g; 693218792Snp } 694218792Snp 695218792Snp pi->xact_addr_filt = -1; 696252814Snp pi->linkdnrc = -1; 697218792Snp 698231093Snp pi->qsize_rxq = t4_qsize_rxq; 699231093Snp pi->qsize_txq = t4_qsize_txq; 700218792Snp 701252495Snp pi->dev = device_add_child(dev, is_t4(sc) ? "cxgbe" : "cxl", -1); 702218792Snp if (pi->dev == NULL) { 703218792Snp device_printf(dev, 704218792Snp "failed to add device for port %d.\n", i); 705218792Snp rc = ENXIO; 706218792Snp goto done; 707218792Snp } 708218792Snp device_set_softc(pi->dev, pi); 709218792Snp } 710218792Snp 711218792Snp /* 712218792Snp * Interrupt type, # of interrupts, # of rx/tx queues, etc. 713218792Snp */ 714218792Snp rc = cfg_itype_and_nqueues(sc, n10g, n1g, &iaq); 715218792Snp if (rc != 0) 716218792Snp goto done; /* error message displayed already */ 717218792Snp 718218792Snp sc->intr_type = iaq.intr_type; 719218792Snp sc->intr_count = iaq.nirq; 720231093Snp sc->flags |= iaq.intr_flags; 721218792Snp 722218792Snp s = &sc->sge; 723218792Snp s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g; 724218792Snp s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g; 725220873Snp s->neq = s->ntxq + s->nrxq; /* the free list in an rxq is an eq */ 726231093Snp s->neq += sc->params.nports + 1;/* ctrl queues: 1 per port + 1 mgmt */ 727218792Snp s->niq = s->nrxq + 1; /* 1 extra for firmware event queue */ 728222510Snp 729237920Snp#ifdef TCP_OFFLOAD 730231093Snp if (is_offload(sc)) { 731231093Snp 732231093Snp s->nofldrxq = n10g * iaq.nofldrxq10g + n1g * iaq.nofldrxq1g; 733231093Snp s->nofldtxq = n10g * iaq.nofldtxq10g + n1g * iaq.nofldtxq1g; 734231093Snp s->neq += s->nofldtxq + s->nofldrxq; 735231093Snp s->niq += s->nofldrxq; 736231093Snp 737231093Snp s->ofld_rxq = malloc(s->nofldrxq * sizeof(struct sge_ofld_rxq), 738231093Snp M_CXGBE, M_ZERO | M_WAITOK); 739231093Snp s->ofld_txq = malloc(s->nofldtxq * sizeof(struct sge_wrq), 740231093Snp M_CXGBE, M_ZERO | M_WAITOK); 741231093Snp } 742231093Snp#endif 743231093Snp 744231093Snp s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_wrq), M_CXGBE, 745220873Snp M_ZERO | M_WAITOK); 746218792Snp s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE, 747218792Snp M_ZERO | M_WAITOK); 748218792Snp s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE, 749218792Snp M_ZERO | M_WAITOK); 750218792Snp s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE, 751218792Snp M_ZERO | M_WAITOK); 752218792Snp s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE, 753218792Snp M_ZERO | M_WAITOK); 754218792Snp 755218792Snp sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE, 756218792Snp M_ZERO | M_WAITOK); 757218792Snp 758231093Snp t4_init_l2t(sc, M_WAITOK); 759222509Snp 760218792Snp /* 761218792Snp * Second pass over the ports. This time we know the number of rx and 762218792Snp * tx queues that each port should get. 763218792Snp */ 764218792Snp rqidx = tqidx = 0; 765237920Snp#ifdef TCP_OFFLOAD 766231093Snp ofld_rqidx = ofld_tqidx = 0; 767231093Snp#endif 768218792Snp for_each_port(sc, i) { 769218792Snp struct port_info *pi = sc->port[i]; 770218792Snp 771218792Snp if (pi == NULL) 772218792Snp continue; 773218792Snp 774218792Snp pi->first_rxq = rqidx; 775218792Snp pi->first_txq = tqidx; 776252495Snp if (is_10G_port(pi) || is_40G_port(pi)) { 777231093Snp pi->nrxq = iaq.nrxq10g; 778231093Snp pi->ntxq = iaq.ntxq10g; 779231093Snp } else { 780231093Snp pi->nrxq = iaq.nrxq1g; 781231093Snp pi->ntxq = iaq.ntxq1g; 782231093Snp } 783218792Snp 784265582Snp if (pi->ntxq > 1) 785265582Snp pi->rsrv_noflowq = iaq.rsrv_noflowq ? 1 : 0; 786265582Snp else 787265582Snp pi->rsrv_noflowq = 0; 788265582Snp 789218792Snp rqidx += pi->nrxq; 790218792Snp tqidx += pi->ntxq; 791231093Snp 792237920Snp#ifdef TCP_OFFLOAD 793231093Snp if (is_offload(sc)) { 794231093Snp pi->first_ofld_rxq = ofld_rqidx; 795231093Snp pi->first_ofld_txq = ofld_tqidx; 796252495Snp if (is_10G_port(pi) || is_40G_port(pi)) { 797231093Snp pi->nofldrxq = iaq.nofldrxq10g; 798231093Snp pi->nofldtxq = iaq.nofldtxq10g; 799231093Snp } else { 800231093Snp pi->nofldrxq = iaq.nofldrxq1g; 801231093Snp pi->nofldtxq = iaq.nofldtxq1g; 802231093Snp } 803231093Snp ofld_rqidx += pi->nofldrxq; 804231093Snp ofld_tqidx += pi->nofldtxq; 805231093Snp } 806231093Snp#endif 807218792Snp } 808218792Snp 809241467Snp rc = setup_intr_handlers(sc); 810241467Snp if (rc != 0) { 811241467Snp device_printf(dev, 812241467Snp "failed to setup interrupt handlers: %d\n", rc); 813241467Snp goto done; 814241467Snp } 815241467Snp 816218792Snp rc = bus_generic_attach(dev); 817218792Snp if (rc != 0) { 818218792Snp device_printf(dev, 819218792Snp "failed to attach all child ports: %d\n", rc); 820218792Snp goto done; 821218792Snp } 822218792Snp 823218792Snp device_printf(dev, 824231093Snp "PCIe x%d, %d ports, %d %s interrupt%s, %d eq, %d iq\n", 825231093Snp sc->params.pci.width, sc->params.nports, sc->intr_count, 826231093Snp sc->intr_type == INTR_MSIX ? "MSI-X" : 827231093Snp (sc->intr_type == INTR_MSI ? "MSI" : "INTx"), 828231093Snp sc->intr_count > 1 ? "s" : "", sc->sge.neq, sc->sge.niq); 829231093Snp 830218792Snp t4_set_desc(sc); 831218792Snp 832218792Snpdone: 833231093Snp if (rc != 0 && sc->cdev) { 834231093Snp /* cdev was created and so cxgbetool works; recover that way. */ 835231093Snp device_printf(dev, 836231093Snp "error during attach, adapter is now in recovery mode.\n"); 837231093Snp rc = 0; 838231093Snp } 839231093Snp 840218792Snp if (rc != 0) 841218792Snp t4_detach(dev); 842231093Snp else 843231093Snp t4_sysctls(sc); 844218792Snp 845218792Snp return (rc); 846218792Snp} 847218792Snp 848218792Snp/* 849218792Snp * Idempotent 850218792Snp */ 851218792Snpstatic int 852218792Snpt4_detach(device_t dev) 853218792Snp{ 854218792Snp struct adapter *sc; 855218792Snp struct port_info *pi; 856231093Snp int i, rc; 857218792Snp 858218792Snp sc = device_get_softc(dev); 859218792Snp 860231093Snp if (sc->flags & FULL_INIT_DONE) 861231093Snp t4_intr_disable(sc); 862231093Snp 863231093Snp if (sc->cdev) { 864218792Snp destroy_dev(sc->cdev); 865231093Snp sc->cdev = NULL; 866231093Snp } 867218792Snp 868231093Snp rc = bus_generic_detach(dev); 869231093Snp if (rc) { 870231093Snp device_printf(dev, 871231093Snp "failed to detach child devices: %d\n", rc); 872231093Snp return (rc); 873231093Snp } 874231093Snp 875241467Snp for (i = 0; i < sc->intr_count; i++) 876241467Snp t4_free_irq(sc, &sc->irq[i]); 877241467Snp 878218792Snp for (i = 0; i < MAX_NPORTS; i++) { 879218792Snp pi = sc->port[i]; 880218792Snp if (pi) { 881218792Snp t4_free_vi(pi->adapter, sc->mbox, sc->pf, 0, pi->viid); 882218792Snp if (pi->dev) 883218792Snp device_delete_child(dev, pi->dev); 884218792Snp 885218792Snp mtx_destroy(&pi->pi_lock); 886218792Snp free(pi, M_CXGBE); 887218792Snp } 888218792Snp } 889218792Snp 890231093Snp if (sc->flags & FULL_INIT_DONE) 891231093Snp adapter_full_uninit(sc); 892231093Snp 893218792Snp if (sc->flags & FW_OK) 894218792Snp t4_fw_bye(sc, sc->mbox); 895218792Snp 896219944Snp if (sc->intr_type == INTR_MSI || sc->intr_type == INTR_MSIX) 897218792Snp pci_release_msi(dev); 898218792Snp 899218792Snp if (sc->regs_res) 900218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid, 901218792Snp sc->regs_res); 902218792Snp 903252495Snp if (sc->udbs_res) 904252495Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->udbs_rid, 905252495Snp sc->udbs_res); 906252495Snp 907218792Snp if (sc->msix_res) 908218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid, 909218792Snp sc->msix_res); 910218792Snp 911222509Snp if (sc->l2t) 912222509Snp t4_free_l2t(sc->l2t); 913222509Snp 914237920Snp#ifdef TCP_OFFLOAD 915231093Snp free(sc->sge.ofld_rxq, M_CXGBE); 916231093Snp free(sc->sge.ofld_txq, M_CXGBE); 917231093Snp#endif 918218792Snp free(sc->irq, M_CXGBE); 919218792Snp free(sc->sge.rxq, M_CXGBE); 920218792Snp free(sc->sge.txq, M_CXGBE); 921220873Snp free(sc->sge.ctrlq, M_CXGBE); 922218792Snp free(sc->sge.iqmap, M_CXGBE); 923218792Snp free(sc->sge.eqmap, M_CXGBE); 924221474Snp free(sc->tids.ftid_tab, M_CXGBE); 925218792Snp t4_destroy_dma_tag(sc); 926231093Snp if (mtx_initialized(&sc->sc_lock)) { 927231093Snp mtx_lock(&t4_list_lock); 928231093Snp SLIST_REMOVE(&t4_list, sc, adapter, link); 929231093Snp mtx_unlock(&t4_list_lock); 930231093Snp mtx_destroy(&sc->sc_lock); 931231093Snp } 932218792Snp 933247434Snp if (mtx_initialized(&sc->tids.ftid_lock)) 934247434Snp mtx_destroy(&sc->tids.ftid_lock); 935231093Snp if (mtx_initialized(&sc->sfl_lock)) 936231093Snp mtx_destroy(&sc->sfl_lock); 937231093Snp 938218792Snp bzero(sc, sizeof(*sc)); 939218792Snp 940218792Snp return (0); 941218792Snp} 942218792Snp 943218792Snp 944218792Snpstatic int 945218792Snpcxgbe_probe(device_t dev) 946218792Snp{ 947218792Snp char buf[128]; 948218792Snp struct port_info *pi = device_get_softc(dev); 949218792Snp 950231093Snp snprintf(buf, sizeof(buf), "port %d", pi->port_id); 951218792Snp device_set_desc_copy(dev, buf); 952218792Snp 953218792Snp return (BUS_PROBE_DEFAULT); 954218792Snp} 955218792Snp 956218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \ 957218792Snp IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \ 958237925Snp IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6) 959238302Snp#define T4_CAP_ENABLE (T4_CAP) 960218792Snp 961218792Snpstatic int 962218792Snpcxgbe_attach(device_t dev) 963218792Snp{ 964218792Snp struct port_info *pi = device_get_softc(dev); 965218792Snp struct ifnet *ifp; 966218792Snp 967218792Snp /* Allocate an ifnet and set it up */ 968218792Snp ifp = if_alloc(IFT_ETHER); 969218792Snp if (ifp == NULL) { 970218792Snp device_printf(dev, "Cannot allocate ifnet\n"); 971218792Snp return (ENOMEM); 972218792Snp } 973218792Snp pi->ifp = ifp; 974218792Snp ifp->if_softc = pi; 975218792Snp 976218792Snp callout_init(&pi->tick, CALLOUT_MPSAFE); 977218792Snp 978218792Snp if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 979218792Snp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 980218792Snp 981218792Snp ifp->if_init = cxgbe_init; 982218792Snp ifp->if_ioctl = cxgbe_ioctl; 983218792Snp ifp->if_transmit = cxgbe_transmit; 984218792Snp ifp->if_qflush = cxgbe_qflush; 985218792Snp 986218792Snp ifp->if_capabilities = T4_CAP; 987237920Snp#ifdef TCP_OFFLOAD 988231093Snp if (is_offload(pi->adapter)) 989247434Snp ifp->if_capabilities |= IFCAP_TOE; 990231093Snp#endif 991218792Snp ifp->if_capenable = T4_CAP_ENABLE; 992237925Snp ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO | 993237925Snp CSUM_UDP_IPV6 | CSUM_TCP_IPV6; 994218792Snp 995218792Snp /* Initialize ifmedia for this port */ 996218792Snp ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change, 997218792Snp cxgbe_media_status); 998218792Snp build_medialist(pi); 999218792Snp 1000237920Snp pi->vlan_c = EVENTHANDLER_REGISTER(vlan_config, cxgbe_vlan_config, ifp, 1001237920Snp EVENTHANDLER_PRI_ANY); 1002237920Snp 1003218792Snp ether_ifattach(ifp, pi->hw_addr); 1004218792Snp 1005237920Snp#ifdef TCP_OFFLOAD 1006231093Snp if (is_offload(pi->adapter)) { 1007231093Snp device_printf(dev, 1008231093Snp "%d txq, %d rxq (NIC); %d txq, %d rxq (TOE)\n", 1009231093Snp pi->ntxq, pi->nrxq, pi->nofldtxq, pi->nofldrxq); 1010231093Snp } else 1011218792Snp#endif 1012231093Snp device_printf(dev, "%d txq, %d rxq\n", pi->ntxq, pi->nrxq); 1013218792Snp 1014218792Snp cxgbe_sysctls(pi); 1015218792Snp 1016218792Snp return (0); 1017218792Snp} 1018218792Snp 1019218792Snpstatic int 1020218792Snpcxgbe_detach(device_t dev) 1021218792Snp{ 1022218792Snp struct port_info *pi = device_get_softc(dev); 1023218792Snp struct adapter *sc = pi->adapter; 1024231093Snp struct ifnet *ifp = pi->ifp; 1025218792Snp 1026218792Snp /* Tell if_ioctl and if_init that the port is going away */ 1027218792Snp ADAPTER_LOCK(sc); 1028218792Snp SET_DOOMED(pi); 1029218792Snp wakeup(&sc->flags); 1030218792Snp while (IS_BUSY(sc)) 1031218792Snp mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0); 1032218792Snp SET_BUSY(sc); 1033247434Snp#ifdef INVARIANTS 1034247434Snp sc->last_op = "t4detach"; 1035247434Snp sc->last_op_thr = curthread; 1036247434Snp#endif 1037218792Snp ADAPTER_UNLOCK(sc); 1038218792Snp 1039237920Snp if (pi->vlan_c) 1040237920Snp EVENTHANDLER_DEREGISTER(vlan_config, pi->vlan_c); 1041237920Snp 1042231093Snp PORT_LOCK(pi); 1043231093Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1044231093Snp callout_stop(&pi->tick); 1045231093Snp PORT_UNLOCK(pi); 1046231093Snp callout_drain(&pi->tick); 1047218792Snp 1048231093Snp /* Let detach proceed even if these fail. */ 1049231093Snp cxgbe_uninit_synchronized(pi); 1050231093Snp port_full_uninit(pi); 1051219286Snp 1052218792Snp ifmedia_removeall(&pi->media); 1053218792Snp ether_ifdetach(pi->ifp); 1054218792Snp if_free(pi->ifp); 1055218792Snp 1056218792Snp ADAPTER_LOCK(sc); 1057218792Snp CLR_BUSY(sc); 1058247434Snp wakeup(&sc->flags); 1059218792Snp ADAPTER_UNLOCK(sc); 1060218792Snp 1061218792Snp return (0); 1062218792Snp} 1063218792Snp 1064218792Snpstatic void 1065218792Snpcxgbe_init(void *arg) 1066218792Snp{ 1067218792Snp struct port_info *pi = arg; 1068218792Snp struct adapter *sc = pi->adapter; 1069218792Snp 1070247434Snp if (begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4init") != 0) 1071247434Snp return; 1072247434Snp cxgbe_init_synchronized(pi); 1073247434Snp end_synchronized_op(sc, 0); 1074218792Snp} 1075218792Snp 1076218792Snpstatic int 1077218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) 1078218792Snp{ 1079218792Snp int rc = 0, mtu, flags; 1080218792Snp struct port_info *pi = ifp->if_softc; 1081218792Snp struct adapter *sc = pi->adapter; 1082218792Snp struct ifreq *ifr = (struct ifreq *)data; 1083218792Snp uint32_t mask; 1084218792Snp 1085218792Snp switch (cmd) { 1086218792Snp case SIOCSIFMTU: 1087247434Snp mtu = ifr->ifr_mtu; 1088247434Snp if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) 1089247434Snp return (EINVAL); 1090247434Snp 1091247434Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4mtu"); 1092247434Snp if (rc) 1093218792Snp return (rc); 1094247434Snp ifp->if_mtu = mtu; 1095252814Snp if (pi->flags & PORT_INIT_DONE) { 1096247434Snp t4_update_fl_bufsize(ifp); 1097252814Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1098252814Snp rc = update_mac_settings(pi, XGMAC_MTU); 1099218792Snp } 1100247434Snp end_synchronized_op(sc, 0); 1101218792Snp break; 1102218792Snp 1103218792Snp case SIOCSIFFLAGS: 1104247434Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4flg"); 1105247434Snp if (rc) 1106247434Snp return (rc); 1107247434Snp 1108218792Snp if (ifp->if_flags & IFF_UP) { 1109218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1110218792Snp flags = pi->if_flags; 1111218792Snp if ((ifp->if_flags ^ flags) & 1112218792Snp (IFF_PROMISC | IFF_ALLMULTI)) { 1113218792Snp rc = update_mac_settings(pi, 1114218792Snp XGMAC_PROMISC | XGMAC_ALLMULTI); 1115218792Snp } 1116218792Snp } else 1117247434Snp rc = cxgbe_init_synchronized(pi); 1118218792Snp pi->if_flags = ifp->if_flags; 1119218792Snp } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1120247434Snp rc = cxgbe_uninit_synchronized(pi); 1121247434Snp end_synchronized_op(sc, 0); 1122218792Snp break; 1123218792Snp 1124218792Snp case SIOCADDMULTI: 1125247434Snp case SIOCDELMULTI: /* these two are called with a mutex held :-( */ 1126247434Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK, "t4multi"); 1127218792Snp if (rc) 1128247434Snp return (rc); 1129247434Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1130218792Snp rc = update_mac_settings(pi, XGMAC_MCADDRS); 1131247434Snp end_synchronized_op(sc, LOCK_HELD); 1132218792Snp break; 1133218792Snp 1134218792Snp case SIOCSIFCAP: 1135247434Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4cap"); 1136218792Snp if (rc) 1137247434Snp return (rc); 1138218792Snp 1139218792Snp mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1140218792Snp if (mask & IFCAP_TXCSUM) { 1141218792Snp ifp->if_capenable ^= IFCAP_TXCSUM; 1142218792Snp ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 1143218792Snp 1144237925Snp if (IFCAP_TSO4 & ifp->if_capenable && 1145218792Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1146237925Snp ifp->if_capenable &= ~IFCAP_TSO4; 1147218792Snp if_printf(ifp, 1148237925Snp "tso4 disabled due to -txcsum.\n"); 1149218792Snp } 1150218792Snp } 1151237925Snp if (mask & IFCAP_TXCSUM_IPV6) { 1152237925Snp ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 1153237925Snp ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); 1154237925Snp 1155237925Snp if (IFCAP_TSO6 & ifp->if_capenable && 1156237925Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1157237925Snp ifp->if_capenable &= ~IFCAP_TSO6; 1158237925Snp if_printf(ifp, 1159237925Snp "tso6 disabled due to -txcsum6.\n"); 1160237925Snp } 1161237925Snp } 1162218792Snp if (mask & IFCAP_RXCSUM) 1163218792Snp ifp->if_capenable ^= IFCAP_RXCSUM; 1164237925Snp if (mask & IFCAP_RXCSUM_IPV6) 1165237925Snp ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 1166237925Snp 1167237925Snp /* 1168237925Snp * Note that we leave CSUM_TSO alone (it is always set). The 1169237925Snp * kernel takes both IFCAP_TSOx and CSUM_TSO into account before 1170237925Snp * sending a TSO request our way, so it's sufficient to toggle 1171237925Snp * IFCAP_TSOx only. 1172237925Snp */ 1173218792Snp if (mask & IFCAP_TSO4) { 1174237925Snp if (!(IFCAP_TSO4 & ifp->if_capenable) && 1175237925Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1176237925Snp if_printf(ifp, "enable txcsum first.\n"); 1177237925Snp rc = EAGAIN; 1178237925Snp goto fail; 1179237925Snp } 1180218792Snp ifp->if_capenable ^= IFCAP_TSO4; 1181218792Snp } 1182237925Snp if (mask & IFCAP_TSO6) { 1183237925Snp if (!(IFCAP_TSO6 & ifp->if_capenable) && 1184237925Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1185237925Snp if_printf(ifp, "enable txcsum6 first.\n"); 1186237925Snp rc = EAGAIN; 1187237925Snp goto fail; 1188237925Snp } 1189237925Snp ifp->if_capenable ^= IFCAP_TSO6; 1190237925Snp } 1191218792Snp if (mask & IFCAP_LRO) { 1192237925Snp#if defined(INET) || defined(INET6) 1193218792Snp int i; 1194218792Snp struct sge_rxq *rxq; 1195218792Snp 1196218792Snp ifp->if_capenable ^= IFCAP_LRO; 1197218792Snp for_each_rxq(pi, i, rxq) { 1198218792Snp if (ifp->if_capenable & IFCAP_LRO) 1199231093Snp rxq->iq.flags |= IQ_LRO_ENABLED; 1200218792Snp else 1201231093Snp rxq->iq.flags &= ~IQ_LRO_ENABLED; 1202218792Snp } 1203218792Snp#endif 1204218792Snp } 1205237920Snp#ifdef TCP_OFFLOAD 1206231093Snp if (mask & IFCAP_TOE) { 1207231093Snp int enable = (ifp->if_capenable ^ mask) & IFCAP_TOE; 1208231093Snp 1209231093Snp rc = toe_capability(pi, enable); 1210231093Snp if (rc != 0) 1211231093Snp goto fail; 1212231093Snp 1213231093Snp ifp->if_capenable ^= mask; 1214218792Snp } 1215218792Snp#endif 1216218792Snp if (mask & IFCAP_VLAN_HWTAGGING) { 1217218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1218247434Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1219218792Snp rc = update_mac_settings(pi, XGMAC_VLANEX); 1220218792Snp } 1221218792Snp if (mask & IFCAP_VLAN_MTU) { 1222218792Snp ifp->if_capenable ^= IFCAP_VLAN_MTU; 1223218792Snp 1224218792Snp /* Need to find out how to disable auto-mtu-inflation */ 1225218792Snp } 1226218792Snp if (mask & IFCAP_VLAN_HWTSO) 1227218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1228218792Snp if (mask & IFCAP_VLAN_HWCSUM) 1229218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 1230218792Snp 1231218792Snp#ifdef VLAN_CAPABILITIES 1232218792Snp VLAN_CAPABILITIES(ifp); 1233218792Snp#endif 1234247434Snpfail: 1235247434Snp end_synchronized_op(sc, 0); 1236218792Snp break; 1237218792Snp 1238218792Snp case SIOCSIFMEDIA: 1239218792Snp case SIOCGIFMEDIA: 1240218792Snp ifmedia_ioctl(ifp, ifr, &pi->media, cmd); 1241218792Snp break; 1242218792Snp 1243218792Snp default: 1244218792Snp rc = ether_ioctl(ifp, cmd, data); 1245218792Snp } 1246218792Snp 1247218792Snp return (rc); 1248218792Snp} 1249218792Snp 1250218792Snpstatic int 1251218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m) 1252218792Snp{ 1253218792Snp struct port_info *pi = ifp->if_softc; 1254218792Snp struct adapter *sc = pi->adapter; 1255218792Snp struct sge_txq *txq = &sc->sge.txq[pi->first_txq]; 1256218792Snp struct buf_ring *br; 1257218792Snp int rc; 1258218792Snp 1259218792Snp M_ASSERTPKTHDR(m); 1260218792Snp 1261231093Snp if (__predict_false(pi->link_cfg.link_ok == 0)) { 1262218792Snp m_freem(m); 1263231093Snp return (ENETDOWN); 1264218792Snp } 1265218792Snp 1266218792Snp if (m->m_flags & M_FLOWID) 1267265582Snp txq += ((m->m_pkthdr.flowid % (pi->ntxq - pi->rsrv_noflowq)) 1268265582Snp + pi->rsrv_noflowq); 1269220873Snp br = txq->br; 1270218792Snp 1271218792Snp if (TXQ_TRYLOCK(txq) == 0) { 1272231093Snp struct sge_eq *eq = &txq->eq; 1273231093Snp 1274218792Snp /* 1275231093Snp * It is possible that t4_eth_tx finishes up and releases the 1276231093Snp * lock between the TRYLOCK above and the drbr_enqueue here. We 1277231093Snp * need to make sure that this mbuf doesn't just sit there in 1278231093Snp * the drbr. 1279218792Snp */ 1280218792Snp 1281231093Snp rc = drbr_enqueue(ifp, br, m); 1282231093Snp if (rc == 0 && callout_pending(&eq->tx_callout) == 0 && 1283231093Snp !(eq->flags & EQ_DOOMED)) 1284231093Snp callout_reset(&eq->tx_callout, 1, t4_tx_callout, eq); 1285231093Snp return (rc); 1286218792Snp } 1287218792Snp 1288218792Snp /* 1289218792Snp * txq->m is the mbuf that is held up due to a temporary shortage of 1290218792Snp * resources and it should be put on the wire first. Then what's in 1291218792Snp * drbr and finally the mbuf that was just passed in to us. 1292218792Snp * 1293218792Snp * Return code should indicate the fate of the mbuf that was passed in 1294218792Snp * this time. 1295218792Snp */ 1296218792Snp 1297218792Snp TXQ_LOCK_ASSERT_OWNED(txq); 1298218792Snp if (drbr_needs_enqueue(ifp, br) || txq->m) { 1299218792Snp 1300218792Snp /* Queued for transmission. */ 1301218792Snp 1302218792Snp rc = drbr_enqueue(ifp, br, m); 1303218792Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 1304218792Snp (void) t4_eth_tx(ifp, txq, m); 1305218792Snp TXQ_UNLOCK(txq); 1306218792Snp return (rc); 1307218792Snp } 1308218792Snp 1309218792Snp /* Direct transmission. */ 1310218792Snp rc = t4_eth_tx(ifp, txq, m); 1311218792Snp if (rc != 0 && txq->m) 1312218792Snp rc = 0; /* held, will be transmitted soon (hopefully) */ 1313218792Snp 1314218792Snp TXQ_UNLOCK(txq); 1315218792Snp return (rc); 1316218792Snp} 1317218792Snp 1318218792Snpstatic void 1319218792Snpcxgbe_qflush(struct ifnet *ifp) 1320218792Snp{ 1321218792Snp struct port_info *pi = ifp->if_softc; 1322220649Snp struct sge_txq *txq; 1323220649Snp int i; 1324220649Snp struct mbuf *m; 1325218792Snp 1326231093Snp /* queues do not exist if !PORT_INIT_DONE. */ 1327231093Snp if (pi->flags & PORT_INIT_DONE) { 1328220649Snp for_each_txq(pi, i, txq) { 1329220649Snp TXQ_LOCK(txq); 1330220649Snp m_freem(txq->m); 1331231093Snp txq->m = NULL; 1332220873Snp while ((m = buf_ring_dequeue_sc(txq->br)) != NULL) 1333220649Snp m_freem(m); 1334220649Snp TXQ_UNLOCK(txq); 1335220649Snp } 1336220649Snp } 1337220649Snp if_qflush(ifp); 1338218792Snp} 1339218792Snp 1340218792Snpstatic int 1341218792Snpcxgbe_media_change(struct ifnet *ifp) 1342218792Snp{ 1343218792Snp struct port_info *pi = ifp->if_softc; 1344218792Snp 1345218792Snp device_printf(pi->dev, "%s unimplemented.\n", __func__); 1346218792Snp 1347218792Snp return (EOPNOTSUPP); 1348218792Snp} 1349218792Snp 1350218792Snpstatic void 1351218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1352218792Snp{ 1353218792Snp struct port_info *pi = ifp->if_softc; 1354218792Snp struct ifmedia_entry *cur = pi->media.ifm_cur; 1355218792Snp int speed = pi->link_cfg.speed; 1356218792Snp int data = (pi->port_type << 8) | pi->mod_type; 1357218792Snp 1358218792Snp if (cur->ifm_data != data) { 1359218792Snp build_medialist(pi); 1360218792Snp cur = pi->media.ifm_cur; 1361218792Snp } 1362218792Snp 1363218792Snp ifmr->ifm_status = IFM_AVALID; 1364218792Snp if (!pi->link_cfg.link_ok) 1365218792Snp return; 1366218792Snp 1367218792Snp ifmr->ifm_status |= IFM_ACTIVE; 1368218792Snp 1369218792Snp /* active and current will differ iff current media is autoselect. */ 1370218792Snp if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO) 1371218792Snp return; 1372218792Snp 1373218792Snp ifmr->ifm_active = IFM_ETHER | IFM_FDX; 1374218792Snp if (speed == SPEED_10000) 1375218792Snp ifmr->ifm_active |= IFM_10G_T; 1376218792Snp else if (speed == SPEED_1000) 1377218792Snp ifmr->ifm_active |= IFM_1000_T; 1378218792Snp else if (speed == SPEED_100) 1379218792Snp ifmr->ifm_active |= IFM_100_TX; 1380218792Snp else if (speed == SPEED_10) 1381218792Snp ifmr->ifm_active |= IFM_10_T; 1382218792Snp else 1383218792Snp KASSERT(0, ("%s: link up but speed unknown (%u)", __func__, 1384218792Snp speed)); 1385218792Snp} 1386218792Snp 1387218792Snpvoid 1388218792Snpt4_fatal_err(struct adapter *sc) 1389218792Snp{ 1390218792Snp t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0); 1391218792Snp t4_intr_disable(sc); 1392218792Snp log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n", 1393218792Snp device_get_nameunit(sc->dev)); 1394218792Snp} 1395218792Snp 1396218792Snpstatic int 1397252495Snpmap_bars_0_and_4(struct adapter *sc) 1398218792Snp{ 1399218792Snp sc->regs_rid = PCIR_BAR(0); 1400218792Snp sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1401218792Snp &sc->regs_rid, RF_ACTIVE); 1402218792Snp if (sc->regs_res == NULL) { 1403218792Snp device_printf(sc->dev, "cannot map registers.\n"); 1404218792Snp return (ENXIO); 1405218792Snp } 1406218792Snp sc->bt = rman_get_bustag(sc->regs_res); 1407218792Snp sc->bh = rman_get_bushandle(sc->regs_res); 1408218792Snp sc->mmio_len = rman_get_size(sc->regs_res); 1409252495Snp setbit(&sc->doorbells, DOORBELL_KDB); 1410218792Snp 1411218792Snp sc->msix_rid = PCIR_BAR(4); 1412218792Snp sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1413218792Snp &sc->msix_rid, RF_ACTIVE); 1414218792Snp if (sc->msix_res == NULL) { 1415218792Snp device_printf(sc->dev, "cannot map MSI-X BAR.\n"); 1416218792Snp return (ENXIO); 1417218792Snp } 1418218792Snp 1419218792Snp return (0); 1420218792Snp} 1421218792Snp 1422252495Snpstatic int 1423252495Snpmap_bar_2(struct adapter *sc) 1424252495Snp{ 1425252495Snp 1426252495Snp /* 1427252495Snp * T4: only iWARP driver uses the userspace doorbells. There is no need 1428252495Snp * to map it if RDMA is disabled. 1429252495Snp */ 1430252495Snp if (is_t4(sc) && sc->rdmacaps == 0) 1431252495Snp return (0); 1432252495Snp 1433252495Snp sc->udbs_rid = PCIR_BAR(2); 1434252495Snp sc->udbs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1435252495Snp &sc->udbs_rid, RF_ACTIVE); 1436252495Snp if (sc->udbs_res == NULL) { 1437252495Snp device_printf(sc->dev, "cannot map doorbell BAR.\n"); 1438252495Snp return (ENXIO); 1439252495Snp } 1440252495Snp sc->udbs_base = rman_get_virtual(sc->udbs_res); 1441252495Snp 1442252495Snp if (is_t5(sc)) { 1443252495Snp setbit(&sc->doorbells, DOORBELL_UDB); 1444252495Snp#if defined(__i386__) || defined(__amd64__) 1445252495Snp if (t5_write_combine) { 1446252495Snp int rc; 1447252495Snp 1448252495Snp /* 1449252495Snp * Enable write combining on BAR2. This is the 1450252495Snp * userspace doorbell BAR and is split into 128B 1451252495Snp * (UDBS_SEG_SIZE) doorbell regions, each associated 1452252495Snp * with an egress queue. The first 64B has the doorbell 1453252495Snp * and the second 64B can be used to submit a tx work 1454252495Snp * request with an implicit doorbell. 1455252495Snp */ 1456252495Snp 1457252495Snp rc = pmap_change_attr((vm_offset_t)sc->udbs_base, 1458252495Snp rman_get_size(sc->udbs_res), PAT_WRITE_COMBINING); 1459252495Snp if (rc == 0) { 1460252495Snp clrbit(&sc->doorbells, DOORBELL_UDB); 1461252495Snp setbit(&sc->doorbells, DOORBELL_WCWR); 1462252495Snp setbit(&sc->doorbells, DOORBELL_UDBWC); 1463252495Snp } else { 1464252495Snp device_printf(sc->dev, 1465252495Snp "couldn't enable write combining: %d\n", 1466252495Snp rc); 1467252495Snp } 1468252495Snp 1469252495Snp t4_write_reg(sc, A_SGE_STAT_CFG, 1470252495Snp V_STATSOURCE_T5(7) | V_STATMODE(0)); 1471252495Snp } 1472252495Snp#endif 1473252495Snp } 1474252495Snp 1475252495Snp return (0); 1476252495Snp} 1477252495Snp 1478252495Snpstatic const struct memwin t4_memwin[] = { 1479252495Snp { MEMWIN0_BASE, MEMWIN0_APERTURE }, 1480252495Snp { MEMWIN1_BASE, MEMWIN1_APERTURE }, 1481252495Snp { MEMWIN2_BASE_T4, MEMWIN2_APERTURE_T4 } 1482252495Snp}; 1483252495Snp 1484252495Snpstatic const struct memwin t5_memwin[] = { 1485252495Snp { MEMWIN0_BASE, MEMWIN0_APERTURE }, 1486252495Snp { MEMWIN1_BASE, MEMWIN1_APERTURE }, 1487252495Snp { MEMWIN2_BASE_T5, MEMWIN2_APERTURE_T5 }, 1488252495Snp}; 1489252495Snp 1490218792Snpstatic void 1491218792Snpsetup_memwin(struct adapter *sc) 1492218792Snp{ 1493252495Snp const struct memwin *mw; 1494252495Snp int i, n; 1495237925Snp uint32_t bar0; 1496218792Snp 1497252495Snp if (is_t4(sc)) { 1498252495Snp /* 1499252495Snp * Read low 32b of bar0 indirectly via the hardware backdoor 1500252495Snp * mechanism. Works from within PCI passthrough environments 1501252495Snp * too, where rman_get_start() can return a different value. We 1502252495Snp * need to program the T4 memory window decoders with the actual 1503252495Snp * addresses that will be coming across the PCIe link. 1504252495Snp */ 1505252495Snp bar0 = t4_hw_pci_read_cfg4(sc, PCIR_BAR(0)); 1506252495Snp bar0 &= (uint32_t) PCIM_BAR_MEM_BASE; 1507218792Snp 1508252495Snp mw = &t4_memwin[0]; 1509252495Snp n = nitems(t4_memwin); 1510252495Snp } else { 1511252495Snp /* T5 uses the relative offset inside the PCIe BAR */ 1512252495Snp bar0 = 0; 1513218792Snp 1514252495Snp mw = &t5_memwin[0]; 1515252495Snp n = nitems(t5_memwin); 1516252495Snp } 1517218792Snp 1518252495Snp for (i = 0; i < n; i++, mw++) { 1519252495Snp t4_write_reg(sc, 1520252495Snp PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, i), 1521252495Snp (mw->base + bar0) | V_BIR(0) | 1522252495Snp V_WINDOW(ilog2(mw->aperture) - 10)); 1523252495Snp } 1524237925Snp 1525237925Snp /* flush */ 1526237925Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2)); 1527218792Snp} 1528218792Snp 1529252495Snp/* 1530252495Snp * Verify that the memory range specified by the addr/len pair is valid and lies 1531252495Snp * entirely within a single region (EDCx or MCx). 1532252495Snp */ 1533218792Snpstatic int 1534252495Snpvalidate_mem_range(struct adapter *sc, uint32_t addr, int len) 1535252495Snp{ 1536252495Snp uint32_t em, addr_len, maddr, mlen; 1537252495Snp 1538252495Snp /* Memory can only be accessed in naturally aligned 4 byte units */ 1539252495Snp if (addr & 3 || len & 3 || len == 0) 1540252495Snp return (EINVAL); 1541252495Snp 1542252495Snp /* Enabled memories */ 1543252495Snp em = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 1544252495Snp if (em & F_EDRAM0_ENABLE) { 1545252495Snp addr_len = t4_read_reg(sc, A_MA_EDRAM0_BAR); 1546252495Snp maddr = G_EDRAM0_BASE(addr_len) << 20; 1547252495Snp mlen = G_EDRAM0_SIZE(addr_len) << 20; 1548252495Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1549252495Snp addr + len <= maddr + mlen) 1550252495Snp return (0); 1551252495Snp } 1552252495Snp if (em & F_EDRAM1_ENABLE) { 1553252495Snp addr_len = t4_read_reg(sc, A_MA_EDRAM1_BAR); 1554252495Snp maddr = G_EDRAM1_BASE(addr_len) << 20; 1555252495Snp mlen = G_EDRAM1_SIZE(addr_len) << 20; 1556252495Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1557252495Snp addr + len <= maddr + mlen) 1558252495Snp return (0); 1559252495Snp } 1560252495Snp if (em & F_EXT_MEM_ENABLE) { 1561252495Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 1562252495Snp maddr = G_EXT_MEM_BASE(addr_len) << 20; 1563252495Snp mlen = G_EXT_MEM_SIZE(addr_len) << 20; 1564252495Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1565252495Snp addr + len <= maddr + mlen) 1566252495Snp return (0); 1567252495Snp } 1568252495Snp if (!is_t4(sc) && em & F_EXT_MEM1_ENABLE) { 1569252495Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 1570252495Snp maddr = G_EXT_MEM1_BASE(addr_len) << 20; 1571252495Snp mlen = G_EXT_MEM1_SIZE(addr_len) << 20; 1572252495Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1573252495Snp addr + len <= maddr + mlen) 1574252495Snp return (0); 1575252495Snp } 1576252495Snp 1577252495Snp return (EFAULT); 1578252495Snp} 1579252495Snp 1580265483Snpstatic int 1581265483Snpfwmtype_to_hwmtype(int mtype) 1582265483Snp{ 1583265483Snp 1584265483Snp switch (mtype) { 1585265483Snp case FW_MEMTYPE_EDC0: 1586265483Snp return (MEM_EDC0); 1587265483Snp case FW_MEMTYPE_EDC1: 1588265483Snp return (MEM_EDC1); 1589265483Snp case FW_MEMTYPE_EXTMEM: 1590265483Snp return (MEM_MC0); 1591265483Snp case FW_MEMTYPE_EXTMEM1: 1592265483Snp return (MEM_MC1); 1593265483Snp default: 1594265483Snp panic("%s: cannot translate fw mtype %d.", __func__, mtype); 1595265483Snp } 1596265483Snp} 1597265483Snp 1598252495Snp/* 1599252495Snp * Verify that the memory range specified by the memtype/offset/len pair is 1600252495Snp * valid and lies entirely within the memtype specified. The global address of 1601252495Snp * the start of the range is returned in addr. 1602252495Snp */ 1603252495Snpstatic int 1604252495Snpvalidate_mt_off_len(struct adapter *sc, int mtype, uint32_t off, int len, 1605252495Snp uint32_t *addr) 1606252495Snp{ 1607252495Snp uint32_t em, addr_len, maddr, mlen; 1608252495Snp 1609252495Snp /* Memory can only be accessed in naturally aligned 4 byte units */ 1610252495Snp if (off & 3 || len & 3 || len == 0) 1611252495Snp return (EINVAL); 1612252495Snp 1613252495Snp em = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 1614265483Snp switch (fwmtype_to_hwmtype(mtype)) { 1615252495Snp case MEM_EDC0: 1616252495Snp if (!(em & F_EDRAM0_ENABLE)) 1617252495Snp return (EINVAL); 1618252495Snp addr_len = t4_read_reg(sc, A_MA_EDRAM0_BAR); 1619252495Snp maddr = G_EDRAM0_BASE(addr_len) << 20; 1620252495Snp mlen = G_EDRAM0_SIZE(addr_len) << 20; 1621252495Snp break; 1622252495Snp case MEM_EDC1: 1623252495Snp if (!(em & F_EDRAM1_ENABLE)) 1624252495Snp return (EINVAL); 1625252495Snp addr_len = t4_read_reg(sc, A_MA_EDRAM1_BAR); 1626252495Snp maddr = G_EDRAM1_BASE(addr_len) << 20; 1627252495Snp mlen = G_EDRAM1_SIZE(addr_len) << 20; 1628252495Snp break; 1629252495Snp case MEM_MC: 1630252495Snp if (!(em & F_EXT_MEM_ENABLE)) 1631252495Snp return (EINVAL); 1632252495Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 1633252495Snp maddr = G_EXT_MEM_BASE(addr_len) << 20; 1634252495Snp mlen = G_EXT_MEM_SIZE(addr_len) << 20; 1635252495Snp break; 1636252495Snp case MEM_MC1: 1637252495Snp if (is_t4(sc) || !(em & F_EXT_MEM1_ENABLE)) 1638252495Snp return (EINVAL); 1639252495Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 1640252495Snp maddr = G_EXT_MEM1_BASE(addr_len) << 20; 1641252495Snp mlen = G_EXT_MEM1_SIZE(addr_len) << 20; 1642252495Snp break; 1643252495Snp default: 1644252495Snp return (EINVAL); 1645252495Snp } 1646252495Snp 1647252495Snp if (mlen > 0 && off < mlen && off + len <= mlen) { 1648252495Snp *addr = maddr + off; /* global address */ 1649252495Snp return (0); 1650252495Snp } 1651252495Snp 1652252495Snp return (EFAULT); 1653252495Snp} 1654252495Snp 1655252495Snpstatic void 1656252495Snpmemwin_info(struct adapter *sc, int win, uint32_t *base, uint32_t *aperture) 1657252495Snp{ 1658252495Snp const struct memwin *mw; 1659252495Snp 1660252495Snp if (is_t4(sc)) { 1661252495Snp KASSERT(win >= 0 && win < nitems(t4_memwin), 1662252495Snp ("%s: incorrect memwin# (%d)", __func__, win)); 1663252495Snp mw = &t4_memwin[win]; 1664252495Snp } else { 1665252495Snp KASSERT(win >= 0 && win < nitems(t5_memwin), 1666252495Snp ("%s: incorrect memwin# (%d)", __func__, win)); 1667252495Snp mw = &t5_memwin[win]; 1668252495Snp } 1669252495Snp 1670252495Snp if (base != NULL) 1671252495Snp *base = mw->base; 1672252495Snp if (aperture != NULL) 1673252495Snp *aperture = mw->aperture; 1674252495Snp} 1675252495Snp 1676252495Snp/* 1677252495Snp * Positions the memory window such that it can be used to access the specified 1678252495Snp * address in the chip's address space. The return value is the offset of addr 1679252495Snp * from the start of the window. 1680252495Snp */ 1681252495Snpstatic uint32_t 1682252495Snpposition_memwin(struct adapter *sc, int n, uint32_t addr) 1683252495Snp{ 1684252495Snp uint32_t start, pf; 1685252495Snp uint32_t reg; 1686252495Snp 1687252495Snp KASSERT(n >= 0 && n <= 3, 1688252495Snp ("%s: invalid window %d.", __func__, n)); 1689252495Snp KASSERT((addr & 3) == 0, 1690252495Snp ("%s: addr (0x%x) is not at a 4B boundary.", __func__, addr)); 1691252495Snp 1692252495Snp if (is_t4(sc)) { 1693252495Snp pf = 0; 1694252495Snp start = addr & ~0xf; /* start must be 16B aligned */ 1695252495Snp } else { 1696252495Snp pf = V_PFNUM(sc->pf); 1697252495Snp start = addr & ~0x7f; /* start must be 128B aligned */ 1698252495Snp } 1699252495Snp reg = PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, n); 1700252495Snp 1701252495Snp t4_write_reg(sc, reg, start | pf); 1702252495Snp t4_read_reg(sc, reg); 1703252495Snp 1704252495Snp return (addr - start); 1705252495Snp} 1706252495Snp 1707252495Snpstatic int 1708218792Snpcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g, 1709218792Snp struct intrs_and_queues *iaq) 1710218792Snp{ 1711231093Snp int rc, itype, navail, nrxq10g, nrxq1g, n; 1712231093Snp int nofldrxq10g = 0, nofldrxq1g = 0; 1713218792Snp 1714218792Snp bzero(iaq, sizeof(*iaq)); 1715218792Snp 1716231093Snp iaq->ntxq10g = t4_ntxq10g; 1717231093Snp iaq->ntxq1g = t4_ntxq1g; 1718231093Snp iaq->nrxq10g = nrxq10g = t4_nrxq10g; 1719231093Snp iaq->nrxq1g = nrxq1g = t4_nrxq1g; 1720265582Snp iaq->rsrv_noflowq = t4_rsrv_noflowq; 1721237920Snp#ifdef TCP_OFFLOAD 1722237925Snp if (is_offload(sc)) { 1723237925Snp iaq->nofldtxq10g = t4_nofldtxq10g; 1724237925Snp iaq->nofldtxq1g = t4_nofldtxq1g; 1725237925Snp iaq->nofldrxq10g = nofldrxq10g = t4_nofldrxq10g; 1726237925Snp iaq->nofldrxq1g = nofldrxq1g = t4_nofldrxq1g; 1727237925Snp } 1728231093Snp#endif 1729231093Snp 1730219944Snp for (itype = INTR_MSIX; itype; itype >>= 1) { 1731218792Snp 1732231093Snp if ((itype & t4_intr_types) == 0) 1733218792Snp continue; /* not allowed */ 1734218792Snp 1735219944Snp if (itype == INTR_MSIX) 1736218792Snp navail = pci_msix_count(sc->dev); 1737219944Snp else if (itype == INTR_MSI) 1738218792Snp navail = pci_msi_count(sc->dev); 1739218792Snp else 1740218792Snp navail = 1; 1741231093Snprestart: 1742218792Snp if (navail == 0) 1743218792Snp continue; 1744218792Snp 1745218792Snp iaq->intr_type = itype; 1746231093Snp iaq->intr_flags = 0; 1747218792Snp 1748231093Snp /* 1749231093Snp * Best option: an interrupt vector for errors, one for the 1750231093Snp * firmware event queue, and one each for each rxq (NIC as well 1751231093Snp * as offload). 1752231093Snp */ 1753231093Snp iaq->nirq = T4_EXTRA_INTR; 1754231093Snp iaq->nirq += n10g * (nrxq10g + nofldrxq10g); 1755231093Snp iaq->nirq += n1g * (nrxq1g + nofldrxq1g); 1756231093Snp if (iaq->nirq <= navail && 1757231093Snp (itype != INTR_MSI || powerof2(iaq->nirq))) { 1758231093Snp iaq->intr_flags |= INTR_DIRECT; 1759231093Snp goto allocate; 1760231093Snp } 1761218792Snp 1762231093Snp /* 1763231093Snp * Second best option: an interrupt vector for errors, one for 1764231093Snp * the firmware event queue, and one each for either NIC or 1765231093Snp * offload rxq's. 1766231093Snp */ 1767231093Snp iaq->nirq = T4_EXTRA_INTR; 1768231093Snp iaq->nirq += n10g * max(nrxq10g, nofldrxq10g); 1769231093Snp iaq->nirq += n1g * max(nrxq1g, nofldrxq1g); 1770231093Snp if (iaq->nirq <= navail && 1771231093Snp (itype != INTR_MSI || powerof2(iaq->nirq))) 1772231093Snp goto allocate; 1773218792Snp 1774231093Snp /* 1775231093Snp * Next best option: an interrupt vector for errors, one for the 1776231093Snp * firmware event queue, and at least one per port. At this 1777231093Snp * point we know we'll have to downsize nrxq or nofldrxq to fit 1778231093Snp * what's available to us. 1779231093Snp */ 1780231093Snp iaq->nirq = T4_EXTRA_INTR; 1781231093Snp iaq->nirq += n10g + n1g; 1782231093Snp if (iaq->nirq <= navail) { 1783231093Snp int leftover = navail - iaq->nirq; 1784218792Snp 1785231093Snp if (n10g > 0) { 1786231093Snp int target = max(nrxq10g, nofldrxq10g); 1787219944Snp 1788231093Snp n = 1; 1789231093Snp while (n < target && leftover >= n10g) { 1790231093Snp leftover -= n10g; 1791231093Snp iaq->nirq += n10g; 1792231093Snp n++; 1793231093Snp } 1794231093Snp iaq->nrxq10g = min(n, nrxq10g); 1795237920Snp#ifdef TCP_OFFLOAD 1796237925Snp if (is_offload(sc)) 1797237925Snp iaq->nofldrxq10g = min(n, nofldrxq10g); 1798231093Snp#endif 1799231093Snp } 1800218792Snp 1801231093Snp if (n1g > 0) { 1802231093Snp int target = max(nrxq1g, nofldrxq1g); 1803219944Snp 1804231093Snp n = 1; 1805231093Snp while (n < target && leftover >= n1g) { 1806231093Snp leftover -= n1g; 1807231093Snp iaq->nirq += n1g; 1808231093Snp n++; 1809219944Snp } 1810231093Snp iaq->nrxq1g = min(n, nrxq1g); 1811237920Snp#ifdef TCP_OFFLOAD 1812237925Snp if (is_offload(sc)) 1813237925Snp iaq->nofldrxq1g = min(n, nofldrxq1g); 1814231093Snp#endif 1815219944Snp } 1816219944Snp 1817231093Snp if (itype != INTR_MSI || powerof2(iaq->nirq)) 1818231093Snp goto allocate; 1819218792Snp } 1820218792Snp 1821231093Snp /* 1822231093Snp * Least desirable option: one interrupt vector for everything. 1823231093Snp */ 1824231093Snp iaq->nirq = iaq->nrxq10g = iaq->nrxq1g = 1; 1825237920Snp#ifdef TCP_OFFLOAD 1826237925Snp if (is_offload(sc)) 1827237925Snp iaq->nofldrxq10g = iaq->nofldrxq1g = 1; 1828231093Snp#endif 1829231093Snp 1830231093Snpallocate: 1831218792Snp navail = iaq->nirq; 1832218792Snp rc = 0; 1833219944Snp if (itype == INTR_MSIX) 1834218792Snp rc = pci_alloc_msix(sc->dev, &navail); 1835219944Snp else if (itype == INTR_MSI) 1836218792Snp rc = pci_alloc_msi(sc->dev, &navail); 1837218792Snp 1838218792Snp if (rc == 0) { 1839218792Snp if (navail == iaq->nirq) 1840218792Snp return (0); 1841218792Snp 1842218792Snp /* 1843218792Snp * Didn't get the number requested. Use whatever number 1844218792Snp * the kernel is willing to allocate (it's in navail). 1845218792Snp */ 1846231093Snp device_printf(sc->dev, "fewer vectors than requested, " 1847231093Snp "type=%d, req=%d, rcvd=%d; will downshift req.\n", 1848231093Snp itype, iaq->nirq, navail); 1849218792Snp pci_release_msi(sc->dev); 1850231093Snp goto restart; 1851218792Snp } 1852218792Snp 1853218792Snp device_printf(sc->dev, 1854218792Snp "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n", 1855218792Snp itype, rc, iaq->nirq, navail); 1856218792Snp } 1857218792Snp 1858218792Snp device_printf(sc->dev, 1859218792Snp "failed to find a usable interrupt type. " 1860231093Snp "allowed=%d, msi-x=%d, msi=%d, intx=1", t4_intr_types, 1861218792Snp pci_msix_count(sc->dev), pci_msi_count(sc->dev)); 1862218792Snp 1863218792Snp return (ENXIO); 1864218792Snp} 1865218792Snp 1866252495Snp#define FW_VERSION(chip) ( \ 1867252814Snp V_FW_HDR_FW_VER_MAJOR(chip##FW_VERSION_MAJOR) | \ 1868252814Snp V_FW_HDR_FW_VER_MINOR(chip##FW_VERSION_MINOR) | \ 1869252814Snp V_FW_HDR_FW_VER_MICRO(chip##FW_VERSION_MICRO) | \ 1870252814Snp V_FW_HDR_FW_VER_BUILD(chip##FW_VERSION_BUILD)) 1871252814Snp#define FW_INTFVER(chip, intf) (chip##FW_HDR_INTFVER_##intf) 1872252495Snp 1873252495Snpstruct fw_info { 1874252495Snp uint8_t chip; 1875252495Snp char *kld_name; 1876252495Snp char *fw_mod_name; 1877252495Snp struct fw_hdr fw_hdr; /* XXX: waste of space, need a sparse struct */ 1878252495Snp} fw_info[] = { 1879252495Snp { 1880252495Snp .chip = CHELSIO_T4, 1881252495Snp .kld_name = "t4fw_cfg", 1882252495Snp .fw_mod_name = "t4fw", 1883252495Snp .fw_hdr = { 1884252495Snp .chip = FW_HDR_CHIP_T4, 1885252495Snp .fw_ver = htobe32_const(FW_VERSION(T4)), 1886252495Snp .intfver_nic = FW_INTFVER(T4, NIC), 1887252495Snp .intfver_vnic = FW_INTFVER(T4, VNIC), 1888252495Snp .intfver_ofld = FW_INTFVER(T4, OFLD), 1889252495Snp .intfver_ri = FW_INTFVER(T4, RI), 1890252495Snp .intfver_iscsipdu = FW_INTFVER(T4, ISCSIPDU), 1891252495Snp .intfver_iscsi = FW_INTFVER(T4, ISCSI), 1892252495Snp .intfver_fcoepdu = FW_INTFVER(T4, FCOEPDU), 1893252495Snp .intfver_fcoe = FW_INTFVER(T4, FCOE), 1894252495Snp }, 1895252495Snp }, { 1896252495Snp .chip = CHELSIO_T5, 1897252495Snp .kld_name = "t5fw_cfg", 1898252495Snp .fw_mod_name = "t5fw", 1899252495Snp .fw_hdr = { 1900252495Snp .chip = FW_HDR_CHIP_T5, 1901252495Snp .fw_ver = htobe32_const(FW_VERSION(T5)), 1902252495Snp .intfver_nic = FW_INTFVER(T5, NIC), 1903252495Snp .intfver_vnic = FW_INTFVER(T5, VNIC), 1904252495Snp .intfver_ofld = FW_INTFVER(T5, OFLD), 1905252495Snp .intfver_ri = FW_INTFVER(T5, RI), 1906252495Snp .intfver_iscsipdu = FW_INTFVER(T5, ISCSIPDU), 1907252495Snp .intfver_iscsi = FW_INTFVER(T5, ISCSI), 1908252495Snp .intfver_fcoepdu = FW_INTFVER(T5, FCOEPDU), 1909252495Snp .intfver_fcoe = FW_INTFVER(T5, FCOE), 1910252495Snp }, 1911252495Snp } 1912252495Snp}; 1913252495Snp 1914252495Snpstatic struct fw_info * 1915252495Snpfind_fw_info(int chip) 1916252495Snp{ 1917252495Snp int i; 1918252495Snp 1919252495Snp for (i = 0; i < nitems(fw_info); i++) { 1920252495Snp if (fw_info[i].chip == chip) 1921252495Snp return (&fw_info[i]); 1922252495Snp } 1923252495Snp return (NULL); 1924252495Snp} 1925252495Snp 1926218792Snp/* 1927252495Snp * Is the given firmware API compatible with the one the driver was compiled 1928252495Snp * with? 1929247434Snp */ 1930247434Snpstatic int 1931252495Snpfw_compatible(const struct fw_hdr *hdr1, const struct fw_hdr *hdr2) 1932247434Snp{ 1933247434Snp 1934252495Snp /* short circuit if it's the exact same firmware version */ 1935252495Snp if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver) 1936247434Snp return (1); 1937247434Snp 1938247434Snp /* 1939247434Snp * XXX: Is this too conservative? Perhaps I should limit this to the 1940247434Snp * features that are supported in the driver. 1941247434Snp */ 1942252495Snp#define SAME_INTF(x) (hdr1->intfver_##x == hdr2->intfver_##x) 1943252495Snp if (hdr1->chip == hdr2->chip && SAME_INTF(nic) && SAME_INTF(vnic) && 1944252495Snp SAME_INTF(ofld) && SAME_INTF(ri) && SAME_INTF(iscsipdu) && 1945252495Snp SAME_INTF(iscsi) && SAME_INTF(fcoepdu) && SAME_INTF(fcoe)) 1946247434Snp return (1); 1947252495Snp#undef SAME_INTF 1948247434Snp 1949247434Snp return (0); 1950247434Snp} 1951247434Snp 1952247434Snp/* 1953252495Snp * The firmware in the KLD is usable, but should it be installed? This routine 1954252495Snp * explains itself in detail if it indicates the KLD firmware should be 1955252495Snp * installed. 1956218792Snp */ 1957218792Snpstatic int 1958252495Snpshould_install_kld_fw(struct adapter *sc, int card_fw_usable, int k, int c) 1959252495Snp{ 1960252495Snp const char *reason; 1961252495Snp 1962252495Snp if (!card_fw_usable) { 1963252495Snp reason = "incompatible or unusable"; 1964252495Snp goto install; 1965252495Snp } 1966252495Snp 1967252495Snp if (k > c) { 1968252495Snp reason = "older than the version bundled with this driver"; 1969252495Snp goto install; 1970252495Snp } 1971252495Snp 1972252495Snp if (t4_fw_install == 2 && k != c) { 1973252495Snp reason = "different than the version bundled with this driver"; 1974252495Snp goto install; 1975252495Snp } 1976252495Snp 1977252495Snp return (0); 1978252495Snp 1979252495Snpinstall: 1980252495Snp if (t4_fw_install == 0) { 1981252495Snp device_printf(sc->dev, "firmware on card (%u.%u.%u.%u) is %s, " 1982252495Snp "but the driver is prohibited from installing a different " 1983252495Snp "firmware on the card.\n", 1984252495Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 1985252495Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), reason); 1986252495Snp 1987252495Snp return (0); 1988252495Snp } 1989252495Snp 1990252495Snp device_printf(sc->dev, "firmware on card (%u.%u.%u.%u) is %s, " 1991252495Snp "installing firmware %u.%u.%u.%u on card.\n", 1992252495Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 1993252495Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), reason, 1994252495Snp G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k), 1995252495Snp G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k)); 1996252495Snp 1997252495Snp return (1); 1998252495Snp} 1999252495Snp/* 2000252495Snp * Establish contact with the firmware and determine if we are the master driver 2001252495Snp * or not, and whether we are responsible for chip initialization. 2002252495Snp */ 2003252495Snpstatic int 2004218792Snpprep_firmware(struct adapter *sc) 2005218792Snp{ 2006252495Snp const struct firmware *fw = NULL, *default_cfg; 2007252495Snp int rc, pf, card_fw_usable, kld_fw_usable, need_fw_reset = 1; 2008218792Snp enum dev_state state; 2009252495Snp struct fw_info *fw_info; 2010252495Snp struct fw_hdr *card_fw; /* fw on the card */ 2011252495Snp const struct fw_hdr *kld_fw; /* fw in the KLD */ 2012252495Snp const struct fw_hdr *drv_fw; /* fw header the driver was compiled 2013252495Snp against */ 2014218792Snp 2015252495Snp /* Contact firmware. */ 2016252495Snp rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state); 2017252495Snp if (rc < 0 || state == DEV_STATE_ERR) { 2018252495Snp rc = -rc; 2019252495Snp device_printf(sc->dev, 2020252495Snp "failed to connect to the firmware: %d, %d.\n", rc, state); 2021252495Snp return (rc); 2022252495Snp } 2023252495Snp pf = rc; 2024252495Snp if (pf == sc->mbox) 2025252495Snp sc->flags |= MASTER_PF; 2026252495Snp else if (state == DEV_STATE_UNINIT) { 2027252495Snp /* 2028252495Snp * We didn't get to be the master so we definitely won't be 2029252495Snp * configuring the chip. It's a bug if someone else hasn't 2030252495Snp * configured it already. 2031252495Snp */ 2032252495Snp device_printf(sc->dev, "couldn't be master(%d), " 2033252495Snp "device not already initialized either(%d).\n", rc, state); 2034252495Snp return (EDOOFUS); 2035252495Snp } 2036231093Snp 2037252495Snp /* This is the firmware whose headers the driver was compiled against */ 2038252495Snp fw_info = find_fw_info(chip_id(sc)); 2039252495Snp if (fw_info == NULL) { 2040252495Snp device_printf(sc->dev, 2041252495Snp "unable to look up firmware information for chip %d.\n", 2042252495Snp chip_id(sc)); 2043252495Snp return (EINVAL); 2044252495Snp } 2045252495Snp drv_fw = &fw_info->fw_hdr; 2046252495Snp 2047252495Snp /* 2048252495Snp * The firmware KLD contains many modules. The KLD name is also the 2049252495Snp * name of the module that contains the default config file. 2050252495Snp */ 2051252495Snp default_cfg = firmware_get(fw_info->kld_name); 2052252495Snp 2053247434Snp /* Read the header of the firmware on the card */ 2054247434Snp card_fw = malloc(sizeof(*card_fw), M_CXGBE, M_ZERO | M_WAITOK); 2055247434Snp rc = -t4_read_flash(sc, FLASH_FW_START, 2056247434Snp sizeof (*card_fw) / sizeof (uint32_t), (uint32_t *)card_fw, 1); 2057247434Snp if (rc == 0) 2058252495Snp card_fw_usable = fw_compatible(drv_fw, (const void*)card_fw); 2059247434Snp else { 2060247434Snp device_printf(sc->dev, 2061247434Snp "Unable to read card's firmware header: %d\n", rc); 2062247434Snp card_fw_usable = 0; 2063247434Snp } 2064218792Snp 2065247434Snp /* This is the firmware in the KLD */ 2066252495Snp fw = firmware_get(fw_info->fw_mod_name); 2067247434Snp if (fw != NULL) { 2068247434Snp kld_fw = (const void *)fw->data; 2069252495Snp kld_fw_usable = fw_compatible(drv_fw, kld_fw); 2070247434Snp } else { 2071247434Snp kld_fw = NULL; 2072247434Snp kld_fw_usable = 0; 2073247434Snp } 2074219287Snp 2075252495Snp if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver && 2076252495Snp (!kld_fw_usable || kld_fw->fw_ver == drv_fw->fw_ver)) { 2077252495Snp /* 2078252495Snp * Common case: the firmware on the card is an exact match and 2079252495Snp * the KLD is an exact match too, or the KLD is 2080252495Snp * absent/incompatible. Note that t4_fw_install = 2 is ignored 2081252495Snp * here -- use cxgbetool loadfw if you want to reinstall the 2082252495Snp * same firmware as the one on the card. 2083252495Snp */ 2084252495Snp } else if (kld_fw_usable && state == DEV_STATE_UNINIT && 2085252495Snp should_install_kld_fw(sc, card_fw_usable, be32toh(kld_fw->fw_ver), 2086252495Snp be32toh(card_fw->fw_ver))) { 2087219287Snp 2088252495Snp rc = -t4_fw_upgrade(sc, sc->mbox, fw->data, fw->datasize, 0); 2089247434Snp if (rc != 0) { 2090247434Snp device_printf(sc->dev, 2091247434Snp "failed to install firmware: %d\n", rc); 2092231093Snp goto done; 2093219287Snp } 2094219287Snp 2095247434Snp /* Installed successfully, update the cached header too. */ 2096247434Snp memcpy(card_fw, kld_fw, sizeof(*card_fw)); 2097247434Snp card_fw_usable = 1; 2098252495Snp need_fw_reset = 0; /* already reset as part of load_fw */ 2099247434Snp } 2100219287Snp 2101247434Snp if (!card_fw_usable) { 2102252495Snp uint32_t d, c, k; 2103247434Snp 2104252495Snp d = ntohl(drv_fw->fw_ver); 2105247434Snp c = ntohl(card_fw->fw_ver); 2106247434Snp k = kld_fw ? ntohl(kld_fw->fw_ver) : 0; 2107247434Snp 2108247434Snp device_printf(sc->dev, "Cannot find a usable firmware: " 2109252495Snp "fw_install %d, chip state %d, " 2110252495Snp "driver compiled with %d.%d.%d.%d, " 2111247434Snp "card has %d.%d.%d.%d, KLD has %d.%d.%d.%d\n", 2112252495Snp t4_fw_install, state, 2113252495Snp G_FW_HDR_FW_VER_MAJOR(d), G_FW_HDR_FW_VER_MINOR(d), 2114252495Snp G_FW_HDR_FW_VER_MICRO(d), G_FW_HDR_FW_VER_BUILD(d), 2115247434Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 2116247434Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), 2117247434Snp G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k), 2118247434Snp G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k)); 2119252495Snp rc = EINVAL; 2120247434Snp goto done; 2121218792Snp } 2122218792Snp 2123247434Snp /* We're using whatever's on the card and it's known to be good. */ 2124247434Snp sc->params.fw_vers = ntohl(card_fw->fw_ver); 2125247434Snp snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u", 2126247434Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 2127247434Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 2128247434Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 2129247434Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 2130252814Snp t4_get_tp_version(sc, &sc->params.tp_vers); 2131247434Snp 2132218792Snp /* Reset device */ 2133252495Snp if (need_fw_reset && 2134252495Snp (rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST)) != 0) { 2135218792Snp device_printf(sc->dev, "firmware reset failed: %d.\n", rc); 2136218792Snp if (rc != ETIMEDOUT && rc != EIO) 2137218792Snp t4_fw_bye(sc, sc->mbox); 2138231093Snp goto done; 2139218792Snp } 2140252495Snp sc->flags |= FW_OK; 2141218792Snp 2142252495Snp rc = get_params__pre_init(sc); 2143252495Snp if (rc != 0) 2144252495Snp goto done; /* error message displayed already */ 2145252495Snp 2146231093Snp /* Partition adapter resources as specified in the config file. */ 2147252495Snp if (state == DEV_STATE_UNINIT) { 2148231093Snp 2149252495Snp KASSERT(sc->flags & MASTER_PF, 2150252495Snp ("%s: trying to change chip settings when not master.", 2151252495Snp __func__)); 2152231093Snp 2153252495Snp rc = partition_resources(sc, default_cfg, fw_info->kld_name); 2154231093Snp if (rc != 0) 2155231093Snp goto done; /* error message displayed already */ 2156252495Snp 2157252495Snp t4_tweak_chip_settings(sc); 2158252495Snp 2159252495Snp /* get basic stuff going */ 2160252495Snp rc = -t4_fw_initialize(sc, sc->mbox); 2161252495Snp if (rc != 0) { 2162252495Snp device_printf(sc->dev, "fw init failed: %d.\n", rc); 2163252495Snp goto done; 2164252495Snp } 2165247434Snp } else { 2166252495Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "pf%d", pf); 2167252495Snp sc->cfcsum = 0; 2168231093Snp } 2169231093Snp 2170231093Snpdone: 2171247434Snp free(card_fw, M_CXGBE); 2172231093Snp if (fw != NULL) 2173231093Snp firmware_put(fw, FIRMWARE_UNLOAD); 2174231093Snp if (default_cfg != NULL) 2175231093Snp firmware_put(default_cfg, FIRMWARE_UNLOAD); 2176231093Snp 2177231093Snp return (rc); 2178218792Snp} 2179218792Snp 2180231093Snp#define FW_PARAM_DEV(param) \ 2181231093Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ 2182231093Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) 2183231093Snp#define FW_PARAM_PFVF(param) \ 2184231093Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ 2185231093Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)) 2186231093Snp 2187231093Snp/* 2188252495Snp * Partition chip resources for use between various PFs, VFs, etc. 2189231093Snp */ 2190218792Snpstatic int 2191252495Snppartition_resources(struct adapter *sc, const struct firmware *default_cfg, 2192252495Snp const char *name_prefix) 2193222551Snp{ 2194252495Snp const struct firmware *cfg = NULL; 2195252495Snp int rc = 0; 2196252495Snp struct fw_caps_config_cmd caps; 2197252495Snp uint32_t mtype, moff, finicsum, cfcsum; 2198222551Snp 2199252495Snp /* 2200252495Snp * Figure out what configuration file to use. Pick the default config 2201252495Snp * file for the card if the user hasn't specified one explicitly. 2202252495Snp */ 2203252495Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", t4_cfg_file); 2204252495Snp if (strncmp(t4_cfg_file, DEFAULT_CF, sizeof(t4_cfg_file)) == 0) { 2205252495Snp /* Card specific overrides go here. */ 2206252495Snp if (pci_get_device(sc->dev) == 0x440a) 2207252495Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), UWIRE_CF); 2208252495Snp if (is_fpga(sc)) 2209252495Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), FPGA_CF); 2210222551Snp } 2211222551Snp 2212252495Snp /* 2213252495Snp * We need to load another module if the profile is anything except 2214252495Snp * "default" or "flash". 2215252495Snp */ 2216252495Snp if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) != 0 && 2217252495Snp strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) { 2218252495Snp char s[32]; 2219252495Snp 2220252495Snp snprintf(s, sizeof(s), "%s_%s", name_prefix, sc->cfg_file); 2221252495Snp cfg = firmware_get(s); 2222252495Snp if (cfg == NULL) { 2223252495Snp if (default_cfg != NULL) { 2224252495Snp device_printf(sc->dev, 2225252495Snp "unable to load module \"%s\" for " 2226252495Snp "configuration profile \"%s\", will use " 2227252495Snp "the default config file instead.\n", 2228252495Snp s, sc->cfg_file); 2229252495Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), 2230252495Snp "%s", DEFAULT_CF); 2231252495Snp } else { 2232252495Snp device_printf(sc->dev, 2233252495Snp "unable to load module \"%s\" for " 2234252495Snp "configuration profile \"%s\", will use " 2235252495Snp "the config file on the card's flash " 2236252495Snp "instead.\n", s, sc->cfg_file); 2237252495Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), 2238252495Snp "%s", FLASH_CF); 2239252495Snp } 2240252495Snp } 2241231093Snp } 2242222551Snp 2243252495Snp if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) == 0 && 2244252495Snp default_cfg == NULL) { 2245231093Snp device_printf(sc->dev, 2246252495Snp "default config file not available, will use the config " 2247252495Snp "file on the card's flash instead.\n"); 2248252495Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", FLASH_CF); 2249231093Snp } 2250231093Snp 2251252495Snp if (strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) { 2252252495Snp u_int cflen, i, n; 2253252495Snp const uint32_t *cfdata; 2254252495Snp uint32_t param, val, addr, off, mw_base, mw_aperture; 2255231093Snp 2256252495Snp KASSERT(cfg != NULL || default_cfg != NULL, 2257252495Snp ("%s: no config to upload", __func__)); 2258231093Snp 2259252495Snp /* 2260252495Snp * Ask the firmware where it wants us to upload the config file. 2261252495Snp */ 2262252495Snp param = FW_PARAM_DEV(CF); 2263252495Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 2264252495Snp if (rc != 0) { 2265252495Snp /* No support for config file? Shouldn't happen. */ 2266252495Snp device_printf(sc->dev, 2267252495Snp "failed to query config file location: %d.\n", rc); 2268252495Snp goto done; 2269252495Snp } 2270252495Snp mtype = G_FW_PARAMS_PARAM_Y(val); 2271252495Snp moff = G_FW_PARAMS_PARAM_Z(val) << 16; 2272231093Snp 2273252495Snp /* 2274252495Snp * XXX: sheer laziness. We deliberately added 4 bytes of 2275252495Snp * useless stuffing/comments at the end of the config file so 2276252495Snp * it's ok to simply throw away the last remaining bytes when 2277252495Snp * the config file is not an exact multiple of 4. This also 2278252495Snp * helps with the validate_mt_off_len check. 2279252495Snp */ 2280252495Snp if (cfg != NULL) { 2281252495Snp cflen = cfg->datasize & ~3; 2282252495Snp cfdata = cfg->data; 2283252495Snp } else { 2284252495Snp cflen = default_cfg->datasize & ~3; 2285252495Snp cfdata = default_cfg->data; 2286252495Snp } 2287222551Snp 2288252495Snp if (cflen > FLASH_CFG_MAX_SIZE) { 2289252495Snp device_printf(sc->dev, 2290252495Snp "config file too long (%d, max allowed is %d). " 2291252495Snp "Will try to use the config on the card, if any.\n", 2292252495Snp cflen, FLASH_CFG_MAX_SIZE); 2293252495Snp goto use_config_on_flash; 2294252495Snp } 2295218792Snp 2296252495Snp rc = validate_mt_off_len(sc, mtype, moff, cflen, &addr); 2297252495Snp if (rc != 0) { 2298252495Snp device_printf(sc->dev, 2299252495Snp "%s: addr (%d/0x%x) or len %d is not valid: %d. " 2300252495Snp "Will try to use the config on the card, if any.\n", 2301252495Snp __func__, mtype, moff, cflen, rc); 2302252495Snp goto use_config_on_flash; 2303252495Snp } 2304252495Snp 2305252495Snp memwin_info(sc, 2, &mw_base, &mw_aperture); 2306252495Snp while (cflen) { 2307252495Snp off = position_memwin(sc, 2, addr); 2308252495Snp n = min(cflen, mw_aperture - off); 2309252495Snp for (i = 0; i < n; i += 4) 2310252495Snp t4_write_reg(sc, mw_base + off + i, *cfdata++); 2311252495Snp cflen -= n; 2312252495Snp addr += n; 2313252495Snp } 2314252495Snp } else { 2315252495Snpuse_config_on_flash: 2316265483Snp mtype = FW_MEMTYPE_FLASH; 2317252495Snp moff = t4_flash_cfg_addr(sc); 2318231093Snp } 2319231093Snp 2320231093Snp bzero(&caps, sizeof(caps)); 2321231093Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2322218792Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2323231093Snp caps.cfvalid_to_len16 = htobe32(F_FW_CAPS_CONFIG_CMD_CFVALID | 2324231093Snp V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) | 2325252495Snp V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(moff >> 16) | FW_LEN16(caps)); 2326231093Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 2327231093Snp if (rc != 0) { 2328231093Snp device_printf(sc->dev, 2329252495Snp "failed to pre-process config file: %d " 2330252495Snp "(mtype %d, moff 0x%x).\n", rc, mtype, moff); 2331252495Snp goto done; 2332231093Snp } 2333218792Snp 2334231093Snp finicsum = be32toh(caps.finicsum); 2335231093Snp cfcsum = be32toh(caps.cfcsum); 2336231093Snp if (finicsum != cfcsum) { 2337231093Snp device_printf(sc->dev, 2338231093Snp "WARNING: config file checksum mismatch: %08x %08x\n", 2339231093Snp finicsum, cfcsum); 2340231093Snp } 2341231093Snp sc->cfcsum = cfcsum; 2342218792Snp 2343231093Snp#define LIMIT_CAPS(x) do { \ 2344231093Snp caps.x &= htobe16(t4_##x##_allowed); \ 2345231093Snp} while (0) 2346231093Snp 2347231093Snp /* 2348231093Snp * Let the firmware know what features will (not) be used so it can tune 2349231093Snp * things accordingly. 2350231093Snp */ 2351231093Snp LIMIT_CAPS(linkcaps); 2352231093Snp LIMIT_CAPS(niccaps); 2353231093Snp LIMIT_CAPS(toecaps); 2354231093Snp LIMIT_CAPS(rdmacaps); 2355231093Snp LIMIT_CAPS(iscsicaps); 2356231093Snp LIMIT_CAPS(fcoecaps); 2357231093Snp#undef LIMIT_CAPS 2358231093Snp 2359231093Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2360218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE); 2361231093Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 2362231093Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), NULL); 2363231093Snp if (rc != 0) { 2364231093Snp device_printf(sc->dev, 2365231093Snp "failed to process config file: %d.\n", rc); 2366231093Snp } 2367252495Snpdone: 2368252495Snp if (cfg != NULL) 2369252495Snp firmware_put(cfg, FIRMWARE_UNLOAD); 2370252495Snp return (rc); 2371218792Snp} 2372218792Snp 2373231093Snp/* 2374252495Snp * Retrieve parameters that are needed (or nice to have) very early. 2375231093Snp */ 2376218792Snpstatic int 2377231093Snpget_params__pre_init(struct adapter *sc) 2378218792Snp{ 2379218792Snp int rc; 2380231093Snp uint32_t param[2], val[2]; 2381231093Snp struct fw_devlog_cmd cmd; 2382231093Snp struct devlog_params *dlog = &sc->params.devlog; 2383218792Snp 2384231093Snp param[0] = FW_PARAM_DEV(PORTVEC); 2385231093Snp param[1] = FW_PARAM_DEV(CCLK); 2386231093Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 2387218792Snp if (rc != 0) { 2388218792Snp device_printf(sc->dev, 2389231093Snp "failed to query parameters (pre_init): %d.\n", rc); 2390231093Snp return (rc); 2391218792Snp } 2392218792Snp 2393218792Snp sc->params.portvec = val[0]; 2394241467Snp sc->params.nports = bitcount32(val[0]); 2395231093Snp sc->params.vpd.cclk = val[1]; 2396218792Snp 2397231093Snp /* Read device log parameters. */ 2398231093Snp bzero(&cmd, sizeof(cmd)); 2399231093Snp cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) | 2400231093Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2401231093Snp cmd.retval_len16 = htobe32(FW_LEN16(cmd)); 2402231093Snp rc = -t4_wr_mbox(sc, sc->mbox, &cmd, sizeof(cmd), &cmd); 2403231093Snp if (rc != 0) { 2404231093Snp device_printf(sc->dev, 2405231093Snp "failed to get devlog parameters: %d.\n", rc); 2406231093Snp bzero(dlog, sizeof (*dlog)); 2407231093Snp rc = 0; /* devlog isn't critical for device operation */ 2408231093Snp } else { 2409231093Snp val[0] = be32toh(cmd.memtype_devlog_memaddr16_devlog); 2410231093Snp dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(val[0]); 2411231093Snp dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(val[0]) << 4; 2412231093Snp dlog->size = be32toh(cmd.memsize_devlog); 2413231093Snp } 2414231093Snp 2415231093Snp return (rc); 2416231093Snp} 2417231093Snp 2418231093Snp/* 2419231093Snp * Retrieve various parameters that are of interest to the driver. The device 2420231093Snp * has been initialized by the firmware at this point. 2421231093Snp */ 2422231093Snpstatic int 2423231093Snpget_params__post_init(struct adapter *sc) 2424231093Snp{ 2425231093Snp int rc; 2426231093Snp uint32_t param[7], val[7]; 2427231093Snp struct fw_caps_config_cmd caps; 2428231093Snp 2429231093Snp param[0] = FW_PARAM_PFVF(IQFLINT_START); 2430231093Snp param[1] = FW_PARAM_PFVF(EQ_START); 2431231093Snp param[2] = FW_PARAM_PFVF(FILTER_START); 2432231093Snp param[3] = FW_PARAM_PFVF(FILTER_END); 2433247434Snp param[4] = FW_PARAM_PFVF(L2T_START); 2434247434Snp param[5] = FW_PARAM_PFVF(L2T_END); 2435247434Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2436231093Snp if (rc != 0) { 2437231093Snp device_printf(sc->dev, 2438231093Snp "failed to query parameters (post_init): %d.\n", rc); 2439231093Snp return (rc); 2440231093Snp } 2441231093Snp 2442231093Snp sc->sge.iq_start = val[0]; 2443231093Snp sc->sge.eq_start = val[1]; 2444231093Snp sc->tids.ftid_base = val[2]; 2445231093Snp sc->tids.nftids = val[3] - val[2] + 1; 2446265553Snp sc->params.ftid_min = val[2]; 2447265553Snp sc->params.ftid_max = val[3]; 2448247434Snp sc->vres.l2t.start = val[4]; 2449247434Snp sc->vres.l2t.size = val[5] - val[4] + 1; 2450247434Snp KASSERT(sc->vres.l2t.size <= L2T_SIZE, 2451247434Snp ("%s: L2 table size (%u) larger than expected (%u)", 2452247434Snp __func__, sc->vres.l2t.size, L2T_SIZE)); 2453231093Snp 2454231093Snp /* get capabilites */ 2455231093Snp bzero(&caps, sizeof(caps)); 2456231093Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2457231093Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2458231093Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 2459231093Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 2460231093Snp if (rc != 0) { 2461231093Snp device_printf(sc->dev, 2462231093Snp "failed to get card capabilities: %d.\n", rc); 2463231093Snp return (rc); 2464231093Snp } 2465231093Snp 2466265553Snp#define READ_CAPS(x) do { \ 2467265553Snp sc->x = htobe16(caps.x); \ 2468265553Snp} while (0) 2469265553Snp READ_CAPS(linkcaps); 2470265553Snp READ_CAPS(niccaps); 2471265553Snp READ_CAPS(toecaps); 2472265553Snp READ_CAPS(rdmacaps); 2473265553Snp READ_CAPS(iscsicaps); 2474265553Snp READ_CAPS(fcoecaps); 2475265553Snp 2476265553Snp if (sc->niccaps & FW_CAPS_CONFIG_NIC_ETHOFLD) { 2477265553Snp param[0] = FW_PARAM_PFVF(ETHOFLD_START); 2478265553Snp param[1] = FW_PARAM_PFVF(ETHOFLD_END); 2479265553Snp param[2] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 2480265553Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 3, param, val); 2481265553Snp if (rc != 0) { 2482265553Snp device_printf(sc->dev, 2483265553Snp "failed to query NIC parameters: %d.\n", rc); 2484265553Snp return (rc); 2485265553Snp } 2486265553Snp sc->tids.etid_base = val[0]; 2487265553Snp sc->params.etid_min = val[0]; 2488265553Snp sc->tids.netids = val[1] - val[0] + 1; 2489265553Snp sc->params.netids = sc->tids.netids; 2490265553Snp sc->params.eo_wr_cred = val[2]; 2491265553Snp sc->params.ethoffload = 1; 2492265553Snp } 2493265553Snp 2494265553Snp if (sc->toecaps) { 2495218792Snp /* query offload-related parameters */ 2496231093Snp param[0] = FW_PARAM_DEV(NTID); 2497231093Snp param[1] = FW_PARAM_PFVF(SERVER_START); 2498231093Snp param[2] = FW_PARAM_PFVF(SERVER_END); 2499231093Snp param[3] = FW_PARAM_PFVF(TDDP_START); 2500231093Snp param[4] = FW_PARAM_PFVF(TDDP_END); 2501231093Snp param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 2502231093Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2503218792Snp if (rc != 0) { 2504218792Snp device_printf(sc->dev, 2505218792Snp "failed to query TOE parameters: %d.\n", rc); 2506231093Snp return (rc); 2507218792Snp } 2508218792Snp sc->tids.ntids = val[0]; 2509218792Snp sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS); 2510218792Snp sc->tids.stid_base = val[1]; 2511218792Snp sc->tids.nstids = val[2] - val[1] + 1; 2512218792Snp sc->vres.ddp.start = val[3]; 2513218792Snp sc->vres.ddp.size = val[4] - val[3] + 1; 2514218792Snp sc->params.ofldq_wr_cred = val[5]; 2515218792Snp sc->params.offload = 1; 2516218792Snp } 2517265553Snp if (sc->rdmacaps) { 2518231093Snp param[0] = FW_PARAM_PFVF(STAG_START); 2519231093Snp param[1] = FW_PARAM_PFVF(STAG_END); 2520231093Snp param[2] = FW_PARAM_PFVF(RQ_START); 2521231093Snp param[3] = FW_PARAM_PFVF(RQ_END); 2522231093Snp param[4] = FW_PARAM_PFVF(PBL_START); 2523231093Snp param[5] = FW_PARAM_PFVF(PBL_END); 2524231093Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2525218792Snp if (rc != 0) { 2526218792Snp device_printf(sc->dev, 2527231093Snp "failed to query RDMA parameters(1): %d.\n", rc); 2528231093Snp return (rc); 2529218792Snp } 2530218792Snp sc->vres.stag.start = val[0]; 2531218792Snp sc->vres.stag.size = val[1] - val[0] + 1; 2532218792Snp sc->vres.rq.start = val[2]; 2533218792Snp sc->vres.rq.size = val[3] - val[2] + 1; 2534218792Snp sc->vres.pbl.start = val[4]; 2535218792Snp sc->vres.pbl.size = val[5] - val[4] + 1; 2536231093Snp 2537231093Snp param[0] = FW_PARAM_PFVF(SQRQ_START); 2538231093Snp param[1] = FW_PARAM_PFVF(SQRQ_END); 2539231093Snp param[2] = FW_PARAM_PFVF(CQ_START); 2540231093Snp param[3] = FW_PARAM_PFVF(CQ_END); 2541231093Snp param[4] = FW_PARAM_PFVF(OCQ_START); 2542231093Snp param[5] = FW_PARAM_PFVF(OCQ_END); 2543265478Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2544231093Snp if (rc != 0) { 2545231093Snp device_printf(sc->dev, 2546231093Snp "failed to query RDMA parameters(2): %d.\n", rc); 2547231093Snp return (rc); 2548231093Snp } 2549231093Snp sc->vres.qp.start = val[0]; 2550231093Snp sc->vres.qp.size = val[1] - val[0] + 1; 2551231093Snp sc->vres.cq.start = val[2]; 2552231093Snp sc->vres.cq.size = val[3] - val[2] + 1; 2553231093Snp sc->vres.ocq.start = val[4]; 2554231093Snp sc->vres.ocq.size = val[5] - val[4] + 1; 2555218792Snp } 2556265553Snp if (sc->iscsicaps) { 2557231093Snp param[0] = FW_PARAM_PFVF(ISCSI_START); 2558231093Snp param[1] = FW_PARAM_PFVF(ISCSI_END); 2559231093Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 2560218792Snp if (rc != 0) { 2561218792Snp device_printf(sc->dev, 2562218792Snp "failed to query iSCSI parameters: %d.\n", rc); 2563231093Snp return (rc); 2564218792Snp } 2565218792Snp sc->vres.iscsi.start = val[0]; 2566218792Snp sc->vres.iscsi.size = val[1] - val[0] + 1; 2567218792Snp } 2568218792Snp 2569252495Snp /* 2570252495Snp * We've got the params we wanted to query via the firmware. Now grab 2571252495Snp * some others directly from the chip. 2572252495Snp */ 2573252495Snp rc = t4_read_chip_settings(sc); 2574231093Snp 2575218792Snp return (rc); 2576218792Snp} 2577218792Snp 2578247434Snpstatic int 2579247434Snpset_params__post_init(struct adapter *sc) 2580247434Snp{ 2581247434Snp uint32_t param, val; 2582247434Snp 2583252495Snp /* ask for encapsulated CPLs */ 2584247434Snp param = FW_PARAM_PFVF(CPLFW4MSG_ENCAP); 2585252495Snp val = 1; 2586252495Snp (void)t4_set_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 2587247434Snp 2588252495Snp return (0); 2589247434Snp} 2590247434Snp 2591231093Snp#undef FW_PARAM_PFVF 2592231093Snp#undef FW_PARAM_DEV 2593231093Snp 2594218792Snpstatic void 2595218792Snpt4_set_desc(struct adapter *sc) 2596218792Snp{ 2597218792Snp char buf[128]; 2598218792Snp struct adapter_params *p = &sc->params; 2599218792Snp 2600265478Snp snprintf(buf, sizeof(buf), "Chelsio %s %sNIC (rev %d), S/N:%s, " 2601265478Snp "P/N:%s, E/C:%s", p->vpd.id, is_offload(sc) ? "R" : "", 2602265478Snp chip_rev(sc), p->vpd.sn, p->vpd.pn, p->vpd.ec); 2603218792Snp 2604218792Snp device_set_desc_copy(sc->dev, buf); 2605218792Snp} 2606218792Snp 2607218792Snpstatic void 2608218792Snpbuild_medialist(struct port_info *pi) 2609218792Snp{ 2610218792Snp struct ifmedia *media = &pi->media; 2611218792Snp int data, m; 2612218792Snp 2613218792Snp PORT_LOCK(pi); 2614218792Snp 2615218792Snp ifmedia_removeall(media); 2616218792Snp 2617218792Snp m = IFM_ETHER | IFM_FDX; 2618218792Snp data = (pi->port_type << 8) | pi->mod_type; 2619218792Snp 2620218792Snp switch(pi->port_type) { 2621218792Snp case FW_PORT_TYPE_BT_XFI: 2622218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2623218792Snp break; 2624218792Snp 2625218792Snp case FW_PORT_TYPE_BT_XAUI: 2626218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2627218792Snp /* fall through */ 2628218792Snp 2629218792Snp case FW_PORT_TYPE_BT_SGMII: 2630218792Snp ifmedia_add(media, m | IFM_1000_T, data, NULL); 2631218792Snp ifmedia_add(media, m | IFM_100_TX, data, NULL); 2632218792Snp ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL); 2633218792Snp ifmedia_set(media, IFM_ETHER | IFM_AUTO); 2634218792Snp break; 2635218792Snp 2636218792Snp case FW_PORT_TYPE_CX4: 2637218792Snp ifmedia_add(media, m | IFM_10G_CX4, data, NULL); 2638218792Snp ifmedia_set(media, m | IFM_10G_CX4); 2639218792Snp break; 2640218792Snp 2641265582Snp case FW_PORT_TYPE_QSFP_10G: 2642218792Snp case FW_PORT_TYPE_SFP: 2643218792Snp case FW_PORT_TYPE_FIBER_XFI: 2644218792Snp case FW_PORT_TYPE_FIBER_XAUI: 2645218792Snp switch (pi->mod_type) { 2646218792Snp 2647218792Snp case FW_PORT_MOD_TYPE_LR: 2648218792Snp ifmedia_add(media, m | IFM_10G_LR, data, NULL); 2649218792Snp ifmedia_set(media, m | IFM_10G_LR); 2650218792Snp break; 2651218792Snp 2652218792Snp case FW_PORT_MOD_TYPE_SR: 2653218792Snp ifmedia_add(media, m | IFM_10G_SR, data, NULL); 2654218792Snp ifmedia_set(media, m | IFM_10G_SR); 2655218792Snp break; 2656218792Snp 2657218792Snp case FW_PORT_MOD_TYPE_LRM: 2658218792Snp ifmedia_add(media, m | IFM_10G_LRM, data, NULL); 2659218792Snp ifmedia_set(media, m | IFM_10G_LRM); 2660218792Snp break; 2661218792Snp 2662218792Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2663218792Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2664218792Snp ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL); 2665218792Snp ifmedia_set(media, m | IFM_10G_TWINAX); 2666218792Snp break; 2667218792Snp 2668218792Snp case FW_PORT_MOD_TYPE_NONE: 2669218792Snp m &= ~IFM_FDX; 2670218792Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2671218792Snp ifmedia_set(media, m | IFM_NONE); 2672218792Snp break; 2673218792Snp 2674218792Snp case FW_PORT_MOD_TYPE_NA: 2675218792Snp case FW_PORT_MOD_TYPE_ER: 2676218792Snp default: 2677252495Snp device_printf(pi->dev, 2678252495Snp "unknown port_type (%d), mod_type (%d)\n", 2679252495Snp pi->port_type, pi->mod_type); 2680218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2681218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2682218792Snp break; 2683218792Snp } 2684218792Snp break; 2685218792Snp 2686252495Snp case FW_PORT_TYPE_QSFP: 2687252495Snp switch (pi->mod_type) { 2688252495Snp 2689252495Snp case FW_PORT_MOD_TYPE_LR: 2690252495Snp ifmedia_add(media, m | IFM_40G_LR4, data, NULL); 2691252495Snp ifmedia_set(media, m | IFM_40G_LR4); 2692252495Snp break; 2693252495Snp 2694252495Snp case FW_PORT_MOD_TYPE_SR: 2695252495Snp ifmedia_add(media, m | IFM_40G_SR4, data, NULL); 2696252495Snp ifmedia_set(media, m | IFM_40G_SR4); 2697252495Snp break; 2698252495Snp 2699252495Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2700252495Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2701252495Snp ifmedia_add(media, m | IFM_40G_CR4, data, NULL); 2702252495Snp ifmedia_set(media, m | IFM_40G_CR4); 2703252495Snp break; 2704252495Snp 2705252495Snp case FW_PORT_MOD_TYPE_NONE: 2706252495Snp m &= ~IFM_FDX; 2707252495Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2708252495Snp ifmedia_set(media, m | IFM_NONE); 2709252495Snp break; 2710252495Snp 2711252495Snp default: 2712252495Snp device_printf(pi->dev, 2713252495Snp "unknown port_type (%d), mod_type (%d)\n", 2714252495Snp pi->port_type, pi->mod_type); 2715252495Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2716252495Snp ifmedia_set(media, m | IFM_UNKNOWN); 2717252495Snp break; 2718252495Snp } 2719252495Snp break; 2720252495Snp 2721218792Snp default: 2722252495Snp device_printf(pi->dev, 2723252495Snp "unknown port_type (%d), mod_type (%d)\n", pi->port_type, 2724252495Snp pi->mod_type); 2725218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2726218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2727218792Snp break; 2728218792Snp } 2729218792Snp 2730218792Snp PORT_UNLOCK(pi); 2731218792Snp} 2732218792Snp 2733231601Snp#define FW_MAC_EXACT_CHUNK 7 2734231601Snp 2735218792Snp/* 2736218792Snp * Program the port's XGMAC based on parameters in ifnet. The caller also 2737218792Snp * indicates which parameters should be programmed (the rest are left alone). 2738218792Snp */ 2739218792Snpstatic int 2740218792Snpupdate_mac_settings(struct port_info *pi, int flags) 2741218792Snp{ 2742218792Snp int rc; 2743218792Snp struct ifnet *ifp = pi->ifp; 2744218792Snp struct adapter *sc = pi->adapter; 2745218792Snp int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1; 2746218792Snp 2747247434Snp ASSERT_SYNCHRONIZED_OP(sc); 2748218792Snp KASSERT(flags, ("%s: not told what to update.", __func__)); 2749218792Snp 2750218792Snp if (flags & XGMAC_MTU) 2751218792Snp mtu = ifp->if_mtu; 2752218792Snp 2753218792Snp if (flags & XGMAC_PROMISC) 2754218792Snp promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0; 2755218792Snp 2756218792Snp if (flags & XGMAC_ALLMULTI) 2757218792Snp allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0; 2758218792Snp 2759218792Snp if (flags & XGMAC_VLANEX) 2760218792Snp vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0; 2761218792Snp 2762218792Snp rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, mtu, promisc, allmulti, 1, 2763218792Snp vlanex, false); 2764218792Snp if (rc) { 2765218792Snp if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, rc); 2766218792Snp return (rc); 2767218792Snp } 2768218792Snp 2769218792Snp if (flags & XGMAC_UCADDR) { 2770218792Snp uint8_t ucaddr[ETHER_ADDR_LEN]; 2771218792Snp 2772218792Snp bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr)); 2773218792Snp rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, 2774218792Snp ucaddr, true, true); 2775218792Snp if (rc < 0) { 2776218792Snp rc = -rc; 2777218792Snp if_printf(ifp, "change_mac failed: %d\n", rc); 2778218792Snp return (rc); 2779218792Snp } else { 2780218792Snp pi->xact_addr_filt = rc; 2781218792Snp rc = 0; 2782218792Snp } 2783218792Snp } 2784218792Snp 2785218792Snp if (flags & XGMAC_MCADDRS) { 2786231601Snp const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK]; 2787218792Snp int del = 1; 2788218792Snp uint64_t hash = 0; 2789218792Snp struct ifmultiaddr *ifma; 2790231601Snp int i = 0, j; 2791218792Snp 2792218792Snp if_maddr_rlock(ifp); 2793218792Snp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2794238057Snp if (ifma->ifma_addr->sa_family != AF_LINK) 2795218792Snp continue; 2796231601Snp mcaddr[i++] = 2797231601Snp LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 2798218792Snp 2799231601Snp if (i == FW_MAC_EXACT_CHUNK) { 2800231601Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2801231601Snp del, i, mcaddr, NULL, &hash, 0); 2802231601Snp if (rc < 0) { 2803231601Snp rc = -rc; 2804231601Snp for (j = 0; j < i; j++) { 2805231601Snp if_printf(ifp, 2806231601Snp "failed to add mc address" 2807231601Snp " %02x:%02x:%02x:" 2808231601Snp "%02x:%02x:%02x rc=%d\n", 2809231601Snp mcaddr[j][0], mcaddr[j][1], 2810231601Snp mcaddr[j][2], mcaddr[j][3], 2811231601Snp mcaddr[j][4], mcaddr[j][5], 2812231601Snp rc); 2813231601Snp } 2814231601Snp goto mcfail; 2815231601Snp } 2816231601Snp del = 0; 2817231601Snp i = 0; 2818231601Snp } 2819231601Snp } 2820231601Snp if (i > 0) { 2821231601Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2822231601Snp del, i, mcaddr, NULL, &hash, 0); 2823218792Snp if (rc < 0) { 2824218792Snp rc = -rc; 2825231601Snp for (j = 0; j < i; j++) { 2826231601Snp if_printf(ifp, 2827231601Snp "failed to add mc address" 2828231601Snp " %02x:%02x:%02x:" 2829231601Snp "%02x:%02x:%02x rc=%d\n", 2830231601Snp mcaddr[j][0], mcaddr[j][1], 2831231601Snp mcaddr[j][2], mcaddr[j][3], 2832231601Snp mcaddr[j][4], mcaddr[j][5], 2833231601Snp rc); 2834231601Snp } 2835218792Snp goto mcfail; 2836218792Snp } 2837218792Snp } 2838218792Snp 2839218792Snp rc = -t4_set_addr_hash(sc, sc->mbox, pi->viid, 0, hash, 0); 2840218792Snp if (rc != 0) 2841218792Snp if_printf(ifp, "failed to set mc address hash: %d", rc); 2842218792Snpmcfail: 2843218792Snp if_maddr_runlock(ifp); 2844218792Snp } 2845218792Snp 2846218792Snp return (rc); 2847218792Snp} 2848218792Snp 2849247434Snpint 2850247434Snpbegin_synchronized_op(struct adapter *sc, struct port_info *pi, int flags, 2851247434Snp char *wmesg) 2852218792Snp{ 2853247434Snp int rc, pri; 2854218792Snp 2855247434Snp#ifdef WITNESS 2856247434Snp /* the caller thinks it's ok to sleep, but is it really? */ 2857247434Snp if (flags & SLEEP_OK) 2858247434Snp pause("t4slptst", 1); 2859247434Snp#endif 2860218792Snp 2861247434Snp if (INTR_OK) 2862247434Snp pri = PCATCH; 2863247434Snp else 2864247434Snp pri = 0; 2865247434Snp 2866247434Snp ADAPTER_LOCK(sc); 2867247434Snp for (;;) { 2868247434Snp 2869247434Snp if (pi && IS_DOOMED(pi)) { 2870247434Snp rc = ENXIO; 2871247434Snp goto done; 2872247434Snp } 2873247434Snp 2874247434Snp if (!IS_BUSY(sc)) { 2875247434Snp rc = 0; 2876247434Snp break; 2877247434Snp } 2878247434Snp 2879247434Snp if (!(flags & SLEEP_OK)) { 2880247434Snp rc = EBUSY; 2881247434Snp goto done; 2882247434Snp } 2883247434Snp 2884247434Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, pri, wmesg, 0)) { 2885218792Snp rc = EINTR; 2886218792Snp goto done; 2887218792Snp } 2888218792Snp } 2889247434Snp 2890218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 2891218792Snp SET_BUSY(sc); 2892247434Snp#ifdef INVARIANTS 2893247434Snp sc->last_op = wmesg; 2894247434Snp sc->last_op_thr = curthread; 2895247434Snp#endif 2896218792Snp 2897247434Snpdone: 2898247434Snp if (!(flags & HOLD_LOCK) || rc) 2899247434Snp ADAPTER_UNLOCK(sc); 2900218792Snp 2901247434Snp return (rc); 2902247434Snp} 2903247434Snp 2904247434Snpvoid 2905247434Snpend_synchronized_op(struct adapter *sc, int flags) 2906247434Snp{ 2907247434Snp 2908247434Snp if (flags & LOCK_HELD) 2909247434Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 2910247434Snp else 2911247434Snp ADAPTER_LOCK(sc); 2912247434Snp 2913218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 2914218792Snp CLR_BUSY(sc); 2915247434Snp wakeup(&sc->flags); 2916218792Snp ADAPTER_UNLOCK(sc); 2917218792Snp} 2918218792Snp 2919218792Snpstatic int 2920218792Snpcxgbe_init_synchronized(struct port_info *pi) 2921218792Snp{ 2922218792Snp struct adapter *sc = pi->adapter; 2923218792Snp struct ifnet *ifp = pi->ifp; 2924231093Snp int rc = 0; 2925218792Snp 2926247434Snp ASSERT_SYNCHRONIZED_OP(sc); 2927218792Snp 2928218792Snp if (isset(&sc->open_device_map, pi->port_id)) { 2929218792Snp KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, 2930218792Snp ("mismatch between open_device_map and if_drv_flags")); 2931218792Snp return (0); /* already running */ 2932218792Snp } 2933218792Snp 2934231093Snp if (!(sc->flags & FULL_INIT_DONE) && 2935231093Snp ((rc = adapter_full_init(sc)) != 0)) 2936218792Snp return (rc); /* error message displayed already */ 2937218792Snp 2938231093Snp if (!(pi->flags & PORT_INIT_DONE) && 2939231093Snp ((rc = port_full_init(pi)) != 0)) 2940231093Snp return (rc); /* error message displayed already */ 2941218792Snp 2942218792Snp rc = update_mac_settings(pi, XGMAC_ALL); 2943218792Snp if (rc) 2944218792Snp goto done; /* error message displayed already */ 2945218792Snp 2946218792Snp rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg); 2947218792Snp if (rc != 0) { 2948218792Snp if_printf(ifp, "start_link failed: %d\n", rc); 2949218792Snp goto done; 2950218792Snp } 2951218792Snp 2952218792Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true); 2953218792Snp if (rc != 0) { 2954218792Snp if_printf(ifp, "enable_vi failed: %d\n", rc); 2955218792Snp goto done; 2956218792Snp } 2957218792Snp 2958218792Snp /* all ok */ 2959218792Snp setbit(&sc->open_device_map, pi->port_id); 2960247434Snp PORT_LOCK(pi); 2961218792Snp ifp->if_drv_flags |= IFF_DRV_RUNNING; 2962247434Snp PORT_UNLOCK(pi); 2963218792Snp 2964218792Snp callout_reset(&pi->tick, hz, cxgbe_tick, pi); 2965218792Snpdone: 2966218792Snp if (rc != 0) 2967218792Snp cxgbe_uninit_synchronized(pi); 2968218792Snp 2969218792Snp return (rc); 2970218792Snp} 2971218792Snp 2972218792Snp/* 2973218792Snp * Idempotent. 2974218792Snp */ 2975218792Snpstatic int 2976218792Snpcxgbe_uninit_synchronized(struct port_info *pi) 2977218792Snp{ 2978218792Snp struct adapter *sc = pi->adapter; 2979218792Snp struct ifnet *ifp = pi->ifp; 2980218792Snp int rc; 2981218792Snp 2982247434Snp ASSERT_SYNCHRONIZED_OP(sc); 2983218792Snp 2984218792Snp /* 2985231093Snp * Disable the VI so that all its data in either direction is discarded 2986231093Snp * by the MPS. Leave everything else (the queues, interrupts, and 1Hz 2987231093Snp * tick) intact as the TP can deliver negative advice or data that it's 2988231093Snp * holding in its RAM (for an offloaded connection) even after the VI is 2989231093Snp * disabled. 2990218792Snp */ 2991231093Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false); 2992231093Snp if (rc) { 2993231093Snp if_printf(ifp, "disable_vi failed: %d\n", rc); 2994231093Snp return (rc); 2995231093Snp } 2996231093Snp 2997218792Snp clrbit(&sc->open_device_map, pi->port_id); 2998247434Snp PORT_LOCK(pi); 2999231093Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 3000247434Snp PORT_UNLOCK(pi); 3001218792Snp 3002218792Snp pi->link_cfg.link_ok = 0; 3003218792Snp pi->link_cfg.speed = 0; 3004252814Snp pi->linkdnrc = -1; 3005252814Snp t4_os_link_changed(sc, pi->port_id, 0, -1); 3006218792Snp 3007218792Snp return (0); 3008218792Snp} 3009218792Snp 3010241467Snp/* 3011241467Snp * It is ok for this function to fail midway and return right away. t4_detach 3012241467Snp * will walk the entire sc->irq list and clean up whatever is valid. 3013241467Snp */ 3014218792Snpstatic int 3015241467Snpsetup_intr_handlers(struct adapter *sc) 3016218792Snp{ 3017241467Snp int rc, rid, p, q; 3018222510Snp char s[8]; 3019222510Snp struct irq *irq; 3020231093Snp struct port_info *pi; 3021231093Snp struct sge_rxq *rxq; 3022237920Snp#ifdef TCP_OFFLOAD 3023231093Snp struct sge_ofld_rxq *ofld_rxq; 3024231093Snp#endif 3025218792Snp 3026218792Snp /* 3027218792Snp * Setup interrupts. 3028218792Snp */ 3029222510Snp irq = &sc->irq[0]; 3030222510Snp rid = sc->intr_type == INTR_INTX ? 0 : 1; 3031218792Snp if (sc->intr_count == 1) { 3032231093Snp KASSERT(!(sc->flags & INTR_DIRECT), 3033231093Snp ("%s: single interrupt && INTR_DIRECT?", __func__)); 3034222510Snp 3035241467Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_all, sc, "all"); 3036241467Snp if (rc != 0) 3037241467Snp return (rc); 3038218792Snp } else { 3039231093Snp /* Multiple interrupts. */ 3040231093Snp KASSERT(sc->intr_count >= T4_EXTRA_INTR + sc->params.nports, 3041231093Snp ("%s: too few intr.", __func__)); 3042231093Snp 3043231093Snp /* The first one is always error intr */ 3044241467Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_err, sc, "err"); 3045241467Snp if (rc != 0) 3046241467Snp return (rc); 3047222510Snp irq++; 3048222510Snp rid++; 3049218792Snp 3050231093Snp /* The second one is always the firmware event queue */ 3051241467Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_evt, &sc->sge.fwq, 3052241467Snp "evt"); 3053241467Snp if (rc != 0) 3054241467Snp return (rc); 3055231093Snp irq++; 3056231093Snp rid++; 3057222510Snp 3058231093Snp /* 3059231093Snp * Note that if INTR_DIRECT is not set then either the NIC rx 3060231093Snp * queues or (exclusive or) the TOE rx queueus will be taking 3061231093Snp * direct interrupts. 3062231093Snp * 3063231093Snp * There is no need to check for is_offload(sc) as nofldrxq 3064231093Snp * will be 0 if offload is disabled. 3065231093Snp */ 3066231093Snp for_each_port(sc, p) { 3067231093Snp pi = sc->port[p]; 3068222510Snp 3069237920Snp#ifdef TCP_OFFLOAD 3070231093Snp /* 3071231093Snp * Skip over the NIC queues if they aren't taking direct 3072231093Snp * interrupts. 3073231093Snp */ 3074231093Snp if (!(sc->flags & INTR_DIRECT) && 3075231093Snp pi->nofldrxq > pi->nrxq) 3076231093Snp goto ofld_queues; 3077231093Snp#endif 3078231093Snp rxq = &sc->sge.rxq[pi->first_rxq]; 3079231093Snp for (q = 0; q < pi->nrxq; q++, rxq++) { 3080231093Snp snprintf(s, sizeof(s), "%d.%d", p, q); 3081241467Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, rxq, 3082241467Snp s); 3083241467Snp if (rc != 0) 3084241467Snp return (rc); 3085222510Snp irq++; 3086222510Snp rid++; 3087218792Snp } 3088218792Snp 3089237920Snp#ifdef TCP_OFFLOAD 3090231093Snp /* 3091231093Snp * Skip over the offload queues if they aren't taking 3092231093Snp * direct interrupts. 3093231093Snp */ 3094231093Snp if (!(sc->flags & INTR_DIRECT)) 3095231093Snp continue; 3096231093Snpofld_queues: 3097231093Snp ofld_rxq = &sc->sge.ofld_rxq[pi->first_ofld_rxq]; 3098231093Snp for (q = 0; q < pi->nofldrxq; q++, ofld_rxq++) { 3099231093Snp snprintf(s, sizeof(s), "%d,%d", p, q); 3100241467Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, 3101241467Snp ofld_rxq, s); 3102241467Snp if (rc != 0) 3103241467Snp return (rc); 3104231093Snp irq++; 3105231093Snp rid++; 3106218792Snp } 3107231093Snp#endif 3108218792Snp } 3109218792Snp } 3110218792Snp 3111241467Snp return (0); 3112241467Snp} 3113241467Snp 3114241467Snpstatic int 3115241467Snpadapter_full_init(struct adapter *sc) 3116241467Snp{ 3117241467Snp int rc, i; 3118241467Snp 3119241467Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 3120241467Snp KASSERT((sc->flags & FULL_INIT_DONE) == 0, 3121241467Snp ("%s: FULL_INIT_DONE already", __func__)); 3122241467Snp 3123241467Snp /* 3124241467Snp * queues that belong to the adapter (not any particular port). 3125241467Snp */ 3126241467Snp rc = t4_setup_adapter_queues(sc); 3127241467Snp if (rc != 0) 3128241467Snp goto done; 3129241467Snp 3130241467Snp for (i = 0; i < nitems(sc->tq); i++) { 3131241467Snp sc->tq[i] = taskqueue_create("t4 taskq", M_NOWAIT, 3132241467Snp taskqueue_thread_enqueue, &sc->tq[i]); 3133241467Snp if (sc->tq[i] == NULL) { 3134241467Snp device_printf(sc->dev, 3135241467Snp "failed to allocate task queue %d\n", i); 3136241467Snp rc = ENOMEM; 3137241467Snp goto done; 3138241467Snp } 3139241467Snp taskqueue_start_threads(&sc->tq[i], 1, PI_NET, "%s tq%d", 3140241467Snp device_get_nameunit(sc->dev), i); 3141241467Snp } 3142241467Snp 3143218792Snp t4_intr_enable(sc); 3144218792Snp sc->flags |= FULL_INIT_DONE; 3145218792Snpdone: 3146218792Snp if (rc != 0) 3147231093Snp adapter_full_uninit(sc); 3148218792Snp 3149218792Snp return (rc); 3150218792Snp} 3151218792Snp 3152218792Snpstatic int 3153231093Snpadapter_full_uninit(struct adapter *sc) 3154218792Snp{ 3155218792Snp int i; 3156218792Snp 3157218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 3158218792Snp 3159220873Snp t4_teardown_adapter_queues(sc); 3160218792Snp 3161241467Snp for (i = 0; i < nitems(sc->tq) && sc->tq[i]; i++) { 3162231093Snp taskqueue_free(sc->tq[i]); 3163231093Snp sc->tq[i] = NULL; 3164231093Snp } 3165231093Snp 3166218792Snp sc->flags &= ~FULL_INIT_DONE; 3167218792Snp 3168218792Snp return (0); 3169218792Snp} 3170218792Snp 3171218792Snpstatic int 3172231093Snpport_full_init(struct port_info *pi) 3173231093Snp{ 3174231093Snp struct adapter *sc = pi->adapter; 3175231093Snp struct ifnet *ifp = pi->ifp; 3176231093Snp uint16_t *rss; 3177231093Snp struct sge_rxq *rxq; 3178265553Snp int rc, i, j; 3179231093Snp 3180247434Snp ASSERT_SYNCHRONIZED_OP(sc); 3181231093Snp KASSERT((pi->flags & PORT_INIT_DONE) == 0, 3182231093Snp ("%s: PORT_INIT_DONE already", __func__)); 3183231093Snp 3184231093Snp sysctl_ctx_init(&pi->ctx); 3185231093Snp pi->flags |= PORT_SYSCTL_CTX; 3186231093Snp 3187231093Snp /* 3188231093Snp * Allocate tx/rx/fl queues for this port. 3189231093Snp */ 3190231093Snp rc = t4_setup_port_queues(pi); 3191231093Snp if (rc != 0) 3192231093Snp goto done; /* error message displayed already */ 3193231093Snp 3194231093Snp /* 3195265553Snp * Setup RSS for this port. Save a copy of the RSS table for later use. 3196231093Snp */ 3197265553Snp rss = malloc(pi->rss_size * sizeof (*rss), M_CXGBE, M_ZERO | M_WAITOK); 3198265553Snp for (i = 0; i < pi->rss_size;) { 3199265553Snp for_each_rxq(pi, j, rxq) { 3200265553Snp rss[i++] = rxq->iq.abs_id; 3201265553Snp if (i == pi->rss_size) 3202265553Snp break; 3203265553Snp } 3204231093Snp } 3205265553Snp 3206265553Snp rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, pi->rss_size, rss, 3207265553Snp pi->rss_size); 3208231093Snp if (rc != 0) { 3209231093Snp if_printf(ifp, "rss_config failed: %d\n", rc); 3210231093Snp goto done; 3211231093Snp } 3212231093Snp 3213265553Snp pi->rss = rss; 3214231093Snp pi->flags |= PORT_INIT_DONE; 3215231093Snpdone: 3216231093Snp if (rc != 0) 3217231093Snp port_full_uninit(pi); 3218231093Snp 3219231093Snp return (rc); 3220231093Snp} 3221231093Snp 3222231093Snp/* 3223231093Snp * Idempotent. 3224231093Snp */ 3225231093Snpstatic int 3226231093Snpport_full_uninit(struct port_info *pi) 3227231093Snp{ 3228231093Snp struct adapter *sc = pi->adapter; 3229231093Snp int i; 3230231093Snp struct sge_rxq *rxq; 3231231093Snp struct sge_txq *txq; 3232237920Snp#ifdef TCP_OFFLOAD 3233231093Snp struct sge_ofld_rxq *ofld_rxq; 3234231093Snp struct sge_wrq *ofld_txq; 3235231093Snp#endif 3236231093Snp 3237231093Snp if (pi->flags & PORT_INIT_DONE) { 3238231093Snp 3239231093Snp /* Need to quiesce queues. XXX: ctrl queues? */ 3240231093Snp 3241231093Snp for_each_txq(pi, i, txq) { 3242231093Snp quiesce_eq(sc, &txq->eq); 3243231093Snp } 3244231093Snp 3245237920Snp#ifdef TCP_OFFLOAD 3246231093Snp for_each_ofld_txq(pi, i, ofld_txq) { 3247231093Snp quiesce_eq(sc, &ofld_txq->eq); 3248231093Snp } 3249231093Snp#endif 3250231093Snp 3251231093Snp for_each_rxq(pi, i, rxq) { 3252231093Snp quiesce_iq(sc, &rxq->iq); 3253231093Snp quiesce_fl(sc, &rxq->fl); 3254231093Snp } 3255231093Snp 3256237920Snp#ifdef TCP_OFFLOAD 3257231093Snp for_each_ofld_rxq(pi, i, ofld_rxq) { 3258231093Snp quiesce_iq(sc, &ofld_rxq->iq); 3259231093Snp quiesce_fl(sc, &ofld_rxq->fl); 3260231093Snp } 3261231093Snp#endif 3262265553Snp free(pi->rss, M_CXGBE); 3263231093Snp } 3264231093Snp 3265231093Snp t4_teardown_port_queues(pi); 3266231093Snp pi->flags &= ~PORT_INIT_DONE; 3267231093Snp 3268231093Snp return (0); 3269231093Snp} 3270231093Snp 3271231093Snpstatic void 3272231093Snpquiesce_eq(struct adapter *sc, struct sge_eq *eq) 3273231093Snp{ 3274231093Snp EQ_LOCK(eq); 3275231093Snp eq->flags |= EQ_DOOMED; 3276231093Snp 3277231093Snp /* 3278231093Snp * Wait for the response to a credit flush if one's 3279231093Snp * pending. 3280231093Snp */ 3281231093Snp while (eq->flags & EQ_CRFLUSHED) 3282231093Snp mtx_sleep(eq, &eq->eq_lock, 0, "crflush", 0); 3283231093Snp EQ_UNLOCK(eq); 3284231093Snp 3285231093Snp callout_drain(&eq->tx_callout); /* XXX: iffy */ 3286231093Snp pause("callout", 10); /* Still iffy */ 3287231093Snp 3288231093Snp taskqueue_drain(sc->tq[eq->tx_chan], &eq->tx_task); 3289231093Snp} 3290231093Snp 3291231093Snpstatic void 3292231093Snpquiesce_iq(struct adapter *sc, struct sge_iq *iq) 3293231093Snp{ 3294231093Snp (void) sc; /* unused */ 3295231093Snp 3296231093Snp /* Synchronize with the interrupt handler */ 3297231093Snp while (!atomic_cmpset_int(&iq->state, IQS_IDLE, IQS_DISABLED)) 3298231093Snp pause("iqfree", 1); 3299231093Snp} 3300231093Snp 3301231093Snpstatic void 3302231093Snpquiesce_fl(struct adapter *sc, struct sge_fl *fl) 3303231093Snp{ 3304231093Snp mtx_lock(&sc->sfl_lock); 3305231093Snp FL_LOCK(fl); 3306231093Snp fl->flags |= FL_DOOMED; 3307231093Snp FL_UNLOCK(fl); 3308231093Snp mtx_unlock(&sc->sfl_lock); 3309231093Snp 3310231093Snp callout_drain(&sc->sfl_callout); 3311231093Snp KASSERT((fl->flags & FL_STARVING) == 0, 3312231093Snp ("%s: still starving", __func__)); 3313231093Snp} 3314231093Snp 3315231093Snpstatic int 3316218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid, 3317231093Snp driver_intr_t *handler, void *arg, char *name) 3318218792Snp{ 3319218792Snp int rc; 3320218792Snp 3321218792Snp irq->rid = rid; 3322218792Snp irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid, 3323218792Snp RF_SHAREABLE | RF_ACTIVE); 3324218792Snp if (irq->res == NULL) { 3325218792Snp device_printf(sc->dev, 3326218792Snp "failed to allocate IRQ for rid %d, name %s.\n", rid, name); 3327218792Snp return (ENOMEM); 3328218792Snp } 3329218792Snp 3330218792Snp rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET, 3331218792Snp NULL, handler, arg, &irq->tag); 3332218792Snp if (rc != 0) { 3333218792Snp device_printf(sc->dev, 3334218792Snp "failed to setup interrupt for rid %d, name %s: %d\n", 3335218792Snp rid, name, rc); 3336218792Snp } else if (name) 3337218792Snp bus_describe_intr(sc->dev, irq->res, irq->tag, name); 3338218792Snp 3339218792Snp return (rc); 3340218792Snp} 3341218792Snp 3342218792Snpstatic int 3343218792Snpt4_free_irq(struct adapter *sc, struct irq *irq) 3344218792Snp{ 3345218792Snp if (irq->tag) 3346218792Snp bus_teardown_intr(sc->dev, irq->res, irq->tag); 3347218792Snp if (irq->res) 3348218792Snp bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res); 3349218792Snp 3350218792Snp bzero(irq, sizeof(*irq)); 3351218792Snp 3352218792Snp return (0); 3353218792Snp} 3354218792Snp 3355218792Snpstatic void 3356218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start, 3357218792Snp unsigned int end) 3358218792Snp{ 3359218792Snp uint32_t *p = (uint32_t *)(buf + start); 3360218792Snp 3361218792Snp for ( ; start <= end; start += sizeof(uint32_t)) 3362218792Snp *p++ = t4_read_reg(sc, start); 3363218792Snp} 3364218792Snp 3365218792Snpstatic void 3366218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf) 3367218792Snp{ 3368252495Snp int i, n; 3369252495Snp const unsigned int *reg_ranges; 3370252495Snp static const unsigned int t4_reg_ranges[] = { 3371218792Snp 0x1008, 0x1108, 3372218792Snp 0x1180, 0x11b4, 3373218792Snp 0x11fc, 0x123c, 3374218792Snp 0x1300, 0x173c, 3375218792Snp 0x1800, 0x18fc, 3376218792Snp 0x3000, 0x30d8, 3377218792Snp 0x30e0, 0x5924, 3378218792Snp 0x5960, 0x59d4, 3379218792Snp 0x5a00, 0x5af8, 3380218792Snp 0x6000, 0x6098, 3381218792Snp 0x6100, 0x6150, 3382218792Snp 0x6200, 0x6208, 3383218792Snp 0x6240, 0x6248, 3384218792Snp 0x6280, 0x6338, 3385218792Snp 0x6370, 0x638c, 3386218792Snp 0x6400, 0x643c, 3387218792Snp 0x6500, 0x6524, 3388218792Snp 0x6a00, 0x6a38, 3389218792Snp 0x6a60, 0x6a78, 3390218792Snp 0x6b00, 0x6b84, 3391218792Snp 0x6bf0, 0x6c84, 3392218792Snp 0x6cf0, 0x6d84, 3393218792Snp 0x6df0, 0x6e84, 3394218792Snp 0x6ef0, 0x6f84, 3395218792Snp 0x6ff0, 0x7084, 3396218792Snp 0x70f0, 0x7184, 3397218792Snp 0x71f0, 0x7284, 3398218792Snp 0x72f0, 0x7384, 3399218792Snp 0x73f0, 0x7450, 3400218792Snp 0x7500, 0x7530, 3401218792Snp 0x7600, 0x761c, 3402218792Snp 0x7680, 0x76cc, 3403218792Snp 0x7700, 0x7798, 3404218792Snp 0x77c0, 0x77fc, 3405218792Snp 0x7900, 0x79fc, 3406218792Snp 0x7b00, 0x7c38, 3407218792Snp 0x7d00, 0x7efc, 3408218792Snp 0x8dc0, 0x8e1c, 3409218792Snp 0x8e30, 0x8e78, 3410218792Snp 0x8ea0, 0x8f6c, 3411218792Snp 0x8fc0, 0x9074, 3412218792Snp 0x90fc, 0x90fc, 3413218792Snp 0x9400, 0x9458, 3414218792Snp 0x9600, 0x96bc, 3415218792Snp 0x9800, 0x9808, 3416218792Snp 0x9820, 0x983c, 3417218792Snp 0x9850, 0x9864, 3418218792Snp 0x9c00, 0x9c6c, 3419218792Snp 0x9c80, 0x9cec, 3420218792Snp 0x9d00, 0x9d6c, 3421218792Snp 0x9d80, 0x9dec, 3422218792Snp 0x9e00, 0x9e6c, 3423218792Snp 0x9e80, 0x9eec, 3424218792Snp 0x9f00, 0x9f6c, 3425218792Snp 0x9f80, 0x9fec, 3426218792Snp 0xd004, 0xd03c, 3427218792Snp 0xdfc0, 0xdfe0, 3428218792Snp 0xe000, 0xea7c, 3429265549Snp 0xf000, 0x11110, 3430265549Snp 0x11118, 0x11190, 3431237925Snp 0x19040, 0x1906c, 3432237925Snp 0x19078, 0x19080, 3433237925Snp 0x1908c, 0x19124, 3434218792Snp 0x19150, 0x191b0, 3435218792Snp 0x191d0, 0x191e8, 3436218792Snp 0x19238, 0x1924c, 3437218792Snp 0x193f8, 0x19474, 3438218792Snp 0x19490, 0x194f8, 3439218792Snp 0x19800, 0x19f30, 3440218792Snp 0x1a000, 0x1a06c, 3441218792Snp 0x1a0b0, 0x1a120, 3442218792Snp 0x1a128, 0x1a138, 3443218792Snp 0x1a190, 0x1a1c4, 3444218792Snp 0x1a1fc, 0x1a1fc, 3445218792Snp 0x1e040, 0x1e04c, 3446237925Snp 0x1e284, 0x1e28c, 3447218792Snp 0x1e2c0, 0x1e2c0, 3448218792Snp 0x1e2e0, 0x1e2e0, 3449218792Snp 0x1e300, 0x1e384, 3450218792Snp 0x1e3c0, 0x1e3c8, 3451218792Snp 0x1e440, 0x1e44c, 3452237925Snp 0x1e684, 0x1e68c, 3453218792Snp 0x1e6c0, 0x1e6c0, 3454218792Snp 0x1e6e0, 0x1e6e0, 3455218792Snp 0x1e700, 0x1e784, 3456218792Snp 0x1e7c0, 0x1e7c8, 3457218792Snp 0x1e840, 0x1e84c, 3458237925Snp 0x1ea84, 0x1ea8c, 3459218792Snp 0x1eac0, 0x1eac0, 3460218792Snp 0x1eae0, 0x1eae0, 3461218792Snp 0x1eb00, 0x1eb84, 3462218792Snp 0x1ebc0, 0x1ebc8, 3463218792Snp 0x1ec40, 0x1ec4c, 3464237925Snp 0x1ee84, 0x1ee8c, 3465218792Snp 0x1eec0, 0x1eec0, 3466218792Snp 0x1eee0, 0x1eee0, 3467218792Snp 0x1ef00, 0x1ef84, 3468218792Snp 0x1efc0, 0x1efc8, 3469218792Snp 0x1f040, 0x1f04c, 3470237925Snp 0x1f284, 0x1f28c, 3471218792Snp 0x1f2c0, 0x1f2c0, 3472218792Snp 0x1f2e0, 0x1f2e0, 3473218792Snp 0x1f300, 0x1f384, 3474218792Snp 0x1f3c0, 0x1f3c8, 3475218792Snp 0x1f440, 0x1f44c, 3476237925Snp 0x1f684, 0x1f68c, 3477218792Snp 0x1f6c0, 0x1f6c0, 3478218792Snp 0x1f6e0, 0x1f6e0, 3479218792Snp 0x1f700, 0x1f784, 3480218792Snp 0x1f7c0, 0x1f7c8, 3481218792Snp 0x1f840, 0x1f84c, 3482237925Snp 0x1fa84, 0x1fa8c, 3483218792Snp 0x1fac0, 0x1fac0, 3484218792Snp 0x1fae0, 0x1fae0, 3485218792Snp 0x1fb00, 0x1fb84, 3486218792Snp 0x1fbc0, 0x1fbc8, 3487218792Snp 0x1fc40, 0x1fc4c, 3488237925Snp 0x1fe84, 0x1fe8c, 3489218792Snp 0x1fec0, 0x1fec0, 3490218792Snp 0x1fee0, 0x1fee0, 3491218792Snp 0x1ff00, 0x1ff84, 3492218792Snp 0x1ffc0, 0x1ffc8, 3493218792Snp 0x20000, 0x2002c, 3494218792Snp 0x20100, 0x2013c, 3495218792Snp 0x20190, 0x201c8, 3496218792Snp 0x20200, 0x20318, 3497218792Snp 0x20400, 0x20528, 3498218792Snp 0x20540, 0x20614, 3499218792Snp 0x21000, 0x21040, 3500218792Snp 0x2104c, 0x21060, 3501218792Snp 0x210c0, 0x210ec, 3502218792Snp 0x21200, 0x21268, 3503218792Snp 0x21270, 0x21284, 3504218792Snp 0x212fc, 0x21388, 3505218792Snp 0x21400, 0x21404, 3506218792Snp 0x21500, 0x21518, 3507218792Snp 0x2152c, 0x2153c, 3508218792Snp 0x21550, 0x21554, 3509218792Snp 0x21600, 0x21600, 3510218792Snp 0x21608, 0x21628, 3511218792Snp 0x21630, 0x2163c, 3512218792Snp 0x21700, 0x2171c, 3513218792Snp 0x21780, 0x2178c, 3514218792Snp 0x21800, 0x21c38, 3515218792Snp 0x21c80, 0x21d7c, 3516218792Snp 0x21e00, 0x21e04, 3517218792Snp 0x22000, 0x2202c, 3518218792Snp 0x22100, 0x2213c, 3519218792Snp 0x22190, 0x221c8, 3520218792Snp 0x22200, 0x22318, 3521218792Snp 0x22400, 0x22528, 3522218792Snp 0x22540, 0x22614, 3523218792Snp 0x23000, 0x23040, 3524218792Snp 0x2304c, 0x23060, 3525218792Snp 0x230c0, 0x230ec, 3526218792Snp 0x23200, 0x23268, 3527218792Snp 0x23270, 0x23284, 3528218792Snp 0x232fc, 0x23388, 3529218792Snp 0x23400, 0x23404, 3530218792Snp 0x23500, 0x23518, 3531218792Snp 0x2352c, 0x2353c, 3532218792Snp 0x23550, 0x23554, 3533218792Snp 0x23600, 0x23600, 3534218792Snp 0x23608, 0x23628, 3535218792Snp 0x23630, 0x2363c, 3536218792Snp 0x23700, 0x2371c, 3537218792Snp 0x23780, 0x2378c, 3538218792Snp 0x23800, 0x23c38, 3539218792Snp 0x23c80, 0x23d7c, 3540218792Snp 0x23e00, 0x23e04, 3541218792Snp 0x24000, 0x2402c, 3542218792Snp 0x24100, 0x2413c, 3543218792Snp 0x24190, 0x241c8, 3544218792Snp 0x24200, 0x24318, 3545218792Snp 0x24400, 0x24528, 3546218792Snp 0x24540, 0x24614, 3547218792Snp 0x25000, 0x25040, 3548218792Snp 0x2504c, 0x25060, 3549218792Snp 0x250c0, 0x250ec, 3550218792Snp 0x25200, 0x25268, 3551218792Snp 0x25270, 0x25284, 3552218792Snp 0x252fc, 0x25388, 3553218792Snp 0x25400, 0x25404, 3554218792Snp 0x25500, 0x25518, 3555218792Snp 0x2552c, 0x2553c, 3556218792Snp 0x25550, 0x25554, 3557218792Snp 0x25600, 0x25600, 3558218792Snp 0x25608, 0x25628, 3559218792Snp 0x25630, 0x2563c, 3560218792Snp 0x25700, 0x2571c, 3561218792Snp 0x25780, 0x2578c, 3562218792Snp 0x25800, 0x25c38, 3563218792Snp 0x25c80, 0x25d7c, 3564218792Snp 0x25e00, 0x25e04, 3565218792Snp 0x26000, 0x2602c, 3566218792Snp 0x26100, 0x2613c, 3567218792Snp 0x26190, 0x261c8, 3568218792Snp 0x26200, 0x26318, 3569218792Snp 0x26400, 0x26528, 3570218792Snp 0x26540, 0x26614, 3571218792Snp 0x27000, 0x27040, 3572218792Snp 0x2704c, 0x27060, 3573218792Snp 0x270c0, 0x270ec, 3574218792Snp 0x27200, 0x27268, 3575218792Snp 0x27270, 0x27284, 3576218792Snp 0x272fc, 0x27388, 3577218792Snp 0x27400, 0x27404, 3578218792Snp 0x27500, 0x27518, 3579218792Snp 0x2752c, 0x2753c, 3580218792Snp 0x27550, 0x27554, 3581218792Snp 0x27600, 0x27600, 3582218792Snp 0x27608, 0x27628, 3583218792Snp 0x27630, 0x2763c, 3584218792Snp 0x27700, 0x2771c, 3585218792Snp 0x27780, 0x2778c, 3586218792Snp 0x27800, 0x27c38, 3587218792Snp 0x27c80, 0x27d7c, 3588218792Snp 0x27e00, 0x27e04 3589218792Snp }; 3590252495Snp static const unsigned int t5_reg_ranges[] = { 3591252495Snp 0x1008, 0x1148, 3592252495Snp 0x1180, 0x11b4, 3593252495Snp 0x11fc, 0x123c, 3594252495Snp 0x1280, 0x173c, 3595252495Snp 0x1800, 0x18fc, 3596252495Snp 0x3000, 0x3028, 3597252495Snp 0x3060, 0x30d8, 3598252495Snp 0x30e0, 0x30fc, 3599252495Snp 0x3140, 0x357c, 3600252495Snp 0x35a8, 0x35cc, 3601252495Snp 0x35ec, 0x35ec, 3602252495Snp 0x3600, 0x5624, 3603252495Snp 0x56cc, 0x575c, 3604252495Snp 0x580c, 0x5814, 3605252495Snp 0x5890, 0x58bc, 3606252495Snp 0x5940, 0x59dc, 3607252495Snp 0x59fc, 0x5a18, 3608252495Snp 0x5a60, 0x5a9c, 3609252495Snp 0x5b94, 0x5bfc, 3610252495Snp 0x6000, 0x6040, 3611252495Snp 0x6058, 0x614c, 3612252495Snp 0x7700, 0x7798, 3613252495Snp 0x77c0, 0x78fc, 3614252495Snp 0x7b00, 0x7c54, 3615252495Snp 0x7d00, 0x7efc, 3616252495Snp 0x8dc0, 0x8de0, 3617252495Snp 0x8df8, 0x8e84, 3618252495Snp 0x8ea0, 0x8f84, 3619252495Snp 0x8fc0, 0x90f8, 3620252495Snp 0x9400, 0x9470, 3621252495Snp 0x9600, 0x96f4, 3622252495Snp 0x9800, 0x9808, 3623252495Snp 0x9820, 0x983c, 3624252495Snp 0x9850, 0x9864, 3625252495Snp 0x9c00, 0x9c6c, 3626252495Snp 0x9c80, 0x9cec, 3627252495Snp 0x9d00, 0x9d6c, 3628252495Snp 0x9d80, 0x9dec, 3629252495Snp 0x9e00, 0x9e6c, 3630252495Snp 0x9e80, 0x9eec, 3631252495Snp 0x9f00, 0x9f6c, 3632252495Snp 0x9f80, 0xa020, 3633252495Snp 0xd004, 0xd03c, 3634252495Snp 0xdfc0, 0xdfe0, 3635252495Snp 0xe000, 0x11088, 3636265549Snp 0x1109c, 0x11110, 3637265549Snp 0x11118, 0x1117c, 3638252495Snp 0x11190, 0x11204, 3639252495Snp 0x19040, 0x1906c, 3640252495Snp 0x19078, 0x19080, 3641252495Snp 0x1908c, 0x19124, 3642252495Snp 0x19150, 0x191b0, 3643252495Snp 0x191d0, 0x191e8, 3644252495Snp 0x19238, 0x19290, 3645252495Snp 0x193f8, 0x19474, 3646252495Snp 0x19490, 0x194cc, 3647252495Snp 0x194f0, 0x194f8, 3648252495Snp 0x19c00, 0x19c60, 3649252495Snp 0x19c94, 0x19e10, 3650252495Snp 0x19e50, 0x19f34, 3651252495Snp 0x19f40, 0x19f50, 3652252495Snp 0x19f90, 0x19fe4, 3653252495Snp 0x1a000, 0x1a06c, 3654252495Snp 0x1a0b0, 0x1a120, 3655252495Snp 0x1a128, 0x1a138, 3656252495Snp 0x1a190, 0x1a1c4, 3657252495Snp 0x1a1fc, 0x1a1fc, 3658252495Snp 0x1e008, 0x1e00c, 3659252495Snp 0x1e040, 0x1e04c, 3660252495Snp 0x1e284, 0x1e290, 3661252495Snp 0x1e2c0, 0x1e2c0, 3662252495Snp 0x1e2e0, 0x1e2e0, 3663252495Snp 0x1e300, 0x1e384, 3664252495Snp 0x1e3c0, 0x1e3c8, 3665252495Snp 0x1e408, 0x1e40c, 3666252495Snp 0x1e440, 0x1e44c, 3667252495Snp 0x1e684, 0x1e690, 3668252495Snp 0x1e6c0, 0x1e6c0, 3669252495Snp 0x1e6e0, 0x1e6e0, 3670252495Snp 0x1e700, 0x1e784, 3671252495Snp 0x1e7c0, 0x1e7c8, 3672252495Snp 0x1e808, 0x1e80c, 3673252495Snp 0x1e840, 0x1e84c, 3674252495Snp 0x1ea84, 0x1ea90, 3675252495Snp 0x1eac0, 0x1eac0, 3676252495Snp 0x1eae0, 0x1eae0, 3677252495Snp 0x1eb00, 0x1eb84, 3678252495Snp 0x1ebc0, 0x1ebc8, 3679252495Snp 0x1ec08, 0x1ec0c, 3680252495Snp 0x1ec40, 0x1ec4c, 3681252495Snp 0x1ee84, 0x1ee90, 3682252495Snp 0x1eec0, 0x1eec0, 3683252495Snp 0x1eee0, 0x1eee0, 3684252495Snp 0x1ef00, 0x1ef84, 3685252495Snp 0x1efc0, 0x1efc8, 3686252495Snp 0x1f008, 0x1f00c, 3687252495Snp 0x1f040, 0x1f04c, 3688252495Snp 0x1f284, 0x1f290, 3689252495Snp 0x1f2c0, 0x1f2c0, 3690252495Snp 0x1f2e0, 0x1f2e0, 3691252495Snp 0x1f300, 0x1f384, 3692252495Snp 0x1f3c0, 0x1f3c8, 3693252495Snp 0x1f408, 0x1f40c, 3694252495Snp 0x1f440, 0x1f44c, 3695252495Snp 0x1f684, 0x1f690, 3696252495Snp 0x1f6c0, 0x1f6c0, 3697252495Snp 0x1f6e0, 0x1f6e0, 3698252495Snp 0x1f700, 0x1f784, 3699252495Snp 0x1f7c0, 0x1f7c8, 3700252495Snp 0x1f808, 0x1f80c, 3701252495Snp 0x1f840, 0x1f84c, 3702252495Snp 0x1fa84, 0x1fa90, 3703252495Snp 0x1fac0, 0x1fac0, 3704252495Snp 0x1fae0, 0x1fae0, 3705252495Snp 0x1fb00, 0x1fb84, 3706252495Snp 0x1fbc0, 0x1fbc8, 3707252495Snp 0x1fc08, 0x1fc0c, 3708252495Snp 0x1fc40, 0x1fc4c, 3709252495Snp 0x1fe84, 0x1fe90, 3710252495Snp 0x1fec0, 0x1fec0, 3711252495Snp 0x1fee0, 0x1fee0, 3712252495Snp 0x1ff00, 0x1ff84, 3713252495Snp 0x1ffc0, 0x1ffc8, 3714252495Snp 0x30000, 0x30030, 3715252495Snp 0x30100, 0x30144, 3716252495Snp 0x30190, 0x301d0, 3717252495Snp 0x30200, 0x30318, 3718252495Snp 0x30400, 0x3052c, 3719252495Snp 0x30540, 0x3061c, 3720252495Snp 0x30800, 0x30834, 3721252495Snp 0x308c0, 0x30908, 3722252495Snp 0x30910, 0x309ac, 3723252495Snp 0x30a00, 0x30a2c, 3724252495Snp 0x30a44, 0x30a50, 3725252495Snp 0x30a74, 0x30c24, 3726252495Snp 0x30d00, 0x30d00, 3727252495Snp 0x30d08, 0x30d14, 3728252495Snp 0x30d1c, 0x30d20, 3729252495Snp 0x30d3c, 0x30d50, 3730252495Snp 0x31200, 0x3120c, 3731252495Snp 0x31220, 0x31220, 3732252495Snp 0x31240, 0x31240, 3733252495Snp 0x31600, 0x3160c, 3734252495Snp 0x31a00, 0x31a1c, 3735252495Snp 0x31e00, 0x31e20, 3736252495Snp 0x31e38, 0x31e3c, 3737252495Snp 0x31e80, 0x31e80, 3738252495Snp 0x31e88, 0x31ea8, 3739252495Snp 0x31eb0, 0x31eb4, 3740252495Snp 0x31ec8, 0x31ed4, 3741252495Snp 0x31fb8, 0x32004, 3742252495Snp 0x32200, 0x32200, 3743252495Snp 0x32208, 0x32240, 3744252495Snp 0x32248, 0x32280, 3745252495Snp 0x32288, 0x322c0, 3746252495Snp 0x322c8, 0x322fc, 3747252495Snp 0x32600, 0x32630, 3748252495Snp 0x32a00, 0x32abc, 3749252495Snp 0x32b00, 0x32b70, 3750252495Snp 0x33000, 0x33048, 3751252495Snp 0x33060, 0x3309c, 3752252495Snp 0x330f0, 0x33148, 3753252495Snp 0x33160, 0x3319c, 3754252495Snp 0x331f0, 0x332e4, 3755252495Snp 0x332f8, 0x333e4, 3756252495Snp 0x333f8, 0x33448, 3757252495Snp 0x33460, 0x3349c, 3758252495Snp 0x334f0, 0x33548, 3759252495Snp 0x33560, 0x3359c, 3760252495Snp 0x335f0, 0x336e4, 3761252495Snp 0x336f8, 0x337e4, 3762252495Snp 0x337f8, 0x337fc, 3763252495Snp 0x33814, 0x33814, 3764252495Snp 0x3382c, 0x3382c, 3765252495Snp 0x33880, 0x3388c, 3766252495Snp 0x338e8, 0x338ec, 3767252495Snp 0x33900, 0x33948, 3768252495Snp 0x33960, 0x3399c, 3769252495Snp 0x339f0, 0x33ae4, 3770252495Snp 0x33af8, 0x33b10, 3771252495Snp 0x33b28, 0x33b28, 3772252495Snp 0x33b3c, 0x33b50, 3773252495Snp 0x33bf0, 0x33c10, 3774252495Snp 0x33c28, 0x33c28, 3775252495Snp 0x33c3c, 0x33c50, 3776252495Snp 0x33cf0, 0x33cfc, 3777252495Snp 0x34000, 0x34030, 3778252495Snp 0x34100, 0x34144, 3779252495Snp 0x34190, 0x341d0, 3780252495Snp 0x34200, 0x34318, 3781252495Snp 0x34400, 0x3452c, 3782252495Snp 0x34540, 0x3461c, 3783252495Snp 0x34800, 0x34834, 3784252495Snp 0x348c0, 0x34908, 3785252495Snp 0x34910, 0x349ac, 3786252495Snp 0x34a00, 0x34a2c, 3787252495Snp 0x34a44, 0x34a50, 3788252495Snp 0x34a74, 0x34c24, 3789252495Snp 0x34d00, 0x34d00, 3790252495Snp 0x34d08, 0x34d14, 3791252495Snp 0x34d1c, 0x34d20, 3792252495Snp 0x34d3c, 0x34d50, 3793252495Snp 0x35200, 0x3520c, 3794252495Snp 0x35220, 0x35220, 3795252495Snp 0x35240, 0x35240, 3796252495Snp 0x35600, 0x3560c, 3797252495Snp 0x35a00, 0x35a1c, 3798252495Snp 0x35e00, 0x35e20, 3799252495Snp 0x35e38, 0x35e3c, 3800252495Snp 0x35e80, 0x35e80, 3801252495Snp 0x35e88, 0x35ea8, 3802252495Snp 0x35eb0, 0x35eb4, 3803252495Snp 0x35ec8, 0x35ed4, 3804252495Snp 0x35fb8, 0x36004, 3805252495Snp 0x36200, 0x36200, 3806252495Snp 0x36208, 0x36240, 3807252495Snp 0x36248, 0x36280, 3808252495Snp 0x36288, 0x362c0, 3809252495Snp 0x362c8, 0x362fc, 3810252495Snp 0x36600, 0x36630, 3811252495Snp 0x36a00, 0x36abc, 3812252495Snp 0x36b00, 0x36b70, 3813252495Snp 0x37000, 0x37048, 3814252495Snp 0x37060, 0x3709c, 3815252495Snp 0x370f0, 0x37148, 3816252495Snp 0x37160, 0x3719c, 3817252495Snp 0x371f0, 0x372e4, 3818252495Snp 0x372f8, 0x373e4, 3819252495Snp 0x373f8, 0x37448, 3820252495Snp 0x37460, 0x3749c, 3821252495Snp 0x374f0, 0x37548, 3822252495Snp 0x37560, 0x3759c, 3823252495Snp 0x375f0, 0x376e4, 3824252495Snp 0x376f8, 0x377e4, 3825252495Snp 0x377f8, 0x377fc, 3826252495Snp 0x37814, 0x37814, 3827252495Snp 0x3782c, 0x3782c, 3828252495Snp 0x37880, 0x3788c, 3829252495Snp 0x378e8, 0x378ec, 3830252495Snp 0x37900, 0x37948, 3831252495Snp 0x37960, 0x3799c, 3832252495Snp 0x379f0, 0x37ae4, 3833252495Snp 0x37af8, 0x37b10, 3834252495Snp 0x37b28, 0x37b28, 3835252495Snp 0x37b3c, 0x37b50, 3836252495Snp 0x37bf0, 0x37c10, 3837252495Snp 0x37c28, 0x37c28, 3838252495Snp 0x37c3c, 0x37c50, 3839252495Snp 0x37cf0, 0x37cfc, 3840252495Snp 0x38000, 0x38030, 3841252495Snp 0x38100, 0x38144, 3842252495Snp 0x38190, 0x381d0, 3843252495Snp 0x38200, 0x38318, 3844252495Snp 0x38400, 0x3852c, 3845252495Snp 0x38540, 0x3861c, 3846252495Snp 0x38800, 0x38834, 3847252495Snp 0x388c0, 0x38908, 3848252495Snp 0x38910, 0x389ac, 3849252495Snp 0x38a00, 0x38a2c, 3850252495Snp 0x38a44, 0x38a50, 3851252495Snp 0x38a74, 0x38c24, 3852252495Snp 0x38d00, 0x38d00, 3853252495Snp 0x38d08, 0x38d14, 3854252495Snp 0x38d1c, 0x38d20, 3855252495Snp 0x38d3c, 0x38d50, 3856252495Snp 0x39200, 0x3920c, 3857252495Snp 0x39220, 0x39220, 3858252495Snp 0x39240, 0x39240, 3859252495Snp 0x39600, 0x3960c, 3860252495Snp 0x39a00, 0x39a1c, 3861252495Snp 0x39e00, 0x39e20, 3862252495Snp 0x39e38, 0x39e3c, 3863252495Snp 0x39e80, 0x39e80, 3864252495Snp 0x39e88, 0x39ea8, 3865252495Snp 0x39eb0, 0x39eb4, 3866252495Snp 0x39ec8, 0x39ed4, 3867252495Snp 0x39fb8, 0x3a004, 3868252495Snp 0x3a200, 0x3a200, 3869252495Snp 0x3a208, 0x3a240, 3870252495Snp 0x3a248, 0x3a280, 3871252495Snp 0x3a288, 0x3a2c0, 3872252495Snp 0x3a2c8, 0x3a2fc, 3873252495Snp 0x3a600, 0x3a630, 3874252495Snp 0x3aa00, 0x3aabc, 3875252495Snp 0x3ab00, 0x3ab70, 3876252495Snp 0x3b000, 0x3b048, 3877252495Snp 0x3b060, 0x3b09c, 3878252495Snp 0x3b0f0, 0x3b148, 3879252495Snp 0x3b160, 0x3b19c, 3880252495Snp 0x3b1f0, 0x3b2e4, 3881252495Snp 0x3b2f8, 0x3b3e4, 3882252495Snp 0x3b3f8, 0x3b448, 3883252495Snp 0x3b460, 0x3b49c, 3884252495Snp 0x3b4f0, 0x3b548, 3885252495Snp 0x3b560, 0x3b59c, 3886252495Snp 0x3b5f0, 0x3b6e4, 3887252495Snp 0x3b6f8, 0x3b7e4, 3888252495Snp 0x3b7f8, 0x3b7fc, 3889252495Snp 0x3b814, 0x3b814, 3890252495Snp 0x3b82c, 0x3b82c, 3891252495Snp 0x3b880, 0x3b88c, 3892252495Snp 0x3b8e8, 0x3b8ec, 3893252495Snp 0x3b900, 0x3b948, 3894252495Snp 0x3b960, 0x3b99c, 3895252495Snp 0x3b9f0, 0x3bae4, 3896252495Snp 0x3baf8, 0x3bb10, 3897252495Snp 0x3bb28, 0x3bb28, 3898252495Snp 0x3bb3c, 0x3bb50, 3899252495Snp 0x3bbf0, 0x3bc10, 3900252495Snp 0x3bc28, 0x3bc28, 3901252495Snp 0x3bc3c, 0x3bc50, 3902252495Snp 0x3bcf0, 0x3bcfc, 3903252495Snp 0x3c000, 0x3c030, 3904252495Snp 0x3c100, 0x3c144, 3905252495Snp 0x3c190, 0x3c1d0, 3906252495Snp 0x3c200, 0x3c318, 3907252495Snp 0x3c400, 0x3c52c, 3908252495Snp 0x3c540, 0x3c61c, 3909252495Snp 0x3c800, 0x3c834, 3910252495Snp 0x3c8c0, 0x3c908, 3911252495Snp 0x3c910, 0x3c9ac, 3912252495Snp 0x3ca00, 0x3ca2c, 3913252495Snp 0x3ca44, 0x3ca50, 3914252495Snp 0x3ca74, 0x3cc24, 3915252495Snp 0x3cd00, 0x3cd00, 3916252495Snp 0x3cd08, 0x3cd14, 3917252495Snp 0x3cd1c, 0x3cd20, 3918252495Snp 0x3cd3c, 0x3cd50, 3919252495Snp 0x3d200, 0x3d20c, 3920252495Snp 0x3d220, 0x3d220, 3921252495Snp 0x3d240, 0x3d240, 3922252495Snp 0x3d600, 0x3d60c, 3923252495Snp 0x3da00, 0x3da1c, 3924252495Snp 0x3de00, 0x3de20, 3925252495Snp 0x3de38, 0x3de3c, 3926252495Snp 0x3de80, 0x3de80, 3927252495Snp 0x3de88, 0x3dea8, 3928252495Snp 0x3deb0, 0x3deb4, 3929252495Snp 0x3dec8, 0x3ded4, 3930252495Snp 0x3dfb8, 0x3e004, 3931252495Snp 0x3e200, 0x3e200, 3932252495Snp 0x3e208, 0x3e240, 3933252495Snp 0x3e248, 0x3e280, 3934252495Snp 0x3e288, 0x3e2c0, 3935252495Snp 0x3e2c8, 0x3e2fc, 3936252495Snp 0x3e600, 0x3e630, 3937252495Snp 0x3ea00, 0x3eabc, 3938252495Snp 0x3eb00, 0x3eb70, 3939252495Snp 0x3f000, 0x3f048, 3940252495Snp 0x3f060, 0x3f09c, 3941252495Snp 0x3f0f0, 0x3f148, 3942252495Snp 0x3f160, 0x3f19c, 3943252495Snp 0x3f1f0, 0x3f2e4, 3944252495Snp 0x3f2f8, 0x3f3e4, 3945252495Snp 0x3f3f8, 0x3f448, 3946252495Snp 0x3f460, 0x3f49c, 3947252495Snp 0x3f4f0, 0x3f548, 3948252495Snp 0x3f560, 0x3f59c, 3949252495Snp 0x3f5f0, 0x3f6e4, 3950252495Snp 0x3f6f8, 0x3f7e4, 3951252495Snp 0x3f7f8, 0x3f7fc, 3952252495Snp 0x3f814, 0x3f814, 3953252495Snp 0x3f82c, 0x3f82c, 3954252495Snp 0x3f880, 0x3f88c, 3955252495Snp 0x3f8e8, 0x3f8ec, 3956252495Snp 0x3f900, 0x3f948, 3957252495Snp 0x3f960, 0x3f99c, 3958252495Snp 0x3f9f0, 0x3fae4, 3959252495Snp 0x3faf8, 0x3fb10, 3960252495Snp 0x3fb28, 0x3fb28, 3961252495Snp 0x3fb3c, 0x3fb50, 3962252495Snp 0x3fbf0, 0x3fc10, 3963252495Snp 0x3fc28, 0x3fc28, 3964252495Snp 0x3fc3c, 0x3fc50, 3965252495Snp 0x3fcf0, 0x3fcfc, 3966252495Snp 0x40000, 0x4000c, 3967252495Snp 0x40040, 0x40068, 3968252495Snp 0x4007c, 0x40144, 3969252495Snp 0x40180, 0x4018c, 3970252495Snp 0x40200, 0x40298, 3971252495Snp 0x402ac, 0x4033c, 3972252495Snp 0x403f8, 0x403fc, 3973252495Snp 0x41304, 0x413c4, 3974252495Snp 0x41400, 0x4141c, 3975252495Snp 0x41480, 0x414d0, 3976252495Snp 0x44000, 0x44078, 3977252495Snp 0x440c0, 0x44278, 3978252495Snp 0x442c0, 0x44478, 3979252495Snp 0x444c0, 0x44678, 3980252495Snp 0x446c0, 0x44878, 3981252495Snp 0x448c0, 0x449fc, 3982252495Snp 0x45000, 0x45068, 3983252495Snp 0x45080, 0x45084, 3984252495Snp 0x450a0, 0x450b0, 3985252495Snp 0x45200, 0x45268, 3986252495Snp 0x45280, 0x45284, 3987252495Snp 0x452a0, 0x452b0, 3988252495Snp 0x460c0, 0x460e4, 3989252495Snp 0x47000, 0x4708c, 3990252495Snp 0x47200, 0x47250, 3991252495Snp 0x47400, 0x47420, 3992252495Snp 0x47600, 0x47618, 3993252495Snp 0x47800, 0x47814, 3994252495Snp 0x48000, 0x4800c, 3995252495Snp 0x48040, 0x48068, 3996252495Snp 0x4807c, 0x48144, 3997252495Snp 0x48180, 0x4818c, 3998252495Snp 0x48200, 0x48298, 3999252495Snp 0x482ac, 0x4833c, 4000252495Snp 0x483f8, 0x483fc, 4001252495Snp 0x49304, 0x493c4, 4002252495Snp 0x49400, 0x4941c, 4003252495Snp 0x49480, 0x494d0, 4004252495Snp 0x4c000, 0x4c078, 4005252495Snp 0x4c0c0, 0x4c278, 4006252495Snp 0x4c2c0, 0x4c478, 4007252495Snp 0x4c4c0, 0x4c678, 4008252495Snp 0x4c6c0, 0x4c878, 4009252495Snp 0x4c8c0, 0x4c9fc, 4010252495Snp 0x4d000, 0x4d068, 4011252495Snp 0x4d080, 0x4d084, 4012252495Snp 0x4d0a0, 0x4d0b0, 4013252495Snp 0x4d200, 0x4d268, 4014252495Snp 0x4d280, 0x4d284, 4015252495Snp 0x4d2a0, 0x4d2b0, 4016252495Snp 0x4e0c0, 0x4e0e4, 4017252495Snp 0x4f000, 0x4f08c, 4018252495Snp 0x4f200, 0x4f250, 4019252495Snp 0x4f400, 0x4f420, 4020252495Snp 0x4f600, 0x4f618, 4021252495Snp 0x4f800, 0x4f814, 4022252495Snp 0x50000, 0x500cc, 4023252495Snp 0x50400, 0x50400, 4024252495Snp 0x50800, 0x508cc, 4025252495Snp 0x50c00, 0x50c00, 4026252495Snp 0x51000, 0x5101c, 4027252495Snp 0x51300, 0x51308, 4028252495Snp }; 4029218792Snp 4030252495Snp if (is_t4(sc)) { 4031252495Snp reg_ranges = &t4_reg_ranges[0]; 4032252495Snp n = nitems(t4_reg_ranges); 4033252495Snp } else { 4034252495Snp reg_ranges = &t5_reg_ranges[0]; 4035252495Snp n = nitems(t5_reg_ranges); 4036252495Snp } 4037252495Snp 4038252495Snp regs->version = chip_id(sc) | chip_rev(sc) << 10; 4039252495Snp for (i = 0; i < n; i += 2) 4040218792Snp reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]); 4041218792Snp} 4042218792Snp 4043218792Snpstatic void 4044218792Snpcxgbe_tick(void *arg) 4045218792Snp{ 4046218792Snp struct port_info *pi = arg; 4047265582Snp struct adapter *sc = pi->adapter; 4048218792Snp struct ifnet *ifp = pi->ifp; 4049218792Snp struct sge_txq *txq; 4050218792Snp int i, drops; 4051218792Snp struct port_stats *s = &pi->stats; 4052218792Snp 4053218792Snp PORT_LOCK(pi); 4054218792Snp if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 4055218792Snp PORT_UNLOCK(pi); 4056218792Snp return; /* without scheduling another callout */ 4057218792Snp } 4058218792Snp 4059265582Snp t4_get_port_stats(sc, pi->tx_chan, s); 4060218792Snp 4061231093Snp ifp->if_opackets = s->tx_frames - s->tx_pause; 4062231093Snp ifp->if_ipackets = s->rx_frames - s->rx_pause; 4063231093Snp ifp->if_obytes = s->tx_octets - s->tx_pause * 64; 4064231093Snp ifp->if_ibytes = s->rx_octets - s->rx_pause * 64; 4065231093Snp ifp->if_omcasts = s->tx_mcast_frames - s->tx_pause; 4066231093Snp ifp->if_imcasts = s->rx_mcast_frames - s->rx_pause; 4067218792Snp ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 + 4068240169Snp s->rx_ovflow3 + s->rx_trunc0 + s->rx_trunc1 + s->rx_trunc2 + 4069240169Snp s->rx_trunc3; 4070265582Snp for (i = 0; i < 4; i++) { 4071265582Snp if (pi->rx_chan_map & (1 << i)) { 4072265582Snp uint32_t v; 4073218792Snp 4074265582Snp /* 4075265582Snp * XXX: indirect reads from the same ADDR/DATA pair can 4076265582Snp * race with each other. 4077265582Snp */ 4078265582Snp t4_read_indirect(sc, A_TP_MIB_INDEX, A_TP_MIB_DATA, &v, 4079265582Snp 1, A_TP_MIB_TNL_CNG_DROP_0 + i); 4080265582Snp ifp->if_iqdrops += v; 4081265582Snp } 4082265582Snp } 4083265582Snp 4084218792Snp drops = s->tx_drop; 4085218792Snp for_each_txq(pi, i, txq) 4086220873Snp drops += txq->br->br_drops; 4087218792Snp ifp->if_snd.ifq_drops = drops; 4088218792Snp 4089218792Snp ifp->if_oerrors = s->tx_error_frames; 4090218792Snp ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long + 4091218792Snp s->rx_fcs_err + s->rx_len_err; 4092218792Snp 4093218792Snp callout_schedule(&pi->tick, hz); 4094218792Snp PORT_UNLOCK(pi); 4095218792Snp} 4096218792Snp 4097237920Snpstatic void 4098237920Snpcxgbe_vlan_config(void *arg, struct ifnet *ifp, uint16_t vid) 4099237920Snp{ 4100237920Snp struct ifnet *vlan; 4101237920Snp 4102241573Snp if (arg != ifp || ifp->if_type != IFT_ETHER) 4103237920Snp return; 4104237920Snp 4105237920Snp vlan = VLAN_DEVAT(ifp, vid); 4106237920Snp VLAN_SETCOOKIE(vlan, ifp); 4107237920Snp} 4108237920Snp 4109218792Snpstatic int 4110231093Snpcpl_not_handled(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 4111231093Snp{ 4112237920Snp 4113231093Snp#ifdef INVARIANTS 4114237920Snp panic("%s: opcode 0x%02x on iq %p with payload %p", 4115231093Snp __func__, rss->opcode, iq, m); 4116231093Snp#else 4117240169Snp log(LOG_ERR, "%s: opcode 0x%02x on iq %p with payload %p\n", 4118231093Snp __func__, rss->opcode, iq, m); 4119231093Snp m_freem(m); 4120231093Snp#endif 4121231093Snp return (EDOOFUS); 4122231093Snp} 4123231093Snp 4124231093Snpint 4125231093Snpt4_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h) 4126231093Snp{ 4127231093Snp uintptr_t *loc, new; 4128231093Snp 4129241467Snp if (opcode >= nitems(sc->cpl_handler)) 4130231093Snp return (EINVAL); 4131231093Snp 4132231093Snp new = h ? (uintptr_t)h : (uintptr_t)cpl_not_handled; 4133231093Snp loc = (uintptr_t *) &sc->cpl_handler[opcode]; 4134231093Snp atomic_store_rel_ptr(loc, new); 4135231093Snp 4136231093Snp return (0); 4137231093Snp} 4138231093Snp 4139231093Snpstatic int 4140237920Snpan_not_handled(struct sge_iq *iq, const struct rsp_ctrl *ctrl) 4141237920Snp{ 4142237920Snp 4143237920Snp#ifdef INVARIANTS 4144237920Snp panic("%s: async notification on iq %p (ctrl %p)", __func__, iq, ctrl); 4145237920Snp#else 4146240169Snp log(LOG_ERR, "%s: async notification on iq %p (ctrl %p)\n", 4147237920Snp __func__, iq, ctrl); 4148237920Snp#endif 4149237920Snp return (EDOOFUS); 4150237920Snp} 4151237920Snp 4152237920Snpint 4153237920Snpt4_register_an_handler(struct adapter *sc, an_handler_t h) 4154237920Snp{ 4155237920Snp uintptr_t *loc, new; 4156237920Snp 4157237920Snp new = h ? (uintptr_t)h : (uintptr_t)an_not_handled; 4158237920Snp loc = (uintptr_t *) &sc->an_handler; 4159237920Snp atomic_store_rel_ptr(loc, new); 4160237920Snp 4161237920Snp return (0); 4162237920Snp} 4163237920Snp 4164237920Snpstatic int 4165240169Snpfw_msg_not_handled(struct adapter *sc, const __be64 *rpl) 4166240169Snp{ 4167247434Snp const struct cpl_fw6_msg *cpl = 4168247434Snp __containerof(rpl, struct cpl_fw6_msg, data[0]); 4169240169Snp 4170240169Snp#ifdef INVARIANTS 4171240169Snp panic("%s: fw_msg type %d", __func__, cpl->type); 4172240169Snp#else 4173240169Snp log(LOG_ERR, "%s: fw_msg type %d\n", __func__, cpl->type); 4174240169Snp#endif 4175240169Snp return (EDOOFUS); 4176240169Snp} 4177240169Snp 4178240169Snpint 4179240169Snpt4_register_fw_msg_handler(struct adapter *sc, int type, fw_msg_handler_t h) 4180240169Snp{ 4181240169Snp uintptr_t *loc, new; 4182240169Snp 4183241467Snp if (type >= nitems(sc->fw_msg_handler)) 4184240169Snp return (EINVAL); 4185240169Snp 4186247434Snp /* 4187247434Snp * These are dispatched by the handler for FW{4|6}_CPL_MSG using the CPL 4188247434Snp * handler dispatch table. Reject any attempt to install a handler for 4189247434Snp * this subtype. 4190247434Snp */ 4191247434Snp if (type == FW_TYPE_RSSCPL || type == FW6_TYPE_RSSCPL) 4192247434Snp return (EINVAL); 4193247434Snp 4194240169Snp new = h ? (uintptr_t)h : (uintptr_t)fw_msg_not_handled; 4195240169Snp loc = (uintptr_t *) &sc->fw_msg_handler[type]; 4196240169Snp atomic_store_rel_ptr(loc, new); 4197240169Snp 4198240169Snp return (0); 4199240169Snp} 4200240169Snp 4201240169Snpstatic int 4202218792Snpt4_sysctls(struct adapter *sc) 4203218792Snp{ 4204218792Snp struct sysctl_ctx_list *ctx; 4205218792Snp struct sysctl_oid *oid; 4206231093Snp struct sysctl_oid_list *children, *c0; 4207231093Snp static char *caps[] = { 4208231093Snp "\20\1PPP\2QFC\3DCBX", /* caps[0] linkcaps */ 4209265551Snp "\20\1NIC\2VM\3IDS\4UM\5UM_ISGL" /* caps[1] niccaps */ 4210265551Snp "\6HASHFILTER\7ETHOFLD", 4211231093Snp "\20\1TOE", /* caps[2] toecaps */ 4212231093Snp "\20\1RDDP\2RDMAC", /* caps[3] rdmacaps */ 4213231093Snp "\20\1INITIATOR_PDU\2TARGET_PDU" /* caps[4] iscsicaps */ 4214231093Snp "\3INITIATOR_CNXOFLD\4TARGET_CNXOFLD" 4215231093Snp "\5INITIATOR_SSNOFLD\6TARGET_SSNOFLD", 4216231093Snp "\20\1INITIATOR\2TARGET\3CTRL_OFLD" /* caps[5] fcoecaps */ 4217265551Snp "\4PO_INITIAOR\5PO_TARGET" 4218231093Snp }; 4219252495Snp static char *doorbells = {"\20\1UDB\2WCWR\3UDBWC\4KDB"}; 4220218792Snp 4221218792Snp ctx = device_get_sysctl_ctx(sc->dev); 4222231093Snp 4223231093Snp /* 4224231093Snp * dev.t4nex.X. 4225231093Snp */ 4226218792Snp oid = device_get_sysctl_tree(sc->dev); 4227231093Snp c0 = children = SYSCTL_CHILDREN(oid); 4228218792Snp 4229265582Snp sc->sc_do_rxcopy = 1; 4230265582Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "do_rx_copy", CTLFLAG_RW, 4231265582Snp &sc->sc_do_rxcopy, 1, "Do RX copy of small frames"); 4232265582Snp 4233252495Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, NULL, 4234252495Snp sc->params.nports, "# of ports"); 4235218792Snp 4236218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD, 4237252495Snp NULL, chip_rev(sc), "chip hardware revision"); 4238218792Snp 4239218792Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 4240218792Snp CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 4241218792Snp 4242231093Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "cf", 4243247434Snp CTLFLAG_RD, &sc->cfg_file, 0, "configuration file"); 4244218792Snp 4245252495Snp SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cfcsum", CTLFLAG_RD, NULL, 4246252495Snp sc->cfcsum, "config file checksum"); 4247231093Snp 4248252495Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "doorbells", 4249252495Snp CTLTYPE_STRING | CTLFLAG_RD, doorbells, sc->doorbells, 4250252495Snp sysctl_bitfield, "A", "available doorbells"); 4251252495Snp 4252231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkcaps", 4253231093Snp CTLTYPE_STRING | CTLFLAG_RD, caps[0], sc->linkcaps, 4254231093Snp sysctl_bitfield, "A", "available link capabilities"); 4255231093Snp 4256231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "niccaps", 4257231093Snp CTLTYPE_STRING | CTLFLAG_RD, caps[1], sc->niccaps, 4258231093Snp sysctl_bitfield, "A", "available NIC capabilities"); 4259231093Snp 4260231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "toecaps", 4261231093Snp CTLTYPE_STRING | CTLFLAG_RD, caps[2], sc->toecaps, 4262231093Snp sysctl_bitfield, "A", "available TCP offload capabilities"); 4263231093Snp 4264231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdmacaps", 4265231093Snp CTLTYPE_STRING | CTLFLAG_RD, caps[3], sc->rdmacaps, 4266231093Snp sysctl_bitfield, "A", "available RDMA capabilities"); 4267231093Snp 4268231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "iscsicaps", 4269231093Snp CTLTYPE_STRING | CTLFLAG_RD, caps[4], sc->iscsicaps, 4270231093Snp sysctl_bitfield, "A", "available iSCSI capabilities"); 4271231093Snp 4272231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoecaps", 4273231093Snp CTLTYPE_STRING | CTLFLAG_RD, caps[5], sc->fcoecaps, 4274231093Snp sysctl_bitfield, "A", "available FCoE capabilities"); 4275231093Snp 4276252495Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, NULL, 4277252495Snp sc->params.vpd.cclk, "core clock frequency (in KHz)"); 4278218792Snp 4279219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers", 4280231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.timer_val, 4281231093Snp sizeof(sc->sge.timer_val), sysctl_int_array, "A", 4282231093Snp "interrupt holdoff timer values (us)"); 4283218792Snp 4284219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts", 4285231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.counter_val, 4286231093Snp sizeof(sc->sge.counter_val), sysctl_int_array, "A", 4287231093Snp "interrupt holdoff packet counter values"); 4288218792Snp 4289252495Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nfilters", CTLFLAG_RD, 4290252495Snp NULL, sc->tids.nftids, "number of filters"); 4291252495Snp 4292265478Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "temperature", CTLTYPE_INT | 4293265582Snp CTLFLAG_RD, sc, 0, sysctl_temperature, "I", 4294265478Snp "chip temperature (in Celsius)"); 4295265478Snp 4296265478Snp t4_sge_sysctls(sc, ctx, children); 4297265478Snp 4298231593Snp#ifdef SBUF_DRAIN 4299231093Snp /* 4300231093Snp * dev.t4nex.X.misc. Marked CTLFLAG_SKIP to avoid information overload. 4301231093Snp */ 4302231093Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "misc", 4303231093Snp CTLFLAG_RD | CTLFLAG_SKIP, NULL, 4304231093Snp "logs and miscellaneous information"); 4305231093Snp children = SYSCTL_CHILDREN(oid); 4306231093Snp 4307231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cctrl", 4308231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4309231093Snp sysctl_cctrl, "A", "congestion control"); 4310231093Snp 4311247434Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp0", 4312247434Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4313247434Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 0 (TP0)"); 4314247434Snp 4315247434Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp1", 4316247434Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 1, 4317247434Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 1 (TP1)"); 4318247434Snp 4319247434Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ulp", 4320247434Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 2, 4321247434Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 2 (ULP)"); 4322247434Snp 4323247434Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge0", 4324247434Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 3, 4325247434Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 3 (SGE0)"); 4326247434Snp 4327247434Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge1", 4328247434Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 4, 4329247434Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 4 (SGE1)"); 4330247434Snp 4331247434Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ncsi", 4332247434Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 5, 4333247434Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 5 (NCSI)"); 4334247434Snp 4335247434Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_la", 4336247434Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4337247434Snp sysctl_cim_la, "A", "CIM logic analyzer"); 4338247434Snp 4339252495Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ma_la", 4340252495Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4341252495Snp sysctl_cim_ma_la, "A", "CIM MA logic analyzer"); 4342252495Snp 4343247434Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp0", 4344247434Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0 + CIM_NUM_IBQ, 4345247434Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 0 (ULP0)"); 4346247434Snp 4347247434Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp1", 4348247434Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 1 + CIM_NUM_IBQ, 4349247434Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 1 (ULP1)"); 4350247434Snp 4351247434Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp2", 4352247434Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 2 + CIM_NUM_IBQ, 4353247434Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 2 (ULP2)"); 4354247434Snp 4355247434Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp3", 4356247434Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 3 + CIM_NUM_IBQ, 4357247434Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 3 (ULP3)"); 4358247434Snp 4359247434Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge", 4360247434Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 4 + CIM_NUM_IBQ, 4361247434Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 4 (SGE)"); 4362247434Snp 4363247434Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ncsi", 4364247434Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 5 + CIM_NUM_IBQ, 4365247434Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 5 (NCSI)"); 4366247434Snp 4367252495Snp if (is_t5(sc)) { 4368252495Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge0_rx", 4369252495Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 6 + CIM_NUM_IBQ, 4370252495Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 6 (SGE0-RX)"); 4371252495Snp 4372252495Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge1_rx", 4373252495Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 7 + CIM_NUM_IBQ, 4374252495Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 7 (SGE1-RX)"); 4375252495Snp } 4376252495Snp 4377252495Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_pif_la", 4378252495Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4379252495Snp sysctl_cim_pif_la, "A", "CIM PIF logic analyzer"); 4380252495Snp 4381247434Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_qcfg", 4382247434Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4383247434Snp sysctl_cim_qcfg, "A", "CIM queue configuration"); 4384247434Snp 4385231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats", 4386231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4387231093Snp sysctl_cpl_stats, "A", "CPL statistics"); 4388231093Snp 4389231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ddp_stats", 4390231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4391231093Snp sysctl_ddp_stats, "A", "DDP statistics"); 4392231093Snp 4393222551Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog", 4394222551Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4395231093Snp sysctl_devlog, "A", "firmware's device log"); 4396222551Snp 4397231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoe_stats", 4398231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4399231093Snp sysctl_fcoe_stats, "A", "FCoE statistics"); 4400231093Snp 4401231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hw_sched", 4402231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4403231093Snp sysctl_hw_sched, "A", "hardware scheduler "); 4404231093Snp 4405231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "l2t", 4406231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4407231093Snp sysctl_l2t, "A", "hardware L2 table"); 4408231093Snp 4409231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats", 4410231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4411231093Snp sysctl_lb_stats, "A", "loopback statistics"); 4412231093Snp 4413231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "meminfo", 4414231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4415231093Snp sysctl_meminfo, "A", "memory regions"); 4416231093Snp 4417252495Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "mps_tcam", 4418252495Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4419252495Snp sysctl_mps_tcam, "A", "MPS TCAM entries"); 4420252495Snp 4421231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "path_mtus", 4422231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4423231093Snp sysctl_path_mtus, "A", "path MTUs"); 4424231093Snp 4425231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pm_stats", 4426231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4427231093Snp sysctl_pm_stats, "A", "PM statistics"); 4428231093Snp 4429231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_stats", 4430231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4431231093Snp sysctl_rdma_stats, "A", "RDMA statistics"); 4432231093Snp 4433231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tcp_stats", 4434231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4435231093Snp sysctl_tcp_stats, "A", "TCP statistics"); 4436231093Snp 4437231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tids", 4438231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4439231093Snp sysctl_tids, "A", "TID information"); 4440231093Snp 4441231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_err_stats", 4442231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4443231093Snp sysctl_tp_err_stats, "A", "TP error statistics"); 4444231093Snp 4445252495Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_la", 4446252495Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4447252495Snp sysctl_tp_la, "A", "TP logic analyzer"); 4448252495Snp 4449231093Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_rate", 4450231093Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4451231093Snp sysctl_tx_rate, "A", "Tx rate"); 4452252495Snp 4453252495Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ulprx_la", 4454252495Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4455252495Snp sysctl_ulprx_la, "A", "ULPRX logic analyzer"); 4456252495Snp 4457252495Snp if (is_t5(sc)) { 4458252495Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "wcwr_stats", 4459252495Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4460252495Snp sysctl_wcwr_stats, "A", "write combined work requests"); 4461252495Snp } 4462231593Snp#endif 4463231093Snp 4464237920Snp#ifdef TCP_OFFLOAD 4465231093Snp if (is_offload(sc)) { 4466231093Snp /* 4467231093Snp * dev.t4nex.X.toe. 4468231093Snp */ 4469231093Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "toe", CTLFLAG_RD, 4470231093Snp NULL, "TOE parameters"); 4471231093Snp children = SYSCTL_CHILDREN(oid); 4472231093Snp 4473231093Snp sc->tt.sndbuf = 256 * 1024; 4474231093Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "sndbuf", CTLFLAG_RW, 4475231093Snp &sc->tt.sndbuf, 0, "max hardware send buffer size"); 4476231093Snp 4477231093Snp sc->tt.ddp = 0; 4478231093Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp", CTLFLAG_RW, 4479231093Snp &sc->tt.ddp, 0, "DDP allowed"); 4480240169Snp 4481240169Snp sc->tt.indsz = G_INDICATESIZE(t4_read_reg(sc, A_TP_PARA_REG5)); 4482231093Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "indsz", CTLFLAG_RW, 4483231093Snp &sc->tt.indsz, 0, "DDP max indicate size allowed"); 4484240169Snp 4485240169Snp sc->tt.ddp_thres = 4486240169Snp G_RXCOALESCESIZE(t4_read_reg(sc, A_TP_PARA_REG2)); 4487231093Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp_thres", CTLFLAG_RW, 4488231093Snp &sc->tt.ddp_thres, 0, "DDP threshold"); 4489252814Snp 4490252814Snp sc->tt.rx_coalesce = 1; 4491252814Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_coalesce", 4492252814Snp CTLFLAG_RW, &sc->tt.rx_coalesce, 0, "receive coalescing"); 4493231093Snp } 4494231093Snp#endif 4495231093Snp 4496231093Snp 4497218792Snp return (0); 4498218792Snp} 4499218792Snp 4500218792Snpstatic int 4501218792Snpcxgbe_sysctls(struct port_info *pi) 4502218792Snp{ 4503218792Snp struct sysctl_ctx_list *ctx; 4504218792Snp struct sysctl_oid *oid; 4505218792Snp struct sysctl_oid_list *children; 4506265553Snp struct adapter *sc = pi->adapter; 4507218792Snp 4508218792Snp ctx = device_get_sysctl_ctx(pi->dev); 4509218792Snp 4510218792Snp /* 4511218792Snp * dev.cxgbe.X. 4512218792Snp */ 4513218792Snp oid = device_get_sysctl_tree(pi->dev); 4514218792Snp children = SYSCTL_CHILDREN(oid); 4515218792Snp 4516265478Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkdnrc", CTLTYPE_STRING | 4517265478Snp CTLFLAG_RD, pi, 0, sysctl_linkdnrc, "A", "reason why link is down"); 4518252814Snp if (pi->port_type == FW_PORT_TYPE_BT_XAUI) { 4519252814Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "temperature", 4520252814Snp CTLTYPE_INT | CTLFLAG_RD, pi, 0, sysctl_btphy, "I", 4521252814Snp "PHY temperature (in Celsius)"); 4522252814Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fw_version", 4523252814Snp CTLTYPE_INT | CTLFLAG_RD, pi, 1, sysctl_btphy, "I", 4524252814Snp "PHY firmware version"); 4525252814Snp } 4526218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD, 4527218792Snp &pi->nrxq, 0, "# of rx queues"); 4528218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD, 4529218792Snp &pi->ntxq, 0, "# of tx queues"); 4530218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD, 4531218792Snp &pi->first_rxq, 0, "index of first rx queue"); 4532218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD, 4533218792Snp &pi->first_txq, 0, "index of first tx queue"); 4534265582Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rsrv_noflowq", CTLTYPE_INT | 4535265582Snp CTLFLAG_RW, pi, 0, sysctl_noflowq, "IU", 4536265582Snp "Reserve queue 0 for non-flowid packets"); 4537218792Snp 4538237920Snp#ifdef TCP_OFFLOAD 4539265553Snp if (is_offload(sc)) { 4540231093Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldrxq", CTLFLAG_RD, 4541231093Snp &pi->nofldrxq, 0, 4542231093Snp "# of rx queues for offloaded TCP connections"); 4543231093Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldtxq", CTLFLAG_RD, 4544231093Snp &pi->nofldtxq, 0, 4545231093Snp "# of tx queues for offloaded TCP connections"); 4546231093Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_rxq", 4547231093Snp CTLFLAG_RD, &pi->first_ofld_rxq, 0, 4548231093Snp "index of first TOE rx queue"); 4549231093Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_txq", 4550231093Snp CTLFLAG_RD, &pi->first_ofld_txq, 0, 4551231093Snp "index of first TOE tx queue"); 4552231093Snp } 4553231093Snp#endif 4554231093Snp 4555218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx", 4556218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I", 4557218792Snp "holdoff timer index"); 4558218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx", 4559218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I", 4560218792Snp "holdoff packet counter index"); 4561218792Snp 4562218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq", 4563218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I", 4564218792Snp "rx queue size"); 4565218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq", 4566218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I", 4567218792Snp "tx queue size"); 4568218792Snp 4569218792Snp /* 4570218792Snp * dev.cxgbe.X.stats. 4571218792Snp */ 4572218792Snp oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, 4573218792Snp NULL, "port statistics"); 4574218792Snp children = SYSCTL_CHILDREN(oid); 4575218792Snp 4576218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \ 4577218792Snp SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \ 4578265553Snp CTLTYPE_U64 | CTLFLAG_RD, sc, reg, \ 4579218792Snp sysctl_handle_t4_reg64, "QU", desc) 4580218792Snp 4581218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames", 4582218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L)); 4583218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames", 4584218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L)); 4585218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames", 4586218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L)); 4587218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames", 4588218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L)); 4589218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames", 4590218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L)); 4591218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames", 4592218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L)); 4593218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_64", 4594218792Snp "# of tx frames in this range", 4595218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L)); 4596218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127", 4597218792Snp "# of tx frames in this range", 4598218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L)); 4599218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255", 4600218792Snp "# of tx frames in this range", 4601218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L)); 4602218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511", 4603218792Snp "# of tx frames in this range", 4604218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L)); 4605218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023", 4606218792Snp "# of tx frames in this range", 4607218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L)); 4608218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518", 4609218792Snp "# of tx frames in this range", 4610218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L)); 4611218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max", 4612218792Snp "# of tx frames in this range", 4613218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L)); 4614218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames", 4615218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L)); 4616218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted", 4617218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L)); 4618218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted", 4619218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L)); 4620218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted", 4621218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L)); 4622218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted", 4623218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L)); 4624218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted", 4625218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L)); 4626218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted", 4627218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L)); 4628218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted", 4629218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L)); 4630218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted", 4631218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L)); 4632218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted", 4633218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L)); 4634218792Snp 4635218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames", 4636218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L)); 4637218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames", 4638218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L)); 4639218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames", 4640218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L)); 4641218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames", 4642218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L)); 4643218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames", 4644218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L)); 4645218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU", 4646218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L)); 4647218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames", 4648218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L)); 4649218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err", 4650218792Snp "# of frames received with bad FCS", 4651218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L)); 4652218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_len_err", 4653218792Snp "# of frames received with length error", 4654218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L)); 4655218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors", 4656218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L)); 4657218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received", 4658218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L)); 4659218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_64", 4660218792Snp "# of rx frames in this range", 4661218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L)); 4662218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127", 4663218792Snp "# of rx frames in this range", 4664218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L)); 4665218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255", 4666218792Snp "# of rx frames in this range", 4667218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L)); 4668218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511", 4669218792Snp "# of rx frames in this range", 4670218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L)); 4671218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023", 4672218792Snp "# of rx frames in this range", 4673218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L)); 4674218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518", 4675218792Snp "# of rx frames in this range", 4676218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L)); 4677218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max", 4678218792Snp "# of rx frames in this range", 4679218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L)); 4680218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received", 4681218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L)); 4682218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received", 4683218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L)); 4684218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received", 4685218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L)); 4686218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received", 4687218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L)); 4688218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received", 4689218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L)); 4690218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received", 4691218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L)); 4692218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received", 4693218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L)); 4694218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received", 4695218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L)); 4696218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received", 4697218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L)); 4698218792Snp 4699218792Snp#undef SYSCTL_ADD_T4_REG64 4700218792Snp 4701218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \ 4702218792Snp SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \ 4703218792Snp &pi->stats.name, desc) 4704218792Snp 4705218792Snp /* We get these from port_stats and they may be stale by upto 1s */ 4706218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0, 4707218792Snp "# drops due to buffer-group 0 overflows"); 4708218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1, 4709218792Snp "# drops due to buffer-group 1 overflows"); 4710218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2, 4711218792Snp "# drops due to buffer-group 2 overflows"); 4712218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3, 4713218792Snp "# drops due to buffer-group 3 overflows"); 4714218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc0, 4715218792Snp "# of buffer-group 0 truncated packets"); 4716218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc1, 4717218792Snp "# of buffer-group 1 truncated packets"); 4718218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc2, 4719218792Snp "# of buffer-group 2 truncated packets"); 4720218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc3, 4721218792Snp "# of buffer-group 3 truncated packets"); 4722218792Snp 4723218792Snp#undef SYSCTL_ADD_T4_PORTSTAT 4724218792Snp 4725218792Snp return (0); 4726218792Snp} 4727218792Snp 4728218792Snpstatic int 4729219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS) 4730219436Snp{ 4731219436Snp int rc, *i; 4732219436Snp struct sbuf sb; 4733219436Snp 4734219436Snp sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); 4735219436Snp for (i = arg1; arg2; arg2 -= sizeof(int), i++) 4736219436Snp sbuf_printf(&sb, "%d ", *i); 4737219436Snp sbuf_trim(&sb); 4738219436Snp sbuf_finish(&sb); 4739219436Snp rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 4740219436Snp sbuf_delete(&sb); 4741219436Snp return (rc); 4742219436Snp} 4743219436Snp 4744219436Snpstatic int 4745231093Snpsysctl_bitfield(SYSCTL_HANDLER_ARGS) 4746231093Snp{ 4747231093Snp int rc; 4748231093Snp struct sbuf *sb; 4749231093Snp 4750231093Snp rc = sysctl_wire_old_buffer(req, 0); 4751231093Snp if (rc != 0) 4752231093Snp return(rc); 4753231093Snp 4754231093Snp sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 4755231093Snp if (sb == NULL) 4756231093Snp return (ENOMEM); 4757231093Snp 4758231093Snp sbuf_printf(sb, "%b", (int)arg2, (char *)arg1); 4759231093Snp rc = sbuf_finish(sb); 4760231093Snp sbuf_delete(sb); 4761231093Snp 4762231093Snp return (rc); 4763231093Snp} 4764231093Snp 4765231093Snpstatic int 4766252814Snpsysctl_btphy(SYSCTL_HANDLER_ARGS) 4767252814Snp{ 4768252814Snp struct port_info *pi = arg1; 4769252814Snp int op = arg2; 4770252814Snp struct adapter *sc = pi->adapter; 4771252814Snp u_int v; 4772252814Snp int rc; 4773252814Snp 4774252814Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4btt"); 4775252814Snp if (rc) 4776252814Snp return (rc); 4777252814Snp /* XXX: magic numbers */ 4778252814Snp rc = -t4_mdio_rd(sc, sc->mbox, pi->mdio_addr, 0x1e, op ? 0x20 : 0xc820, 4779252814Snp &v); 4780252814Snp end_synchronized_op(sc, 0); 4781252814Snp if (rc) 4782252814Snp return (rc); 4783252814Snp if (op == 0) 4784252814Snp v /= 256; 4785252814Snp 4786252814Snp rc = sysctl_handle_int(oidp, &v, 0, req); 4787252814Snp return (rc); 4788252814Snp} 4789252814Snp 4790252814Snpstatic int 4791265582Snpsysctl_noflowq(SYSCTL_HANDLER_ARGS) 4792265582Snp{ 4793265582Snp struct port_info *pi = arg1; 4794265582Snp int rc, val; 4795265582Snp 4796265582Snp val = pi->rsrv_noflowq; 4797265582Snp rc = sysctl_handle_int(oidp, &val, 0, req); 4798265582Snp if (rc != 0 || req->newptr == NULL) 4799265582Snp return (rc); 4800265582Snp 4801265582Snp if ((val >= 1) && (pi->ntxq > 1)) 4802265582Snp pi->rsrv_noflowq = 1; 4803265582Snp else 4804265582Snp pi->rsrv_noflowq = 0; 4805265582Snp 4806265582Snp return (rc); 4807265582Snp} 4808265582Snp 4809265582Snpstatic int 4810218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS) 4811218792Snp{ 4812218792Snp struct port_info *pi = arg1; 4813218792Snp struct adapter *sc = pi->adapter; 4814218792Snp int idx, rc, i; 4815247434Snp struct sge_rxq *rxq; 4816252814Snp#ifdef TCP_OFFLOAD 4817252814Snp struct sge_ofld_rxq *ofld_rxq; 4818252814Snp#endif 4819247434Snp uint8_t v; 4820218792Snp 4821218792Snp idx = pi->tmr_idx; 4822218792Snp 4823218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 4824218792Snp if (rc != 0 || req->newptr == NULL) 4825218792Snp return (rc); 4826218792Snp 4827218792Snp if (idx < 0 || idx >= SGE_NTIMERS) 4828218792Snp return (EINVAL); 4829218792Snp 4830247434Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4831247434Snp "t4tmr"); 4832247434Snp if (rc) 4833247434Snp return (rc); 4834231093Snp 4835247434Snp v = V_QINTR_TIMER_IDX(idx) | V_QINTR_CNT_EN(pi->pktc_idx != -1); 4836247434Snp for_each_rxq(pi, i, rxq) { 4837231093Snp#ifdef atomic_store_rel_8 4838247434Snp atomic_store_rel_8(&rxq->iq.intr_params, v); 4839231093Snp#else 4840247434Snp rxq->iq.intr_params = v; 4841231093Snp#endif 4842218792Snp } 4843252814Snp#ifdef TCP_OFFLOAD 4844252814Snp for_each_ofld_rxq(pi, i, ofld_rxq) { 4845252814Snp#ifdef atomic_store_rel_8 4846252814Snp atomic_store_rel_8(&ofld_rxq->iq.intr_params, v); 4847252814Snp#else 4848252814Snp ofld_rxq->iq.intr_params = v; 4849252814Snp#endif 4850252814Snp } 4851252814Snp#endif 4852247434Snp pi->tmr_idx = idx; 4853218792Snp 4854247434Snp end_synchronized_op(sc, LOCK_HELD); 4855247434Snp return (0); 4856218792Snp} 4857218792Snp 4858218792Snpstatic int 4859218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS) 4860218792Snp{ 4861218792Snp struct port_info *pi = arg1; 4862218792Snp struct adapter *sc = pi->adapter; 4863218792Snp int idx, rc; 4864218792Snp 4865218792Snp idx = pi->pktc_idx; 4866218792Snp 4867218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 4868218792Snp if (rc != 0 || req->newptr == NULL) 4869218792Snp return (rc); 4870218792Snp 4871218792Snp if (idx < -1 || idx >= SGE_NCOUNTERS) 4872218792Snp return (EINVAL); 4873218792Snp 4874247434Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4875247434Snp "t4pktc"); 4876247434Snp if (rc) 4877247434Snp return (rc); 4878247434Snp 4879247434Snp if (pi->flags & PORT_INIT_DONE) 4880231093Snp rc = EBUSY; /* cannot be changed once the queues are created */ 4881247434Snp else 4882218792Snp pi->pktc_idx = idx; 4883218792Snp 4884247434Snp end_synchronized_op(sc, LOCK_HELD); 4885218792Snp return (rc); 4886218792Snp} 4887218792Snp 4888218792Snpstatic int 4889218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS) 4890218792Snp{ 4891218792Snp struct port_info *pi = arg1; 4892218792Snp struct adapter *sc = pi->adapter; 4893218792Snp int qsize, rc; 4894218792Snp 4895218792Snp qsize = pi->qsize_rxq; 4896218792Snp 4897218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 4898218792Snp if (rc != 0 || req->newptr == NULL) 4899218792Snp return (rc); 4900218792Snp 4901218792Snp if (qsize < 128 || (qsize & 7)) 4902218792Snp return (EINVAL); 4903218792Snp 4904247434Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4905247434Snp "t4rxqs"); 4906247434Snp if (rc) 4907247434Snp return (rc); 4908247434Snp 4909247434Snp if (pi->flags & PORT_INIT_DONE) 4910231093Snp rc = EBUSY; /* cannot be changed once the queues are created */ 4911247434Snp else 4912218792Snp pi->qsize_rxq = qsize; 4913218792Snp 4914247434Snp end_synchronized_op(sc, LOCK_HELD); 4915218792Snp return (rc); 4916218792Snp} 4917218792Snp 4918218792Snpstatic int 4919218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS) 4920218792Snp{ 4921218792Snp struct port_info *pi = arg1; 4922218792Snp struct adapter *sc = pi->adapter; 4923218792Snp int qsize, rc; 4924218792Snp 4925218792Snp qsize = pi->qsize_txq; 4926218792Snp 4927218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 4928218792Snp if (rc != 0 || req->newptr == NULL) 4929218792Snp return (rc); 4930218792Snp 4931247434Snp /* bufring size must be powerof2 */ 4932247434Snp if (qsize < 128 || !powerof2(qsize)) 4933218792Snp return (EINVAL); 4934218792Snp 4935247434Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4936247434Snp "t4txqs"); 4937247434Snp if (rc) 4938247434Snp return (rc); 4939247434Snp 4940247434Snp if (pi->flags & PORT_INIT_DONE) 4941231093Snp rc = EBUSY; /* cannot be changed once the queues are created */ 4942247434Snp else 4943218792Snp pi->qsize_txq = qsize; 4944218792Snp 4945247434Snp end_synchronized_op(sc, LOCK_HELD); 4946218792Snp return (rc); 4947218792Snp} 4948218792Snp 4949218792Snpstatic int 4950218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS) 4951218792Snp{ 4952218792Snp struct adapter *sc = arg1; 4953218792Snp int reg = arg2; 4954218792Snp uint64_t val; 4955218792Snp 4956218792Snp val = t4_read_reg64(sc, reg); 4957218792Snp 4958218792Snp return (sysctl_handle_64(oidp, &val, 0, req)); 4959218792Snp} 4960218792Snp 4961265478Snpstatic int 4962265478Snpsysctl_temperature(SYSCTL_HANDLER_ARGS) 4963265478Snp{ 4964265478Snp struct adapter *sc = arg1; 4965265478Snp int rc, t; 4966265478Snp uint32_t param, val; 4967265478Snp 4968265478Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4temp"); 4969265478Snp if (rc) 4970265478Snp return (rc); 4971265478Snp param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | 4972265478Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_DIAG) | 4973265478Snp V_FW_PARAMS_PARAM_Y(FW_PARAM_DEV_DIAG_TMP); 4974265478Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 4975265478Snp end_synchronized_op(sc, 0); 4976265478Snp if (rc) 4977265478Snp return (rc); 4978265478Snp 4979265478Snp /* unknown is returned as 0 but we display -1 in that case */ 4980265478Snp t = val == 0 ? -1 : val; 4981265478Snp 4982265478Snp rc = sysctl_handle_int(oidp, &t, 0, req); 4983265478Snp return (rc); 4984265478Snp} 4985265478Snp 4986231593Snp#ifdef SBUF_DRAIN 4987231093Snpstatic int 4988231093Snpsysctl_cctrl(SYSCTL_HANDLER_ARGS) 4989231093Snp{ 4990231093Snp struct adapter *sc = arg1; 4991231093Snp struct sbuf *sb; 4992231093Snp int rc, i; 4993231093Snp uint16_t incr[NMTUS][NCCTRL_WIN]; 4994231093Snp static const char *dec_fac[] = { 4995231093Snp "0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875", 4996231093Snp "0.9375" 4997231093Snp }; 4998231093Snp 4999231093Snp rc = sysctl_wire_old_buffer(req, 0); 5000231093Snp if (rc != 0) 5001231093Snp return (rc); 5002231093Snp 5003231093Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5004231093Snp if (sb == NULL) 5005231093Snp return (ENOMEM); 5006231093Snp 5007231093Snp t4_read_cong_tbl(sc, incr); 5008231093Snp 5009231093Snp for (i = 0; i < NCCTRL_WIN; ++i) { 5010231093Snp sbuf_printf(sb, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i, 5011231093Snp incr[0][i], incr[1][i], incr[2][i], incr[3][i], incr[4][i], 5012231093Snp incr[5][i], incr[6][i], incr[7][i]); 5013231093Snp sbuf_printf(sb, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n", 5014231093Snp incr[8][i], incr[9][i], incr[10][i], incr[11][i], 5015231093Snp incr[12][i], incr[13][i], incr[14][i], incr[15][i], 5016231093Snp sc->params.a_wnd[i], dec_fac[sc->params.b_wnd[i]]); 5017231093Snp } 5018231093Snp 5019231093Snp rc = sbuf_finish(sb); 5020231093Snp sbuf_delete(sb); 5021231093Snp 5022231093Snp return (rc); 5023231093Snp} 5024231093Snp 5025252495Snpstatic const char *qname[CIM_NUM_IBQ + CIM_NUM_OBQ_T5] = { 5026247434Snp "TP0", "TP1", "ULP", "SGE0", "SGE1", "NC-SI", /* ibq's */ 5027252495Snp "ULP0", "ULP1", "ULP2", "ULP3", "SGE", "NC-SI", /* obq's */ 5028252495Snp "SGE0-RX", "SGE1-RX" /* additional obq's (T5 onwards) */ 5029247434Snp}; 5030247434Snp 5031231093Snpstatic int 5032247434Snpsysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS) 5033247434Snp{ 5034247434Snp struct adapter *sc = arg1; 5035247434Snp struct sbuf *sb; 5036247434Snp int rc, i, n, qid = arg2; 5037247434Snp uint32_t *buf, *p; 5038247434Snp char *qtype; 5039252495Snp u_int cim_num_obq = is_t4(sc) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5; 5040247434Snp 5041252495Snp KASSERT(qid >= 0 && qid < CIM_NUM_IBQ + cim_num_obq, 5042247434Snp ("%s: bad qid %d\n", __func__, qid)); 5043247434Snp 5044247434Snp if (qid < CIM_NUM_IBQ) { 5045247434Snp /* inbound queue */ 5046247434Snp qtype = "IBQ"; 5047247434Snp n = 4 * CIM_IBQ_SIZE; 5048247434Snp buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); 5049247434Snp rc = t4_read_cim_ibq(sc, qid, buf, n); 5050247434Snp } else { 5051247434Snp /* outbound queue */ 5052247434Snp qtype = "OBQ"; 5053247434Snp qid -= CIM_NUM_IBQ; 5054252495Snp n = 4 * cim_num_obq * CIM_OBQ_SIZE; 5055247434Snp buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); 5056247434Snp rc = t4_read_cim_obq(sc, qid, buf, n); 5057247434Snp } 5058247434Snp 5059247434Snp if (rc < 0) { 5060247434Snp rc = -rc; 5061247434Snp goto done; 5062247434Snp } 5063247434Snp n = rc * sizeof(uint32_t); /* rc has # of words actually read */ 5064247434Snp 5065247434Snp rc = sysctl_wire_old_buffer(req, 0); 5066247434Snp if (rc != 0) 5067247434Snp goto done; 5068247434Snp 5069252495Snp sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req); 5070247434Snp if (sb == NULL) { 5071247434Snp rc = ENOMEM; 5072247434Snp goto done; 5073247434Snp } 5074247434Snp 5075247434Snp sbuf_printf(sb, "%s%d %s", qtype , qid, qname[arg2]); 5076247434Snp for (i = 0, p = buf; i < n; i += 16, p += 4) 5077247434Snp sbuf_printf(sb, "\n%#06x: %08x %08x %08x %08x", i, p[0], p[1], 5078247434Snp p[2], p[3]); 5079247434Snp 5080247434Snp rc = sbuf_finish(sb); 5081247434Snp sbuf_delete(sb); 5082247434Snpdone: 5083247434Snp free(buf, M_CXGBE); 5084247434Snp return (rc); 5085247434Snp} 5086247434Snp 5087247434Snpstatic int 5088247434Snpsysctl_cim_la(SYSCTL_HANDLER_ARGS) 5089247434Snp{ 5090247434Snp struct adapter *sc = arg1; 5091247434Snp u_int cfg; 5092247434Snp struct sbuf *sb; 5093247434Snp uint32_t *buf, *p; 5094247434Snp int rc; 5095247434Snp 5096247434Snp rc = -t4_cim_read(sc, A_UP_UP_DBG_LA_CFG, 1, &cfg); 5097247434Snp if (rc != 0) 5098247434Snp return (rc); 5099247434Snp 5100247434Snp rc = sysctl_wire_old_buffer(req, 0); 5101247434Snp if (rc != 0) 5102247434Snp return (rc); 5103247434Snp 5104247434Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5105247434Snp if (sb == NULL) 5106247434Snp return (ENOMEM); 5107247434Snp 5108247434Snp buf = malloc(sc->params.cim_la_size * sizeof(uint32_t), M_CXGBE, 5109247434Snp M_ZERO | M_WAITOK); 5110247434Snp 5111247434Snp rc = -t4_cim_read_la(sc, buf, NULL); 5112247434Snp if (rc != 0) 5113247434Snp goto done; 5114247434Snp 5115247434Snp sbuf_printf(sb, "Status Data PC%s", 5116247434Snp cfg & F_UPDBGLACAPTPCONLY ? "" : 5117247434Snp " LS0Stat LS0Addr LS0Data"); 5118247434Snp 5119247434Snp KASSERT((sc->params.cim_la_size & 7) == 0, 5120247434Snp ("%s: p will walk off the end of buf", __func__)); 5121247434Snp 5122247434Snp for (p = buf; p < &buf[sc->params.cim_la_size]; p += 8) { 5123247434Snp if (cfg & F_UPDBGLACAPTPCONLY) { 5124247434Snp sbuf_printf(sb, "\n %02x %08x %08x", p[5] & 0xff, 5125247434Snp p[6], p[7]); 5126247434Snp sbuf_printf(sb, "\n %02x %02x%06x %02x%06x", 5127247434Snp (p[3] >> 8) & 0xff, p[3] & 0xff, p[4] >> 8, 5128247434Snp p[4] & 0xff, p[5] >> 8); 5129247434Snp sbuf_printf(sb, "\n %02x %x%07x %x%07x", 5130247434Snp (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, 5131247434Snp p[1] & 0xf, p[2] >> 4); 5132247434Snp } else { 5133247434Snp sbuf_printf(sb, 5134247434Snp "\n %02x %x%07x %x%07x %08x %08x " 5135247434Snp "%08x%08x%08x%08x", 5136247434Snp (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, 5137247434Snp p[1] & 0xf, p[2] >> 4, p[2] & 0xf, p[3], p[4], p[5], 5138247434Snp p[6], p[7]); 5139247434Snp } 5140247434Snp } 5141247434Snp 5142247434Snp rc = sbuf_finish(sb); 5143247434Snp sbuf_delete(sb); 5144247434Snpdone: 5145247434Snp free(buf, M_CXGBE); 5146247434Snp return (rc); 5147247434Snp} 5148247434Snp 5149247434Snpstatic int 5150252495Snpsysctl_cim_ma_la(SYSCTL_HANDLER_ARGS) 5151252495Snp{ 5152252495Snp struct adapter *sc = arg1; 5153252495Snp u_int i; 5154252495Snp struct sbuf *sb; 5155252495Snp uint32_t *buf, *p; 5156252495Snp int rc; 5157252495Snp 5158252495Snp rc = sysctl_wire_old_buffer(req, 0); 5159252495Snp if (rc != 0) 5160252495Snp return (rc); 5161252495Snp 5162252495Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5163252495Snp if (sb == NULL) 5164252495Snp return (ENOMEM); 5165252495Snp 5166252495Snp buf = malloc(2 * CIM_MALA_SIZE * 5 * sizeof(uint32_t), M_CXGBE, 5167252495Snp M_ZERO | M_WAITOK); 5168252495Snp 5169252495Snp t4_cim_read_ma_la(sc, buf, buf + 5 * CIM_MALA_SIZE); 5170252495Snp p = buf; 5171252495Snp 5172252495Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) { 5173252495Snp sbuf_printf(sb, "\n%02x%08x%08x%08x%08x", p[4], p[3], p[2], 5174252495Snp p[1], p[0]); 5175252495Snp } 5176252495Snp 5177252495Snp sbuf_printf(sb, "\n\nCnt ID Tag UE Data RDY VLD"); 5178252495Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) { 5179252495Snp sbuf_printf(sb, "\n%3u %2u %x %u %08x%08x %u %u", 5180252495Snp (p[2] >> 10) & 0xff, (p[2] >> 7) & 7, 5181252495Snp (p[2] >> 3) & 0xf, (p[2] >> 2) & 1, 5182252495Snp (p[1] >> 2) | ((p[2] & 3) << 30), 5183252495Snp (p[0] >> 2) | ((p[1] & 3) << 30), (p[0] >> 1) & 1, 5184252495Snp p[0] & 1); 5185252495Snp } 5186252495Snp 5187252495Snp rc = sbuf_finish(sb); 5188252495Snp sbuf_delete(sb); 5189252495Snp free(buf, M_CXGBE); 5190252495Snp return (rc); 5191252495Snp} 5192252495Snp 5193252495Snpstatic int 5194252495Snpsysctl_cim_pif_la(SYSCTL_HANDLER_ARGS) 5195252495Snp{ 5196252495Snp struct adapter *sc = arg1; 5197252495Snp u_int i; 5198252495Snp struct sbuf *sb; 5199252495Snp uint32_t *buf, *p; 5200252495Snp int rc; 5201252495Snp 5202252495Snp rc = sysctl_wire_old_buffer(req, 0); 5203252495Snp if (rc != 0) 5204252495Snp return (rc); 5205252495Snp 5206252495Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5207252495Snp if (sb == NULL) 5208252495Snp return (ENOMEM); 5209252495Snp 5210252495Snp buf = malloc(2 * CIM_PIFLA_SIZE * 6 * sizeof(uint32_t), M_CXGBE, 5211252495Snp M_ZERO | M_WAITOK); 5212252495Snp 5213252495Snp t4_cim_read_pif_la(sc, buf, buf + 6 * CIM_PIFLA_SIZE, NULL, NULL); 5214252495Snp p = buf; 5215252495Snp 5216252495Snp sbuf_printf(sb, "Cntl ID DataBE Addr Data"); 5217252495Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 6) { 5218252495Snp sbuf_printf(sb, "\n %02x %02x %04x %08x %08x%08x%08x%08x", 5219252495Snp (p[5] >> 22) & 0xff, (p[5] >> 16) & 0x3f, p[5] & 0xffff, 5220252495Snp p[4], p[3], p[2], p[1], p[0]); 5221252495Snp } 5222252495Snp 5223252495Snp sbuf_printf(sb, "\n\nCntl ID Data"); 5224252495Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 6) { 5225252495Snp sbuf_printf(sb, "\n %02x %02x %08x%08x%08x%08x", 5226252495Snp (p[4] >> 6) & 0xff, p[4] & 0x3f, p[3], p[2], p[1], p[0]); 5227252495Snp } 5228252495Snp 5229252495Snp rc = sbuf_finish(sb); 5230252495Snp sbuf_delete(sb); 5231252495Snp free(buf, M_CXGBE); 5232252495Snp return (rc); 5233252495Snp} 5234252495Snp 5235252495Snpstatic int 5236247434Snpsysctl_cim_qcfg(SYSCTL_HANDLER_ARGS) 5237247434Snp{ 5238247434Snp struct adapter *sc = arg1; 5239247434Snp struct sbuf *sb; 5240247434Snp int rc, i; 5241252495Snp uint16_t base[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; 5242252495Snp uint16_t size[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; 5243247434Snp uint16_t thres[CIM_NUM_IBQ]; 5244252495Snp uint32_t obq_wr[2 * CIM_NUM_OBQ_T5], *wr = obq_wr; 5245252495Snp uint32_t stat[4 * (CIM_NUM_IBQ + CIM_NUM_OBQ_T5)], *p = stat; 5246252495Snp u_int cim_num_obq, ibq_rdaddr, obq_rdaddr, nq; 5247247434Snp 5248252495Snp if (is_t4(sc)) { 5249252495Snp cim_num_obq = CIM_NUM_OBQ; 5250252495Snp ibq_rdaddr = A_UP_IBQ_0_RDADDR; 5251252495Snp obq_rdaddr = A_UP_OBQ_0_REALADDR; 5252252495Snp } else { 5253252495Snp cim_num_obq = CIM_NUM_OBQ_T5; 5254252495Snp ibq_rdaddr = A_UP_IBQ_0_SHADOW_RDADDR; 5255252495Snp obq_rdaddr = A_UP_OBQ_0_SHADOW_REALADDR; 5256252495Snp } 5257252495Snp nq = CIM_NUM_IBQ + cim_num_obq; 5258252495Snp 5259252495Snp rc = -t4_cim_read(sc, ibq_rdaddr, 4 * nq, stat); 5260247434Snp if (rc == 0) 5261252495Snp rc = -t4_cim_read(sc, obq_rdaddr, 2 * cim_num_obq, obq_wr); 5262247434Snp if (rc != 0) 5263247434Snp return (rc); 5264247434Snp 5265247434Snp t4_read_cimq_cfg(sc, base, size, thres); 5266247434Snp 5267247434Snp rc = sysctl_wire_old_buffer(req, 0); 5268247434Snp if (rc != 0) 5269247434Snp return (rc); 5270247434Snp 5271252495Snp sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req); 5272247434Snp if (sb == NULL) 5273247434Snp return (ENOMEM); 5274247434Snp 5275247434Snp sbuf_printf(sb, "Queue Base Size Thres RdPtr WrPtr SOP EOP Avail"); 5276247434Snp 5277247434Snp for (i = 0; i < CIM_NUM_IBQ; i++, p += 4) 5278252495Snp sbuf_printf(sb, "\n%7s %5x %5u %5u %6x %4x %4u %4u %5u", 5279247434Snp qname[i], base[i], size[i], thres[i], G_IBQRDADDR(p[0]), 5280247434Snp G_IBQWRADDR(p[1]), G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), 5281247434Snp G_QUEREMFLITS(p[2]) * 16); 5282252495Snp for ( ; i < nq; i++, p += 4, wr += 2) 5283252495Snp sbuf_printf(sb, "\n%7s %5x %5u %12x %4x %4u %4u %5u", qname[i], 5284247434Snp base[i], size[i], G_QUERDADDR(p[0]) & 0x3fff, 5285247434Snp wr[0] - base[i], G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), 5286247434Snp G_QUEREMFLITS(p[2]) * 16); 5287247434Snp 5288247434Snp rc = sbuf_finish(sb); 5289247434Snp sbuf_delete(sb); 5290247434Snp 5291247434Snp return (rc); 5292247434Snp} 5293247434Snp 5294247434Snpstatic int 5295231093Snpsysctl_cpl_stats(SYSCTL_HANDLER_ARGS) 5296231093Snp{ 5297231093Snp struct adapter *sc = arg1; 5298231093Snp struct sbuf *sb; 5299231093Snp int rc; 5300231093Snp struct tp_cpl_stats stats; 5301231093Snp 5302231093Snp rc = sysctl_wire_old_buffer(req, 0); 5303231093Snp if (rc != 0) 5304231093Snp return (rc); 5305231093Snp 5306231093Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5307231093Snp if (sb == NULL) 5308231093Snp return (ENOMEM); 5309231093Snp 5310231093Snp t4_tp_get_cpl_stats(sc, &stats); 5311231093Snp 5312231093Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 5313231093Snp "channel 3\n"); 5314231093Snp sbuf_printf(sb, "CPL requests: %10u %10u %10u %10u\n", 5315231093Snp stats.req[0], stats.req[1], stats.req[2], stats.req[3]); 5316231093Snp sbuf_printf(sb, "CPL responses: %10u %10u %10u %10u", 5317231093Snp stats.rsp[0], stats.rsp[1], stats.rsp[2], stats.rsp[3]); 5318231093Snp 5319231093Snp rc = sbuf_finish(sb); 5320231093Snp sbuf_delete(sb); 5321231093Snp 5322231093Snp return (rc); 5323231093Snp} 5324231093Snp 5325231093Snpstatic int 5326231093Snpsysctl_ddp_stats(SYSCTL_HANDLER_ARGS) 5327231093Snp{ 5328231093Snp struct adapter *sc = arg1; 5329231093Snp struct sbuf *sb; 5330231093Snp int rc; 5331231093Snp struct tp_usm_stats stats; 5332231093Snp 5333231093Snp rc = sysctl_wire_old_buffer(req, 0); 5334231093Snp if (rc != 0) 5335231093Snp return(rc); 5336231093Snp 5337231093Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5338231093Snp if (sb == NULL) 5339231093Snp return (ENOMEM); 5340231093Snp 5341231093Snp t4_get_usm_stats(sc, &stats); 5342231093Snp 5343231093Snp sbuf_printf(sb, "Frames: %u\n", stats.frames); 5344231093Snp sbuf_printf(sb, "Octets: %ju\n", stats.octets); 5345231093Snp sbuf_printf(sb, "Drops: %u", stats.drops); 5346231093Snp 5347231093Snp rc = sbuf_finish(sb); 5348231093Snp sbuf_delete(sb); 5349231093Snp 5350231093Snp return (rc); 5351231093Snp} 5352231093Snp 5353222551Snpconst char *devlog_level_strings[] = { 5354222551Snp [FW_DEVLOG_LEVEL_EMERG] = "EMERG", 5355222551Snp [FW_DEVLOG_LEVEL_CRIT] = "CRIT", 5356222551Snp [FW_DEVLOG_LEVEL_ERR] = "ERR", 5357222551Snp [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", 5358222551Snp [FW_DEVLOG_LEVEL_INFO] = "INFO", 5359222551Snp [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" 5360222551Snp}; 5361222551Snp 5362222551Snpconst char *devlog_facility_strings[] = { 5363222551Snp [FW_DEVLOG_FACILITY_CORE] = "CORE", 5364222551Snp [FW_DEVLOG_FACILITY_SCHED] = "SCHED", 5365222551Snp [FW_DEVLOG_FACILITY_TIMER] = "TIMER", 5366222551Snp [FW_DEVLOG_FACILITY_RES] = "RES", 5367222551Snp [FW_DEVLOG_FACILITY_HW] = "HW", 5368222551Snp [FW_DEVLOG_FACILITY_FLR] = "FLR", 5369222551Snp [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", 5370222551Snp [FW_DEVLOG_FACILITY_PHY] = "PHY", 5371222551Snp [FW_DEVLOG_FACILITY_MAC] = "MAC", 5372222551Snp [FW_DEVLOG_FACILITY_PORT] = "PORT", 5373222551Snp [FW_DEVLOG_FACILITY_VI] = "VI", 5374222551Snp [FW_DEVLOG_FACILITY_FILTER] = "FILTER", 5375222551Snp [FW_DEVLOG_FACILITY_ACL] = "ACL", 5376222551Snp [FW_DEVLOG_FACILITY_TM] = "TM", 5377222551Snp [FW_DEVLOG_FACILITY_QFC] = "QFC", 5378222551Snp [FW_DEVLOG_FACILITY_DCB] = "DCB", 5379222551Snp [FW_DEVLOG_FACILITY_ETH] = "ETH", 5380222551Snp [FW_DEVLOG_FACILITY_OFLD] = "OFLD", 5381222551Snp [FW_DEVLOG_FACILITY_RI] = "RI", 5382222551Snp [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", 5383222551Snp [FW_DEVLOG_FACILITY_FCOE] = "FCOE", 5384222551Snp [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", 5385222551Snp [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE" 5386222551Snp}; 5387222551Snp 5388222551Snpstatic int 5389222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS) 5390222551Snp{ 5391222551Snp struct adapter *sc = arg1; 5392222551Snp struct devlog_params *dparams = &sc->params.devlog; 5393222551Snp struct fw_devlog_e *buf, *e; 5394265483Snp int i, j, rc, nentries, first = 0, m; 5395222551Snp struct sbuf *sb; 5396222551Snp uint64_t ftstamp = UINT64_MAX; 5397222551Snp 5398252495Snp if (dparams->start == 0) { 5399265483Snp dparams->memtype = FW_MEMTYPE_EDC0; 5400252495Snp dparams->start = 0x84000; 5401252495Snp dparams->size = 32768; 5402252495Snp } 5403222551Snp 5404222551Snp nentries = dparams->size / sizeof(struct fw_devlog_e); 5405222551Snp 5406222551Snp buf = malloc(dparams->size, M_CXGBE, M_NOWAIT); 5407222551Snp if (buf == NULL) 5408222551Snp return (ENOMEM); 5409222551Snp 5410265483Snp m = fwmtype_to_hwmtype(dparams->memtype); 5411265483Snp rc = -t4_mem_read(sc, m, dparams->start, dparams->size, (void *)buf); 5412222551Snp if (rc != 0) 5413222551Snp goto done; 5414222551Snp 5415222551Snp for (i = 0; i < nentries; i++) { 5416222551Snp e = &buf[i]; 5417222551Snp 5418222551Snp if (e->timestamp == 0) 5419222551Snp break; /* end */ 5420222551Snp 5421222551Snp e->timestamp = be64toh(e->timestamp); 5422222551Snp e->seqno = be32toh(e->seqno); 5423222551Snp for (j = 0; j < 8; j++) 5424222551Snp e->params[j] = be32toh(e->params[j]); 5425222551Snp 5426222551Snp if (e->timestamp < ftstamp) { 5427222551Snp ftstamp = e->timestamp; 5428222551Snp first = i; 5429222551Snp } 5430222551Snp } 5431222551Snp 5432222551Snp if (buf[first].timestamp == 0) 5433222551Snp goto done; /* nothing in the log */ 5434222551Snp 5435222551Snp rc = sysctl_wire_old_buffer(req, 0); 5436222551Snp if (rc != 0) 5437222551Snp goto done; 5438222551Snp 5439222551Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5440231093Snp if (sb == NULL) { 5441231093Snp rc = ENOMEM; 5442231093Snp goto done; 5443231093Snp } 5444231093Snp sbuf_printf(sb, "%10s %15s %8s %8s %s\n", 5445222551Snp "Seq#", "Tstamp", "Level", "Facility", "Message"); 5446222551Snp 5447222551Snp i = first; 5448222551Snp do { 5449222551Snp e = &buf[i]; 5450222551Snp if (e->timestamp == 0) 5451222551Snp break; /* end */ 5452222551Snp 5453222551Snp sbuf_printf(sb, "%10d %15ju %8s %8s ", 5454222551Snp e->seqno, e->timestamp, 5455241467Snp (e->level < nitems(devlog_level_strings) ? 5456222551Snp devlog_level_strings[e->level] : "UNKNOWN"), 5457241467Snp (e->facility < nitems(devlog_facility_strings) ? 5458222551Snp devlog_facility_strings[e->facility] : "UNKNOWN")); 5459222551Snp sbuf_printf(sb, e->fmt, e->params[0], e->params[1], 5460222551Snp e->params[2], e->params[3], e->params[4], 5461222551Snp e->params[5], e->params[6], e->params[7]); 5462222551Snp 5463222551Snp if (++i == nentries) 5464222551Snp i = 0; 5465222551Snp } while (i != first); 5466222551Snp 5467222551Snp rc = sbuf_finish(sb); 5468222551Snp sbuf_delete(sb); 5469222551Snpdone: 5470222551Snp free(buf, M_CXGBE); 5471222551Snp return (rc); 5472222551Snp} 5473222551Snp 5474231093Snpstatic int 5475231093Snpsysctl_fcoe_stats(SYSCTL_HANDLER_ARGS) 5476231093Snp{ 5477231093Snp struct adapter *sc = arg1; 5478231093Snp struct sbuf *sb; 5479231093Snp int rc; 5480231093Snp struct tp_fcoe_stats stats[4]; 5481231093Snp 5482231093Snp rc = sysctl_wire_old_buffer(req, 0); 5483231093Snp if (rc != 0) 5484231093Snp return (rc); 5485231093Snp 5486231093Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5487231093Snp if (sb == NULL) 5488231093Snp return (ENOMEM); 5489231093Snp 5490231093Snp t4_get_fcoe_stats(sc, 0, &stats[0]); 5491231093Snp t4_get_fcoe_stats(sc, 1, &stats[1]); 5492231093Snp t4_get_fcoe_stats(sc, 2, &stats[2]); 5493231093Snp t4_get_fcoe_stats(sc, 3, &stats[3]); 5494231093Snp 5495231093Snp sbuf_printf(sb, " channel 0 channel 1 " 5496231093Snp "channel 2 channel 3\n"); 5497231093Snp sbuf_printf(sb, "octetsDDP: %16ju %16ju %16ju %16ju\n", 5498231093Snp stats[0].octetsDDP, stats[1].octetsDDP, stats[2].octetsDDP, 5499231093Snp stats[3].octetsDDP); 5500231093Snp sbuf_printf(sb, "framesDDP: %16u %16u %16u %16u\n", stats[0].framesDDP, 5501231093Snp stats[1].framesDDP, stats[2].framesDDP, stats[3].framesDDP); 5502231093Snp sbuf_printf(sb, "framesDrop: %16u %16u %16u %16u", 5503231093Snp stats[0].framesDrop, stats[1].framesDrop, stats[2].framesDrop, 5504231093Snp stats[3].framesDrop); 5505231093Snp 5506231093Snp rc = sbuf_finish(sb); 5507231093Snp sbuf_delete(sb); 5508231093Snp 5509231093Snp return (rc); 5510231093Snp} 5511231093Snp 5512231093Snpstatic int 5513231093Snpsysctl_hw_sched(SYSCTL_HANDLER_ARGS) 5514231093Snp{ 5515231093Snp struct adapter *sc = arg1; 5516231093Snp struct sbuf *sb; 5517231093Snp int rc, i; 5518231093Snp unsigned int map, kbps, ipg, mode; 5519231093Snp unsigned int pace_tab[NTX_SCHED]; 5520231093Snp 5521231093Snp rc = sysctl_wire_old_buffer(req, 0); 5522231093Snp if (rc != 0) 5523231093Snp return (rc); 5524231093Snp 5525231093Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5526231093Snp if (sb == NULL) 5527231093Snp return (ENOMEM); 5528231093Snp 5529231093Snp map = t4_read_reg(sc, A_TP_TX_MOD_QUEUE_REQ_MAP); 5530231093Snp mode = G_TIMERMODE(t4_read_reg(sc, A_TP_MOD_CONFIG)); 5531231093Snp t4_read_pace_tbl(sc, pace_tab); 5532231093Snp 5533231093Snp sbuf_printf(sb, "Scheduler Mode Channel Rate (Kbps) " 5534231093Snp "Class IPG (0.1 ns) Flow IPG (us)"); 5535231093Snp 5536231093Snp for (i = 0; i < NTX_SCHED; ++i, map >>= 2) { 5537231093Snp t4_get_tx_sched(sc, i, &kbps, &ipg); 5538231093Snp sbuf_printf(sb, "\n %u %-5s %u ", i, 5539231093Snp (mode & (1 << i)) ? "flow" : "class", map & 3); 5540231093Snp if (kbps) 5541231093Snp sbuf_printf(sb, "%9u ", kbps); 5542231093Snp else 5543231093Snp sbuf_printf(sb, " disabled "); 5544231093Snp 5545231093Snp if (ipg) 5546231093Snp sbuf_printf(sb, "%13u ", ipg); 5547231093Snp else 5548231093Snp sbuf_printf(sb, " disabled "); 5549231093Snp 5550231093Snp if (pace_tab[i]) 5551231093Snp sbuf_printf(sb, "%10u", pace_tab[i]); 5552231093Snp else 5553231093Snp sbuf_printf(sb, " disabled"); 5554231093Snp } 5555231093Snp 5556231093Snp rc = sbuf_finish(sb); 5557231093Snp sbuf_delete(sb); 5558231093Snp 5559231093Snp return (rc); 5560231093Snp} 5561231093Snp 5562231093Snpstatic int 5563231093Snpsysctl_lb_stats(SYSCTL_HANDLER_ARGS) 5564231093Snp{ 5565231093Snp struct adapter *sc = arg1; 5566231093Snp struct sbuf *sb; 5567231093Snp int rc, i, j; 5568231093Snp uint64_t *p0, *p1; 5569231093Snp struct lb_port_stats s[2]; 5570231093Snp static const char *stat_name[] = { 5571231093Snp "OctetsOK:", "FramesOK:", "BcastFrames:", "McastFrames:", 5572231093Snp "UcastFrames:", "ErrorFrames:", "Frames64:", "Frames65To127:", 5573231093Snp "Frames128To255:", "Frames256To511:", "Frames512To1023:", 5574231093Snp "Frames1024To1518:", "Frames1519ToMax:", "FramesDropped:", 5575231093Snp "BG0FramesDropped:", "BG1FramesDropped:", "BG2FramesDropped:", 5576231093Snp "BG3FramesDropped:", "BG0FramesTrunc:", "BG1FramesTrunc:", 5577231093Snp "BG2FramesTrunc:", "BG3FramesTrunc:" 5578231093Snp }; 5579231093Snp 5580231093Snp rc = sysctl_wire_old_buffer(req, 0); 5581231093Snp if (rc != 0) 5582231093Snp return (rc); 5583231093Snp 5584231093Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5585231093Snp if (sb == NULL) 5586231093Snp return (ENOMEM); 5587231093Snp 5588231093Snp memset(s, 0, sizeof(s)); 5589231093Snp 5590231093Snp for (i = 0; i < 4; i += 2) { 5591231093Snp t4_get_lb_stats(sc, i, &s[0]); 5592231093Snp t4_get_lb_stats(sc, i + 1, &s[1]); 5593231093Snp 5594231093Snp p0 = &s[0].octets; 5595231093Snp p1 = &s[1].octets; 5596231093Snp sbuf_printf(sb, "%s Loopback %u" 5597231093Snp " Loopback %u", i == 0 ? "" : "\n", i, i + 1); 5598231093Snp 5599241467Snp for (j = 0; j < nitems(stat_name); j++) 5600231093Snp sbuf_printf(sb, "\n%-17s %20ju %20ju", stat_name[j], 5601231093Snp *p0++, *p1++); 5602231093Snp } 5603231093Snp 5604231093Snp rc = sbuf_finish(sb); 5605231093Snp sbuf_delete(sb); 5606231093Snp 5607231093Snp return (rc); 5608231093Snp} 5609231093Snp 5610265478Snpstatic int 5611265478Snpsysctl_linkdnrc(SYSCTL_HANDLER_ARGS) 5612265478Snp{ 5613265478Snp int rc = 0; 5614265478Snp struct port_info *pi = arg1; 5615265478Snp struct sbuf *sb; 5616265478Snp static const char *linkdnreasons[] = { 5617265478Snp "non-specific", "remote fault", "autoneg failed", "reserved3", 5618265478Snp "PHY overheated", "unknown", "rx los", "reserved7" 5619265478Snp }; 5620265478Snp 5621265478Snp rc = sysctl_wire_old_buffer(req, 0); 5622265478Snp if (rc != 0) 5623265478Snp return(rc); 5624265478Snp sb = sbuf_new_for_sysctl(NULL, NULL, 64, req); 5625265478Snp if (sb == NULL) 5626265478Snp return (ENOMEM); 5627265478Snp 5628265478Snp if (pi->linkdnrc < 0) 5629265478Snp sbuf_printf(sb, "n/a"); 5630265478Snp else if (pi->linkdnrc < nitems(linkdnreasons)) 5631265478Snp sbuf_printf(sb, "%s", linkdnreasons[pi->linkdnrc]); 5632265478Snp else 5633265478Snp sbuf_printf(sb, "%d", pi->linkdnrc); 5634265478Snp 5635265478Snp rc = sbuf_finish(sb); 5636265478Snp sbuf_delete(sb); 5637265478Snp 5638265478Snp return (rc); 5639265478Snp} 5640265478Snp 5641231093Snpstruct mem_desc { 5642231093Snp unsigned int base; 5643231093Snp unsigned int limit; 5644231093Snp unsigned int idx; 5645231093Snp}; 5646231093Snp 5647231093Snpstatic int 5648231093Snpmem_desc_cmp(const void *a, const void *b) 5649231093Snp{ 5650231093Snp return ((const struct mem_desc *)a)->base - 5651231093Snp ((const struct mem_desc *)b)->base; 5652231093Snp} 5653231093Snp 5654231093Snpstatic void 5655231093Snpmem_region_show(struct sbuf *sb, const char *name, unsigned int from, 5656231093Snp unsigned int to) 5657231093Snp{ 5658231093Snp unsigned int size; 5659231093Snp 5660231093Snp size = to - from + 1; 5661231093Snp if (size == 0) 5662231093Snp return; 5663231093Snp 5664231093Snp /* XXX: need humanize_number(3) in libkern for a more readable 'size' */ 5665231093Snp sbuf_printf(sb, "%-15s %#x-%#x [%u]\n", name, from, to, size); 5666231093Snp} 5667231093Snp 5668231093Snpstatic int 5669231093Snpsysctl_meminfo(SYSCTL_HANDLER_ARGS) 5670231093Snp{ 5671231093Snp struct adapter *sc = arg1; 5672231093Snp struct sbuf *sb; 5673231093Snp int rc, i, n; 5674252495Snp uint32_t lo, hi, used, alloc; 5675252495Snp static const char *memory[] = {"EDC0:", "EDC1:", "MC:", "MC0:", "MC1:"}; 5676231093Snp static const char *region[] = { 5677231093Snp "DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:", 5678231093Snp "Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:", 5679231093Snp "Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:", 5680231093Snp "TDDP region:", "TPT region:", "STAG region:", "RQ region:", 5681252495Snp "RQUDP region:", "PBL region:", "TXPBL region:", 5682252495Snp "DBVFIFO region:", "ULPRX state:", "ULPTX state:", 5683252495Snp "On-chip queues:" 5684231093Snp }; 5685252495Snp struct mem_desc avail[4]; 5686241467Snp struct mem_desc mem[nitems(region) + 3]; /* up to 3 holes */ 5687231093Snp struct mem_desc *md = mem; 5688231093Snp 5689231093Snp rc = sysctl_wire_old_buffer(req, 0); 5690231093Snp if (rc != 0) 5691231093Snp return (rc); 5692231093Snp 5693231093Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5694231093Snp if (sb == NULL) 5695231093Snp return (ENOMEM); 5696231093Snp 5697241467Snp for (i = 0; i < nitems(mem); i++) { 5698231093Snp mem[i].limit = 0; 5699231093Snp mem[i].idx = i; 5700231093Snp } 5701231093Snp 5702231093Snp /* Find and sort the populated memory ranges */ 5703231093Snp i = 0; 5704231093Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 5705231093Snp if (lo & F_EDRAM0_ENABLE) { 5706231093Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 5707231093Snp avail[i].base = G_EDRAM0_BASE(hi) << 20; 5708231093Snp avail[i].limit = avail[i].base + (G_EDRAM0_SIZE(hi) << 20); 5709231093Snp avail[i].idx = 0; 5710231093Snp i++; 5711231093Snp } 5712231093Snp if (lo & F_EDRAM1_ENABLE) { 5713231093Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 5714231093Snp avail[i].base = G_EDRAM1_BASE(hi) << 20; 5715231093Snp avail[i].limit = avail[i].base + (G_EDRAM1_SIZE(hi) << 20); 5716231093Snp avail[i].idx = 1; 5717231093Snp i++; 5718231093Snp } 5719231093Snp if (lo & F_EXT_MEM_ENABLE) { 5720231093Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 5721231093Snp avail[i].base = G_EXT_MEM_BASE(hi) << 20; 5722252495Snp avail[i].limit = avail[i].base + 5723252495Snp (G_EXT_MEM_SIZE(hi) << 20); 5724252495Snp avail[i].idx = is_t4(sc) ? 2 : 3; /* Call it MC for T4 */ 5725231093Snp i++; 5726231093Snp } 5727252495Snp if (!is_t4(sc) && lo & F_EXT_MEM1_ENABLE) { 5728252495Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 5729252495Snp avail[i].base = G_EXT_MEM1_BASE(hi) << 20; 5730252495Snp avail[i].limit = avail[i].base + 5731252495Snp (G_EXT_MEM1_SIZE(hi) << 20); 5732252495Snp avail[i].idx = 4; 5733252495Snp i++; 5734252495Snp } 5735231093Snp if (!i) /* no memory available */ 5736231093Snp return 0; 5737231093Snp qsort(avail, i, sizeof(struct mem_desc), mem_desc_cmp); 5738231093Snp 5739231093Snp (md++)->base = t4_read_reg(sc, A_SGE_DBQ_CTXT_BADDR); 5740231093Snp (md++)->base = t4_read_reg(sc, A_SGE_IMSG_CTXT_BADDR); 5741231093Snp (md++)->base = t4_read_reg(sc, A_SGE_FLM_CACHE_BADDR); 5742231093Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 5743231093Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_BASE); 5744231093Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TIMER_BASE); 5745231093Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_RX_FLST_BASE); 5746231093Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_TX_FLST_BASE); 5747231093Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_PS_FLST_BASE); 5748231093Snp 5749231093Snp /* the next few have explicit upper bounds */ 5750231093Snp md->base = t4_read_reg(sc, A_TP_PMM_TX_BASE); 5751231093Snp md->limit = md->base - 1 + 5752231093Snp t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE) * 5753231093Snp G_PMTXMAXPAGE(t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE)); 5754231093Snp md++; 5755231093Snp 5756231093Snp md->base = t4_read_reg(sc, A_TP_PMM_RX_BASE); 5757231093Snp md->limit = md->base - 1 + 5758231093Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) * 5759231093Snp G_PMRXMAXPAGE(t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE)); 5760231093Snp md++; 5761231093Snp 5762231093Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 5763231093Snp hi = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4; 5764231093Snp md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE); 5765231093Snp md->limit = (sc->tids.ntids - hi) * 16 + md->base - 1; 5766231093Snp } else { 5767231093Snp md->base = 0; 5768241467Snp md->idx = nitems(region); /* hide it */ 5769231093Snp } 5770231093Snp md++; 5771231093Snp 5772231093Snp#define ulp_region(reg) \ 5773231093Snp md->base = t4_read_reg(sc, A_ULP_ ## reg ## _LLIMIT);\ 5774231093Snp (md++)->limit = t4_read_reg(sc, A_ULP_ ## reg ## _ULIMIT) 5775231093Snp 5776231093Snp ulp_region(RX_ISCSI); 5777231093Snp ulp_region(RX_TDDP); 5778231093Snp ulp_region(TX_TPT); 5779231093Snp ulp_region(RX_STAG); 5780231093Snp ulp_region(RX_RQ); 5781231093Snp ulp_region(RX_RQUDP); 5782231093Snp ulp_region(RX_PBL); 5783231093Snp ulp_region(TX_PBL); 5784231093Snp#undef ulp_region 5785231093Snp 5786252495Snp md->base = 0; 5787252495Snp md->idx = nitems(region); 5788252495Snp if (!is_t4(sc) && t4_read_reg(sc, A_SGE_CONTROL2) & F_VFIFO_ENABLE) { 5789252495Snp md->base = G_BASEADDR(t4_read_reg(sc, A_SGE_DBVFIFO_BADDR)); 5790252495Snp md->limit = md->base + (G_DBVFIFO_SIZE((t4_read_reg(sc, 5791252495Snp A_SGE_DBVFIFO_SIZE))) << 2) - 1; 5792252495Snp } 5793252495Snp md++; 5794252495Snp 5795231093Snp md->base = t4_read_reg(sc, A_ULP_RX_CTX_BASE); 5796231093Snp md->limit = md->base + sc->tids.ntids - 1; 5797231093Snp md++; 5798231093Snp md->base = t4_read_reg(sc, A_ULP_TX_ERR_TABLE_BASE); 5799231093Snp md->limit = md->base + sc->tids.ntids - 1; 5800231093Snp md++; 5801231093Snp 5802231093Snp md->base = sc->vres.ocq.start; 5803231093Snp if (sc->vres.ocq.size) 5804231093Snp md->limit = md->base + sc->vres.ocq.size - 1; 5805231093Snp else 5806241467Snp md->idx = nitems(region); /* hide it */ 5807231093Snp md++; 5808231093Snp 5809231093Snp /* add any address-space holes, there can be up to 3 */ 5810231093Snp for (n = 0; n < i - 1; n++) 5811231093Snp if (avail[n].limit < avail[n + 1].base) 5812231093Snp (md++)->base = avail[n].limit; 5813231093Snp if (avail[n].limit) 5814231093Snp (md++)->base = avail[n].limit; 5815231093Snp 5816231093Snp n = md - mem; 5817231093Snp qsort(mem, n, sizeof(struct mem_desc), mem_desc_cmp); 5818231093Snp 5819231093Snp for (lo = 0; lo < i; lo++) 5820231093Snp mem_region_show(sb, memory[avail[lo].idx], avail[lo].base, 5821231093Snp avail[lo].limit - 1); 5822231093Snp 5823231093Snp sbuf_printf(sb, "\n"); 5824231093Snp for (i = 0; i < n; i++) { 5825241467Snp if (mem[i].idx >= nitems(region)) 5826231093Snp continue; /* skip holes */ 5827231093Snp if (!mem[i].limit) 5828231093Snp mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0; 5829231093Snp mem_region_show(sb, region[mem[i].idx], mem[i].base, 5830231093Snp mem[i].limit); 5831231093Snp } 5832231093Snp 5833231093Snp sbuf_printf(sb, "\n"); 5834231093Snp lo = t4_read_reg(sc, A_CIM_SDRAM_BASE_ADDR); 5835231093Snp hi = t4_read_reg(sc, A_CIM_SDRAM_ADDR_SIZE) + lo - 1; 5836231093Snp mem_region_show(sb, "uP RAM:", lo, hi); 5837231093Snp 5838231093Snp lo = t4_read_reg(sc, A_CIM_EXTMEM2_BASE_ADDR); 5839231093Snp hi = t4_read_reg(sc, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1; 5840231093Snp mem_region_show(sb, "uP Extmem2:", lo, hi); 5841231093Snp 5842231093Snp lo = t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE); 5843231093Snp sbuf_printf(sb, "\n%u Rx pages of size %uKiB for %u channels\n", 5844231093Snp G_PMRXMAXPAGE(lo), 5845231093Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) >> 10, 5846231093Snp (lo & F_PMRXNUMCHN) ? 2 : 1); 5847231093Snp 5848231093Snp lo = t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE); 5849231093Snp hi = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE); 5850231093Snp sbuf_printf(sb, "%u Tx pages of size %u%ciB for %u channels\n", 5851231093Snp G_PMTXMAXPAGE(lo), 5852231093Snp hi >= (1 << 20) ? (hi >> 20) : (hi >> 10), 5853231093Snp hi >= (1 << 20) ? 'M' : 'K', 1 << G_PMTXNUMCHN(lo)); 5854231093Snp sbuf_printf(sb, "%u p-structs\n", 5855231093Snp t4_read_reg(sc, A_TP_CMM_MM_MAX_PSTRUCT)); 5856231093Snp 5857231093Snp for (i = 0; i < 4; i++) { 5858231093Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV0 + i * 4); 5859252495Snp if (is_t4(sc)) { 5860252495Snp used = G_USED(lo); 5861252495Snp alloc = G_ALLOC(lo); 5862252495Snp } else { 5863252495Snp used = G_T5_USED(lo); 5864252495Snp alloc = G_T5_ALLOC(lo); 5865252495Snp } 5866231093Snp sbuf_printf(sb, "\nPort %d using %u pages out of %u allocated", 5867252495Snp i, used, alloc); 5868231093Snp } 5869231093Snp for (i = 0; i < 4; i++) { 5870231093Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV4 + i * 4); 5871252495Snp if (is_t4(sc)) { 5872252495Snp used = G_USED(lo); 5873252495Snp alloc = G_ALLOC(lo); 5874252495Snp } else { 5875252495Snp used = G_T5_USED(lo); 5876252495Snp alloc = G_T5_ALLOC(lo); 5877252495Snp } 5878231093Snp sbuf_printf(sb, 5879231093Snp "\nLoopback %d using %u pages out of %u allocated", 5880252495Snp i, used, alloc); 5881231093Snp } 5882231093Snp 5883231093Snp rc = sbuf_finish(sb); 5884231093Snp sbuf_delete(sb); 5885231093Snp 5886231093Snp return (rc); 5887231093Snp} 5888231093Snp 5889252495Snpstatic inline void 5890252495Snptcamxy2valmask(uint64_t x, uint64_t y, uint8_t *addr, uint64_t *mask) 5891252495Snp{ 5892252495Snp *mask = x | y; 5893252495Snp y = htobe64(y); 5894252495Snp memcpy(addr, (char *)&y + 2, ETHER_ADDR_LEN); 5895252495Snp} 5896252495Snp 5897231093Snpstatic int 5898252495Snpsysctl_mps_tcam(SYSCTL_HANDLER_ARGS) 5899252495Snp{ 5900252495Snp struct adapter *sc = arg1; 5901252495Snp struct sbuf *sb; 5902252495Snp int rc, i, n; 5903252495Snp 5904252495Snp rc = sysctl_wire_old_buffer(req, 0); 5905252495Snp if (rc != 0) 5906252495Snp return (rc); 5907252495Snp 5908252495Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5909252495Snp if (sb == NULL) 5910252495Snp return (ENOMEM); 5911252495Snp 5912252495Snp sbuf_printf(sb, 5913252495Snp "Idx Ethernet address Mask Vld Ports PF" 5914252495Snp " VF Replication P0 P1 P2 P3 ML"); 5915252495Snp n = is_t4(sc) ? NUM_MPS_CLS_SRAM_L_INSTANCES : 5916252495Snp NUM_MPS_T5_CLS_SRAM_L_INSTANCES; 5917252495Snp for (i = 0; i < n; i++) { 5918252495Snp uint64_t tcamx, tcamy, mask; 5919252495Snp uint32_t cls_lo, cls_hi; 5920252495Snp uint8_t addr[ETHER_ADDR_LEN]; 5921252495Snp 5922252495Snp tcamy = t4_read_reg64(sc, MPS_CLS_TCAM_Y_L(i)); 5923252495Snp tcamx = t4_read_reg64(sc, MPS_CLS_TCAM_X_L(i)); 5924252495Snp cls_lo = t4_read_reg(sc, MPS_CLS_SRAM_L(i)); 5925252495Snp cls_hi = t4_read_reg(sc, MPS_CLS_SRAM_H(i)); 5926252495Snp 5927252495Snp if (tcamx & tcamy) 5928252495Snp continue; 5929252495Snp 5930252495Snp tcamxy2valmask(tcamx, tcamy, addr, &mask); 5931252495Snp sbuf_printf(sb, "\n%3u %02x:%02x:%02x:%02x:%02x:%02x %012jx" 5932252495Snp " %c %#x%4u%4d", i, addr[0], addr[1], addr[2], 5933252495Snp addr[3], addr[4], addr[5], (uintmax_t)mask, 5934252495Snp (cls_lo & F_SRAM_VLD) ? 'Y' : 'N', 5935252495Snp G_PORTMAP(cls_hi), G_PF(cls_lo), 5936252495Snp (cls_lo & F_VF_VALID) ? G_VF(cls_lo) : -1); 5937252495Snp 5938252495Snp if (cls_lo & F_REPLICATE) { 5939252495Snp struct fw_ldst_cmd ldst_cmd; 5940252495Snp 5941252495Snp memset(&ldst_cmd, 0, sizeof(ldst_cmd)); 5942252495Snp ldst_cmd.op_to_addrspace = 5943252495Snp htobe32(V_FW_CMD_OP(FW_LDST_CMD) | 5944252495Snp F_FW_CMD_REQUEST | F_FW_CMD_READ | 5945252495Snp V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MPS)); 5946252495Snp ldst_cmd.cycles_to_len16 = htobe32(FW_LEN16(ldst_cmd)); 5947252495Snp ldst_cmd.u.mps.fid_ctl = 5948252495Snp htobe16(V_FW_LDST_CMD_FID(FW_LDST_MPS_RPLC) | 5949252495Snp V_FW_LDST_CMD_CTL(i)); 5950252495Snp 5951252495Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, 5952252495Snp "t4mps"); 5953252495Snp if (rc) 5954252495Snp break; 5955252495Snp rc = -t4_wr_mbox(sc, sc->mbox, &ldst_cmd, 5956252495Snp sizeof(ldst_cmd), &ldst_cmd); 5957252495Snp end_synchronized_op(sc, 0); 5958252495Snp 5959252495Snp if (rc != 0) { 5960252495Snp sbuf_printf(sb, 5961252495Snp " ------------ error %3u ------------", rc); 5962252495Snp rc = 0; 5963252495Snp } else { 5964252495Snp sbuf_printf(sb, " %08x %08x %08x %08x", 5965252495Snp be32toh(ldst_cmd.u.mps.rplc127_96), 5966252495Snp be32toh(ldst_cmd.u.mps.rplc95_64), 5967252495Snp be32toh(ldst_cmd.u.mps.rplc63_32), 5968252495Snp be32toh(ldst_cmd.u.mps.rplc31_0)); 5969252495Snp } 5970252495Snp } else 5971252495Snp sbuf_printf(sb, "%36s", ""); 5972252495Snp 5973252495Snp sbuf_printf(sb, "%4u%3u%3u%3u %#3x", G_SRAM_PRIO0(cls_lo), 5974252495Snp G_SRAM_PRIO1(cls_lo), G_SRAM_PRIO2(cls_lo), 5975252495Snp G_SRAM_PRIO3(cls_lo), (cls_lo >> S_MULTILISTEN0) & 0xf); 5976252495Snp } 5977252495Snp 5978252495Snp if (rc) 5979252495Snp (void) sbuf_finish(sb); 5980252495Snp else 5981252495Snp rc = sbuf_finish(sb); 5982252495Snp sbuf_delete(sb); 5983252495Snp 5984252495Snp return (rc); 5985252495Snp} 5986252495Snp 5987252495Snpstatic int 5988231093Snpsysctl_path_mtus(SYSCTL_HANDLER_ARGS) 5989231093Snp{ 5990231093Snp struct adapter *sc = arg1; 5991231093Snp struct sbuf *sb; 5992231093Snp int rc; 5993231093Snp uint16_t mtus[NMTUS]; 5994231093Snp 5995231093Snp rc = sysctl_wire_old_buffer(req, 0); 5996231093Snp if (rc != 0) 5997231093Snp return (rc); 5998231093Snp 5999231093Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6000231093Snp if (sb == NULL) 6001231093Snp return (ENOMEM); 6002231093Snp 6003231093Snp t4_read_mtu_tbl(sc, mtus, NULL); 6004231093Snp 6005231093Snp sbuf_printf(sb, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", 6006231093Snp mtus[0], mtus[1], mtus[2], mtus[3], mtus[4], mtus[5], mtus[6], 6007231093Snp mtus[7], mtus[8], mtus[9], mtus[10], mtus[11], mtus[12], mtus[13], 6008231093Snp mtus[14], mtus[15]); 6009231093Snp 6010231093Snp rc = sbuf_finish(sb); 6011231093Snp sbuf_delete(sb); 6012231093Snp 6013231093Snp return (rc); 6014231093Snp} 6015231093Snp 6016231093Snpstatic int 6017231093Snpsysctl_pm_stats(SYSCTL_HANDLER_ARGS) 6018231093Snp{ 6019231093Snp struct adapter *sc = arg1; 6020231093Snp struct sbuf *sb; 6021231093Snp int rc, i; 6022265551Snp uint32_t cnt[PM_NSTATS]; 6023265551Snp uint64_t cyc[PM_NSTATS]; 6024265551Snp static const char *rx_stats[] = { 6025265551Snp "Read:", "Write bypass:", "Write mem:", "Flush:" 6026231093Snp }; 6027265551Snp static const char *tx_stats[] = { 6028265551Snp "Read:", "Write bypass:", "Write mem:", "Bypass + mem:" 6029265551Snp }; 6030231093Snp 6031231093Snp rc = sysctl_wire_old_buffer(req, 0); 6032231093Snp if (rc != 0) 6033231093Snp return (rc); 6034231093Snp 6035231093Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6036231093Snp if (sb == NULL) 6037231093Snp return (ENOMEM); 6038231093Snp 6039265551Snp t4_pmtx_get_stats(sc, cnt, cyc); 6040265551Snp sbuf_printf(sb, " Tx pcmds Tx bytes"); 6041265551Snp for (i = 0; i < ARRAY_SIZE(tx_stats); i++) 6042265551Snp sbuf_printf(sb, "\n%-13s %10u %20ju", tx_stats[i], cnt[i], 6043265551Snp cyc[i]); 6044231093Snp 6045265551Snp t4_pmrx_get_stats(sc, cnt, cyc); 6046265551Snp sbuf_printf(sb, "\n Rx pcmds Rx bytes"); 6047265551Snp for (i = 0; i < ARRAY_SIZE(rx_stats); i++) 6048265551Snp sbuf_printf(sb, "\n%-13s %10u %20ju", rx_stats[i], cnt[i], 6049265551Snp cyc[i]); 6050231093Snp 6051231093Snp rc = sbuf_finish(sb); 6052231093Snp sbuf_delete(sb); 6053231093Snp 6054231093Snp return (rc); 6055231093Snp} 6056231093Snp 6057231093Snpstatic int 6058231093Snpsysctl_rdma_stats(SYSCTL_HANDLER_ARGS) 6059231093Snp{ 6060231093Snp struct adapter *sc = arg1; 6061231093Snp struct sbuf *sb; 6062231093Snp int rc; 6063231093Snp struct tp_rdma_stats stats; 6064231093Snp 6065231093Snp rc = sysctl_wire_old_buffer(req, 0); 6066231093Snp if (rc != 0) 6067231093Snp return (rc); 6068231093Snp 6069231093Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6070231093Snp if (sb == NULL) 6071231093Snp return (ENOMEM); 6072231093Snp 6073231093Snp t4_tp_get_rdma_stats(sc, &stats); 6074231093Snp sbuf_printf(sb, "NoRQEModDefferals: %u\n", stats.rqe_dfr_mod); 6075231093Snp sbuf_printf(sb, "NoRQEPktDefferals: %u", stats.rqe_dfr_pkt); 6076231093Snp 6077231093Snp rc = sbuf_finish(sb); 6078231093Snp sbuf_delete(sb); 6079231093Snp 6080231093Snp return (rc); 6081231093Snp} 6082231093Snp 6083231093Snpstatic int 6084231093Snpsysctl_tcp_stats(SYSCTL_HANDLER_ARGS) 6085231093Snp{ 6086231093Snp struct adapter *sc = arg1; 6087231093Snp struct sbuf *sb; 6088231093Snp int rc; 6089231093Snp struct tp_tcp_stats v4, v6; 6090231093Snp 6091231093Snp rc = sysctl_wire_old_buffer(req, 0); 6092231093Snp if (rc != 0) 6093231093Snp return (rc); 6094231093Snp 6095231093Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6096231093Snp if (sb == NULL) 6097231093Snp return (ENOMEM); 6098231093Snp 6099231093Snp t4_tp_get_tcp_stats(sc, &v4, &v6); 6100231093Snp sbuf_printf(sb, 6101231093Snp " IP IPv6\n"); 6102231093Snp sbuf_printf(sb, "OutRsts: %20u %20u\n", 6103231093Snp v4.tcpOutRsts, v6.tcpOutRsts); 6104231093Snp sbuf_printf(sb, "InSegs: %20ju %20ju\n", 6105231093Snp v4.tcpInSegs, v6.tcpInSegs); 6106231093Snp sbuf_printf(sb, "OutSegs: %20ju %20ju\n", 6107231093Snp v4.tcpOutSegs, v6.tcpOutSegs); 6108231093Snp sbuf_printf(sb, "RetransSegs: %20ju %20ju", 6109231093Snp v4.tcpRetransSegs, v6.tcpRetransSegs); 6110231093Snp 6111231093Snp rc = sbuf_finish(sb); 6112231093Snp sbuf_delete(sb); 6113231093Snp 6114231093Snp return (rc); 6115231093Snp} 6116231093Snp 6117231093Snpstatic int 6118231093Snpsysctl_tids(SYSCTL_HANDLER_ARGS) 6119231093Snp{ 6120231093Snp struct adapter *sc = arg1; 6121231093Snp struct sbuf *sb; 6122231093Snp int rc; 6123231093Snp struct tid_info *t = &sc->tids; 6124231093Snp 6125231093Snp rc = sysctl_wire_old_buffer(req, 0); 6126231093Snp if (rc != 0) 6127231093Snp return (rc); 6128231093Snp 6129231093Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6130231093Snp if (sb == NULL) 6131231093Snp return (ENOMEM); 6132231093Snp 6133231093Snp if (t->natids) { 6134231093Snp sbuf_printf(sb, "ATID range: 0-%u, in use: %u\n", t->natids - 1, 6135231093Snp t->atids_in_use); 6136231093Snp } 6137231093Snp 6138231093Snp if (t->ntids) { 6139231093Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 6140231093Snp uint32_t b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4; 6141231093Snp 6142231093Snp if (b) { 6143231093Snp sbuf_printf(sb, "TID range: 0-%u, %u-%u", b - 1, 6144231093Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 6145231093Snp t->ntids - 1); 6146231093Snp } else { 6147231093Snp sbuf_printf(sb, "TID range: %u-%u", 6148231093Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 6149231093Snp t->ntids - 1); 6150231093Snp } 6151231093Snp } else 6152231093Snp sbuf_printf(sb, "TID range: 0-%u", t->ntids - 1); 6153231093Snp sbuf_printf(sb, ", in use: %u\n", 6154231093Snp atomic_load_acq_int(&t->tids_in_use)); 6155231093Snp } 6156231093Snp 6157231093Snp if (t->nstids) { 6158231093Snp sbuf_printf(sb, "STID range: %u-%u, in use: %u\n", t->stid_base, 6159231093Snp t->stid_base + t->nstids - 1, t->stids_in_use); 6160231093Snp } 6161231093Snp 6162231093Snp if (t->nftids) { 6163231093Snp sbuf_printf(sb, "FTID range: %u-%u\n", t->ftid_base, 6164231093Snp t->ftid_base + t->nftids - 1); 6165231093Snp } 6166231093Snp 6167265553Snp if (t->netids) { 6168265553Snp sbuf_printf(sb, "ETID range: %u-%u\n", t->etid_base, 6169265553Snp t->etid_base + t->netids - 1); 6170265553Snp } 6171265553Snp 6172231093Snp sbuf_printf(sb, "HW TID usage: %u IP users, %u IPv6 users", 6173231093Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV4), 6174231093Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV6)); 6175231093Snp 6176231093Snp rc = sbuf_finish(sb); 6177231093Snp sbuf_delete(sb); 6178231093Snp 6179231093Snp return (rc); 6180231093Snp} 6181231093Snp 6182231093Snpstatic int 6183231093Snpsysctl_tp_err_stats(SYSCTL_HANDLER_ARGS) 6184231093Snp{ 6185231093Snp struct adapter *sc = arg1; 6186231093Snp struct sbuf *sb; 6187231093Snp int rc; 6188231093Snp struct tp_err_stats stats; 6189231093Snp 6190231093Snp rc = sysctl_wire_old_buffer(req, 0); 6191231093Snp if (rc != 0) 6192231093Snp return (rc); 6193231093Snp 6194231093Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6195231093Snp if (sb == NULL) 6196231093Snp return (ENOMEM); 6197231093Snp 6198231093Snp t4_tp_get_err_stats(sc, &stats); 6199231093Snp 6200231093Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 6201231093Snp "channel 3\n"); 6202231093Snp sbuf_printf(sb, "macInErrs: %10u %10u %10u %10u\n", 6203231093Snp stats.macInErrs[0], stats.macInErrs[1], stats.macInErrs[2], 6204231093Snp stats.macInErrs[3]); 6205231093Snp sbuf_printf(sb, "hdrInErrs: %10u %10u %10u %10u\n", 6206231093Snp stats.hdrInErrs[0], stats.hdrInErrs[1], stats.hdrInErrs[2], 6207231093Snp stats.hdrInErrs[3]); 6208231093Snp sbuf_printf(sb, "tcpInErrs: %10u %10u %10u %10u\n", 6209231093Snp stats.tcpInErrs[0], stats.tcpInErrs[1], stats.tcpInErrs[2], 6210231093Snp stats.tcpInErrs[3]); 6211231093Snp sbuf_printf(sb, "tcp6InErrs: %10u %10u %10u %10u\n", 6212231093Snp stats.tcp6InErrs[0], stats.tcp6InErrs[1], stats.tcp6InErrs[2], 6213231093Snp stats.tcp6InErrs[3]); 6214231093Snp sbuf_printf(sb, "tnlCongDrops: %10u %10u %10u %10u\n", 6215231093Snp stats.tnlCongDrops[0], stats.tnlCongDrops[1], stats.tnlCongDrops[2], 6216231093Snp stats.tnlCongDrops[3]); 6217231093Snp sbuf_printf(sb, "tnlTxDrops: %10u %10u %10u %10u\n", 6218231093Snp stats.tnlTxDrops[0], stats.tnlTxDrops[1], stats.tnlTxDrops[2], 6219231093Snp stats.tnlTxDrops[3]); 6220231093Snp sbuf_printf(sb, "ofldVlanDrops: %10u %10u %10u %10u\n", 6221231093Snp stats.ofldVlanDrops[0], stats.ofldVlanDrops[1], 6222231093Snp stats.ofldVlanDrops[2], stats.ofldVlanDrops[3]); 6223231093Snp sbuf_printf(sb, "ofldChanDrops: %10u %10u %10u %10u\n\n", 6224231093Snp stats.ofldChanDrops[0], stats.ofldChanDrops[1], 6225231093Snp stats.ofldChanDrops[2], stats.ofldChanDrops[3]); 6226231093Snp sbuf_printf(sb, "ofldNoNeigh: %u\nofldCongDefer: %u", 6227231093Snp stats.ofldNoNeigh, stats.ofldCongDefer); 6228231093Snp 6229231093Snp rc = sbuf_finish(sb); 6230231093Snp sbuf_delete(sb); 6231231093Snp 6232231093Snp return (rc); 6233231093Snp} 6234231093Snp 6235252495Snpstruct field_desc { 6236252495Snp const char *name; 6237252495Snp u_int start; 6238252495Snp u_int width; 6239252495Snp}; 6240252495Snp 6241252495Snpstatic void 6242252495Snpfield_desc_show(struct sbuf *sb, uint64_t v, const struct field_desc *f) 6243252495Snp{ 6244252495Snp char buf[32]; 6245252495Snp int line_size = 0; 6246252495Snp 6247252495Snp while (f->name) { 6248252495Snp uint64_t mask = (1ULL << f->width) - 1; 6249252495Snp int len = snprintf(buf, sizeof(buf), "%s: %ju", f->name, 6250252495Snp ((uintmax_t)v >> f->start) & mask); 6251252495Snp 6252252495Snp if (line_size + len >= 79) { 6253252495Snp line_size = 8; 6254252495Snp sbuf_printf(sb, "\n "); 6255252495Snp } 6256252495Snp sbuf_printf(sb, "%s ", buf); 6257252495Snp line_size += len + 1; 6258252495Snp f++; 6259252495Snp } 6260252495Snp sbuf_printf(sb, "\n"); 6261252495Snp} 6262252495Snp 6263252495Snpstatic struct field_desc tp_la0[] = { 6264252495Snp { "RcfOpCodeOut", 60, 4 }, 6265252495Snp { "State", 56, 4 }, 6266252495Snp { "WcfState", 52, 4 }, 6267252495Snp { "RcfOpcSrcOut", 50, 2 }, 6268252495Snp { "CRxError", 49, 1 }, 6269252495Snp { "ERxError", 48, 1 }, 6270252495Snp { "SanityFailed", 47, 1 }, 6271252495Snp { "SpuriousMsg", 46, 1 }, 6272252495Snp { "FlushInputMsg", 45, 1 }, 6273252495Snp { "FlushInputCpl", 44, 1 }, 6274252495Snp { "RssUpBit", 43, 1 }, 6275252495Snp { "RssFilterHit", 42, 1 }, 6276252495Snp { "Tid", 32, 10 }, 6277252495Snp { "InitTcb", 31, 1 }, 6278252495Snp { "LineNumber", 24, 7 }, 6279252495Snp { "Emsg", 23, 1 }, 6280252495Snp { "EdataOut", 22, 1 }, 6281252495Snp { "Cmsg", 21, 1 }, 6282252495Snp { "CdataOut", 20, 1 }, 6283252495Snp { "EreadPdu", 19, 1 }, 6284252495Snp { "CreadPdu", 18, 1 }, 6285252495Snp { "TunnelPkt", 17, 1 }, 6286252495Snp { "RcfPeerFin", 16, 1 }, 6287252495Snp { "RcfReasonOut", 12, 4 }, 6288252495Snp { "TxCchannel", 10, 2 }, 6289252495Snp { "RcfTxChannel", 8, 2 }, 6290252495Snp { "RxEchannel", 6, 2 }, 6291252495Snp { "RcfRxChannel", 5, 1 }, 6292252495Snp { "RcfDataOutSrdy", 4, 1 }, 6293252495Snp { "RxDvld", 3, 1 }, 6294252495Snp { "RxOoDvld", 2, 1 }, 6295252495Snp { "RxCongestion", 1, 1 }, 6296252495Snp { "TxCongestion", 0, 1 }, 6297252495Snp { NULL } 6298252495Snp}; 6299252495Snp 6300252495Snpstatic struct field_desc tp_la1[] = { 6301252495Snp { "CplCmdIn", 56, 8 }, 6302252495Snp { "CplCmdOut", 48, 8 }, 6303252495Snp { "ESynOut", 47, 1 }, 6304252495Snp { "EAckOut", 46, 1 }, 6305252495Snp { "EFinOut", 45, 1 }, 6306252495Snp { "ERstOut", 44, 1 }, 6307252495Snp { "SynIn", 43, 1 }, 6308252495Snp { "AckIn", 42, 1 }, 6309252495Snp { "FinIn", 41, 1 }, 6310252495Snp { "RstIn", 40, 1 }, 6311252495Snp { "DataIn", 39, 1 }, 6312252495Snp { "DataInVld", 38, 1 }, 6313252495Snp { "PadIn", 37, 1 }, 6314252495Snp { "RxBufEmpty", 36, 1 }, 6315252495Snp { "RxDdp", 35, 1 }, 6316252495Snp { "RxFbCongestion", 34, 1 }, 6317252495Snp { "TxFbCongestion", 33, 1 }, 6318252495Snp { "TxPktSumSrdy", 32, 1 }, 6319252495Snp { "RcfUlpType", 28, 4 }, 6320252495Snp { "Eread", 27, 1 }, 6321252495Snp { "Ebypass", 26, 1 }, 6322252495Snp { "Esave", 25, 1 }, 6323252495Snp { "Static0", 24, 1 }, 6324252495Snp { "Cread", 23, 1 }, 6325252495Snp { "Cbypass", 22, 1 }, 6326252495Snp { "Csave", 21, 1 }, 6327252495Snp { "CPktOut", 20, 1 }, 6328252495Snp { "RxPagePoolFull", 18, 2 }, 6329252495Snp { "RxLpbkPkt", 17, 1 }, 6330252495Snp { "TxLpbkPkt", 16, 1 }, 6331252495Snp { "RxVfValid", 15, 1 }, 6332252495Snp { "SynLearned", 14, 1 }, 6333252495Snp { "SetDelEntry", 13, 1 }, 6334252495Snp { "SetInvEntry", 12, 1 }, 6335252495Snp { "CpcmdDvld", 11, 1 }, 6336252495Snp { "CpcmdSave", 10, 1 }, 6337252495Snp { "RxPstructsFull", 8, 2 }, 6338252495Snp { "EpcmdDvld", 7, 1 }, 6339252495Snp { "EpcmdFlush", 6, 1 }, 6340252495Snp { "EpcmdTrimPrefix", 5, 1 }, 6341252495Snp { "EpcmdTrimPostfix", 4, 1 }, 6342252495Snp { "ERssIp4Pkt", 3, 1 }, 6343252495Snp { "ERssIp6Pkt", 2, 1 }, 6344252495Snp { "ERssTcpUdpPkt", 1, 1 }, 6345252495Snp { "ERssFceFipPkt", 0, 1 }, 6346252495Snp { NULL } 6347252495Snp}; 6348252495Snp 6349252495Snpstatic struct field_desc tp_la2[] = { 6350252495Snp { "CplCmdIn", 56, 8 }, 6351252495Snp { "MpsVfVld", 55, 1 }, 6352252495Snp { "MpsPf", 52, 3 }, 6353252495Snp { "MpsVf", 44, 8 }, 6354252495Snp { "SynIn", 43, 1 }, 6355252495Snp { "AckIn", 42, 1 }, 6356252495Snp { "FinIn", 41, 1 }, 6357252495Snp { "RstIn", 40, 1 }, 6358252495Snp { "DataIn", 39, 1 }, 6359252495Snp { "DataInVld", 38, 1 }, 6360252495Snp { "PadIn", 37, 1 }, 6361252495Snp { "RxBufEmpty", 36, 1 }, 6362252495Snp { "RxDdp", 35, 1 }, 6363252495Snp { "RxFbCongestion", 34, 1 }, 6364252495Snp { "TxFbCongestion", 33, 1 }, 6365252495Snp { "TxPktSumSrdy", 32, 1 }, 6366252495Snp { "RcfUlpType", 28, 4 }, 6367252495Snp { "Eread", 27, 1 }, 6368252495Snp { "Ebypass", 26, 1 }, 6369252495Snp { "Esave", 25, 1 }, 6370252495Snp { "Static0", 24, 1 }, 6371252495Snp { "Cread", 23, 1 }, 6372252495Snp { "Cbypass", 22, 1 }, 6373252495Snp { "Csave", 21, 1 }, 6374252495Snp { "CPktOut", 20, 1 }, 6375252495Snp { "RxPagePoolFull", 18, 2 }, 6376252495Snp { "RxLpbkPkt", 17, 1 }, 6377252495Snp { "TxLpbkPkt", 16, 1 }, 6378252495Snp { "RxVfValid", 15, 1 }, 6379252495Snp { "SynLearned", 14, 1 }, 6380252495Snp { "SetDelEntry", 13, 1 }, 6381252495Snp { "SetInvEntry", 12, 1 }, 6382252495Snp { "CpcmdDvld", 11, 1 }, 6383252495Snp { "CpcmdSave", 10, 1 }, 6384252495Snp { "RxPstructsFull", 8, 2 }, 6385252495Snp { "EpcmdDvld", 7, 1 }, 6386252495Snp { "EpcmdFlush", 6, 1 }, 6387252495Snp { "EpcmdTrimPrefix", 5, 1 }, 6388252495Snp { "EpcmdTrimPostfix", 4, 1 }, 6389252495Snp { "ERssIp4Pkt", 3, 1 }, 6390252495Snp { "ERssIp6Pkt", 2, 1 }, 6391252495Snp { "ERssTcpUdpPkt", 1, 1 }, 6392252495Snp { "ERssFceFipPkt", 0, 1 }, 6393252495Snp { NULL } 6394252495Snp}; 6395252495Snp 6396252495Snpstatic void 6397252495Snptp_la_show(struct sbuf *sb, uint64_t *p, int idx) 6398252495Snp{ 6399252495Snp 6400252495Snp field_desc_show(sb, *p, tp_la0); 6401252495Snp} 6402252495Snp 6403252495Snpstatic void 6404252495Snptp_la_show2(struct sbuf *sb, uint64_t *p, int idx) 6405252495Snp{ 6406252495Snp 6407252495Snp if (idx) 6408252495Snp sbuf_printf(sb, "\n"); 6409252495Snp field_desc_show(sb, p[0], tp_la0); 6410252495Snp if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) 6411252495Snp field_desc_show(sb, p[1], tp_la0); 6412252495Snp} 6413252495Snp 6414252495Snpstatic void 6415252495Snptp_la_show3(struct sbuf *sb, uint64_t *p, int idx) 6416252495Snp{ 6417252495Snp 6418252495Snp if (idx) 6419252495Snp sbuf_printf(sb, "\n"); 6420252495Snp field_desc_show(sb, p[0], tp_la0); 6421252495Snp if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) 6422252495Snp field_desc_show(sb, p[1], (p[0] & (1 << 17)) ? tp_la2 : tp_la1); 6423252495Snp} 6424252495Snp 6425231093Snpstatic int 6426252495Snpsysctl_tp_la(SYSCTL_HANDLER_ARGS) 6427252495Snp{ 6428252495Snp struct adapter *sc = arg1; 6429252495Snp struct sbuf *sb; 6430252495Snp uint64_t *buf, *p; 6431252495Snp int rc; 6432252495Snp u_int i, inc; 6433252495Snp void (*show_func)(struct sbuf *, uint64_t *, int); 6434252495Snp 6435252495Snp rc = sysctl_wire_old_buffer(req, 0); 6436252495Snp if (rc != 0) 6437252495Snp return (rc); 6438252495Snp 6439252495Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6440252495Snp if (sb == NULL) 6441252495Snp return (ENOMEM); 6442252495Snp 6443252495Snp buf = malloc(TPLA_SIZE * sizeof(uint64_t), M_CXGBE, M_ZERO | M_WAITOK); 6444252495Snp 6445252495Snp t4_tp_read_la(sc, buf, NULL); 6446252495Snp p = buf; 6447252495Snp 6448252495Snp switch (G_DBGLAMODE(t4_read_reg(sc, A_TP_DBG_LA_CONFIG))) { 6449252495Snp case 2: 6450252495Snp inc = 2; 6451252495Snp show_func = tp_la_show2; 6452252495Snp break; 6453252495Snp case 3: 6454252495Snp inc = 2; 6455252495Snp show_func = tp_la_show3; 6456252495Snp break; 6457252495Snp default: 6458252495Snp inc = 1; 6459252495Snp show_func = tp_la_show; 6460252495Snp } 6461252495Snp 6462252495Snp for (i = 0; i < TPLA_SIZE / inc; i++, p += inc) 6463252495Snp (*show_func)(sb, p, i); 6464252495Snp 6465252495Snp rc = sbuf_finish(sb); 6466252495Snp sbuf_delete(sb); 6467252495Snp free(buf, M_CXGBE); 6468252495Snp return (rc); 6469252495Snp} 6470252495Snp 6471252495Snpstatic int 6472231093Snpsysctl_tx_rate(SYSCTL_HANDLER_ARGS) 6473231093Snp{ 6474231093Snp struct adapter *sc = arg1; 6475231093Snp struct sbuf *sb; 6476231093Snp int rc; 6477231093Snp u64 nrate[NCHAN], orate[NCHAN]; 6478231093Snp 6479231093Snp rc = sysctl_wire_old_buffer(req, 0); 6480231093Snp if (rc != 0) 6481231093Snp return (rc); 6482231093Snp 6483231093Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6484231093Snp if (sb == NULL) 6485231093Snp return (ENOMEM); 6486231093Snp 6487231093Snp t4_get_chan_txrate(sc, nrate, orate); 6488231093Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 6489231093Snp "channel 3\n"); 6490231093Snp sbuf_printf(sb, "NIC B/s: %10ju %10ju %10ju %10ju\n", 6491231093Snp nrate[0], nrate[1], nrate[2], nrate[3]); 6492231093Snp sbuf_printf(sb, "Offload B/s: %10ju %10ju %10ju %10ju", 6493231093Snp orate[0], orate[1], orate[2], orate[3]); 6494231093Snp 6495231093Snp rc = sbuf_finish(sb); 6496231093Snp sbuf_delete(sb); 6497231093Snp 6498231093Snp return (rc); 6499231093Snp} 6500252495Snp 6501252495Snpstatic int 6502252495Snpsysctl_ulprx_la(SYSCTL_HANDLER_ARGS) 6503252495Snp{ 6504252495Snp struct adapter *sc = arg1; 6505252495Snp struct sbuf *sb; 6506252495Snp uint32_t *buf, *p; 6507252495Snp int rc, i; 6508252495Snp 6509252495Snp rc = sysctl_wire_old_buffer(req, 0); 6510252495Snp if (rc != 0) 6511252495Snp return (rc); 6512252495Snp 6513252495Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6514252495Snp if (sb == NULL) 6515252495Snp return (ENOMEM); 6516252495Snp 6517252495Snp buf = malloc(ULPRX_LA_SIZE * 8 * sizeof(uint32_t), M_CXGBE, 6518252495Snp M_ZERO | M_WAITOK); 6519252495Snp 6520252495Snp t4_ulprx_read_la(sc, buf); 6521252495Snp p = buf; 6522252495Snp 6523252495Snp sbuf_printf(sb, " Pcmd Type Message" 6524252495Snp " Data"); 6525252495Snp for (i = 0; i < ULPRX_LA_SIZE; i++, p += 8) { 6526252495Snp sbuf_printf(sb, "\n%08x%08x %4x %08x %08x%08x%08x%08x", 6527252495Snp p[1], p[0], p[2], p[3], p[7], p[6], p[5], p[4]); 6528252495Snp } 6529252495Snp 6530252495Snp rc = sbuf_finish(sb); 6531252495Snp sbuf_delete(sb); 6532252495Snp free(buf, M_CXGBE); 6533252495Snp return (rc); 6534252495Snp} 6535252495Snp 6536252495Snpstatic int 6537252495Snpsysctl_wcwr_stats(SYSCTL_HANDLER_ARGS) 6538252495Snp{ 6539252495Snp struct adapter *sc = arg1; 6540252495Snp struct sbuf *sb; 6541252495Snp int rc, v; 6542252495Snp 6543252495Snp rc = sysctl_wire_old_buffer(req, 0); 6544252495Snp if (rc != 0) 6545252495Snp return (rc); 6546252495Snp 6547252495Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6548252495Snp if (sb == NULL) 6549252495Snp return (ENOMEM); 6550252495Snp 6551252495Snp v = t4_read_reg(sc, A_SGE_STAT_CFG); 6552252495Snp if (G_STATSOURCE_T5(v) == 7) { 6553252495Snp if (G_STATMODE(v) == 0) { 6554252495Snp sbuf_printf(sb, "total %d, incomplete %d", 6555252495Snp t4_read_reg(sc, A_SGE_STAT_TOTAL), 6556252495Snp t4_read_reg(sc, A_SGE_STAT_MATCH)); 6557252495Snp } else if (G_STATMODE(v) == 1) { 6558252495Snp sbuf_printf(sb, "total %d, data overflow %d", 6559252495Snp t4_read_reg(sc, A_SGE_STAT_TOTAL), 6560252495Snp t4_read_reg(sc, A_SGE_STAT_MATCH)); 6561252495Snp } 6562252495Snp } 6563252495Snp rc = sbuf_finish(sb); 6564252495Snp sbuf_delete(sb); 6565252495Snp 6566252495Snp return (rc); 6567252495Snp} 6568231593Snp#endif 6569231093Snp 6570219286Snpstatic inline void 6571219286Snptxq_start(struct ifnet *ifp, struct sge_txq *txq) 6572219286Snp{ 6573219286Snp struct buf_ring *br; 6574219286Snp struct mbuf *m; 6575219286Snp 6576219286Snp TXQ_LOCK_ASSERT_OWNED(txq); 6577219286Snp 6578220873Snp br = txq->br; 6579219286Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 6580219286Snp if (m) 6581219286Snp t4_eth_tx(ifp, txq, m); 6582219286Snp} 6583219286Snp 6584219286Snpvoid 6585231093Snpt4_tx_callout(void *arg) 6586219286Snp{ 6587231093Snp struct sge_eq *eq = arg; 6588231093Snp struct adapter *sc; 6589219286Snp 6590231093Snp if (EQ_TRYLOCK(eq) == 0) 6591231093Snp goto reschedule; 6592231093Snp 6593231093Snp if (eq->flags & EQ_STALLED && !can_resume_tx(eq)) { 6594231093Snp EQ_UNLOCK(eq); 6595231093Snpreschedule: 6596231093Snp if (__predict_true(!(eq->flags && EQ_DOOMED))) 6597231093Snp callout_schedule(&eq->tx_callout, 1); 6598231093Snp return; 6599231093Snp } 6600231093Snp 6601231093Snp EQ_LOCK_ASSERT_OWNED(eq); 6602231093Snp 6603231093Snp if (__predict_true((eq->flags & EQ_DOOMED) == 0)) { 6604231093Snp 6605231093Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 6606231093Snp struct sge_txq *txq = arg; 6607231093Snp struct port_info *pi = txq->ifp->if_softc; 6608231093Snp 6609231093Snp sc = pi->adapter; 6610231093Snp } else { 6611231093Snp struct sge_wrq *wrq = arg; 6612231093Snp 6613231093Snp sc = wrq->adapter; 6614231093Snp } 6615231093Snp 6616231093Snp taskqueue_enqueue(sc->tq[eq->tx_chan], &eq->tx_task); 6617231093Snp } 6618231093Snp 6619231093Snp EQ_UNLOCK(eq); 6620231093Snp} 6621231093Snp 6622231093Snpvoid 6623231093Snpt4_tx_task(void *arg, int count) 6624231093Snp{ 6625231093Snp struct sge_eq *eq = arg; 6626231093Snp 6627231093Snp EQ_LOCK(eq); 6628231093Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 6629231093Snp struct sge_txq *txq = arg; 6630220649Snp txq_start(txq->ifp, txq); 6631231093Snp } else { 6632231093Snp struct sge_wrq *wrq = arg; 6633231093Snp t4_wrq_tx_locked(wrq->adapter, wrq, NULL); 6634231093Snp } 6635231093Snp EQ_UNLOCK(eq); 6636219286Snp} 6637219286Snp 6638221474Snpstatic uint32_t 6639221474Snpfconf_to_mode(uint32_t fconf) 6640221474Snp{ 6641221474Snp uint32_t mode; 6642221474Snp 6643221474Snp mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR | 6644221474Snp T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT; 6645221474Snp 6646221474Snp if (fconf & F_FRAGMENTATION) 6647221474Snp mode |= T4_FILTER_IP_FRAGMENT; 6648221474Snp 6649221474Snp if (fconf & F_MPSHITTYPE) 6650221474Snp mode |= T4_FILTER_MPS_HIT_TYPE; 6651221474Snp 6652221474Snp if (fconf & F_MACMATCH) 6653221474Snp mode |= T4_FILTER_MAC_IDX; 6654221474Snp 6655221474Snp if (fconf & F_ETHERTYPE) 6656221474Snp mode |= T4_FILTER_ETH_TYPE; 6657221474Snp 6658221474Snp if (fconf & F_PROTOCOL) 6659221474Snp mode |= T4_FILTER_IP_PROTO; 6660221474Snp 6661221474Snp if (fconf & F_TOS) 6662221474Snp mode |= T4_FILTER_IP_TOS; 6663221474Snp 6664221474Snp if (fconf & F_VLAN) 6665231093Snp mode |= T4_FILTER_VLAN; 6666221474Snp 6667221474Snp if (fconf & F_VNIC_ID) 6668231093Snp mode |= T4_FILTER_VNIC; 6669221474Snp 6670221474Snp if (fconf & F_PORT) 6671221474Snp mode |= T4_FILTER_PORT; 6672221474Snp 6673221474Snp if (fconf & F_FCOE) 6674221474Snp mode |= T4_FILTER_FCoE; 6675221474Snp 6676221474Snp return (mode); 6677221474Snp} 6678221474Snp 6679221474Snpstatic uint32_t 6680221474Snpmode_to_fconf(uint32_t mode) 6681221474Snp{ 6682221474Snp uint32_t fconf = 0; 6683221474Snp 6684221474Snp if (mode & T4_FILTER_IP_FRAGMENT) 6685221474Snp fconf |= F_FRAGMENTATION; 6686221474Snp 6687221474Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 6688221474Snp fconf |= F_MPSHITTYPE; 6689221474Snp 6690221474Snp if (mode & T4_FILTER_MAC_IDX) 6691221474Snp fconf |= F_MACMATCH; 6692221474Snp 6693221474Snp if (mode & T4_FILTER_ETH_TYPE) 6694221474Snp fconf |= F_ETHERTYPE; 6695221474Snp 6696221474Snp if (mode & T4_FILTER_IP_PROTO) 6697221474Snp fconf |= F_PROTOCOL; 6698221474Snp 6699221474Snp if (mode & T4_FILTER_IP_TOS) 6700221474Snp fconf |= F_TOS; 6701221474Snp 6702231093Snp if (mode & T4_FILTER_VLAN) 6703221474Snp fconf |= F_VLAN; 6704221474Snp 6705231093Snp if (mode & T4_FILTER_VNIC) 6706221474Snp fconf |= F_VNIC_ID; 6707221474Snp 6708221474Snp if (mode & T4_FILTER_PORT) 6709221474Snp fconf |= F_PORT; 6710221474Snp 6711221474Snp if (mode & T4_FILTER_FCoE) 6712221474Snp fconf |= F_FCOE; 6713221474Snp 6714221474Snp return (fconf); 6715221474Snp} 6716221474Snp 6717221474Snpstatic uint32_t 6718221474Snpfspec_to_fconf(struct t4_filter_specification *fs) 6719221474Snp{ 6720221474Snp uint32_t fconf = 0; 6721221474Snp 6722221474Snp if (fs->val.frag || fs->mask.frag) 6723221474Snp fconf |= F_FRAGMENTATION; 6724221474Snp 6725221474Snp if (fs->val.matchtype || fs->mask.matchtype) 6726221474Snp fconf |= F_MPSHITTYPE; 6727221474Snp 6728221474Snp if (fs->val.macidx || fs->mask.macidx) 6729221474Snp fconf |= F_MACMATCH; 6730221474Snp 6731221474Snp if (fs->val.ethtype || fs->mask.ethtype) 6732221474Snp fconf |= F_ETHERTYPE; 6733221474Snp 6734221474Snp if (fs->val.proto || fs->mask.proto) 6735221474Snp fconf |= F_PROTOCOL; 6736221474Snp 6737221474Snp if (fs->val.tos || fs->mask.tos) 6738221474Snp fconf |= F_TOS; 6739221474Snp 6740231093Snp if (fs->val.vlan_vld || fs->mask.vlan_vld) 6741221474Snp fconf |= F_VLAN; 6742221474Snp 6743231093Snp if (fs->val.vnic_vld || fs->mask.vnic_vld) 6744221474Snp fconf |= F_VNIC_ID; 6745221474Snp 6746221474Snp if (fs->val.iport || fs->mask.iport) 6747221474Snp fconf |= F_PORT; 6748221474Snp 6749221474Snp if (fs->val.fcoe || fs->mask.fcoe) 6750221474Snp fconf |= F_FCOE; 6751221474Snp 6752221474Snp return (fconf); 6753221474Snp} 6754221474Snp 6755221474Snpstatic int 6756221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode) 6757221474Snp{ 6758247434Snp int rc; 6759221474Snp uint32_t fconf; 6760221474Snp 6761247434Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 6762247434Snp "t4getfm"); 6763247434Snp if (rc) 6764247434Snp return (rc); 6765247434Snp 6766221474Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1, 6767221474Snp A_TP_VLAN_PRI_MAP); 6768221474Snp 6769252814Snp if (sc->params.tp.vlan_pri_map != fconf) { 6770231093Snp log(LOG_WARNING, "%s: cached filter mode out of sync %x %x.\n", 6771252814Snp device_get_nameunit(sc->dev), sc->params.tp.vlan_pri_map, 6772252814Snp fconf); 6773252814Snp sc->params.tp.vlan_pri_map = fconf; 6774231093Snp } 6775221474Snp 6776252814Snp *mode = fconf_to_mode(sc->params.tp.vlan_pri_map); 6777231093Snp 6778247434Snp end_synchronized_op(sc, LOCK_HELD); 6779221474Snp return (0); 6780221474Snp} 6781221474Snp 6782221474Snpstatic int 6783221474Snpset_filter_mode(struct adapter *sc, uint32_t mode) 6784221474Snp{ 6785221474Snp uint32_t fconf; 6786221474Snp int rc; 6787221474Snp 6788221474Snp fconf = mode_to_fconf(mode); 6789221474Snp 6790247434Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 6791247434Snp "t4setfm"); 6792247434Snp if (rc) 6793247434Snp return (rc); 6794221474Snp 6795221474Snp if (sc->tids.ftids_in_use > 0) { 6796221474Snp rc = EBUSY; 6797221474Snp goto done; 6798221474Snp } 6799221474Snp 6800237920Snp#ifdef TCP_OFFLOAD 6801231093Snp if (sc->offload_map) { 6802231093Snp rc = EBUSY; 6803231093Snp goto done; 6804231093Snp } 6805231093Snp#endif 6806231093Snp 6807231093Snp#ifdef notyet 6808221474Snp rc = -t4_set_filter_mode(sc, fconf); 6809231093Snp if (rc == 0) 6810231093Snp sc->filter_mode = fconf; 6811231093Snp#else 6812231093Snp rc = ENOTSUP; 6813231093Snp#endif 6814231093Snp 6815221474Snpdone: 6816247434Snp end_synchronized_op(sc, LOCK_HELD); 6817221474Snp return (rc); 6818221474Snp} 6819221474Snp 6820222552Snpstatic inline uint64_t 6821222552Snpget_filter_hits(struct adapter *sc, uint32_t fid) 6822222552Snp{ 6823252495Snp uint32_t mw_base, off, tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 6824222552Snp uint64_t hits; 6825222552Snp 6826252495Snp memwin_info(sc, 0, &mw_base, NULL); 6827252495Snp off = position_memwin(sc, 0, 6828222552Snp tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE); 6829252495Snp if (is_t4(sc)) { 6830252495Snp hits = t4_read_reg64(sc, mw_base + off + 16); 6831252495Snp hits = be64toh(hits); 6832252495Snp } else { 6833252495Snp hits = t4_read_reg(sc, mw_base + off + 24); 6834252495Snp hits = be32toh(hits); 6835252495Snp } 6836222552Snp 6837252495Snp return (hits); 6838222552Snp} 6839222552Snp 6840221474Snpstatic int 6841221474Snpget_filter(struct adapter *sc, struct t4_filter *t) 6842221474Snp{ 6843247434Snp int i, rc, nfilters = sc->tids.nftids; 6844221474Snp struct filter_entry *f; 6845221474Snp 6846247434Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 6847247434Snp "t4getf"); 6848247434Snp if (rc) 6849247434Snp return (rc); 6850221474Snp 6851221474Snp if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL || 6852221474Snp t->idx >= nfilters) { 6853221474Snp t->idx = 0xffffffff; 6854247434Snp goto done; 6855221474Snp } 6856221474Snp 6857221474Snp f = &sc->tids.ftid_tab[t->idx]; 6858221474Snp for (i = t->idx; i < nfilters; i++, f++) { 6859221474Snp if (f->valid) { 6860221474Snp t->idx = i; 6861222509Snp t->l2tidx = f->l2t ? f->l2t->idx : 0; 6862222509Snp t->smtidx = f->smtidx; 6863222552Snp if (f->fs.hitcnts) 6864222552Snp t->hits = get_filter_hits(sc, t->idx); 6865222552Snp else 6866222552Snp t->hits = UINT64_MAX; 6867221474Snp t->fs = f->fs; 6868221474Snp 6869247434Snp goto done; 6870221474Snp } 6871221474Snp } 6872221474Snp 6873221474Snp t->idx = 0xffffffff; 6874247434Snpdone: 6875247434Snp end_synchronized_op(sc, LOCK_HELD); 6876221474Snp return (0); 6877221474Snp} 6878221474Snp 6879221474Snpstatic int 6880221474Snpset_filter(struct adapter *sc, struct t4_filter *t) 6881221474Snp{ 6882221474Snp unsigned int nfilters, nports; 6883221474Snp struct filter_entry *f; 6884247434Snp int i, rc; 6885221474Snp 6886247434Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setf"); 6887247434Snp if (rc) 6888247434Snp return (rc); 6889221474Snp 6890221474Snp nfilters = sc->tids.nftids; 6891221474Snp nports = sc->params.nports; 6892221474Snp 6893247434Snp if (nfilters == 0) { 6894247434Snp rc = ENOTSUP; 6895247434Snp goto done; 6896247434Snp } 6897221474Snp 6898247434Snp if (!(sc->flags & FULL_INIT_DONE)) { 6899247434Snp rc = EAGAIN; 6900247434Snp goto done; 6901247434Snp } 6902221474Snp 6903247434Snp if (t->idx >= nfilters) { 6904247434Snp rc = EINVAL; 6905247434Snp goto done; 6906247434Snp } 6907221474Snp 6908221474Snp /* Validate against the global filter mode */ 6909252814Snp if ((sc->params.tp.vlan_pri_map | fspec_to_fconf(&t->fs)) != 6910252814Snp sc->params.tp.vlan_pri_map) { 6911247434Snp rc = E2BIG; 6912247434Snp goto done; 6913247434Snp } 6914221474Snp 6915247434Snp if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) { 6916247434Snp rc = EINVAL; 6917247434Snp goto done; 6918247434Snp } 6919221474Snp 6920247434Snp if (t->fs.val.iport >= nports) { 6921247434Snp rc = EINVAL; 6922247434Snp goto done; 6923247434Snp } 6924221474Snp 6925221474Snp /* Can't specify an iq if not steering to it */ 6926247434Snp if (!t->fs.dirsteer && t->fs.iq) { 6927247434Snp rc = EINVAL; 6928247434Snp goto done; 6929247434Snp } 6930221474Snp 6931221474Snp /* IPv6 filter idx must be 4 aligned */ 6932221474Snp if (t->fs.type == 1 && 6933247434Snp ((t->idx & 0x3) || t->idx + 4 >= nfilters)) { 6934247434Snp rc = EINVAL; 6935247434Snp goto done; 6936247434Snp } 6937221474Snp 6938221474Snp if (sc->tids.ftid_tab == NULL) { 6939221474Snp KASSERT(sc->tids.ftids_in_use == 0, 6940221474Snp ("%s: no memory allocated but filters_in_use > 0", 6941221474Snp __func__)); 6942221474Snp 6943221474Snp sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) * 6944221474Snp nfilters, M_CXGBE, M_NOWAIT | M_ZERO); 6945247434Snp if (sc->tids.ftid_tab == NULL) { 6946247434Snp rc = ENOMEM; 6947247434Snp goto done; 6948247434Snp } 6949247434Snp mtx_init(&sc->tids.ftid_lock, "T4 filters", 0, MTX_DEF); 6950221474Snp } 6951221474Snp 6952221474Snp for (i = 0; i < 4; i++) { 6953221474Snp f = &sc->tids.ftid_tab[t->idx + i]; 6954221474Snp 6955247434Snp if (f->pending || f->valid) { 6956247434Snp rc = EBUSY; 6957247434Snp goto done; 6958247434Snp } 6959247434Snp if (f->locked) { 6960247434Snp rc = EPERM; 6961247434Snp goto done; 6962247434Snp } 6963221474Snp 6964221474Snp if (t->fs.type == 0) 6965221474Snp break; 6966221474Snp } 6967221474Snp 6968221474Snp f = &sc->tids.ftid_tab[t->idx]; 6969221474Snp f->fs = t->fs; 6970221474Snp 6971247434Snp rc = set_filter_wr(sc, t->idx); 6972247434Snpdone: 6973247434Snp end_synchronized_op(sc, 0); 6974247434Snp 6975247434Snp if (rc == 0) { 6976247434Snp mtx_lock(&sc->tids.ftid_lock); 6977247434Snp for (;;) { 6978247434Snp if (f->pending == 0) { 6979247434Snp rc = f->valid ? 0 : EIO; 6980247434Snp break; 6981247434Snp } 6982247434Snp 6983247434Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 6984247434Snp PCATCH, "t4setfw", 0)) { 6985247434Snp rc = EINPROGRESS; 6986247434Snp break; 6987247434Snp } 6988247434Snp } 6989247434Snp mtx_unlock(&sc->tids.ftid_lock); 6990247434Snp } 6991247434Snp return (rc); 6992221474Snp} 6993221474Snp 6994221474Snpstatic int 6995221474Snpdel_filter(struct adapter *sc, struct t4_filter *t) 6996221474Snp{ 6997221474Snp unsigned int nfilters; 6998221474Snp struct filter_entry *f; 6999247434Snp int rc; 7000221474Snp 7001247434Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4delf"); 7002247434Snp if (rc) 7003247434Snp return (rc); 7004221474Snp 7005221474Snp nfilters = sc->tids.nftids; 7006221474Snp 7007247434Snp if (nfilters == 0) { 7008247434Snp rc = ENOTSUP; 7009247434Snp goto done; 7010247434Snp } 7011221474Snp 7012221474Snp if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 || 7013247434Snp t->idx >= nfilters) { 7014247434Snp rc = EINVAL; 7015247434Snp goto done; 7016247434Snp } 7017221474Snp 7018247434Snp if (!(sc->flags & FULL_INIT_DONE)) { 7019247434Snp rc = EAGAIN; 7020247434Snp goto done; 7021247434Snp } 7022221474Snp 7023221474Snp f = &sc->tids.ftid_tab[t->idx]; 7024221474Snp 7025247434Snp if (f->pending) { 7026247434Snp rc = EBUSY; 7027247434Snp goto done; 7028247434Snp } 7029247434Snp if (f->locked) { 7030247434Snp rc = EPERM; 7031247434Snp goto done; 7032247434Snp } 7033221474Snp 7034221474Snp if (f->valid) { 7035221474Snp t->fs = f->fs; /* extra info for the caller */ 7036247434Snp rc = del_filter_wr(sc, t->idx); 7037221474Snp } 7038221474Snp 7039247434Snpdone: 7040247434Snp end_synchronized_op(sc, 0); 7041247434Snp 7042247434Snp if (rc == 0) { 7043247434Snp mtx_lock(&sc->tids.ftid_lock); 7044247434Snp for (;;) { 7045247434Snp if (f->pending == 0) { 7046247434Snp rc = f->valid ? EIO : 0; 7047247434Snp break; 7048247434Snp } 7049247434Snp 7050247434Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 7051247434Snp PCATCH, "t4delfw", 0)) { 7052247434Snp rc = EINPROGRESS; 7053247434Snp break; 7054247434Snp } 7055247434Snp } 7056247434Snp mtx_unlock(&sc->tids.ftid_lock); 7057247434Snp } 7058247434Snp 7059247434Snp return (rc); 7060221474Snp} 7061221474Snp 7062221474Snpstatic void 7063222509Snpclear_filter(struct filter_entry *f) 7064221474Snp{ 7065222509Snp if (f->l2t) 7066222509Snp t4_l2t_release(f->l2t); 7067222509Snp 7068221474Snp bzero(f, sizeof (*f)); 7069221474Snp} 7070221474Snp 7071221474Snpstatic int 7072221474Snpset_filter_wr(struct adapter *sc, int fidx) 7073221474Snp{ 7074221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 7075237920Snp struct wrqe *wr; 7076221474Snp struct fw_filter_wr *fwr; 7077221474Snp unsigned int ftid; 7078221474Snp 7079247434Snp ASSERT_SYNCHRONIZED_OP(sc); 7080221474Snp 7081222509Snp if (f->fs.newdmac || f->fs.newvlan) { 7082222509Snp /* This filter needs an L2T entry; allocate one. */ 7083222509Snp f->l2t = t4_l2t_alloc_switching(sc->l2t); 7084222509Snp if (f->l2t == NULL) 7085222509Snp return (EAGAIN); 7086222509Snp if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport, 7087222509Snp f->fs.dmac)) { 7088222509Snp t4_l2t_release(f->l2t); 7089222509Snp f->l2t = NULL; 7090222509Snp return (ENOMEM); 7091222509Snp } 7092222509Snp } 7093221474Snp 7094221474Snp ftid = sc->tids.ftid_base + fidx; 7095221474Snp 7096237920Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 7097237920Snp if (wr == NULL) 7098221474Snp return (ENOMEM); 7099221474Snp 7100237920Snp fwr = wrtod(wr); 7101221474Snp bzero(fwr, sizeof (*fwr)); 7102221474Snp 7103221474Snp fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR)); 7104221474Snp fwr->len16_pkd = htobe32(FW_LEN16(*fwr)); 7105221474Snp fwr->tid_to_iq = 7106221474Snp htobe32(V_FW_FILTER_WR_TID(ftid) | 7107221474Snp V_FW_FILTER_WR_RQTYPE(f->fs.type) | 7108221474Snp V_FW_FILTER_WR_NOREPLY(0) | 7109221474Snp V_FW_FILTER_WR_IQ(f->fs.iq)); 7110221474Snp fwr->del_filter_to_l2tix = 7111221474Snp htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) | 7112221474Snp V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) | 7113221474Snp V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) | 7114221474Snp V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) | 7115221474Snp V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) | 7116221474Snp V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) | 7117221474Snp V_FW_FILTER_WR_DMAC(f->fs.newdmac) | 7118221474Snp V_FW_FILTER_WR_SMAC(f->fs.newsmac) | 7119221474Snp V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT || 7120221474Snp f->fs.newvlan == VLAN_REWRITE) | 7121221474Snp V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE || 7122221474Snp f->fs.newvlan == VLAN_REWRITE) | 7123221474Snp V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) | 7124221474Snp V_FW_FILTER_WR_TXCHAN(f->fs.eport) | 7125221474Snp V_FW_FILTER_WR_PRIO(f->fs.prio) | 7126222509Snp V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0)); 7127221474Snp fwr->ethtype = htobe16(f->fs.val.ethtype); 7128221474Snp fwr->ethtypem = htobe16(f->fs.mask.ethtype); 7129221474Snp fwr->frag_to_ovlan_vldm = 7130221474Snp (V_FW_FILTER_WR_FRAG(f->fs.val.frag) | 7131221474Snp V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) | 7132231093Snp V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) | 7133231093Snp V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.vnic_vld) | 7134231093Snp V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) | 7135231093Snp V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.vnic_vld)); 7136221474Snp fwr->smac_sel = 0; 7137221474Snp fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) | 7138231093Snp V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id)); 7139221474Snp fwr->maci_to_matchtypem = 7140221474Snp htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) | 7141221474Snp V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) | 7142221474Snp V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) | 7143221474Snp V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) | 7144221474Snp V_FW_FILTER_WR_PORT(f->fs.val.iport) | 7145221474Snp V_FW_FILTER_WR_PORTM(f->fs.mask.iport) | 7146221474Snp V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) | 7147221474Snp V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype)); 7148221474Snp fwr->ptcl = f->fs.val.proto; 7149221474Snp fwr->ptclm = f->fs.mask.proto; 7150221474Snp fwr->ttyp = f->fs.val.tos; 7151221474Snp fwr->ttypm = f->fs.mask.tos; 7152231093Snp fwr->ivlan = htobe16(f->fs.val.vlan); 7153231093Snp fwr->ivlanm = htobe16(f->fs.mask.vlan); 7154231093Snp fwr->ovlan = htobe16(f->fs.val.vnic); 7155231093Snp fwr->ovlanm = htobe16(f->fs.mask.vnic); 7156221474Snp bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip)); 7157221474Snp bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm)); 7158221474Snp bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip)); 7159221474Snp bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm)); 7160221474Snp fwr->lp = htobe16(f->fs.val.dport); 7161221474Snp fwr->lpm = htobe16(f->fs.mask.dport); 7162221474Snp fwr->fp = htobe16(f->fs.val.sport); 7163221474Snp fwr->fpm = htobe16(f->fs.mask.sport); 7164221474Snp if (f->fs.newsmac) 7165221474Snp bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma)); 7166221474Snp 7167221474Snp f->pending = 1; 7168221474Snp sc->tids.ftids_in_use++; 7169231093Snp 7170237920Snp t4_wrq_tx(sc, wr); 7171231093Snp return (0); 7172221474Snp} 7173221474Snp 7174221474Snpstatic int 7175221474Snpdel_filter_wr(struct adapter *sc, int fidx) 7176221474Snp{ 7177221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 7178237920Snp struct wrqe *wr; 7179221474Snp struct fw_filter_wr *fwr; 7180231093Snp unsigned int ftid; 7181221474Snp 7182221474Snp ftid = sc->tids.ftid_base + fidx; 7183221474Snp 7184237920Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 7185237920Snp if (wr == NULL) 7186221474Snp return (ENOMEM); 7187237920Snp fwr = wrtod(wr); 7188221474Snp bzero(fwr, sizeof (*fwr)); 7189221474Snp 7190231093Snp t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id); 7191221474Snp 7192221474Snp f->pending = 1; 7193237920Snp t4_wrq_tx(sc, wr); 7194231093Snp return (0); 7195221474Snp} 7196221474Snp 7197240169Snpint 7198240169Snpt4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 7199221474Snp{ 7200231093Snp struct adapter *sc = iq->adapter; 7201231093Snp const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1); 7202221474Snp unsigned int idx = GET_TID(rpl); 7203265553Snp unsigned int rc; 7204265553Snp struct filter_entry *f; 7205221474Snp 7206231093Snp KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__, 7207231093Snp rss->opcode)); 7208231093Snp 7209265553Snp if (is_ftid(sc, idx)) { 7210221474Snp 7211265553Snp idx -= sc->tids.ftid_base; 7212265553Snp f = &sc->tids.ftid_tab[idx]; 7213265553Snp rc = G_COOKIE(rpl->cookie); 7214265553Snp 7215247434Snp mtx_lock(&sc->tids.ftid_lock); 7216231093Snp if (rc == FW_FILTER_WR_FLT_ADDED) { 7217247434Snp KASSERT(f->pending, ("%s: filter[%u] isn't pending.", 7218247434Snp __func__, idx)); 7219221474Snp f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff; 7220221474Snp f->pending = 0; /* asynchronous setup completed */ 7221221474Snp f->valid = 1; 7222231599Snp } else { 7223231599Snp if (rc != FW_FILTER_WR_FLT_DELETED) { 7224231599Snp /* Add or delete failed, display an error */ 7225231599Snp log(LOG_ERR, 7226231599Snp "filter %u setup failed with error %u\n", 7227231599Snp idx, rc); 7228231599Snp } 7229231093Snp 7230231599Snp clear_filter(f); 7231231599Snp sc->tids.ftids_in_use--; 7232221474Snp } 7233247434Snp wakeup(&sc->tids.ftid_tab); 7234247434Snp mtx_unlock(&sc->tids.ftid_lock); 7235221474Snp } 7236231093Snp 7237231093Snp return (0); 7238221474Snp} 7239221474Snp 7240222973Snpstatic int 7241222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt) 7242222973Snp{ 7243247434Snp int rc; 7244222973Snp 7245222973Snp if (cntxt->cid > M_CTXTQID) 7246247434Snp return (EINVAL); 7247222973Snp 7248222973Snp if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS && 7249222973Snp cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM) 7250247434Snp return (EINVAL); 7251247434Snp 7252247434Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ctxt"); 7253247434Snp if (rc) 7254222973Snp return (rc); 7255222973Snp 7256222973Snp if (sc->flags & FW_OK) { 7257222973Snp rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id, 7258222973Snp &cntxt->data[0]); 7259247434Snp if (rc == 0) 7260247434Snp goto done; 7261222973Snp } 7262222973Snp 7263247434Snp /* 7264247434Snp * Read via firmware failed or wasn't even attempted. Read directly via 7265247434Snp * the backdoor. 7266247434Snp */ 7267247434Snp rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id, &cntxt->data[0]); 7268247434Snpdone: 7269247434Snp end_synchronized_op(sc, 0); 7270247434Snp return (rc); 7271247434Snp} 7272222973Snp 7273247434Snpstatic int 7274247434Snpload_fw(struct adapter *sc, struct t4_data *fw) 7275247434Snp{ 7276247434Snp int rc; 7277247434Snp uint8_t *fw_data; 7278247434Snp 7279247434Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ldfw"); 7280247434Snp if (rc) 7281247434Snp return (rc); 7282247434Snp 7283247434Snp if (sc->flags & FULL_INIT_DONE) { 7284247434Snp rc = EBUSY; 7285247434Snp goto done; 7286222973Snp } 7287222973Snp 7288247434Snp fw_data = malloc(fw->len, M_CXGBE, M_WAITOK); 7289247434Snp if (fw_data == NULL) { 7290247434Snp rc = ENOMEM; 7291247434Snp goto done; 7292247434Snp } 7293247434Snp 7294247434Snp rc = copyin(fw->data, fw_data, fw->len); 7295247434Snp if (rc == 0) 7296247434Snp rc = -t4_load_fw(sc, fw_data, fw->len); 7297247434Snp 7298247434Snp free(fw_data, M_CXGBE); 7299247434Snpdone: 7300247434Snp end_synchronized_op(sc, 0); 7301222973Snp return (rc); 7302222973Snp} 7303222973Snp 7304231093Snpstatic int 7305252495Snpread_card_mem(struct adapter *sc, int win, struct t4_mem_range *mr) 7306231093Snp{ 7307252495Snp uint32_t addr, off, remaining, i, n; 7308231093Snp uint32_t *buf, *b; 7309252495Snp uint32_t mw_base, mw_aperture; 7310231093Snp int rc; 7311252495Snp uint8_t *dst; 7312231093Snp 7313252495Snp rc = validate_mem_range(sc, mr->addr, mr->len); 7314252495Snp if (rc != 0) 7315252495Snp return (rc); 7316231093Snp 7317252495Snp memwin_info(sc, win, &mw_base, &mw_aperture); 7318252495Snp buf = b = malloc(min(mr->len, mw_aperture), M_CXGBE, M_WAITOK); 7319252495Snp addr = mr->addr; 7320231093Snp remaining = mr->len; 7321252495Snp dst = (void *)mr->data; 7322231093Snp 7323231093Snp while (remaining) { 7324252495Snp off = position_memwin(sc, win, addr); 7325231093Snp 7326231093Snp /* number of bytes that we'll copy in the inner loop */ 7327252495Snp n = min(remaining, mw_aperture - off); 7328252495Snp for (i = 0; i < n; i += 4) 7329252495Snp *b++ = t4_read_reg(sc, mw_base + off + i); 7330231093Snp 7331252495Snp rc = copyout(buf, dst, n); 7332252495Snp if (rc != 0) 7333252495Snp break; 7334231093Snp 7335252495Snp b = buf; 7336252495Snp dst += n; 7337252495Snp remaining -= n; 7338252495Snp addr += n; 7339231093Snp } 7340231093Snp 7341231093Snp free(buf, M_CXGBE); 7342231093Snp return (rc); 7343231093Snp} 7344231093Snp 7345241573Snpstatic int 7346241573Snpread_i2c(struct adapter *sc, struct t4_i2c_data *i2cd) 7347241573Snp{ 7348241573Snp int rc; 7349241573Snp 7350241573Snp if (i2cd->len == 0 || i2cd->port_id >= sc->params.nports) 7351241573Snp return (EINVAL); 7352241573Snp 7353241573Snp if (i2cd->len > 1) { 7354241573Snp /* XXX: need fw support for longer reads in one go */ 7355241573Snp return (ENOTSUP); 7356241573Snp } 7357241573Snp 7358247434Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4i2crd"); 7359247434Snp if (rc) 7360247434Snp return (rc); 7361241573Snp rc = -t4_i2c_rd(sc, sc->mbox, i2cd->port_id, i2cd->dev_addr, 7362241573Snp i2cd->offset, &i2cd->data[0]); 7363247434Snp end_synchronized_op(sc, 0); 7364241573Snp 7365241573Snp return (rc); 7366241573Snp} 7367241573Snp 7368265552Snpstatic int 7369265552Snpin_range(int val, int lo, int hi) 7370265552Snp{ 7371265552Snp 7372265552Snp return (val < 0 || (val <= hi && val >= lo)); 7373265552Snp} 7374265552Snp 7375265552Snpstatic int 7376265552Snpset_sched_class(struct adapter *sc, struct t4_sched_params *p) 7377265552Snp{ 7378265552Snp int fw_subcmd, fw_type, rc; 7379265552Snp 7380265552Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setsc"); 7381265552Snp if (rc) 7382265552Snp return (rc); 7383265552Snp 7384265552Snp if (!(sc->flags & FULL_INIT_DONE)) { 7385265552Snp rc = EAGAIN; 7386265552Snp goto done; 7387265552Snp } 7388265552Snp 7389265552Snp /* 7390265552Snp * Translate the cxgbetool parameters into T4 firmware parameters. (The 7391265552Snp * sub-command and type are in common locations.) 7392265552Snp */ 7393265552Snp if (p->subcmd == SCHED_CLASS_SUBCMD_CONFIG) 7394265552Snp fw_subcmd = FW_SCHED_SC_CONFIG; 7395265552Snp else if (p->subcmd == SCHED_CLASS_SUBCMD_PARAMS) 7396265552Snp fw_subcmd = FW_SCHED_SC_PARAMS; 7397265552Snp else { 7398265552Snp rc = EINVAL; 7399265552Snp goto done; 7400265552Snp } 7401265552Snp if (p->type == SCHED_CLASS_TYPE_PACKET) 7402265552Snp fw_type = FW_SCHED_TYPE_PKTSCHED; 7403265552Snp else { 7404265552Snp rc = EINVAL; 7405265552Snp goto done; 7406265552Snp } 7407265552Snp 7408265552Snp if (fw_subcmd == FW_SCHED_SC_CONFIG) { 7409265552Snp /* Vet our parameters ..*/ 7410265552Snp if (p->u.config.minmax < 0) { 7411265552Snp rc = EINVAL; 7412265552Snp goto done; 7413265552Snp } 7414265552Snp 7415265552Snp /* And pass the request to the firmware ...*/ 7416265552Snp rc = -t4_sched_config(sc, fw_type, p->u.config.minmax); 7417265552Snp goto done; 7418265552Snp } 7419265552Snp 7420265552Snp if (fw_subcmd == FW_SCHED_SC_PARAMS) { 7421265552Snp int fw_level; 7422265552Snp int fw_mode; 7423265552Snp int fw_rateunit; 7424265552Snp int fw_ratemode; 7425265552Snp 7426265552Snp if (p->u.params.level == SCHED_CLASS_LEVEL_CL_RL) 7427265552Snp fw_level = FW_SCHED_PARAMS_LEVEL_CL_RL; 7428265552Snp else if (p->u.params.level == SCHED_CLASS_LEVEL_CL_WRR) 7429265552Snp fw_level = FW_SCHED_PARAMS_LEVEL_CL_WRR; 7430265552Snp else if (p->u.params.level == SCHED_CLASS_LEVEL_CH_RL) 7431265552Snp fw_level = FW_SCHED_PARAMS_LEVEL_CH_RL; 7432265552Snp else { 7433265552Snp rc = EINVAL; 7434265552Snp goto done; 7435265552Snp } 7436265552Snp 7437265552Snp if (p->u.params.mode == SCHED_CLASS_MODE_CLASS) 7438265552Snp fw_mode = FW_SCHED_PARAMS_MODE_CLASS; 7439265552Snp else if (p->u.params.mode == SCHED_CLASS_MODE_FLOW) 7440265552Snp fw_mode = FW_SCHED_PARAMS_MODE_FLOW; 7441265552Snp else { 7442265552Snp rc = EINVAL; 7443265552Snp goto done; 7444265552Snp } 7445265552Snp 7446265552Snp if (p->u.params.rateunit == SCHED_CLASS_RATEUNIT_BITS) 7447265552Snp fw_rateunit = FW_SCHED_PARAMS_UNIT_BITRATE; 7448265552Snp else if (p->u.params.rateunit == SCHED_CLASS_RATEUNIT_PKTS) 7449265552Snp fw_rateunit = FW_SCHED_PARAMS_UNIT_PKTRATE; 7450265552Snp else { 7451265552Snp rc = EINVAL; 7452265552Snp goto done; 7453265552Snp } 7454265552Snp 7455265552Snp if (p->u.params.ratemode == SCHED_CLASS_RATEMODE_REL) 7456265552Snp fw_ratemode = FW_SCHED_PARAMS_RATE_REL; 7457265552Snp else if (p->u.params.ratemode == SCHED_CLASS_RATEMODE_ABS) 7458265552Snp fw_ratemode = FW_SCHED_PARAMS_RATE_ABS; 7459265552Snp else { 7460265552Snp rc = EINVAL; 7461265552Snp goto done; 7462265552Snp } 7463265552Snp 7464265552Snp /* Vet our parameters ... */ 7465265552Snp if (!in_range(p->u.params.channel, 0, 3) || 7466265552Snp !in_range(p->u.params.cl, 0, is_t4(sc) ? 15 : 16) || 7467265552Snp !in_range(p->u.params.minrate, 0, 10000000) || 7468265552Snp !in_range(p->u.params.maxrate, 0, 10000000) || 7469265552Snp !in_range(p->u.params.weight, 0, 100)) { 7470265552Snp rc = ERANGE; 7471265552Snp goto done; 7472265552Snp } 7473265552Snp 7474265552Snp /* 7475265552Snp * Translate any unset parameters into the firmware's 7476265552Snp * nomenclature and/or fail the call if the parameters 7477265552Snp * are required ... 7478265552Snp */ 7479265552Snp if (p->u.params.rateunit < 0 || p->u.params.ratemode < 0 || 7480265552Snp p->u.params.channel < 0 || p->u.params.cl < 0) { 7481265552Snp rc = EINVAL; 7482265552Snp goto done; 7483265552Snp } 7484265552Snp if (p->u.params.minrate < 0) 7485265552Snp p->u.params.minrate = 0; 7486265552Snp if (p->u.params.maxrate < 0) { 7487265552Snp if (p->u.params.level == SCHED_CLASS_LEVEL_CL_RL || 7488265552Snp p->u.params.level == SCHED_CLASS_LEVEL_CH_RL) { 7489265552Snp rc = EINVAL; 7490265552Snp goto done; 7491265552Snp } else 7492265552Snp p->u.params.maxrate = 0; 7493265552Snp } 7494265552Snp if (p->u.params.weight < 0) { 7495265552Snp if (p->u.params.level == SCHED_CLASS_LEVEL_CL_WRR) { 7496265552Snp rc = EINVAL; 7497265552Snp goto done; 7498265552Snp } else 7499265552Snp p->u.params.weight = 0; 7500265552Snp } 7501265552Snp if (p->u.params.pktsize < 0) { 7502265552Snp if (p->u.params.level == SCHED_CLASS_LEVEL_CL_RL || 7503265552Snp p->u.params.level == SCHED_CLASS_LEVEL_CH_RL) { 7504265552Snp rc = EINVAL; 7505265552Snp goto done; 7506265552Snp } else 7507265552Snp p->u.params.pktsize = 0; 7508265552Snp } 7509265552Snp 7510265552Snp /* See what the firmware thinks of the request ... */ 7511265552Snp rc = -t4_sched_params(sc, fw_type, fw_level, fw_mode, 7512265552Snp fw_rateunit, fw_ratemode, p->u.params.channel, 7513265552Snp p->u.params.cl, p->u.params.minrate, p->u.params.maxrate, 7514265552Snp p->u.params.weight, p->u.params.pktsize); 7515265552Snp goto done; 7516265552Snp } 7517265552Snp 7518265552Snp rc = EINVAL; 7519265552Snpdone: 7520265552Snp end_synchronized_op(sc, 0); 7521265552Snp return (rc); 7522265552Snp} 7523265552Snp 7524265552Snpstatic int 7525265552Snpset_sched_queue(struct adapter *sc, struct t4_sched_queue *p) 7526265552Snp{ 7527265552Snp struct port_info *pi = NULL; 7528265552Snp struct sge_txq *txq; 7529265552Snp uint32_t fw_mnem, fw_queue, fw_class; 7530265552Snp int i, rc; 7531265552Snp 7532265552Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setsq"); 7533265552Snp if (rc) 7534265552Snp return (rc); 7535265552Snp 7536265552Snp if (!(sc->flags & FULL_INIT_DONE)) { 7537265552Snp rc = EAGAIN; 7538265552Snp goto done; 7539265552Snp } 7540265552Snp 7541265552Snp if (p->port >= sc->params.nports) { 7542265552Snp rc = EINVAL; 7543265552Snp goto done; 7544265552Snp } 7545265552Snp 7546265552Snp pi = sc->port[p->port]; 7547265552Snp if (!in_range(p->queue, 0, pi->ntxq - 1) || !in_range(p->cl, 0, 7)) { 7548265552Snp rc = EINVAL; 7549265552Snp goto done; 7550265552Snp } 7551265552Snp 7552265552Snp /* 7553265552Snp * Create a template for the FW_PARAMS_CMD mnemonic and value (TX 7554265552Snp * Scheduling Class in this case). 7555265552Snp */ 7556265552Snp fw_mnem = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) | 7557265552Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH)); 7558265552Snp fw_class = p->cl < 0 ? 0xffffffff : p->cl; 7559265552Snp 7560265552Snp /* 7561265552Snp * If op.queue is non-negative, then we're only changing the scheduling 7562265552Snp * on a single specified TX queue. 7563265552Snp */ 7564265552Snp if (p->queue >= 0) { 7565265552Snp txq = &sc->sge.txq[pi->first_txq + p->queue]; 7566265552Snp fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id)); 7567265552Snp rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue, 7568265552Snp &fw_class); 7569265552Snp goto done; 7570265552Snp } 7571265552Snp 7572265552Snp /* 7573265552Snp * Change the scheduling on all the TX queues for the 7574265552Snp * interface. 7575265552Snp */ 7576265552Snp for_each_txq(pi, i, txq) { 7577265552Snp fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id)); 7578265552Snp rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue, 7579265552Snp &fw_class); 7580265552Snp if (rc) 7581265552Snp goto done; 7582265552Snp } 7583265552Snp 7584265552Snp rc = 0; 7585265552Snpdone: 7586265552Snp end_synchronized_op(sc, 0); 7587265552Snp return (rc); 7588265552Snp} 7589265552Snp 7590218792Snpint 7591218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap) 7592218792Snp{ 7593222102Snp int i; 7594218792Snp 7595222102Snp return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0); 7596218792Snp} 7597218792Snp 7598218792Snpint 7599218792Snpt4_os_pci_save_state(struct adapter *sc) 7600218792Snp{ 7601218792Snp device_t dev; 7602218792Snp struct pci_devinfo *dinfo; 7603218792Snp 7604218792Snp dev = sc->dev; 7605218792Snp dinfo = device_get_ivars(dev); 7606218792Snp 7607218792Snp pci_cfg_save(dev, dinfo, 0); 7608218792Snp return (0); 7609218792Snp} 7610218792Snp 7611218792Snpint 7612218792Snpt4_os_pci_restore_state(struct adapter *sc) 7613218792Snp{ 7614218792Snp device_t dev; 7615218792Snp struct pci_devinfo *dinfo; 7616218792Snp 7617218792Snp dev = sc->dev; 7618218792Snp dinfo = device_get_ivars(dev); 7619218792Snp 7620218792Snp pci_cfg_restore(dev, dinfo); 7621218792Snp return (0); 7622218792Snp} 7623219299Snp 7624218792Snpvoid 7625218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx) 7626218792Snp{ 7627218792Snp struct port_info *pi = sc->port[idx]; 7628218792Snp static const char *mod_str[] = { 7629220232Snp NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM" 7630218792Snp }; 7631218792Snp 7632218792Snp if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 7633218792Snp if_printf(pi->ifp, "transceiver unplugged.\n"); 7634220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) 7635220232Snp if_printf(pi->ifp, "unknown transceiver inserted.\n"); 7636220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) 7637220232Snp if_printf(pi->ifp, "unsupported transceiver inserted.\n"); 7638241467Snp else if (pi->mod_type > 0 && pi->mod_type < nitems(mod_str)) { 7639218792Snp if_printf(pi->ifp, "%s transceiver inserted.\n", 7640218792Snp mod_str[pi->mod_type]); 7641219299Snp } else { 7642219299Snp if_printf(pi->ifp, "transceiver (type %d) inserted.\n", 7643219299Snp pi->mod_type); 7644219299Snp } 7645218792Snp} 7646218792Snp 7647218792Snpvoid 7648252814Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat, int reason) 7649218792Snp{ 7650218792Snp struct port_info *pi = sc->port[idx]; 7651218792Snp struct ifnet *ifp = pi->ifp; 7652218792Snp 7653218792Snp if (link_stat) { 7654252814Snp pi->linkdnrc = -1; 7655218792Snp ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed); 7656218792Snp if_link_state_change(ifp, LINK_STATE_UP); 7657252814Snp } else { 7658252814Snp if (reason >= 0) 7659252814Snp pi->linkdnrc = reason; 7660218792Snp if_link_state_change(ifp, LINK_STATE_DOWN); 7661252814Snp } 7662218792Snp} 7663218792Snp 7664231093Snpvoid 7665231093Snpt4_iterate(void (*func)(struct adapter *, void *), void *arg) 7666231093Snp{ 7667231093Snp struct adapter *sc; 7668231093Snp 7669231093Snp mtx_lock(&t4_list_lock); 7670231093Snp SLIST_FOREACH(sc, &t4_list, link) { 7671231093Snp /* 7672231093Snp * func should not make any assumptions about what state sc is 7673231093Snp * in - the only guarantee is that sc->sc_lock is a valid lock. 7674231093Snp */ 7675231093Snp func(sc, arg); 7676231093Snp } 7677231093Snp mtx_unlock(&t4_list_lock); 7678231093Snp} 7679231093Snp 7680218792Snpstatic int 7681218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td) 7682218792Snp{ 7683218792Snp return (0); 7684218792Snp} 7685218792Snp 7686218792Snpstatic int 7687218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td) 7688218792Snp{ 7689218792Snp return (0); 7690218792Snp} 7691218792Snp 7692218792Snpstatic int 7693218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag, 7694218792Snp struct thread *td) 7695218792Snp{ 7696218792Snp int rc; 7697218792Snp struct adapter *sc = dev->si_drv1; 7698218792Snp 7699218792Snp rc = priv_check(td, PRIV_DRIVER); 7700218792Snp if (rc != 0) 7701218792Snp return (rc); 7702218792Snp 7703218792Snp switch (cmd) { 7704220410Snp case CHELSIO_T4_GETREG: { 7705220410Snp struct t4_reg *edata = (struct t4_reg *)data; 7706220410Snp 7707218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 7708218792Snp return (EFAULT); 7709220410Snp 7710220410Snp if (edata->size == 4) 7711220410Snp edata->val = t4_read_reg(sc, edata->addr); 7712220410Snp else if (edata->size == 8) 7713220410Snp edata->val = t4_read_reg64(sc, edata->addr); 7714220410Snp else 7715220410Snp return (EINVAL); 7716220410Snp 7717218792Snp break; 7718218792Snp } 7719220410Snp case CHELSIO_T4_SETREG: { 7720220410Snp struct t4_reg *edata = (struct t4_reg *)data; 7721220410Snp 7722218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 7723218792Snp return (EFAULT); 7724220410Snp 7725220410Snp if (edata->size == 4) { 7726220410Snp if (edata->val & 0xffffffff00000000) 7727220410Snp return (EINVAL); 7728220410Snp t4_write_reg(sc, edata->addr, (uint32_t) edata->val); 7729220410Snp } else if (edata->size == 8) 7730220410Snp t4_write_reg64(sc, edata->addr, edata->val); 7731220410Snp else 7732220410Snp return (EINVAL); 7733218792Snp break; 7734218792Snp } 7735218792Snp case CHELSIO_T4_REGDUMP: { 7736218792Snp struct t4_regdump *regs = (struct t4_regdump *)data; 7737252495Snp int reglen = is_t4(sc) ? T4_REGDUMP_SIZE : T5_REGDUMP_SIZE; 7738218792Snp uint8_t *buf; 7739218792Snp 7740218792Snp if (regs->len < reglen) { 7741218792Snp regs->len = reglen; /* hint to the caller */ 7742218792Snp return (ENOBUFS); 7743218792Snp } 7744218792Snp 7745218792Snp regs->len = reglen; 7746218792Snp buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO); 7747218792Snp t4_get_regs(sc, regs, buf); 7748218792Snp rc = copyout(buf, regs->data, reglen); 7749218792Snp free(buf, M_CXGBE); 7750218792Snp break; 7751218792Snp } 7752221474Snp case CHELSIO_T4_GET_FILTER_MODE: 7753221474Snp rc = get_filter_mode(sc, (uint32_t *)data); 7754221474Snp break; 7755221474Snp case CHELSIO_T4_SET_FILTER_MODE: 7756221474Snp rc = set_filter_mode(sc, *(uint32_t *)data); 7757221474Snp break; 7758221474Snp case CHELSIO_T4_GET_FILTER: 7759221474Snp rc = get_filter(sc, (struct t4_filter *)data); 7760221474Snp break; 7761221474Snp case CHELSIO_T4_SET_FILTER: 7762221474Snp rc = set_filter(sc, (struct t4_filter *)data); 7763221474Snp break; 7764221474Snp case CHELSIO_T4_DEL_FILTER: 7765221474Snp rc = del_filter(sc, (struct t4_filter *)data); 7766221474Snp break; 7767222973Snp case CHELSIO_T4_GET_SGE_CONTEXT: 7768222973Snp rc = get_sge_context(sc, (struct t4_sge_context *)data); 7769222973Snp break; 7770247434Snp case CHELSIO_T4_LOAD_FW: 7771247434Snp rc = load_fw(sc, (struct t4_data *)data); 7772231093Snp break; 7773231093Snp case CHELSIO_T4_GET_MEM: 7774252495Snp rc = read_card_mem(sc, 2, (struct t4_mem_range *)data); 7775231093Snp break; 7776241573Snp case CHELSIO_T4_GET_I2C: 7777241573Snp rc = read_i2c(sc, (struct t4_i2c_data *)data); 7778241573Snp break; 7779241573Snp case CHELSIO_T4_CLEAR_STATS: { 7780247434Snp int i; 7781241573Snp u_int port_id = *(uint32_t *)data; 7782247434Snp struct port_info *pi; 7783241573Snp 7784241573Snp if (port_id >= sc->params.nports) 7785241573Snp return (EINVAL); 7786265582Snp pi = sc->port[port_id]; 7787241573Snp 7788247434Snp /* MAC stats */ 7789265582Snp t4_clr_port_stats(sc, pi->tx_chan); 7790247434Snp 7791247434Snp if (pi->flags & PORT_INIT_DONE) { 7792247434Snp struct sge_rxq *rxq; 7793247434Snp struct sge_txq *txq; 7794247434Snp struct sge_wrq *wrq; 7795247434Snp 7796247434Snp for_each_rxq(pi, i, rxq) { 7797247434Snp#if defined(INET) || defined(INET6) 7798247434Snp rxq->lro.lro_queued = 0; 7799247434Snp rxq->lro.lro_flushed = 0; 7800247434Snp#endif 7801247434Snp rxq->rxcsum = 0; 7802247434Snp rxq->vlan_extraction = 0; 7803247434Snp } 7804247434Snp 7805247434Snp for_each_txq(pi, i, txq) { 7806247434Snp txq->txcsum = 0; 7807247434Snp txq->tso_wrs = 0; 7808247434Snp txq->vlan_insertion = 0; 7809247434Snp txq->imm_wrs = 0; 7810247434Snp txq->sgl_wrs = 0; 7811247434Snp txq->txpkt_wrs = 0; 7812247434Snp txq->txpkts_wrs = 0; 7813247434Snp txq->txpkts_pkts = 0; 7814247434Snp txq->br->br_drops = 0; 7815247434Snp txq->no_dmamap = 0; 7816247434Snp txq->no_desc = 0; 7817247434Snp } 7818247434Snp 7819247434Snp#ifdef TCP_OFFLOAD 7820247434Snp /* nothing to clear for each ofld_rxq */ 7821247434Snp 7822247434Snp for_each_ofld_txq(pi, i, wrq) { 7823247434Snp wrq->tx_wrs = 0; 7824247434Snp wrq->no_desc = 0; 7825247434Snp } 7826247434Snp#endif 7827247434Snp wrq = &sc->sge.ctrlq[pi->port_id]; 7828247434Snp wrq->tx_wrs = 0; 7829247434Snp wrq->no_desc = 0; 7830247434Snp } 7831241573Snp break; 7832241573Snp } 7833265552Snp case CHELSIO_T4_SCHED_CLASS: 7834265552Snp rc = set_sched_class(sc, (struct t4_sched_params *)data); 7835265552Snp break; 7836265552Snp case CHELSIO_T4_SCHED_QUEUE: 7837265552Snp rc = set_sched_queue(sc, (struct t4_sched_queue *)data); 7838265552Snp break; 7839218792Snp default: 7840218792Snp rc = EINVAL; 7841218792Snp } 7842218792Snp 7843218792Snp return (rc); 7844218792Snp} 7845218792Snp 7846237920Snp#ifdef TCP_OFFLOAD 7847219392Snpstatic int 7848231093Snptoe_capability(struct port_info *pi, int enable) 7849231093Snp{ 7850231093Snp int rc; 7851231093Snp struct adapter *sc = pi->adapter; 7852231093Snp 7853247434Snp ASSERT_SYNCHRONIZED_OP(sc); 7854231093Snp 7855231093Snp if (!is_offload(sc)) 7856231093Snp return (ENODEV); 7857231093Snp 7858231093Snp if (enable) { 7859237920Snp if (!(sc->flags & FULL_INIT_DONE)) { 7860247434Snp rc = cxgbe_init_synchronized(pi); 7861247434Snp if (rc) 7862247434Snp return (rc); 7863237920Snp } 7864237920Snp 7865231093Snp if (isset(&sc->offload_map, pi->port_id)) 7866231093Snp return (0); 7867231093Snp 7868237920Snp if (!(sc->flags & TOM_INIT_DONE)) { 7869237920Snp rc = t4_activate_uld(sc, ULD_TOM); 7870237920Snp if (rc == EAGAIN) { 7871237920Snp log(LOG_WARNING, 7872237920Snp "You must kldload t4_tom.ko before trying " 7873237920Snp "to enable TOE on a cxgbe interface.\n"); 7874237920Snp } 7875231093Snp if (rc != 0) 7876231093Snp return (rc); 7877237920Snp KASSERT(sc->tom_softc != NULL, 7878237920Snp ("%s: TOM activated but softc NULL", __func__)); 7879237920Snp KASSERT(sc->flags & TOM_INIT_DONE, 7880237920Snp ("%s: TOM activated but flag not set", __func__)); 7881231093Snp } 7882231093Snp 7883231093Snp setbit(&sc->offload_map, pi->port_id); 7884231093Snp } else { 7885231093Snp if (!isset(&sc->offload_map, pi->port_id)) 7886231093Snp return (0); 7887231093Snp 7888237920Snp KASSERT(sc->flags & TOM_INIT_DONE, 7889237920Snp ("%s: TOM never initialized?", __func__)); 7890231093Snp clrbit(&sc->offload_map, pi->port_id); 7891231093Snp } 7892231093Snp 7893231093Snp return (0); 7894231093Snp} 7895231093Snp 7896231093Snp/* 7897231093Snp * Add an upper layer driver to the global list. 7898231093Snp */ 7899231093Snpint 7900231093Snpt4_register_uld(struct uld_info *ui) 7901231093Snp{ 7902231093Snp int rc = 0; 7903231093Snp struct uld_info *u; 7904231093Snp 7905231093Snp mtx_lock(&t4_uld_list_lock); 7906231093Snp SLIST_FOREACH(u, &t4_uld_list, link) { 7907231093Snp if (u->uld_id == ui->uld_id) { 7908231093Snp rc = EEXIST; 7909231093Snp goto done; 7910231093Snp } 7911231093Snp } 7912231093Snp 7913231093Snp SLIST_INSERT_HEAD(&t4_uld_list, ui, link); 7914231093Snp ui->refcount = 0; 7915231093Snpdone: 7916231093Snp mtx_unlock(&t4_uld_list_lock); 7917231093Snp return (rc); 7918231093Snp} 7919231093Snp 7920231093Snpint 7921231093Snpt4_unregister_uld(struct uld_info *ui) 7922231093Snp{ 7923231093Snp int rc = EINVAL; 7924231093Snp struct uld_info *u; 7925231093Snp 7926231093Snp mtx_lock(&t4_uld_list_lock); 7927231093Snp 7928231093Snp SLIST_FOREACH(u, &t4_uld_list, link) { 7929231093Snp if (u == ui) { 7930231093Snp if (ui->refcount > 0) { 7931231093Snp rc = EBUSY; 7932231093Snp goto done; 7933231093Snp } 7934231093Snp 7935231093Snp SLIST_REMOVE(&t4_uld_list, ui, uld_info, link); 7936231093Snp rc = 0; 7937231093Snp goto done; 7938231093Snp } 7939231093Snp } 7940231093Snpdone: 7941231093Snp mtx_unlock(&t4_uld_list_lock); 7942231093Snp return (rc); 7943231093Snp} 7944231093Snp 7945237920Snpint 7946237920Snpt4_activate_uld(struct adapter *sc, int id) 7947231093Snp{ 7948231093Snp int rc = EAGAIN; 7949231093Snp struct uld_info *ui; 7950231093Snp 7951247434Snp ASSERT_SYNCHRONIZED_OP(sc); 7952247434Snp 7953231093Snp mtx_lock(&t4_uld_list_lock); 7954231093Snp 7955231093Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 7956231093Snp if (ui->uld_id == id) { 7957237920Snp rc = ui->activate(sc); 7958237920Snp if (rc == 0) 7959231093Snp ui->refcount++; 7960231093Snp goto done; 7961231093Snp } 7962231093Snp } 7963231093Snpdone: 7964231093Snp mtx_unlock(&t4_uld_list_lock); 7965231093Snp 7966231093Snp return (rc); 7967231093Snp} 7968231093Snp 7969237920Snpint 7970237920Snpt4_deactivate_uld(struct adapter *sc, int id) 7971231093Snp{ 7972237920Snp int rc = EINVAL; 7973237920Snp struct uld_info *ui; 7974231093Snp 7975247434Snp ASSERT_SYNCHRONIZED_OP(sc); 7976247434Snp 7977231093Snp mtx_lock(&t4_uld_list_lock); 7978231093Snp 7979237920Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 7980237920Snp if (ui->uld_id == id) { 7981237920Snp rc = ui->deactivate(sc); 7982237920Snp if (rc == 0) 7983237920Snp ui->refcount--; 7984237920Snp goto done; 7985237920Snp } 7986231093Snp } 7987231093Snpdone: 7988231093Snp mtx_unlock(&t4_uld_list_lock); 7989231093Snp 7990231093Snp return (rc); 7991231093Snp} 7992231093Snp#endif 7993231093Snp 7994231093Snp/* 7995231093Snp * Come up with reasonable defaults for some of the tunables, provided they're 7996231093Snp * not set by the user (in which case we'll use the values as is). 7997231093Snp */ 7998231093Snpstatic void 7999231093Snptweak_tunables(void) 8000231093Snp{ 8001231093Snp int nc = mp_ncpus; /* our snapshot of the number of CPUs */ 8002231093Snp 8003231093Snp if (t4_ntxq10g < 1) 8004231093Snp t4_ntxq10g = min(nc, NTXQ_10G); 8005231093Snp 8006231093Snp if (t4_ntxq1g < 1) 8007231093Snp t4_ntxq1g = min(nc, NTXQ_1G); 8008231093Snp 8009231093Snp if (t4_nrxq10g < 1) 8010231093Snp t4_nrxq10g = min(nc, NRXQ_10G); 8011231093Snp 8012231093Snp if (t4_nrxq1g < 1) 8013231093Snp t4_nrxq1g = min(nc, NRXQ_1G); 8014231093Snp 8015237920Snp#ifdef TCP_OFFLOAD 8016231093Snp if (t4_nofldtxq10g < 1) 8017231093Snp t4_nofldtxq10g = min(nc, NOFLDTXQ_10G); 8018231093Snp 8019231093Snp if (t4_nofldtxq1g < 1) 8020231093Snp t4_nofldtxq1g = min(nc, NOFLDTXQ_1G); 8021231093Snp 8022231093Snp if (t4_nofldrxq10g < 1) 8023231093Snp t4_nofldrxq10g = min(nc, NOFLDRXQ_10G); 8024231093Snp 8025231093Snp if (t4_nofldrxq1g < 1) 8026231093Snp t4_nofldrxq1g = min(nc, NOFLDRXQ_1G); 8027238037Snp 8028238037Snp if (t4_toecaps_allowed == -1) 8029238037Snp t4_toecaps_allowed = FW_CAPS_CONFIG_TOE; 8030238037Snp#else 8031238037Snp if (t4_toecaps_allowed == -1) 8032238037Snp t4_toecaps_allowed = 0; 8033231093Snp#endif 8034231093Snp 8035231093Snp if (t4_tmr_idx_10g < 0 || t4_tmr_idx_10g >= SGE_NTIMERS) 8036231093Snp t4_tmr_idx_10g = TMR_IDX_10G; 8037231093Snp 8038231093Snp if (t4_pktc_idx_10g < -1 || t4_pktc_idx_10g >= SGE_NCOUNTERS) 8039231093Snp t4_pktc_idx_10g = PKTC_IDX_10G; 8040231093Snp 8041231093Snp if (t4_tmr_idx_1g < 0 || t4_tmr_idx_1g >= SGE_NTIMERS) 8042231093Snp t4_tmr_idx_1g = TMR_IDX_1G; 8043231093Snp 8044231093Snp if (t4_pktc_idx_1g < -1 || t4_pktc_idx_1g >= SGE_NCOUNTERS) 8045231093Snp t4_pktc_idx_1g = PKTC_IDX_1G; 8046231093Snp 8047231093Snp if (t4_qsize_txq < 128) 8048231093Snp t4_qsize_txq = 128; 8049231093Snp 8050231093Snp if (t4_qsize_rxq < 128) 8051231093Snp t4_qsize_rxq = 128; 8052231093Snp while (t4_qsize_rxq & 7) 8053231093Snp t4_qsize_rxq++; 8054231093Snp 8055231093Snp t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX; 8056231093Snp} 8057231093Snp 8058231093Snpstatic int 8059252495Snpmod_event(module_t mod, int cmd, void *arg) 8060219392Snp{ 8061231093Snp int rc = 0; 8062252495Snp static int loaded = 0; 8063219392Snp 8064231093Snp switch (cmd) { 8065231093Snp case MOD_LOAD: 8066252495Snp if (atomic_fetchadd_int(&loaded, 1)) 8067252495Snp break; 8068219392Snp t4_sge_modload(); 8069231093Snp mtx_init(&t4_list_lock, "T4 adapters", 0, MTX_DEF); 8070231093Snp SLIST_INIT(&t4_list); 8071237920Snp#ifdef TCP_OFFLOAD 8072231093Snp mtx_init(&t4_uld_list_lock, "T4 ULDs", 0, MTX_DEF); 8073231093Snp SLIST_INIT(&t4_uld_list); 8074231093Snp#endif 8075231093Snp tweak_tunables(); 8076231093Snp break; 8077219392Snp 8078231093Snp case MOD_UNLOAD: 8079252495Snp if (atomic_fetchadd_int(&loaded, -1) > 1) 8080252495Snp break; 8081237920Snp#ifdef TCP_OFFLOAD 8082231093Snp mtx_lock(&t4_uld_list_lock); 8083231093Snp if (!SLIST_EMPTY(&t4_uld_list)) { 8084231093Snp rc = EBUSY; 8085231093Snp mtx_unlock(&t4_uld_list_lock); 8086231093Snp break; 8087231093Snp } 8088231093Snp mtx_unlock(&t4_uld_list_lock); 8089231093Snp mtx_destroy(&t4_uld_list_lock); 8090231093Snp#endif 8091231093Snp mtx_lock(&t4_list_lock); 8092231093Snp if (!SLIST_EMPTY(&t4_list)) { 8093231093Snp rc = EBUSY; 8094231093Snp mtx_unlock(&t4_list_lock); 8095231093Snp break; 8096231093Snp } 8097231093Snp mtx_unlock(&t4_list_lock); 8098231093Snp mtx_destroy(&t4_list_lock); 8099231093Snp break; 8100231093Snp } 8101231093Snp 8102231093Snp return (rc); 8103219392Snp} 8104219392Snp 8105252495Snpstatic devclass_t t4_devclass, t5_devclass; 8106252495Snpstatic devclass_t cxgbe_devclass, cxl_devclass; 8107218792Snp 8108252495SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, mod_event, 0); 8109218792SnpMODULE_VERSION(t4nex, 1); 8110252495SnpMODULE_DEPEND(t4nex, firmware, 1, 1, 1); 8111218792Snp 8112252495SnpDRIVER_MODULE(t5nex, pci, t5_driver, t5_devclass, mod_event, 0); 8113252495SnpMODULE_VERSION(t5nex, 1); 8114252495SnpMODULE_DEPEND(t5nex, firmware, 1, 1, 1); 8115252495Snp 8116218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0); 8117218792SnpMODULE_VERSION(cxgbe, 1); 8118252495Snp 8119252495SnpDRIVER_MODULE(cxl, t5nex, cxl_driver, cxl_devclass, 0, 0); 8120252495SnpMODULE_VERSION(cxl, 1); 8121