t4_main.c revision 252469
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: head/sys/dev/cxgbe/t4_main.c 252469 2013-07-01 17:31:04Z np $"); 30218792Snp 31218792Snp#include "opt_inet.h" 32237819Snp#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> 58248925Snp#if defined(__i386__) || defined(__amd64__) 59248925Snp#include <vm/vm.h> 60248925Snp#include <vm/pmap.h> 61248925Snp#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 79227843Smarius 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 117248925Snp/* T5 bus driver interface */ 118248925Snpstatic int t5_probe(device_t); 119248925Snpstatic device_method_t t5_methods[] = { 120248925Snp DEVMETHOD(device_probe, t5_probe), 121248925Snp DEVMETHOD(device_attach, t4_attach), 122248925Snp DEVMETHOD(device_detach, t4_detach), 123248925Snp 124248925Snp DEVMETHOD_END 125248925Snp}; 126248925Snpstatic driver_t t5_driver = { 127248925Snp "t5nex", 128248925Snp t5_methods, 129248925Snp sizeof(struct adapter) 130248925Snp}; 131248925Snp 132248925Snp 133248925Snp/* T5 port (cxl) interface */ 134248925Snpstatic driver_t cxl_driver = { 135248925Snp "cxl", 136248925Snp cxgbe_methods, 137248925Snp sizeof(struct port_info) 138248925Snp}; 139248925Snp 140248925Snpstatic struct cdevsw t5_cdevsw = { 141248925Snp .d_version = D_VERSION, 142248925Snp .d_flags = 0, 143248925Snp .d_open = t4_open, 144248925Snp .d_close = t4_close, 145248925Snp .d_ioctl = t4_ioctl, 146248925Snp .d_name = "t5nex", 147248925Snp}; 148248925Snp 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 157248925SnpMALLOC_DEFINE(M_CXGBE, "cxgbe", "Chelsio T4/T5 Ethernet driver and services"); 158218792Snp 159237263Snp/* 160237263Snp * Correct lock order when you need to acquire multiple locks is t4_list_lock, 161237263Snp * then ADAPTER_LOCK, then t4_uld_list_lock. 162237263Snp */ 163228561Snpstatic struct mtx t4_list_lock; 164228561Snpstatic SLIST_HEAD(, adapter) t4_list; 165237263Snp#ifdef TCP_OFFLOAD 166228561Snpstatic struct mtx t4_uld_list_lock; 167228561Snpstatic SLIST_HEAD(, uld_info) t4_uld_list; 168228561Snp#endif 169218792Snp 170218792Snp/* 171228561Snp * Tunables. See tweak_tunables() too. 172248925Snp * 173248925Snp * Each tunable is set to a default value here if it's known at compile-time. 174248925Snp * Otherwise it is set to -1 as an indication to tweak_tunables() that it should 175248925Snp * provide a reasonable default when the driver is loaded. 176248925Snp * 177248925Snp * Tunables applicable to both T4 and T5 are under hw.cxgbe. Those specific to 178248925Snp * T5 are under hw.cxl. 179218792Snp */ 180218792Snp 181218792Snp/* 182228561Snp * Number of queues for tx and rx, 10G and 1G, NIC and offload. 183218792Snp */ 184228561Snp#define NTXQ_10G 16 185228561Snpstatic int t4_ntxq10g = -1; 186228561SnpTUNABLE_INT("hw.cxgbe.ntxq10g", &t4_ntxq10g); 187218792Snp 188228561Snp#define NRXQ_10G 8 189228561Snpstatic int t4_nrxq10g = -1; 190228561SnpTUNABLE_INT("hw.cxgbe.nrxq10g", &t4_nrxq10g); 191218792Snp 192228561Snp#define NTXQ_1G 4 193228561Snpstatic int t4_ntxq1g = -1; 194228561SnpTUNABLE_INT("hw.cxgbe.ntxq1g", &t4_ntxq1g); 195218792Snp 196228561Snp#define NRXQ_1G 2 197228561Snpstatic int t4_nrxq1g = -1; 198228561SnpTUNABLE_INT("hw.cxgbe.nrxq1g", &t4_nrxq1g); 199218792Snp 200237263Snp#ifdef TCP_OFFLOAD 201228561Snp#define NOFLDTXQ_10G 8 202228561Snpstatic int t4_nofldtxq10g = -1; 203228561SnpTUNABLE_INT("hw.cxgbe.nofldtxq10g", &t4_nofldtxq10g); 204228561Snp 205228561Snp#define NOFLDRXQ_10G 2 206228561Snpstatic int t4_nofldrxq10g = -1; 207228561SnpTUNABLE_INT("hw.cxgbe.nofldrxq10g", &t4_nofldrxq10g); 208228561Snp 209228561Snp#define NOFLDTXQ_1G 2 210228561Snpstatic int t4_nofldtxq1g = -1; 211228561SnpTUNABLE_INT("hw.cxgbe.nofldtxq1g", &t4_nofldtxq1g); 212228561Snp 213228561Snp#define NOFLDRXQ_1G 1 214228561Snpstatic int t4_nofldrxq1g = -1; 215228561SnpTUNABLE_INT("hw.cxgbe.nofldrxq1g", &t4_nofldrxq1g); 216228561Snp#endif 217228561Snp 218218792Snp/* 219218792Snp * Holdoff parameters for 10G and 1G ports. 220218792Snp */ 221228561Snp#define TMR_IDX_10G 1 222228561Snpstatic int t4_tmr_idx_10g = TMR_IDX_10G; 223228561SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_10G", &t4_tmr_idx_10g); 224218792Snp 225234833Snp#define PKTC_IDX_10G (-1) 226228561Snpstatic int t4_pktc_idx_10g = PKTC_IDX_10G; 227228561SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_10G", &t4_pktc_idx_10g); 228218792Snp 229228561Snp#define TMR_IDX_1G 1 230228561Snpstatic int t4_tmr_idx_1g = TMR_IDX_1G; 231228561SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_1G", &t4_tmr_idx_1g); 232218792Snp 233234833Snp#define PKTC_IDX_1G (-1) 234228561Snpstatic int t4_pktc_idx_1g = PKTC_IDX_1G; 235228561SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_1G", &t4_pktc_idx_1g); 236218792Snp 237218792Snp/* 238218792Snp * Size (# of entries) of each tx and rx queue. 239218792Snp */ 240228561Snpstatic unsigned int t4_qsize_txq = TX_EQ_QSIZE; 241228561SnpTUNABLE_INT("hw.cxgbe.qsize_txq", &t4_qsize_txq); 242218792Snp 243228561Snpstatic unsigned int t4_qsize_rxq = RX_IQ_QSIZE; 244228561SnpTUNABLE_INT("hw.cxgbe.qsize_rxq", &t4_qsize_rxq); 245218792Snp 246218792Snp/* 247228561Snp * Interrupt types allowed (bits 0, 1, 2 = INTx, MSI, MSI-X respectively). 248218792Snp */ 249228561Snpstatic int t4_intr_types = INTR_MSIX | INTR_MSI | INTR_INTX; 250228561SnpTUNABLE_INT("hw.cxgbe.interrupt_types", &t4_intr_types); 251218792Snp 252218792Snp/* 253228561Snp * Configuration file. 254218792Snp */ 255248925Snp#define DEFAULT_CF "default" 256248925Snp#define FLASH_CF "flash" 257248925Snp#define UWIRE_CF "uwire" 258249376Snp#define FPGA_CF "fpga" 259248925Snpstatic char t4_cfg_file[32] = DEFAULT_CF; 260228561SnpTUNABLE_STR("hw.cxgbe.config_file", t4_cfg_file, sizeof(t4_cfg_file)); 261218792Snp 262228561Snp/* 263247347Snp * Firmware auto-install by driver during attach (0, 1, 2 = prohibited, allowed, 264247347Snp * encouraged respectively). 265247347Snp */ 266247347Snpstatic unsigned int t4_fw_install = 1; 267247347SnpTUNABLE_INT("hw.cxgbe.fw_install", &t4_fw_install); 268247347Snp 269247347Snp/* 270228561Snp * ASIC features that will be used. Disable the ones you don't want so that the 271228561Snp * chip resources aren't wasted on features that will not be used. 272228561Snp */ 273228561Snpstatic int t4_linkcaps_allowed = 0; /* No DCBX, PPP, etc. by default */ 274228561SnpTUNABLE_INT("hw.cxgbe.linkcaps_allowed", &t4_linkcaps_allowed); 275221474Snp 276228561Snpstatic int t4_niccaps_allowed = FW_CAPS_CONFIG_NIC; 277228561SnpTUNABLE_INT("hw.cxgbe.niccaps_allowed", &t4_niccaps_allowed); 278228561Snp 279238028Snpstatic int t4_toecaps_allowed = -1; 280228561SnpTUNABLE_INT("hw.cxgbe.toecaps_allowed", &t4_toecaps_allowed); 281228561Snp 282228561Snpstatic int t4_rdmacaps_allowed = 0; 283228561SnpTUNABLE_INT("hw.cxgbe.rdmacaps_allowed", &t4_rdmacaps_allowed); 284228561Snp 285228561Snpstatic int t4_iscsicaps_allowed = 0; 286228561SnpTUNABLE_INT("hw.cxgbe.iscsicaps_allowed", &t4_iscsicaps_allowed); 287228561Snp 288228561Snpstatic int t4_fcoecaps_allowed = 0; 289228561SnpTUNABLE_INT("hw.cxgbe.fcoecaps_allowed", &t4_fcoecaps_allowed); 290228561Snp 291248925Snpstatic int t5_write_combine = 0; 292248925SnpTUNABLE_INT("hw.cxl.write_combine", &t5_write_combine); 293248925Snp 294218792Snpstruct intrs_and_queues { 295219944Snp int intr_type; /* INTx, MSI, or MSI-X */ 296218792Snp int nirq; /* Number of vectors */ 297228561Snp int intr_flags; 298218792Snp int ntxq10g; /* # of NIC txq's for each 10G port */ 299218792Snp int nrxq10g; /* # of NIC rxq's for each 10G port */ 300218792Snp int ntxq1g; /* # of NIC txq's for each 1G port */ 301218792Snp int nrxq1g; /* # of NIC rxq's for each 1G port */ 302237263Snp#ifdef TCP_OFFLOAD 303228561Snp int nofldtxq10g; /* # of TOE txq's for each 10G port */ 304228561Snp int nofldrxq10g; /* # of TOE rxq's for each 10G port */ 305228561Snp int nofldtxq1g; /* # of TOE txq's for each 1G port */ 306228561Snp int nofldrxq1g; /* # of TOE rxq's for each 1G port */ 307228561Snp#endif 308218792Snp}; 309218792Snp 310221474Snpstruct filter_entry { 311221474Snp uint32_t valid:1; /* filter allocated and valid */ 312221474Snp uint32_t locked:1; /* filter is administratively locked */ 313221474Snp uint32_t pending:1; /* filter action is pending firmware reply */ 314221474Snp uint32_t smtidx:8; /* Source MAC Table index for smac */ 315222509Snp struct l2t_entry *l2t; /* Layer Two Table entry for dmac */ 316221474Snp 317221474Snp struct t4_filter_specification fs; 318221474Snp}; 319221474Snp 320218792Snpenum { 321218792Snp XGMAC_MTU = (1 << 0), 322218792Snp XGMAC_PROMISC = (1 << 1), 323218792Snp XGMAC_ALLMULTI = (1 << 2), 324218792Snp XGMAC_VLANEX = (1 << 3), 325218792Snp XGMAC_UCADDR = (1 << 4), 326218792Snp XGMAC_MCADDRS = (1 << 5), 327218792Snp 328218792Snp XGMAC_ALL = 0xffff 329218792Snp}; 330218792Snp 331248925Snpstatic int map_bars_0_and_4(struct adapter *); 332248925Snpstatic int map_bar_2(struct adapter *); 333218792Snpstatic void setup_memwin(struct adapter *); 334248925Snpstatic int validate_mem_range(struct adapter *, uint32_t, int); 335248925Snpstatic int validate_mt_off_len(struct adapter *, int, uint32_t, int, 336248925Snp uint32_t *); 337248925Snpstatic void memwin_info(struct adapter *, int, uint32_t *, uint32_t *); 338248925Snpstatic uint32_t position_memwin(struct adapter *, int, uint32_t); 339218792Snpstatic int cfg_itype_and_nqueues(struct adapter *, int, int, 340218792Snp struct intrs_and_queues *); 341218792Snpstatic int prep_firmware(struct adapter *); 342248925Snpstatic int partition_resources(struct adapter *, const struct firmware *, 343248925Snp const char *); 344228561Snpstatic int get_params__pre_init(struct adapter *); 345228561Snpstatic int get_params__post_init(struct adapter *); 346247291Snpstatic int set_params__post_init(struct adapter *); 347218792Snpstatic void t4_set_desc(struct adapter *); 348218792Snpstatic void build_medialist(struct port_info *); 349218792Snpstatic int update_mac_settings(struct port_info *, int); 350218792Snpstatic int cxgbe_init_synchronized(struct port_info *); 351218792Snpstatic int cxgbe_uninit_synchronized(struct port_info *); 352240453Snpstatic int setup_intr_handlers(struct adapter *); 353228561Snpstatic int adapter_full_init(struct adapter *); 354228561Snpstatic int adapter_full_uninit(struct adapter *); 355228561Snpstatic int port_full_init(struct port_info *); 356228561Snpstatic int port_full_uninit(struct port_info *); 357228561Snpstatic void quiesce_eq(struct adapter *, struct sge_eq *); 358228561Snpstatic void quiesce_iq(struct adapter *, struct sge_iq *); 359228561Snpstatic void quiesce_fl(struct adapter *, struct sge_fl *); 360218792Snpstatic int t4_alloc_irq(struct adapter *, struct irq *, int rid, 361228561Snp driver_intr_t *, void *, char *); 362218792Snpstatic int t4_free_irq(struct adapter *, struct irq *); 363218792Snpstatic void reg_block_dump(struct adapter *, uint8_t *, unsigned int, 364218792Snp unsigned int); 365218792Snpstatic void t4_get_regs(struct adapter *, struct t4_regdump *, uint8_t *); 366218792Snpstatic void cxgbe_tick(void *); 367237263Snpstatic void cxgbe_vlan_config(void *, struct ifnet *, uint16_t); 368228561Snpstatic int cpl_not_handled(struct sge_iq *, const struct rss_header *, 369228561Snp struct mbuf *); 370237263Snpstatic int an_not_handled(struct sge_iq *, const struct rsp_ctrl *); 371239336Snpstatic int fw_msg_not_handled(struct adapter *, const __be64 *); 372218792Snpstatic int t4_sysctls(struct adapter *); 373218792Snpstatic int cxgbe_sysctls(struct port_info *); 374219436Snpstatic int sysctl_int_array(SYSCTL_HANDLER_ARGS); 375228561Snpstatic int sysctl_bitfield(SYSCTL_HANDLER_ARGS); 376218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS); 377218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS); 378218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS); 379218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS); 380218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS); 381231115Snp#ifdef SBUF_DRAIN 382228561Snpstatic int sysctl_cctrl(SYSCTL_HANDLER_ARGS); 383247122Snpstatic int sysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS); 384247122Snpstatic int sysctl_cim_la(SYSCTL_HANDLER_ARGS); 385251213Snpstatic int sysctl_cim_ma_la(SYSCTL_HANDLER_ARGS); 386251213Snpstatic int sysctl_cim_pif_la(SYSCTL_HANDLER_ARGS); 387247122Snpstatic int sysctl_cim_qcfg(SYSCTL_HANDLER_ARGS); 388228561Snpstatic int sysctl_cpl_stats(SYSCTL_HANDLER_ARGS); 389228561Snpstatic int sysctl_ddp_stats(SYSCTL_HANDLER_ARGS); 390222551Snpstatic int sysctl_devlog(SYSCTL_HANDLER_ARGS); 391228561Snpstatic int sysctl_fcoe_stats(SYSCTL_HANDLER_ARGS); 392228561Snpstatic int sysctl_hw_sched(SYSCTL_HANDLER_ARGS); 393228561Snpstatic int sysctl_lb_stats(SYSCTL_HANDLER_ARGS); 394228561Snpstatic int sysctl_meminfo(SYSCTL_HANDLER_ARGS); 395251213Snpstatic int sysctl_mps_tcam(SYSCTL_HANDLER_ARGS); 396228561Snpstatic int sysctl_path_mtus(SYSCTL_HANDLER_ARGS); 397228561Snpstatic int sysctl_pm_stats(SYSCTL_HANDLER_ARGS); 398228561Snpstatic int sysctl_rdma_stats(SYSCTL_HANDLER_ARGS); 399228561Snpstatic int sysctl_tcp_stats(SYSCTL_HANDLER_ARGS); 400228561Snpstatic int sysctl_tids(SYSCTL_HANDLER_ARGS); 401228561Snpstatic int sysctl_tp_err_stats(SYSCTL_HANDLER_ARGS); 402251213Snpstatic int sysctl_tp_la(SYSCTL_HANDLER_ARGS); 403228561Snpstatic int sysctl_tx_rate(SYSCTL_HANDLER_ARGS); 404251213Snpstatic int sysctl_ulprx_la(SYSCTL_HANDLER_ARGS); 405249392Snpstatic int sysctl_wcwr_stats(SYSCTL_HANDLER_ARGS); 406231115Snp#endif 407219286Snpstatic inline void txq_start(struct ifnet *, struct sge_txq *); 408221474Snpstatic uint32_t fconf_to_mode(uint32_t); 409221474Snpstatic uint32_t mode_to_fconf(uint32_t); 410221474Snpstatic uint32_t fspec_to_fconf(struct t4_filter_specification *); 411221474Snpstatic int get_filter_mode(struct adapter *, uint32_t *); 412221474Snpstatic int set_filter_mode(struct adapter *, uint32_t); 413222552Snpstatic inline uint64_t get_filter_hits(struct adapter *, uint32_t); 414221474Snpstatic int get_filter(struct adapter *, struct t4_filter *); 415221474Snpstatic int set_filter(struct adapter *, struct t4_filter *); 416221474Snpstatic int del_filter(struct adapter *, struct t4_filter *); 417222509Snpstatic void clear_filter(struct filter_entry *); 418221474Snpstatic int set_filter_wr(struct adapter *, int); 419221474Snpstatic int del_filter_wr(struct adapter *, int); 420222973Snpstatic int get_sge_context(struct adapter *, struct t4_sge_context *); 421245274Snpstatic int load_fw(struct adapter *, struct t4_data *); 422248925Snpstatic int read_card_mem(struct adapter *, int, struct t4_mem_range *); 423241399Snpstatic int read_i2c(struct adapter *, struct t4_i2c_data *); 424237263Snp#ifdef TCP_OFFLOAD 425228561Snpstatic int toe_capability(struct port_info *, int); 426228561Snp#endif 427249370Snpstatic int mod_event(module_t, int, void *); 428218792Snp 429248925Snpstruct { 430218792Snp uint16_t device; 431218792Snp char *desc; 432218792Snp} t4_pciids[] = { 433237587Snp {0xa000, "Chelsio Terminator 4 FPGA"}, 434237587Snp {0x4400, "Chelsio T440-dbg"}, 435237587Snp {0x4401, "Chelsio T420-CR"}, 436237587Snp {0x4402, "Chelsio T422-CR"}, 437237587Snp {0x4403, "Chelsio T440-CR"}, 438237587Snp {0x4404, "Chelsio T420-BCH"}, 439237587Snp {0x4405, "Chelsio T440-BCH"}, 440237587Snp {0x4406, "Chelsio T440-CH"}, 441237587Snp {0x4407, "Chelsio T420-SO"}, 442237587Snp {0x4408, "Chelsio T420-CX"}, 443237587Snp {0x4409, "Chelsio T420-BT"}, 444237587Snp {0x440a, "Chelsio T404-BT"}, 445244580Snp {0x440e, "Chelsio T440-LP-CR"}, 446248925Snp}, t5_pciids[] = { 447248925Snp {0xb000, "Chelsio Terminator 5 FPGA"}, 448248925Snp {0x5400, "Chelsio T580-dbg"}, 449249393Snp {0x5401, "Chelsio T520-CR"}, 450249393Snp {0x5407, "Chelsio T520-SO"}, 451249393Snp {0x5408, "Chelsio T520-CX"}, 452250093Snp {0x5410, "Chelsio T580-LP-CR"}, /* 2 x 40G */ 453249393Snp {0x5411, "Chelsio T520-LL-CR"}, 454249393Snp#ifdef notyet 455249393Snp {0x5402, "Chelsio T522-CR"}, 456249393Snp {0x5403, "Chelsio T540-CR"}, 457249393Snp {0x5404, "Chelsio T520-BCH"}, 458249393Snp {0x5405, "Chelsio T540-BCH"}, 459249393Snp {0x5406, "Chelsio T540-CH"}, 460249393Snp {0x5409, "Chelsio T520-BT"}, 461249393Snp {0x540a, "Chelsio T504-BT"}, 462249393Snp {0x540b, "Chelsio B520-SR"}, 463249393Snp {0x540c, "Chelsio B504-BT"}, 464249393Snp {0x540d, "Chelsio T580-CR"}, 465249393Snp {0x540e, "Chelsio T540-LP-CR"}, 466249393Snp {0x540f, "Chelsio Amsterdam"}, 467249393Snp {0x5412, "Chelsio T560-CR"}, 468249393Snp {0x5413, "Chelsio T580-CR"}, 469249393Snp#endif 470218792Snp}; 471218792Snp 472237263Snp#ifdef TCP_OFFLOAD 473237263Snp/* 474237263Snp * service_iq() has an iq and needs the fl. Offset of fl from the iq should be 475237263Snp * exactly the same for both rxq and ofld_rxq. 476237263Snp */ 477237263SnpCTASSERT(offsetof(struct sge_ofld_rxq, iq) == offsetof(struct sge_rxq, iq)); 478228561SnpCTASSERT(offsetof(struct sge_ofld_rxq, fl) == offsetof(struct sge_rxq, fl)); 479228561Snp#endif 480228561Snp 481239336Snp/* No easy way to include t4_msg.h before adapter.h so we check this way */ 482240452SnpCTASSERT(nitems(((struct adapter *)0)->cpl_handler) == NUM_CPL_CMDS); 483240452SnpCTASSERT(nitems(((struct adapter *)0)->fw_msg_handler) == NUM_FW6_TYPES); 484239336Snp 485218792Snpstatic int 486218792Snpt4_probe(device_t dev) 487218792Snp{ 488218792Snp int i; 489218792Snp uint16_t v = pci_get_vendor(dev); 490218792Snp uint16_t d = pci_get_device(dev); 491237587Snp uint8_t f = pci_get_function(dev); 492218792Snp 493218792Snp if (v != PCI_VENDOR_ID_CHELSIO) 494218792Snp return (ENXIO); 495218792Snp 496237587Snp /* Attach only to PF0 of the FPGA */ 497237587Snp if (d == 0xa000 && f != 0) 498237587Snp return (ENXIO); 499237587Snp 500240452Snp for (i = 0; i < nitems(t4_pciids); i++) { 501237587Snp if (d == t4_pciids[i].device) { 502218792Snp device_set_desc(dev, t4_pciids[i].desc); 503218792Snp return (BUS_PROBE_DEFAULT); 504218792Snp } 505218792Snp } 506218792Snp 507218792Snp return (ENXIO); 508218792Snp} 509218792Snp 510218792Snpstatic int 511248925Snpt5_probe(device_t dev) 512248925Snp{ 513248925Snp int i; 514248925Snp uint16_t v = pci_get_vendor(dev); 515248925Snp uint16_t d = pci_get_device(dev); 516248925Snp uint8_t f = pci_get_function(dev); 517248925Snp 518248925Snp if (v != PCI_VENDOR_ID_CHELSIO) 519248925Snp return (ENXIO); 520248925Snp 521248925Snp /* Attach only to PF0 of the FPGA */ 522248925Snp if (d == 0xb000 && f != 0) 523248925Snp return (ENXIO); 524248925Snp 525248925Snp for (i = 0; i < nitems(t5_pciids); i++) { 526248925Snp if (d == t5_pciids[i].device) { 527248925Snp device_set_desc(dev, t5_pciids[i].desc); 528248925Snp return (BUS_PROBE_DEFAULT); 529248925Snp } 530248925Snp } 531248925Snp 532248925Snp return (ENXIO); 533248925Snp} 534248925Snp 535248925Snpstatic int 536218792Snpt4_attach(device_t dev) 537218792Snp{ 538218792Snp struct adapter *sc; 539218792Snp int rc = 0, i, n10g, n1g, rqidx, tqidx; 540218792Snp struct intrs_and_queues iaq; 541218792Snp struct sge *s; 542237263Snp#ifdef TCP_OFFLOAD 543228561Snp int ofld_rqidx, ofld_tqidx; 544228561Snp#endif 545218792Snp 546218792Snp sc = device_get_softc(dev); 547218792Snp sc->dev = dev; 548218792Snp 549218792Snp pci_enable_busmaster(dev); 550222085Snp if (pci_find_cap(dev, PCIY_EXPRESS, &i) == 0) { 551228561Snp uint32_t v; 552228561Snp 553222085Snp pci_set_max_read_req(dev, 4096); 554240680Sgavin v = pci_read_config(dev, i + PCIER_DEVICE_CTL, 2); 555240680Sgavin v |= PCIEM_CTL_RELAXED_ORD_ENABLE; 556240680Sgavin pci_write_config(dev, i + PCIER_DEVICE_CTL, v, 2); 557222085Snp } 558222085Snp 559218792Snp snprintf(sc->lockname, sizeof(sc->lockname), "%s", 560218792Snp device_get_nameunit(dev)); 561218792Snp mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF); 562228561Snp mtx_lock(&t4_list_lock); 563228561Snp SLIST_INSERT_HEAD(&t4_list, sc, link); 564228561Snp mtx_unlock(&t4_list_lock); 565218792Snp 566228561Snp mtx_init(&sc->sfl_lock, "starving freelists", 0, MTX_DEF); 567228561Snp TAILQ_INIT(&sc->sfl); 568228561Snp callout_init(&sc->sfl_callout, CALLOUT_MPSAFE); 569228561Snp 570248925Snp rc = map_bars_0_and_4(sc); 571218792Snp if (rc != 0) 572218792Snp goto done; /* error message displayed already */ 573218792Snp 574237587Snp /* 575237587Snp * This is the real PF# to which we're attaching. Works from within PCI 576237587Snp * passthrough environments too, where pci_get_function() could return a 577237587Snp * different PF# depending on the passthrough configuration. We need to 578237587Snp * use the real PF# in all our communication with the firmware. 579237587Snp */ 580237587Snp sc->pf = G_SOURCEPF(t4_read_reg(sc, A_PL_WHOAMI)); 581237587Snp sc->mbox = sc->pf; 582237587Snp 583218792Snp memset(sc->chan_map, 0xff, sizeof(sc->chan_map)); 584237263Snp sc->an_handler = an_not_handled; 585240452Snp for (i = 0; i < nitems(sc->cpl_handler); i++) 586228561Snp sc->cpl_handler[i] = cpl_not_handled; 587240452Snp for (i = 0; i < nitems(sc->fw_msg_handler); i++) 588239336Snp sc->fw_msg_handler[i] = fw_msg_not_handled; 589239338Snp t4_register_cpl_handler(sc, CPL_SET_TCB_RPL, t4_filter_rpl); 590248925Snp t4_init_sge_cpl_handlers(sc); 591218792Snp 592218792Snp /* Prepare the adapter for operation */ 593218792Snp rc = -t4_prep_adapter(sc); 594218792Snp if (rc != 0) { 595218792Snp device_printf(dev, "failed to prepare adapter: %d.\n", rc); 596218792Snp goto done; 597218792Snp } 598218792Snp 599228561Snp /* 600228561Snp * Do this really early, with the memory windows set up even before the 601228561Snp * character device. The userland tool's register i/o and mem read 602228561Snp * will work even in "recovery mode". 603228561Snp */ 604228561Snp setup_memwin(sc); 605248925Snp sc->cdev = make_dev(is_t4(sc) ? &t4_cdevsw : &t5_cdevsw, 606248925Snp device_get_unit(dev), UID_ROOT, GID_WHEEL, 0600, "%s", 607248925Snp device_get_nameunit(dev)); 608248925Snp if (sc->cdev == NULL) 609248925Snp device_printf(dev, "failed to create nexus char device.\n"); 610248925Snp else 611248925Snp sc->cdev->si_drv1 = sc; 612218792Snp 613228561Snp /* Go no further if recovery mode has been requested. */ 614228561Snp if (TUNABLE_INT_FETCH("hw.cxgbe.sos", &i) && i != 0) { 615228561Snp device_printf(dev, "recovery mode.\n"); 616228561Snp goto done; 617228561Snp } 618228561Snp 619218792Snp /* Prepare the firmware for operation */ 620218792Snp rc = prep_firmware(sc); 621218792Snp if (rc != 0) 622218792Snp goto done; /* error message displayed already */ 623218792Snp 624248925Snp rc = get_params__post_init(sc); 625228561Snp if (rc != 0) 626228561Snp goto done; /* error message displayed already */ 627222551Snp 628248925Snp rc = set_params__post_init(sc); 629228561Snp if (rc != 0) 630228561Snp goto done; /* error message displayed already */ 631218792Snp 632248925Snp rc = map_bar_2(sc); 633228561Snp if (rc != 0) 634228561Snp goto done; /* error message displayed already */ 635218792Snp 636228561Snp for (i = 0; i < NCHAN; i++) 637228561Snp sc->params.tp.tx_modq[i] = i; 638218792Snp 639218792Snp rc = t4_create_dma_tag(sc); 640218792Snp if (rc != 0) 641218792Snp goto done; /* error message displayed already */ 642218792Snp 643218792Snp /* 644218792Snp * First pass over all the ports - allocate VIs and initialize some 645218792Snp * basic parameters like mac address, port type, etc. We also figure 646218792Snp * out whether a port is 10G or 1G and use that information when 647218792Snp * calculating how many interrupts to attempt to allocate. 648218792Snp */ 649218792Snp n10g = n1g = 0; 650218792Snp for_each_port(sc, i) { 651218792Snp struct port_info *pi; 652218792Snp 653218792Snp pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK); 654218792Snp sc->port[i] = pi; 655218792Snp 656218792Snp /* These must be set before t4_port_init */ 657218792Snp pi->adapter = sc; 658218792Snp pi->port_id = i; 659218792Snp 660218792Snp /* Allocate the vi and initialize parameters like mac addr */ 661218792Snp rc = -t4_port_init(pi, sc->mbox, sc->pf, 0); 662218792Snp if (rc != 0) { 663218792Snp device_printf(dev, "unable to initialize port %d: %d\n", 664218792Snp i, rc); 665218792Snp free(pi, M_CXGBE); 666222510Snp sc->port[i] = NULL; 667222510Snp goto done; 668218792Snp } 669218792Snp 670218792Snp snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d", 671218792Snp device_get_nameunit(dev), i); 672218792Snp mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF); 673218792Snp 674250092Snp if (is_10G_port(pi) || is_40G_port(pi)) { 675218792Snp n10g++; 676228561Snp pi->tmr_idx = t4_tmr_idx_10g; 677228561Snp pi->pktc_idx = t4_pktc_idx_10g; 678218792Snp } else { 679218792Snp n1g++; 680228561Snp pi->tmr_idx = t4_tmr_idx_1g; 681228561Snp pi->pktc_idx = t4_pktc_idx_1g; 682218792Snp } 683218792Snp 684218792Snp pi->xact_addr_filt = -1; 685218792Snp 686228561Snp pi->qsize_rxq = t4_qsize_rxq; 687228561Snp pi->qsize_txq = t4_qsize_txq; 688218792Snp 689248925Snp pi->dev = device_add_child(dev, is_t4(sc) ? "cxgbe" : "cxl", -1); 690218792Snp if (pi->dev == NULL) { 691218792Snp device_printf(dev, 692218792Snp "failed to add device for port %d.\n", i); 693218792Snp rc = ENXIO; 694218792Snp goto done; 695218792Snp } 696218792Snp device_set_softc(pi->dev, pi); 697218792Snp } 698218792Snp 699218792Snp /* 700218792Snp * Interrupt type, # of interrupts, # of rx/tx queues, etc. 701218792Snp */ 702218792Snp rc = cfg_itype_and_nqueues(sc, n10g, n1g, &iaq); 703218792Snp if (rc != 0) 704218792Snp goto done; /* error message displayed already */ 705218792Snp 706218792Snp sc->intr_type = iaq.intr_type; 707218792Snp sc->intr_count = iaq.nirq; 708228561Snp sc->flags |= iaq.intr_flags; 709218792Snp 710218792Snp s = &sc->sge; 711218792Snp s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g; 712218792Snp s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g; 713220873Snp s->neq = s->ntxq + s->nrxq; /* the free list in an rxq is an eq */ 714228561Snp s->neq += sc->params.nports + 1;/* ctrl queues: 1 per port + 1 mgmt */ 715218792Snp s->niq = s->nrxq + 1; /* 1 extra for firmware event queue */ 716222510Snp 717237263Snp#ifdef TCP_OFFLOAD 718228561Snp if (is_offload(sc)) { 719228561Snp 720228561Snp s->nofldrxq = n10g * iaq.nofldrxq10g + n1g * iaq.nofldrxq1g; 721228561Snp s->nofldtxq = n10g * iaq.nofldtxq10g + n1g * iaq.nofldtxq1g; 722228561Snp s->neq += s->nofldtxq + s->nofldrxq; 723228561Snp s->niq += s->nofldrxq; 724228561Snp 725228561Snp s->ofld_rxq = malloc(s->nofldrxq * sizeof(struct sge_ofld_rxq), 726228561Snp M_CXGBE, M_ZERO | M_WAITOK); 727228561Snp s->ofld_txq = malloc(s->nofldtxq * sizeof(struct sge_wrq), 728228561Snp M_CXGBE, M_ZERO | M_WAITOK); 729228561Snp } 730228561Snp#endif 731228561Snp 732228561Snp s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_wrq), M_CXGBE, 733220873Snp M_ZERO | M_WAITOK); 734218792Snp s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE, 735218792Snp M_ZERO | M_WAITOK); 736218792Snp s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE, 737218792Snp M_ZERO | M_WAITOK); 738218792Snp s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE, 739218792Snp M_ZERO | M_WAITOK); 740218792Snp s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE, 741218792Snp M_ZERO | M_WAITOK); 742218792Snp 743218792Snp sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE, 744218792Snp M_ZERO | M_WAITOK); 745218792Snp 746228561Snp t4_init_l2t(sc, M_WAITOK); 747222509Snp 748218792Snp /* 749218792Snp * Second pass over the ports. This time we know the number of rx and 750218792Snp * tx queues that each port should get. 751218792Snp */ 752218792Snp rqidx = tqidx = 0; 753237263Snp#ifdef TCP_OFFLOAD 754228561Snp ofld_rqidx = ofld_tqidx = 0; 755228561Snp#endif 756218792Snp for_each_port(sc, i) { 757218792Snp struct port_info *pi = sc->port[i]; 758218792Snp 759218792Snp if (pi == NULL) 760218792Snp continue; 761218792Snp 762218792Snp pi->first_rxq = rqidx; 763218792Snp pi->first_txq = tqidx; 764250092Snp if (is_10G_port(pi) || is_40G_port(pi)) { 765228561Snp pi->nrxq = iaq.nrxq10g; 766228561Snp pi->ntxq = iaq.ntxq10g; 767228561Snp } else { 768228561Snp pi->nrxq = iaq.nrxq1g; 769228561Snp pi->ntxq = iaq.ntxq1g; 770228561Snp } 771218792Snp 772218792Snp rqidx += pi->nrxq; 773218792Snp tqidx += pi->ntxq; 774228561Snp 775237263Snp#ifdef TCP_OFFLOAD 776228561Snp if (is_offload(sc)) { 777228561Snp pi->first_ofld_rxq = ofld_rqidx; 778228561Snp pi->first_ofld_txq = ofld_tqidx; 779250092Snp if (is_10G_port(pi) || is_40G_port(pi)) { 780228561Snp pi->nofldrxq = iaq.nofldrxq10g; 781228561Snp pi->nofldtxq = iaq.nofldtxq10g; 782228561Snp } else { 783228561Snp pi->nofldrxq = iaq.nofldrxq1g; 784228561Snp pi->nofldtxq = iaq.nofldtxq1g; 785228561Snp } 786228561Snp ofld_rqidx += pi->nofldrxq; 787228561Snp ofld_tqidx += pi->nofldtxq; 788228561Snp } 789228561Snp#endif 790218792Snp } 791218792Snp 792240453Snp rc = setup_intr_handlers(sc); 793240453Snp if (rc != 0) { 794240453Snp device_printf(dev, 795240453Snp "failed to setup interrupt handlers: %d\n", rc); 796240453Snp goto done; 797240453Snp } 798240453Snp 799218792Snp rc = bus_generic_attach(dev); 800218792Snp if (rc != 0) { 801218792Snp device_printf(dev, 802218792Snp "failed to attach all child ports: %d\n", rc); 803218792Snp goto done; 804218792Snp } 805218792Snp 806218792Snp device_printf(dev, 807228561Snp "PCIe x%d, %d ports, %d %s interrupt%s, %d eq, %d iq\n", 808228561Snp sc->params.pci.width, sc->params.nports, sc->intr_count, 809228561Snp sc->intr_type == INTR_MSIX ? "MSI-X" : 810228561Snp (sc->intr_type == INTR_MSI ? "MSI" : "INTx"), 811228561Snp sc->intr_count > 1 ? "s" : "", sc->sge.neq, sc->sge.niq); 812228561Snp 813218792Snp t4_set_desc(sc); 814218792Snp 815218792Snpdone: 816228561Snp if (rc != 0 && sc->cdev) { 817228561Snp /* cdev was created and so cxgbetool works; recover that way. */ 818228561Snp device_printf(dev, 819228561Snp "error during attach, adapter is now in recovery mode.\n"); 820228561Snp rc = 0; 821228561Snp } 822228561Snp 823218792Snp if (rc != 0) 824218792Snp t4_detach(dev); 825228561Snp else 826228561Snp t4_sysctls(sc); 827218792Snp 828218792Snp return (rc); 829218792Snp} 830218792Snp 831218792Snp/* 832218792Snp * Idempotent 833218792Snp */ 834218792Snpstatic int 835218792Snpt4_detach(device_t dev) 836218792Snp{ 837218792Snp struct adapter *sc; 838218792Snp struct port_info *pi; 839228561Snp int i, rc; 840218792Snp 841218792Snp sc = device_get_softc(dev); 842218792Snp 843228561Snp if (sc->flags & FULL_INIT_DONE) 844228561Snp t4_intr_disable(sc); 845228561Snp 846228561Snp if (sc->cdev) { 847218792Snp destroy_dev(sc->cdev); 848228561Snp sc->cdev = NULL; 849228561Snp } 850218792Snp 851228561Snp rc = bus_generic_detach(dev); 852228561Snp if (rc) { 853228561Snp device_printf(dev, 854228561Snp "failed to detach child devices: %d\n", rc); 855228561Snp return (rc); 856228561Snp } 857228561Snp 858240453Snp for (i = 0; i < sc->intr_count; i++) 859240453Snp t4_free_irq(sc, &sc->irq[i]); 860240453Snp 861218792Snp for (i = 0; i < MAX_NPORTS; i++) { 862218792Snp pi = sc->port[i]; 863218792Snp if (pi) { 864218792Snp t4_free_vi(pi->adapter, sc->mbox, sc->pf, 0, pi->viid); 865218792Snp if (pi->dev) 866218792Snp device_delete_child(dev, pi->dev); 867218792Snp 868218792Snp mtx_destroy(&pi->pi_lock); 869218792Snp free(pi, M_CXGBE); 870218792Snp } 871218792Snp } 872218792Snp 873228561Snp if (sc->flags & FULL_INIT_DONE) 874228561Snp adapter_full_uninit(sc); 875228561Snp 876218792Snp if (sc->flags & FW_OK) 877218792Snp t4_fw_bye(sc, sc->mbox); 878218792Snp 879219944Snp if (sc->intr_type == INTR_MSI || sc->intr_type == INTR_MSIX) 880218792Snp pci_release_msi(dev); 881218792Snp 882218792Snp if (sc->regs_res) 883218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid, 884218792Snp sc->regs_res); 885218792Snp 886248925Snp if (sc->udbs_res) 887248925Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->udbs_rid, 888248925Snp sc->udbs_res); 889248925Snp 890218792Snp if (sc->msix_res) 891218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid, 892218792Snp sc->msix_res); 893218792Snp 894222509Snp if (sc->l2t) 895222509Snp t4_free_l2t(sc->l2t); 896222509Snp 897237263Snp#ifdef TCP_OFFLOAD 898228561Snp free(sc->sge.ofld_rxq, M_CXGBE); 899228561Snp free(sc->sge.ofld_txq, M_CXGBE); 900228561Snp#endif 901218792Snp free(sc->irq, M_CXGBE); 902218792Snp free(sc->sge.rxq, M_CXGBE); 903218792Snp free(sc->sge.txq, M_CXGBE); 904220873Snp free(sc->sge.ctrlq, M_CXGBE); 905218792Snp free(sc->sge.iqmap, M_CXGBE); 906218792Snp free(sc->sge.eqmap, M_CXGBE); 907221474Snp free(sc->tids.ftid_tab, M_CXGBE); 908218792Snp t4_destroy_dma_tag(sc); 909228561Snp if (mtx_initialized(&sc->sc_lock)) { 910228561Snp mtx_lock(&t4_list_lock); 911228561Snp SLIST_REMOVE(&t4_list, sc, adapter, link); 912228561Snp mtx_unlock(&t4_list_lock); 913228561Snp mtx_destroy(&sc->sc_lock); 914228561Snp } 915218792Snp 916245274Snp if (mtx_initialized(&sc->tids.ftid_lock)) 917245274Snp mtx_destroy(&sc->tids.ftid_lock); 918228561Snp if (mtx_initialized(&sc->sfl_lock)) 919228561Snp mtx_destroy(&sc->sfl_lock); 920228561Snp 921218792Snp bzero(sc, sizeof(*sc)); 922218792Snp 923218792Snp return (0); 924218792Snp} 925218792Snp 926218792Snp 927218792Snpstatic int 928218792Snpcxgbe_probe(device_t dev) 929218792Snp{ 930218792Snp char buf[128]; 931218792Snp struct port_info *pi = device_get_softc(dev); 932218792Snp 933228561Snp snprintf(buf, sizeof(buf), "port %d", pi->port_id); 934218792Snp device_set_desc_copy(dev, buf); 935218792Snp 936218792Snp return (BUS_PROBE_DEFAULT); 937218792Snp} 938218792Snp 939218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \ 940218792Snp IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \ 941237831Snp IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6) 942237819Snp#define T4_CAP_ENABLE (T4_CAP) 943218792Snp 944218792Snpstatic int 945218792Snpcxgbe_attach(device_t dev) 946218792Snp{ 947218792Snp struct port_info *pi = device_get_softc(dev); 948218792Snp struct ifnet *ifp; 949218792Snp 950218792Snp /* Allocate an ifnet and set it up */ 951218792Snp ifp = if_alloc(IFT_ETHER); 952218792Snp if (ifp == NULL) { 953218792Snp device_printf(dev, "Cannot allocate ifnet\n"); 954218792Snp return (ENOMEM); 955218792Snp } 956218792Snp pi->ifp = ifp; 957218792Snp ifp->if_softc = pi; 958218792Snp 959218792Snp callout_init(&pi->tick, CALLOUT_MPSAFE); 960218792Snp 961218792Snp if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 962218792Snp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 963218792Snp 964218792Snp ifp->if_init = cxgbe_init; 965218792Snp ifp->if_ioctl = cxgbe_ioctl; 966218792Snp ifp->if_transmit = cxgbe_transmit; 967218792Snp ifp->if_qflush = cxgbe_qflush; 968218792Snp 969218792Snp ifp->if_capabilities = T4_CAP; 970237263Snp#ifdef TCP_OFFLOAD 971228561Snp if (is_offload(pi->adapter)) 972245933Snp ifp->if_capabilities |= IFCAP_TOE; 973228561Snp#endif 974218792Snp ifp->if_capenable = T4_CAP_ENABLE; 975237799Snp ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO | 976237799Snp CSUM_UDP_IPV6 | CSUM_TCP_IPV6; 977218792Snp 978218792Snp /* Initialize ifmedia for this port */ 979218792Snp ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change, 980218792Snp cxgbe_media_status); 981218792Snp build_medialist(pi); 982218792Snp 983237263Snp pi->vlan_c = EVENTHANDLER_REGISTER(vlan_config, cxgbe_vlan_config, ifp, 984237263Snp EVENTHANDLER_PRI_ANY); 985237263Snp 986218792Snp ether_ifattach(ifp, pi->hw_addr); 987218792Snp 988237263Snp#ifdef TCP_OFFLOAD 989228561Snp if (is_offload(pi->adapter)) { 990228561Snp device_printf(dev, 991228561Snp "%d txq, %d rxq (NIC); %d txq, %d rxq (TOE)\n", 992228561Snp pi->ntxq, pi->nrxq, pi->nofldtxq, pi->nofldrxq); 993228561Snp } else 994218792Snp#endif 995228561Snp device_printf(dev, "%d txq, %d rxq\n", pi->ntxq, pi->nrxq); 996218792Snp 997218792Snp cxgbe_sysctls(pi); 998218792Snp 999218792Snp return (0); 1000218792Snp} 1001218792Snp 1002218792Snpstatic int 1003218792Snpcxgbe_detach(device_t dev) 1004218792Snp{ 1005218792Snp struct port_info *pi = device_get_softc(dev); 1006218792Snp struct adapter *sc = pi->adapter; 1007228561Snp struct ifnet *ifp = pi->ifp; 1008218792Snp 1009218792Snp /* Tell if_ioctl and if_init that the port is going away */ 1010218792Snp ADAPTER_LOCK(sc); 1011218792Snp SET_DOOMED(pi); 1012218792Snp wakeup(&sc->flags); 1013218792Snp while (IS_BUSY(sc)) 1014218792Snp mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0); 1015218792Snp SET_BUSY(sc); 1016245274Snp#ifdef INVARIANTS 1017245274Snp sc->last_op = "t4detach"; 1018245274Snp sc->last_op_thr = curthread; 1019245274Snp#endif 1020218792Snp ADAPTER_UNLOCK(sc); 1021218792Snp 1022237263Snp if (pi->vlan_c) 1023237263Snp EVENTHANDLER_DEREGISTER(vlan_config, pi->vlan_c); 1024237263Snp 1025228561Snp PORT_LOCK(pi); 1026228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1027228561Snp callout_stop(&pi->tick); 1028228561Snp PORT_UNLOCK(pi); 1029228561Snp callout_drain(&pi->tick); 1030218792Snp 1031228561Snp /* Let detach proceed even if these fail. */ 1032228561Snp cxgbe_uninit_synchronized(pi); 1033228561Snp port_full_uninit(pi); 1034219286Snp 1035218792Snp ifmedia_removeall(&pi->media); 1036218792Snp ether_ifdetach(pi->ifp); 1037218792Snp if_free(pi->ifp); 1038218792Snp 1039218792Snp ADAPTER_LOCK(sc); 1040218792Snp CLR_BUSY(sc); 1041245274Snp wakeup(&sc->flags); 1042218792Snp ADAPTER_UNLOCK(sc); 1043218792Snp 1044218792Snp return (0); 1045218792Snp} 1046218792Snp 1047218792Snpstatic void 1048218792Snpcxgbe_init(void *arg) 1049218792Snp{ 1050218792Snp struct port_info *pi = arg; 1051218792Snp struct adapter *sc = pi->adapter; 1052218792Snp 1053245274Snp if (begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4init") != 0) 1054245274Snp return; 1055245274Snp cxgbe_init_synchronized(pi); 1056245274Snp end_synchronized_op(sc, 0); 1057218792Snp} 1058218792Snp 1059218792Snpstatic int 1060218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) 1061218792Snp{ 1062218792Snp int rc = 0, mtu, flags; 1063218792Snp struct port_info *pi = ifp->if_softc; 1064218792Snp struct adapter *sc = pi->adapter; 1065218792Snp struct ifreq *ifr = (struct ifreq *)data; 1066218792Snp uint32_t mask; 1067218792Snp 1068218792Snp switch (cmd) { 1069218792Snp case SIOCSIFMTU: 1070245274Snp mtu = ifr->ifr_mtu; 1071245274Snp if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) 1072245274Snp return (EINVAL); 1073245274Snp 1074245274Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4mtu"); 1075245274Snp if (rc) 1076218792Snp return (rc); 1077245274Snp ifp->if_mtu = mtu; 1078245274Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1079245274Snp t4_update_fl_bufsize(ifp); 1080245274Snp rc = update_mac_settings(pi, XGMAC_MTU); 1081218792Snp } 1082245274Snp end_synchronized_op(sc, 0); 1083218792Snp break; 1084218792Snp 1085218792Snp case SIOCSIFFLAGS: 1086245274Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4flg"); 1087245274Snp if (rc) 1088245274Snp return (rc); 1089245274Snp 1090218792Snp if (ifp->if_flags & IFF_UP) { 1091218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1092218792Snp flags = pi->if_flags; 1093218792Snp if ((ifp->if_flags ^ flags) & 1094218792Snp (IFF_PROMISC | IFF_ALLMULTI)) { 1095218792Snp rc = update_mac_settings(pi, 1096218792Snp XGMAC_PROMISC | XGMAC_ALLMULTI); 1097218792Snp } 1098218792Snp } else 1099245274Snp rc = cxgbe_init_synchronized(pi); 1100218792Snp pi->if_flags = ifp->if_flags; 1101218792Snp } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1102245274Snp rc = cxgbe_uninit_synchronized(pi); 1103245274Snp end_synchronized_op(sc, 0); 1104218792Snp break; 1105218792Snp 1106218792Snp case SIOCADDMULTI: 1107245274Snp case SIOCDELMULTI: /* these two are called with a mutex held :-( */ 1108245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK, "t4multi"); 1109218792Snp if (rc) 1110245274Snp return (rc); 1111245274Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1112218792Snp rc = update_mac_settings(pi, XGMAC_MCADDRS); 1113245274Snp end_synchronized_op(sc, LOCK_HELD); 1114218792Snp break; 1115218792Snp 1116218792Snp case SIOCSIFCAP: 1117245274Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4cap"); 1118218792Snp if (rc) 1119245274Snp return (rc); 1120218792Snp 1121218792Snp mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1122218792Snp if (mask & IFCAP_TXCSUM) { 1123218792Snp ifp->if_capenable ^= IFCAP_TXCSUM; 1124218792Snp ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 1125218792Snp 1126237831Snp if (IFCAP_TSO4 & ifp->if_capenable && 1127218792Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1128237799Snp ifp->if_capenable &= ~IFCAP_TSO4; 1129218792Snp if_printf(ifp, 1130237831Snp "tso4 disabled due to -txcsum.\n"); 1131218792Snp } 1132218792Snp } 1133237799Snp if (mask & IFCAP_TXCSUM_IPV6) { 1134237799Snp ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 1135237799Snp ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); 1136237799Snp 1137237799Snp if (IFCAP_TSO6 & ifp->if_capenable && 1138237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1139237799Snp ifp->if_capenable &= ~IFCAP_TSO6; 1140237799Snp if_printf(ifp, 1141237799Snp "tso6 disabled due to -txcsum6.\n"); 1142237799Snp } 1143237799Snp } 1144218792Snp if (mask & IFCAP_RXCSUM) 1145218792Snp ifp->if_capenable ^= IFCAP_RXCSUM; 1146237799Snp if (mask & IFCAP_RXCSUM_IPV6) 1147237799Snp ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 1148237799Snp 1149237799Snp /* 1150237799Snp * Note that we leave CSUM_TSO alone (it is always set). The 1151237799Snp * kernel takes both IFCAP_TSOx and CSUM_TSO into account before 1152237799Snp * sending a TSO request our way, so it's sufficient to toggle 1153237799Snp * IFCAP_TSOx only. 1154237799Snp */ 1155218792Snp if (mask & IFCAP_TSO4) { 1156237799Snp if (!(IFCAP_TSO4 & ifp->if_capenable) && 1157237799Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1158237799Snp if_printf(ifp, "enable txcsum first.\n"); 1159237799Snp rc = EAGAIN; 1160237799Snp goto fail; 1161237799Snp } 1162218792Snp ifp->if_capenable ^= IFCAP_TSO4; 1163218792Snp } 1164237799Snp if (mask & IFCAP_TSO6) { 1165237799Snp if (!(IFCAP_TSO6 & ifp->if_capenable) && 1166237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1167237799Snp if_printf(ifp, "enable txcsum6 first.\n"); 1168237799Snp rc = EAGAIN; 1169237799Snp goto fail; 1170237799Snp } 1171237799Snp ifp->if_capenable ^= IFCAP_TSO6; 1172237799Snp } 1173218792Snp if (mask & IFCAP_LRO) { 1174237819Snp#if defined(INET) || defined(INET6) 1175218792Snp int i; 1176218792Snp struct sge_rxq *rxq; 1177218792Snp 1178218792Snp ifp->if_capenable ^= IFCAP_LRO; 1179218792Snp for_each_rxq(pi, i, rxq) { 1180218792Snp if (ifp->if_capenable & IFCAP_LRO) 1181228561Snp rxq->iq.flags |= IQ_LRO_ENABLED; 1182218792Snp else 1183228561Snp rxq->iq.flags &= ~IQ_LRO_ENABLED; 1184218792Snp } 1185218792Snp#endif 1186218792Snp } 1187237263Snp#ifdef TCP_OFFLOAD 1188228561Snp if (mask & IFCAP_TOE) { 1189228561Snp int enable = (ifp->if_capenable ^ mask) & IFCAP_TOE; 1190228561Snp 1191228561Snp rc = toe_capability(pi, enable); 1192228561Snp if (rc != 0) 1193228561Snp goto fail; 1194228561Snp 1195228561Snp ifp->if_capenable ^= mask; 1196218792Snp } 1197218792Snp#endif 1198218792Snp if (mask & IFCAP_VLAN_HWTAGGING) { 1199218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1200245274Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1201218792Snp rc = update_mac_settings(pi, XGMAC_VLANEX); 1202218792Snp } 1203218792Snp if (mask & IFCAP_VLAN_MTU) { 1204218792Snp ifp->if_capenable ^= IFCAP_VLAN_MTU; 1205218792Snp 1206218792Snp /* Need to find out how to disable auto-mtu-inflation */ 1207218792Snp } 1208218792Snp if (mask & IFCAP_VLAN_HWTSO) 1209218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1210218792Snp if (mask & IFCAP_VLAN_HWCSUM) 1211218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 1212218792Snp 1213218792Snp#ifdef VLAN_CAPABILITIES 1214218792Snp VLAN_CAPABILITIES(ifp); 1215218792Snp#endif 1216245274Snpfail: 1217245274Snp end_synchronized_op(sc, 0); 1218218792Snp break; 1219218792Snp 1220218792Snp case SIOCSIFMEDIA: 1221218792Snp case SIOCGIFMEDIA: 1222218792Snp ifmedia_ioctl(ifp, ifr, &pi->media, cmd); 1223218792Snp break; 1224218792Snp 1225218792Snp default: 1226218792Snp rc = ether_ioctl(ifp, cmd, data); 1227218792Snp } 1228218792Snp 1229218792Snp return (rc); 1230218792Snp} 1231218792Snp 1232218792Snpstatic int 1233218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m) 1234218792Snp{ 1235218792Snp struct port_info *pi = ifp->if_softc; 1236218792Snp struct adapter *sc = pi->adapter; 1237218792Snp struct sge_txq *txq = &sc->sge.txq[pi->first_txq]; 1238218792Snp struct buf_ring *br; 1239218792Snp int rc; 1240218792Snp 1241218792Snp M_ASSERTPKTHDR(m); 1242218792Snp 1243228561Snp if (__predict_false(pi->link_cfg.link_ok == 0)) { 1244218792Snp m_freem(m); 1245228561Snp return (ENETDOWN); 1246218792Snp } 1247218792Snp 1248218792Snp if (m->m_flags & M_FLOWID) 1249218792Snp txq += (m->m_pkthdr.flowid % pi->ntxq); 1250220873Snp br = txq->br; 1251218792Snp 1252218792Snp if (TXQ_TRYLOCK(txq) == 0) { 1253228561Snp struct sge_eq *eq = &txq->eq; 1254228561Snp 1255218792Snp /* 1256228561Snp * It is possible that t4_eth_tx finishes up and releases the 1257228561Snp * lock between the TRYLOCK above and the drbr_enqueue here. We 1258228561Snp * need to make sure that this mbuf doesn't just sit there in 1259228561Snp * the drbr. 1260218792Snp */ 1261218792Snp 1262228561Snp rc = drbr_enqueue(ifp, br, m); 1263228561Snp if (rc == 0 && callout_pending(&eq->tx_callout) == 0 && 1264228561Snp !(eq->flags & EQ_DOOMED)) 1265228561Snp callout_reset(&eq->tx_callout, 1, t4_tx_callout, eq); 1266228561Snp return (rc); 1267218792Snp } 1268218792Snp 1269218792Snp /* 1270218792Snp * txq->m is the mbuf that is held up due to a temporary shortage of 1271218792Snp * resources and it should be put on the wire first. Then what's in 1272218792Snp * drbr and finally the mbuf that was just passed in to us. 1273218792Snp * 1274218792Snp * Return code should indicate the fate of the mbuf that was passed in 1275218792Snp * this time. 1276218792Snp */ 1277218792Snp 1278218792Snp TXQ_LOCK_ASSERT_OWNED(txq); 1279218792Snp if (drbr_needs_enqueue(ifp, br) || txq->m) { 1280218792Snp 1281218792Snp /* Queued for transmission. */ 1282218792Snp 1283218792Snp rc = drbr_enqueue(ifp, br, m); 1284218792Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 1285218792Snp (void) t4_eth_tx(ifp, txq, m); 1286218792Snp TXQ_UNLOCK(txq); 1287218792Snp return (rc); 1288218792Snp } 1289218792Snp 1290218792Snp /* Direct transmission. */ 1291218792Snp rc = t4_eth_tx(ifp, txq, m); 1292218792Snp if (rc != 0 && txq->m) 1293218792Snp rc = 0; /* held, will be transmitted soon (hopefully) */ 1294218792Snp 1295218792Snp TXQ_UNLOCK(txq); 1296218792Snp return (rc); 1297218792Snp} 1298218792Snp 1299218792Snpstatic void 1300218792Snpcxgbe_qflush(struct ifnet *ifp) 1301218792Snp{ 1302218792Snp struct port_info *pi = ifp->if_softc; 1303220649Snp struct sge_txq *txq; 1304220649Snp int i; 1305220649Snp struct mbuf *m; 1306218792Snp 1307228561Snp /* queues do not exist if !PORT_INIT_DONE. */ 1308228561Snp if (pi->flags & PORT_INIT_DONE) { 1309220649Snp for_each_txq(pi, i, txq) { 1310220649Snp TXQ_LOCK(txq); 1311220649Snp m_freem(txq->m); 1312228561Snp txq->m = NULL; 1313220873Snp while ((m = buf_ring_dequeue_sc(txq->br)) != NULL) 1314220649Snp m_freem(m); 1315220649Snp TXQ_UNLOCK(txq); 1316220649Snp } 1317220649Snp } 1318220649Snp if_qflush(ifp); 1319218792Snp} 1320218792Snp 1321218792Snpstatic int 1322218792Snpcxgbe_media_change(struct ifnet *ifp) 1323218792Snp{ 1324218792Snp struct port_info *pi = ifp->if_softc; 1325218792Snp 1326218792Snp device_printf(pi->dev, "%s unimplemented.\n", __func__); 1327218792Snp 1328218792Snp return (EOPNOTSUPP); 1329218792Snp} 1330218792Snp 1331218792Snpstatic void 1332218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1333218792Snp{ 1334218792Snp struct port_info *pi = ifp->if_softc; 1335218792Snp struct ifmedia_entry *cur = pi->media.ifm_cur; 1336218792Snp int speed = pi->link_cfg.speed; 1337218792Snp int data = (pi->port_type << 8) | pi->mod_type; 1338218792Snp 1339218792Snp if (cur->ifm_data != data) { 1340218792Snp build_medialist(pi); 1341218792Snp cur = pi->media.ifm_cur; 1342218792Snp } 1343218792Snp 1344218792Snp ifmr->ifm_status = IFM_AVALID; 1345218792Snp if (!pi->link_cfg.link_ok) 1346218792Snp return; 1347218792Snp 1348218792Snp ifmr->ifm_status |= IFM_ACTIVE; 1349218792Snp 1350218792Snp /* active and current will differ iff current media is autoselect. */ 1351218792Snp if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO) 1352218792Snp return; 1353218792Snp 1354218792Snp ifmr->ifm_active = IFM_ETHER | IFM_FDX; 1355218792Snp if (speed == SPEED_10000) 1356218792Snp ifmr->ifm_active |= IFM_10G_T; 1357218792Snp else if (speed == SPEED_1000) 1358218792Snp ifmr->ifm_active |= IFM_1000_T; 1359218792Snp else if (speed == SPEED_100) 1360218792Snp ifmr->ifm_active |= IFM_100_TX; 1361218792Snp else if (speed == SPEED_10) 1362218792Snp ifmr->ifm_active |= IFM_10_T; 1363218792Snp else 1364218792Snp KASSERT(0, ("%s: link up but speed unknown (%u)", __func__, 1365218792Snp speed)); 1366218792Snp} 1367218792Snp 1368218792Snpvoid 1369218792Snpt4_fatal_err(struct adapter *sc) 1370218792Snp{ 1371218792Snp t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0); 1372218792Snp t4_intr_disable(sc); 1373218792Snp log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n", 1374218792Snp device_get_nameunit(sc->dev)); 1375218792Snp} 1376218792Snp 1377218792Snpstatic int 1378248925Snpmap_bars_0_and_4(struct adapter *sc) 1379218792Snp{ 1380218792Snp sc->regs_rid = PCIR_BAR(0); 1381218792Snp sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1382218792Snp &sc->regs_rid, RF_ACTIVE); 1383218792Snp if (sc->regs_res == NULL) { 1384218792Snp device_printf(sc->dev, "cannot map registers.\n"); 1385218792Snp return (ENXIO); 1386218792Snp } 1387218792Snp sc->bt = rman_get_bustag(sc->regs_res); 1388218792Snp sc->bh = rman_get_bushandle(sc->regs_res); 1389218792Snp sc->mmio_len = rman_get_size(sc->regs_res); 1390248925Snp setbit(&sc->doorbells, DOORBELL_KDB); 1391218792Snp 1392218792Snp sc->msix_rid = PCIR_BAR(4); 1393218792Snp sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1394218792Snp &sc->msix_rid, RF_ACTIVE); 1395218792Snp if (sc->msix_res == NULL) { 1396218792Snp device_printf(sc->dev, "cannot map MSI-X BAR.\n"); 1397218792Snp return (ENXIO); 1398218792Snp } 1399218792Snp 1400218792Snp return (0); 1401218792Snp} 1402218792Snp 1403248925Snpstatic int 1404248925Snpmap_bar_2(struct adapter *sc) 1405248925Snp{ 1406248925Snp 1407248925Snp /* 1408248925Snp * T4: only iWARP driver uses the userspace doorbells. There is no need 1409248925Snp * to map it if RDMA is disabled. 1410248925Snp */ 1411248925Snp if (is_t4(sc) && sc->rdmacaps == 0) 1412248925Snp return (0); 1413248925Snp 1414248925Snp sc->udbs_rid = PCIR_BAR(2); 1415248925Snp sc->udbs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1416248925Snp &sc->udbs_rid, RF_ACTIVE); 1417248925Snp if (sc->udbs_res == NULL) { 1418248925Snp device_printf(sc->dev, "cannot map doorbell BAR.\n"); 1419248925Snp return (ENXIO); 1420248925Snp } 1421248925Snp sc->udbs_base = rman_get_virtual(sc->udbs_res); 1422248925Snp 1423248925Snp if (is_t5(sc)) { 1424248925Snp setbit(&sc->doorbells, DOORBELL_UDB); 1425248925Snp#if defined(__i386__) || defined(__amd64__) 1426248925Snp if (t5_write_combine) { 1427248925Snp int rc; 1428248925Snp 1429248925Snp /* 1430248925Snp * Enable write combining on BAR2. This is the 1431248925Snp * userspace doorbell BAR and is split into 128B 1432248925Snp * (UDBS_SEG_SIZE) doorbell regions, each associated 1433248925Snp * with an egress queue. The first 64B has the doorbell 1434248925Snp * and the second 64B can be used to submit a tx work 1435248925Snp * request with an implicit doorbell. 1436248925Snp */ 1437248925Snp 1438248925Snp rc = pmap_change_attr((vm_offset_t)sc->udbs_base, 1439248925Snp rman_get_size(sc->udbs_res), PAT_WRITE_COMBINING); 1440248925Snp if (rc == 0) { 1441248925Snp clrbit(&sc->doorbells, DOORBELL_UDB); 1442249392Snp setbit(&sc->doorbells, DOORBELL_WCWR); 1443248925Snp setbit(&sc->doorbells, DOORBELL_UDBWC); 1444248925Snp } else { 1445248925Snp device_printf(sc->dev, 1446248925Snp "couldn't enable write combining: %d\n", 1447248925Snp rc); 1448248925Snp } 1449248925Snp 1450248925Snp t4_write_reg(sc, A_SGE_STAT_CFG, 1451248925Snp V_STATSOURCE_T5(7) | V_STATMODE(0)); 1452248925Snp } 1453248925Snp#endif 1454248925Snp } 1455248925Snp 1456248925Snp return (0); 1457248925Snp} 1458248925Snp 1459248925Snpstatic const struct memwin t4_memwin[] = { 1460248925Snp { MEMWIN0_BASE, MEMWIN0_APERTURE }, 1461248925Snp { MEMWIN1_BASE, MEMWIN1_APERTURE }, 1462248925Snp { MEMWIN2_BASE_T4, MEMWIN2_APERTURE_T4 } 1463248925Snp}; 1464248925Snp 1465248925Snpstatic const struct memwin t5_memwin[] = { 1466248925Snp { MEMWIN0_BASE, MEMWIN0_APERTURE }, 1467248925Snp { MEMWIN1_BASE, MEMWIN1_APERTURE }, 1468248925Snp { MEMWIN2_BASE_T5, MEMWIN2_APERTURE_T5 }, 1469248925Snp}; 1470248925Snp 1471218792Snpstatic void 1472218792Snpsetup_memwin(struct adapter *sc) 1473218792Snp{ 1474248925Snp const struct memwin *mw; 1475248925Snp int i, n; 1476237587Snp uint32_t bar0; 1477218792Snp 1478248925Snp if (is_t4(sc)) { 1479248925Snp /* 1480248925Snp * Read low 32b of bar0 indirectly via the hardware backdoor 1481248925Snp * mechanism. Works from within PCI passthrough environments 1482248925Snp * too, where rman_get_start() can return a different value. We 1483248925Snp * need to program the T4 memory window decoders with the actual 1484248925Snp * addresses that will be coming across the PCIe link. 1485248925Snp */ 1486248925Snp bar0 = t4_hw_pci_read_cfg4(sc, PCIR_BAR(0)); 1487248925Snp bar0 &= (uint32_t) PCIM_BAR_MEM_BASE; 1488218792Snp 1489248925Snp mw = &t4_memwin[0]; 1490248925Snp n = nitems(t4_memwin); 1491248925Snp } else { 1492248925Snp /* T5 uses the relative offset inside the PCIe BAR */ 1493248925Snp bar0 = 0; 1494218792Snp 1495248925Snp mw = &t5_memwin[0]; 1496248925Snp n = nitems(t5_memwin); 1497248925Snp } 1498218792Snp 1499248925Snp for (i = 0; i < n; i++, mw++) { 1500248925Snp t4_write_reg(sc, 1501248925Snp PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, i), 1502248925Snp (mw->base + bar0) | V_BIR(0) | 1503248925Snp V_WINDOW(ilog2(mw->aperture) - 10)); 1504248925Snp } 1505237587Snp 1506237587Snp /* flush */ 1507237587Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2)); 1508218792Snp} 1509218792Snp 1510248925Snp/* 1511248925Snp * Verify that the memory range specified by the addr/len pair is valid and lies 1512248925Snp * entirely within a single region (EDCx or MCx). 1513248925Snp */ 1514218792Snpstatic int 1515248925Snpvalidate_mem_range(struct adapter *sc, uint32_t addr, int len) 1516248925Snp{ 1517248925Snp uint32_t em, addr_len, maddr, mlen; 1518248925Snp 1519248925Snp /* Memory can only be accessed in naturally aligned 4 byte units */ 1520248925Snp if (addr & 3 || len & 3 || len == 0) 1521248925Snp return (EINVAL); 1522248925Snp 1523248925Snp /* Enabled memories */ 1524248925Snp em = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 1525248925Snp if (em & F_EDRAM0_ENABLE) { 1526248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM0_BAR); 1527248925Snp maddr = G_EDRAM0_BASE(addr_len) << 20; 1528248925Snp mlen = G_EDRAM0_SIZE(addr_len) << 20; 1529248925Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1530248925Snp addr + len <= maddr + mlen) 1531248925Snp return (0); 1532248925Snp } 1533248925Snp if (em & F_EDRAM1_ENABLE) { 1534248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM1_BAR); 1535248925Snp maddr = G_EDRAM1_BASE(addr_len) << 20; 1536248925Snp mlen = G_EDRAM1_SIZE(addr_len) << 20; 1537248925Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1538248925Snp addr + len <= maddr + mlen) 1539248925Snp return (0); 1540248925Snp } 1541248925Snp if (em & F_EXT_MEM_ENABLE) { 1542248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 1543248925Snp maddr = G_EXT_MEM_BASE(addr_len) << 20; 1544248925Snp mlen = G_EXT_MEM_SIZE(addr_len) << 20; 1545248925Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1546248925Snp addr + len <= maddr + mlen) 1547248925Snp return (0); 1548248925Snp } 1549248925Snp if (!is_t4(sc) && em & F_EXT_MEM1_ENABLE) { 1550248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 1551248925Snp maddr = G_EXT_MEM1_BASE(addr_len) << 20; 1552248925Snp mlen = G_EXT_MEM1_SIZE(addr_len) << 20; 1553248925Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1554248925Snp addr + len <= maddr + mlen) 1555248925Snp return (0); 1556248925Snp } 1557248925Snp 1558248925Snp return (EFAULT); 1559248925Snp} 1560248925Snp 1561248925Snp/* 1562248925Snp * Verify that the memory range specified by the memtype/offset/len pair is 1563248925Snp * valid and lies entirely within the memtype specified. The global address of 1564248925Snp * the start of the range is returned in addr. 1565248925Snp */ 1566248925Snpstatic int 1567248925Snpvalidate_mt_off_len(struct adapter *sc, int mtype, uint32_t off, int len, 1568248925Snp uint32_t *addr) 1569248925Snp{ 1570248925Snp uint32_t em, addr_len, maddr, mlen; 1571248925Snp 1572248925Snp /* Memory can only be accessed in naturally aligned 4 byte units */ 1573248925Snp if (off & 3 || len & 3 || len == 0) 1574248925Snp return (EINVAL); 1575248925Snp 1576248925Snp em = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 1577248925Snp switch (mtype) { 1578248925Snp case MEM_EDC0: 1579248925Snp if (!(em & F_EDRAM0_ENABLE)) 1580248925Snp return (EINVAL); 1581248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM0_BAR); 1582248925Snp maddr = G_EDRAM0_BASE(addr_len) << 20; 1583248925Snp mlen = G_EDRAM0_SIZE(addr_len) << 20; 1584248925Snp break; 1585248925Snp case MEM_EDC1: 1586248925Snp if (!(em & F_EDRAM1_ENABLE)) 1587248925Snp return (EINVAL); 1588248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM1_BAR); 1589248925Snp maddr = G_EDRAM1_BASE(addr_len) << 20; 1590248925Snp mlen = G_EDRAM1_SIZE(addr_len) << 20; 1591248925Snp break; 1592248925Snp case MEM_MC: 1593248925Snp if (!(em & F_EXT_MEM_ENABLE)) 1594248925Snp return (EINVAL); 1595248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 1596248925Snp maddr = G_EXT_MEM_BASE(addr_len) << 20; 1597248925Snp mlen = G_EXT_MEM_SIZE(addr_len) << 20; 1598248925Snp break; 1599248925Snp case MEM_MC1: 1600248925Snp if (is_t4(sc) || !(em & F_EXT_MEM1_ENABLE)) 1601248925Snp return (EINVAL); 1602248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 1603248925Snp maddr = G_EXT_MEM1_BASE(addr_len) << 20; 1604248925Snp mlen = G_EXT_MEM1_SIZE(addr_len) << 20; 1605248925Snp break; 1606248925Snp default: 1607248925Snp return (EINVAL); 1608248925Snp } 1609248925Snp 1610248925Snp if (mlen > 0 && off < mlen && off + len <= mlen) { 1611248925Snp *addr = maddr + off; /* global address */ 1612248925Snp return (0); 1613248925Snp } 1614248925Snp 1615248925Snp return (EFAULT); 1616248925Snp} 1617248925Snp 1618248925Snpstatic void 1619248925Snpmemwin_info(struct adapter *sc, int win, uint32_t *base, uint32_t *aperture) 1620248925Snp{ 1621248925Snp const struct memwin *mw; 1622248925Snp 1623248925Snp if (is_t4(sc)) { 1624248925Snp KASSERT(win >= 0 && win < nitems(t4_memwin), 1625248925Snp ("%s: incorrect memwin# (%d)", __func__, win)); 1626248925Snp mw = &t4_memwin[win]; 1627248925Snp } else { 1628248925Snp KASSERT(win >= 0 && win < nitems(t5_memwin), 1629248925Snp ("%s: incorrect memwin# (%d)", __func__, win)); 1630248925Snp mw = &t5_memwin[win]; 1631248925Snp } 1632248925Snp 1633248925Snp if (base != NULL) 1634248925Snp *base = mw->base; 1635248925Snp if (aperture != NULL) 1636248925Snp *aperture = mw->aperture; 1637248925Snp} 1638248925Snp 1639248925Snp/* 1640248925Snp * Positions the memory window such that it can be used to access the specified 1641248925Snp * address in the chip's address space. The return value is the offset of addr 1642248925Snp * from the start of the window. 1643248925Snp */ 1644248925Snpstatic uint32_t 1645248925Snpposition_memwin(struct adapter *sc, int n, uint32_t addr) 1646248925Snp{ 1647248925Snp uint32_t start, pf; 1648248925Snp uint32_t reg; 1649248925Snp 1650248925Snp KASSERT(n >= 0 && n <= 3, 1651248925Snp ("%s: invalid window %d.", __func__, n)); 1652248925Snp KASSERT((addr & 3) == 0, 1653248925Snp ("%s: addr (0x%x) is not at a 4B boundary.", __func__, addr)); 1654248925Snp 1655248925Snp if (is_t4(sc)) { 1656248925Snp pf = 0; 1657248925Snp start = addr & ~0xf; /* start must be 16B aligned */ 1658248925Snp } else { 1659248925Snp pf = V_PFNUM(sc->pf); 1660248925Snp start = addr & ~0x7f; /* start must be 128B aligned */ 1661248925Snp } 1662248925Snp reg = PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, n); 1663248925Snp 1664248925Snp t4_write_reg(sc, reg, start | pf); 1665248925Snp t4_read_reg(sc, reg); 1666248925Snp 1667248925Snp return (addr - start); 1668248925Snp} 1669248925Snp 1670248925Snpstatic int 1671218792Snpcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g, 1672218792Snp struct intrs_and_queues *iaq) 1673218792Snp{ 1674228561Snp int rc, itype, navail, nrxq10g, nrxq1g, n; 1675228561Snp int nofldrxq10g = 0, nofldrxq1g = 0; 1676218792Snp 1677218792Snp bzero(iaq, sizeof(*iaq)); 1678218792Snp 1679228561Snp iaq->ntxq10g = t4_ntxq10g; 1680228561Snp iaq->ntxq1g = t4_ntxq1g; 1681228561Snp iaq->nrxq10g = nrxq10g = t4_nrxq10g; 1682228561Snp iaq->nrxq1g = nrxq1g = t4_nrxq1g; 1683237263Snp#ifdef TCP_OFFLOAD 1684237463Snp if (is_offload(sc)) { 1685237463Snp iaq->nofldtxq10g = t4_nofldtxq10g; 1686237463Snp iaq->nofldtxq1g = t4_nofldtxq1g; 1687237463Snp iaq->nofldrxq10g = nofldrxq10g = t4_nofldrxq10g; 1688237463Snp iaq->nofldrxq1g = nofldrxq1g = t4_nofldrxq1g; 1689237463Snp } 1690228561Snp#endif 1691228561Snp 1692219944Snp for (itype = INTR_MSIX; itype; itype >>= 1) { 1693218792Snp 1694228561Snp if ((itype & t4_intr_types) == 0) 1695218792Snp continue; /* not allowed */ 1696218792Snp 1697219944Snp if (itype == INTR_MSIX) 1698218792Snp navail = pci_msix_count(sc->dev); 1699219944Snp else if (itype == INTR_MSI) 1700218792Snp navail = pci_msi_count(sc->dev); 1701218792Snp else 1702218792Snp navail = 1; 1703228561Snprestart: 1704218792Snp if (navail == 0) 1705218792Snp continue; 1706218792Snp 1707218792Snp iaq->intr_type = itype; 1708228561Snp iaq->intr_flags = 0; 1709218792Snp 1710228561Snp /* 1711228561Snp * Best option: an interrupt vector for errors, one for the 1712228561Snp * firmware event queue, and one each for each rxq (NIC as well 1713228561Snp * as offload). 1714228561Snp */ 1715228561Snp iaq->nirq = T4_EXTRA_INTR; 1716228561Snp iaq->nirq += n10g * (nrxq10g + nofldrxq10g); 1717228561Snp iaq->nirq += n1g * (nrxq1g + nofldrxq1g); 1718228561Snp if (iaq->nirq <= navail && 1719228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) { 1720228561Snp iaq->intr_flags |= INTR_DIRECT; 1721228561Snp goto allocate; 1722228561Snp } 1723218792Snp 1724228561Snp /* 1725228561Snp * Second best option: an interrupt vector for errors, one for 1726228561Snp * the firmware event queue, and one each for either NIC or 1727228561Snp * offload rxq's. 1728228561Snp */ 1729228561Snp iaq->nirq = T4_EXTRA_INTR; 1730228561Snp iaq->nirq += n10g * max(nrxq10g, nofldrxq10g); 1731228561Snp iaq->nirq += n1g * max(nrxq1g, nofldrxq1g); 1732228561Snp if (iaq->nirq <= navail && 1733228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) 1734228561Snp goto allocate; 1735218792Snp 1736228561Snp /* 1737228561Snp * Next best option: an interrupt vector for errors, one for the 1738228561Snp * firmware event queue, and at least one per port. At this 1739228561Snp * point we know we'll have to downsize nrxq or nofldrxq to fit 1740228561Snp * what's available to us. 1741228561Snp */ 1742228561Snp iaq->nirq = T4_EXTRA_INTR; 1743228561Snp iaq->nirq += n10g + n1g; 1744228561Snp if (iaq->nirq <= navail) { 1745228561Snp int leftover = navail - iaq->nirq; 1746218792Snp 1747228561Snp if (n10g > 0) { 1748228561Snp int target = max(nrxq10g, nofldrxq10g); 1749219944Snp 1750228561Snp n = 1; 1751228561Snp while (n < target && leftover >= n10g) { 1752228561Snp leftover -= n10g; 1753228561Snp iaq->nirq += n10g; 1754228561Snp n++; 1755228561Snp } 1756228561Snp iaq->nrxq10g = min(n, nrxq10g); 1757237263Snp#ifdef TCP_OFFLOAD 1758237463Snp if (is_offload(sc)) 1759237463Snp iaq->nofldrxq10g = min(n, nofldrxq10g); 1760228561Snp#endif 1761228561Snp } 1762218792Snp 1763228561Snp if (n1g > 0) { 1764228561Snp int target = max(nrxq1g, nofldrxq1g); 1765219944Snp 1766228561Snp n = 1; 1767228561Snp while (n < target && leftover >= n1g) { 1768228561Snp leftover -= n1g; 1769228561Snp iaq->nirq += n1g; 1770228561Snp n++; 1771219944Snp } 1772228561Snp iaq->nrxq1g = min(n, nrxq1g); 1773237263Snp#ifdef TCP_OFFLOAD 1774237463Snp if (is_offload(sc)) 1775237463Snp iaq->nofldrxq1g = min(n, nofldrxq1g); 1776228561Snp#endif 1777219944Snp } 1778219944Snp 1779228561Snp if (itype != INTR_MSI || powerof2(iaq->nirq)) 1780228561Snp goto allocate; 1781218792Snp } 1782218792Snp 1783228561Snp /* 1784228561Snp * Least desirable option: one interrupt vector for everything. 1785228561Snp */ 1786228561Snp iaq->nirq = iaq->nrxq10g = iaq->nrxq1g = 1; 1787237263Snp#ifdef TCP_OFFLOAD 1788237463Snp if (is_offload(sc)) 1789237463Snp iaq->nofldrxq10g = iaq->nofldrxq1g = 1; 1790228561Snp#endif 1791228561Snp 1792228561Snpallocate: 1793218792Snp navail = iaq->nirq; 1794218792Snp rc = 0; 1795219944Snp if (itype == INTR_MSIX) 1796218792Snp rc = pci_alloc_msix(sc->dev, &navail); 1797219944Snp else if (itype == INTR_MSI) 1798218792Snp rc = pci_alloc_msi(sc->dev, &navail); 1799218792Snp 1800218792Snp if (rc == 0) { 1801218792Snp if (navail == iaq->nirq) 1802218792Snp return (0); 1803218792Snp 1804218792Snp /* 1805218792Snp * Didn't get the number requested. Use whatever number 1806218792Snp * the kernel is willing to allocate (it's in navail). 1807218792Snp */ 1808228561Snp device_printf(sc->dev, "fewer vectors than requested, " 1809228561Snp "type=%d, req=%d, rcvd=%d; will downshift req.\n", 1810228561Snp itype, iaq->nirq, navail); 1811218792Snp pci_release_msi(sc->dev); 1812228561Snp goto restart; 1813218792Snp } 1814218792Snp 1815218792Snp device_printf(sc->dev, 1816218792Snp "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n", 1817218792Snp itype, rc, iaq->nirq, navail); 1818218792Snp } 1819218792Snp 1820218792Snp device_printf(sc->dev, 1821218792Snp "failed to find a usable interrupt type. " 1822228561Snp "allowed=%d, msi-x=%d, msi=%d, intx=1", t4_intr_types, 1823218792Snp pci_msix_count(sc->dev), pci_msi_count(sc->dev)); 1824218792Snp 1825218792Snp return (ENXIO); 1826218792Snp} 1827218792Snp 1828248925Snp#define FW_VERSION(chip) ( \ 1829248925Snp V_FW_HDR_FW_VER_MAJOR(FW_VERSION_MAJOR_##chip) | \ 1830248925Snp V_FW_HDR_FW_VER_MINOR(FW_VERSION_MINOR_##chip) | \ 1831248925Snp V_FW_HDR_FW_VER_MICRO(FW_VERSION_MICRO_##chip) | \ 1832248925Snp V_FW_HDR_FW_VER_BUILD(FW_VERSION_BUILD_##chip)) 1833248925Snp#define FW_INTFVER(chip, intf) (FW_HDR_INTFVER_##intf) 1834248925Snp 1835248925Snpstruct fw_info { 1836248925Snp uint8_t chip; 1837248925Snp char *kld_name; 1838248925Snp char *fw_mod_name; 1839248925Snp struct fw_hdr fw_hdr; /* XXX: waste of space, need a sparse struct */ 1840248925Snp} fw_info[] = { 1841248925Snp { 1842248925Snp .chip = CHELSIO_T4, 1843248925Snp .kld_name = "t4fw_cfg", 1844248925Snp .fw_mod_name = "t4fw", 1845248925Snp .fw_hdr = { 1846248925Snp .chip = FW_HDR_CHIP_T4, 1847248925Snp .fw_ver = htobe32_const(FW_VERSION(T4)), 1848248925Snp .intfver_nic = FW_INTFVER(T4, NIC), 1849248925Snp .intfver_vnic = FW_INTFVER(T4, VNIC), 1850248925Snp .intfver_ofld = FW_INTFVER(T4, OFLD), 1851248925Snp .intfver_ri = FW_INTFVER(T4, RI), 1852248925Snp .intfver_iscsipdu = FW_INTFVER(T4, ISCSIPDU), 1853248925Snp .intfver_iscsi = FW_INTFVER(T4, ISCSI), 1854248925Snp .intfver_fcoepdu = FW_INTFVER(T4, FCOEPDU), 1855248925Snp .intfver_fcoe = FW_INTFVER(T4, FCOE), 1856248925Snp }, 1857248925Snp }, { 1858248925Snp .chip = CHELSIO_T5, 1859248925Snp .kld_name = "t5fw_cfg", 1860248925Snp .fw_mod_name = "t5fw", 1861248925Snp .fw_hdr = { 1862248925Snp .chip = FW_HDR_CHIP_T5, 1863248925Snp .fw_ver = htobe32_const(FW_VERSION(T5)), 1864248925Snp .intfver_nic = FW_INTFVER(T5, NIC), 1865248925Snp .intfver_vnic = FW_INTFVER(T5, VNIC), 1866248925Snp .intfver_ofld = FW_INTFVER(T5, OFLD), 1867248925Snp .intfver_ri = FW_INTFVER(T5, RI), 1868248925Snp .intfver_iscsipdu = FW_INTFVER(T5, ISCSIPDU), 1869248925Snp .intfver_iscsi = FW_INTFVER(T5, ISCSI), 1870248925Snp .intfver_fcoepdu = FW_INTFVER(T5, FCOEPDU), 1871248925Snp .intfver_fcoe = FW_INTFVER(T5, FCOE), 1872248925Snp }, 1873248925Snp } 1874248925Snp}; 1875248925Snp 1876248925Snpstatic struct fw_info * 1877248925Snpfind_fw_info(int chip) 1878248925Snp{ 1879248925Snp int i; 1880248925Snp 1881248925Snp for (i = 0; i < nitems(fw_info); i++) { 1882248925Snp if (fw_info[i].chip == chip) 1883248925Snp return (&fw_info[i]); 1884248925Snp } 1885248925Snp return (NULL); 1886248925Snp} 1887248925Snp 1888218792Snp/* 1889248925Snp * Is the given firmware API compatible with the one the driver was compiled 1890248925Snp * with? 1891247347Snp */ 1892247347Snpstatic int 1893248925Snpfw_compatible(const struct fw_hdr *hdr1, const struct fw_hdr *hdr2) 1894247347Snp{ 1895247347Snp 1896248925Snp /* short circuit if it's the exact same firmware version */ 1897248925Snp if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver) 1898247347Snp return (1); 1899247347Snp 1900247347Snp /* 1901247347Snp * XXX: Is this too conservative? Perhaps I should limit this to the 1902247347Snp * features that are supported in the driver. 1903247347Snp */ 1904248925Snp#define SAME_INTF(x) (hdr1->intfver_##x == hdr2->intfver_##x) 1905248925Snp if (hdr1->chip == hdr2->chip && SAME_INTF(nic) && SAME_INTF(vnic) && 1906248925Snp SAME_INTF(ofld) && SAME_INTF(ri) && SAME_INTF(iscsipdu) && 1907248925Snp SAME_INTF(iscsi) && SAME_INTF(fcoepdu) && SAME_INTF(fcoe)) 1908247347Snp return (1); 1909248925Snp#undef SAME_INTF 1910247347Snp 1911247347Snp return (0); 1912247347Snp} 1913247347Snp 1914247347Snp/* 1915251434Snp * The firmware in the KLD is usable, but should it be installed? This routine 1916251434Snp * explains itself in detail if it indicates the KLD firmware should be 1917251434Snp * installed. 1918249376Snp */ 1919249376Snpstatic int 1920249376Snpshould_install_kld_fw(struct adapter *sc, int card_fw_usable, int k, int c) 1921249376Snp{ 1922249376Snp const char *reason; 1923249376Snp 1924249376Snp if (!card_fw_usable) { 1925249376Snp reason = "incompatible or unusable"; 1926249376Snp goto install; 1927249376Snp } 1928249376Snp 1929249376Snp if (k > c) { 1930249376Snp reason = "older than the version bundled with this driver"; 1931249376Snp goto install; 1932249376Snp } 1933249376Snp 1934249376Snp if (t4_fw_install == 2 && k != c) { 1935249376Snp reason = "different than the version bundled with this driver"; 1936249376Snp goto install; 1937249376Snp } 1938249376Snp 1939249376Snp return (0); 1940249376Snp 1941249376Snpinstall: 1942251434Snp if (t4_fw_install == 0) { 1943251434Snp device_printf(sc->dev, "firmware on card (%u.%u.%u.%u) is %s, " 1944251434Snp "but the driver is prohibited from installing a different " 1945251434Snp "firmware on the card.\n", 1946251434Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 1947251434Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), reason); 1948251434Snp 1949251434Snp return (0); 1950251434Snp } 1951251434Snp 1952249376Snp device_printf(sc->dev, "firmware on card (%u.%u.%u.%u) is %s, " 1953249376Snp "installing firmware %u.%u.%u.%u on card.\n", 1954249376Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 1955249376Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), reason, 1956249376Snp G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k), 1957249376Snp G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k)); 1958249376Snp 1959249376Snp return (1); 1960249376Snp} 1961249376Snp/* 1962248925Snp * Establish contact with the firmware and determine if we are the master driver 1963248925Snp * or not, and whether we are responsible for chip initialization. 1964218792Snp */ 1965218792Snpstatic int 1966218792Snpprep_firmware(struct adapter *sc) 1967218792Snp{ 1968248925Snp const struct firmware *fw = NULL, *default_cfg; 1969248925Snp int rc, pf, card_fw_usable, kld_fw_usable, need_fw_reset = 1; 1970218792Snp enum dev_state state; 1971248925Snp struct fw_info *fw_info; 1972248925Snp struct fw_hdr *card_fw; /* fw on the card */ 1973248925Snp const struct fw_hdr *kld_fw; /* fw in the KLD */ 1974248925Snp const struct fw_hdr *drv_fw; /* fw header the driver was compiled 1975248925Snp against */ 1976218792Snp 1977248925Snp /* Contact firmware. */ 1978248925Snp rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state); 1979248925Snp if (rc < 0 || state == DEV_STATE_ERR) { 1980248925Snp rc = -rc; 1981248925Snp device_printf(sc->dev, 1982248925Snp "failed to connect to the firmware: %d, %d.\n", rc, state); 1983248925Snp return (rc); 1984248925Snp } 1985248925Snp pf = rc; 1986248925Snp if (pf == sc->mbox) 1987248925Snp sc->flags |= MASTER_PF; 1988248925Snp else if (state == DEV_STATE_UNINIT) { 1989248925Snp /* 1990248925Snp * We didn't get to be the master so we definitely won't be 1991248925Snp * configuring the chip. It's a bug if someone else hasn't 1992248925Snp * configured it already. 1993248925Snp */ 1994248925Snp device_printf(sc->dev, "couldn't be master(%d), " 1995248925Snp "device not already initialized either(%d).\n", rc, state); 1996248925Snp return (EDOOFUS); 1997248925Snp } 1998228561Snp 1999248925Snp /* This is the firmware whose headers the driver was compiled against */ 2000248925Snp fw_info = find_fw_info(chip_id(sc)); 2001248925Snp if (fw_info == NULL) { 2002248925Snp device_printf(sc->dev, 2003248925Snp "unable to look up firmware information for chip %d.\n", 2004248925Snp chip_id(sc)); 2005248925Snp return (EINVAL); 2006248925Snp } 2007248925Snp drv_fw = &fw_info->fw_hdr; 2008248925Snp 2009248925Snp /* 2010248925Snp * The firmware KLD contains many modules. The KLD name is also the 2011248925Snp * name of the module that contains the default config file. 2012248925Snp */ 2013248925Snp default_cfg = firmware_get(fw_info->kld_name); 2014248925Snp 2015247347Snp /* Read the header of the firmware on the card */ 2016247347Snp card_fw = malloc(sizeof(*card_fw), M_CXGBE, M_ZERO | M_WAITOK); 2017247347Snp rc = -t4_read_flash(sc, FLASH_FW_START, 2018247347Snp sizeof (*card_fw) / sizeof (uint32_t), (uint32_t *)card_fw, 1); 2019247347Snp if (rc == 0) 2020248925Snp card_fw_usable = fw_compatible(drv_fw, (const void*)card_fw); 2021247347Snp else { 2022247347Snp device_printf(sc->dev, 2023247347Snp "Unable to read card's firmware header: %d\n", rc); 2024247347Snp card_fw_usable = 0; 2025247347Snp } 2026218792Snp 2027247347Snp /* This is the firmware in the KLD */ 2028248925Snp fw = firmware_get(fw_info->fw_mod_name); 2029247347Snp if (fw != NULL) { 2030247347Snp kld_fw = (const void *)fw->data; 2031248925Snp kld_fw_usable = fw_compatible(drv_fw, kld_fw); 2032247347Snp } else { 2033247347Snp kld_fw = NULL; 2034247347Snp kld_fw_usable = 0; 2035247347Snp } 2036219287Snp 2037248925Snp if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver && 2038251434Snp (!kld_fw_usable || kld_fw->fw_ver == drv_fw->fw_ver)) { 2039248925Snp /* 2040248925Snp * Common case: the firmware on the card is an exact match and 2041248925Snp * the KLD is an exact match too, or the KLD is 2042251434Snp * absent/incompatible. Note that t4_fw_install = 2 is ignored 2043251434Snp * here -- use cxgbetool loadfw if you want to reinstall the 2044251434Snp * same firmware as the one on the card. 2045248925Snp */ 2046248925Snp } else if (kld_fw_usable && state == DEV_STATE_UNINIT && 2047249376Snp should_install_kld_fw(sc, card_fw_usable, be32toh(kld_fw->fw_ver), 2048249376Snp be32toh(card_fw->fw_ver))) { 2049219287Snp 2050250221Snp rc = -t4_fw_upgrade(sc, sc->mbox, fw->data, fw->datasize, 0); 2051247347Snp if (rc != 0) { 2052247347Snp device_printf(sc->dev, 2053247347Snp "failed to install firmware: %d\n", rc); 2054228561Snp goto done; 2055219287Snp } 2056219287Snp 2057247347Snp /* Installed successfully, update the cached header too. */ 2058247347Snp memcpy(card_fw, kld_fw, sizeof(*card_fw)); 2059247347Snp card_fw_usable = 1; 2060248925Snp need_fw_reset = 0; /* already reset as part of load_fw */ 2061247347Snp } 2062219287Snp 2063247347Snp if (!card_fw_usable) { 2064248925Snp uint32_t d, c, k; 2065247347Snp 2066248925Snp d = ntohl(drv_fw->fw_ver); 2067247347Snp c = ntohl(card_fw->fw_ver); 2068247347Snp k = kld_fw ? ntohl(kld_fw->fw_ver) : 0; 2069247347Snp 2070247347Snp device_printf(sc->dev, "Cannot find a usable firmware: " 2071248925Snp "fw_install %d, chip state %d, " 2072248925Snp "driver compiled with %d.%d.%d.%d, " 2073247347Snp "card has %d.%d.%d.%d, KLD has %d.%d.%d.%d\n", 2074248925Snp t4_fw_install, state, 2075248925Snp G_FW_HDR_FW_VER_MAJOR(d), G_FW_HDR_FW_VER_MINOR(d), 2076248925Snp G_FW_HDR_FW_VER_MICRO(d), G_FW_HDR_FW_VER_BUILD(d), 2077247347Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 2078247347Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), 2079247347Snp G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k), 2080247347Snp G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k)); 2081248925Snp rc = EINVAL; 2082247347Snp goto done; 2083218792Snp } 2084218792Snp 2085247347Snp /* We're using whatever's on the card and it's known to be good. */ 2086247347Snp sc->params.fw_vers = ntohl(card_fw->fw_ver); 2087247347Snp snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u", 2088247347Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 2089247347Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 2090247347Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 2091247347Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 2092247347Snp 2093218792Snp /* Reset device */ 2094248925Snp if (need_fw_reset && 2095248925Snp (rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST)) != 0) { 2096218792Snp device_printf(sc->dev, "firmware reset failed: %d.\n", rc); 2097218792Snp if (rc != ETIMEDOUT && rc != EIO) 2098218792Snp t4_fw_bye(sc, sc->mbox); 2099228561Snp goto done; 2100218792Snp } 2101248925Snp sc->flags |= FW_OK; 2102218792Snp 2103248925Snp rc = get_params__pre_init(sc); 2104248925Snp if (rc != 0) 2105248925Snp goto done; /* error message displayed already */ 2106248925Snp 2107228561Snp /* Partition adapter resources as specified in the config file. */ 2108248925Snp if (state == DEV_STATE_UNINIT) { 2109228561Snp 2110248925Snp KASSERT(sc->flags & MASTER_PF, 2111248925Snp ("%s: trying to change chip settings when not master.", 2112248925Snp __func__)); 2113228561Snp 2114248925Snp rc = partition_resources(sc, default_cfg, fw_info->kld_name); 2115228561Snp if (rc != 0) 2116228561Snp goto done; /* error message displayed already */ 2117248925Snp 2118248925Snp t4_tweak_chip_settings(sc); 2119248925Snp 2120248925Snp /* get basic stuff going */ 2121248925Snp rc = -t4_fw_initialize(sc, sc->mbox); 2122248925Snp if (rc != 0) { 2123248925Snp device_printf(sc->dev, "fw init failed: %d.\n", rc); 2124248925Snp goto done; 2125248925Snp } 2126245936Snp } else { 2127248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "pf%d", pf); 2128248925Snp sc->cfcsum = 0; 2129228561Snp } 2130228561Snp 2131228561Snpdone: 2132247347Snp free(card_fw, M_CXGBE); 2133228561Snp if (fw != NULL) 2134228561Snp firmware_put(fw, FIRMWARE_UNLOAD); 2135228561Snp if (default_cfg != NULL) 2136228561Snp firmware_put(default_cfg, FIRMWARE_UNLOAD); 2137228561Snp 2138228561Snp return (rc); 2139218792Snp} 2140218792Snp 2141228561Snp#define FW_PARAM_DEV(param) \ 2142228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ 2143228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) 2144228561Snp#define FW_PARAM_PFVF(param) \ 2145228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ 2146228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)) 2147228561Snp 2148228561Snp/* 2149248925Snp * Partition chip resources for use between various PFs, VFs, etc. 2150228561Snp */ 2151218792Snpstatic int 2152248925Snppartition_resources(struct adapter *sc, const struct firmware *default_cfg, 2153248925Snp const char *name_prefix) 2154222551Snp{ 2155248925Snp const struct firmware *cfg = NULL; 2156248925Snp int rc = 0; 2157248925Snp struct fw_caps_config_cmd caps; 2158248925Snp uint32_t mtype, moff, finicsum, cfcsum; 2159222551Snp 2160248925Snp /* 2161248925Snp * Figure out what configuration file to use. Pick the default config 2162248925Snp * file for the card if the user hasn't specified one explicitly. 2163248925Snp */ 2164248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", t4_cfg_file); 2165248925Snp if (strncmp(t4_cfg_file, DEFAULT_CF, sizeof(t4_cfg_file)) == 0) { 2166248925Snp /* Card specific overrides go here. */ 2167248925Snp if (pci_get_device(sc->dev) == 0x440a) 2168248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), UWIRE_CF); 2169249376Snp if (is_fpga(sc)) 2170249376Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), FPGA_CF); 2171222551Snp } 2172222551Snp 2173248925Snp /* 2174248925Snp * We need to load another module if the profile is anything except 2175248925Snp * "default" or "flash". 2176248925Snp */ 2177248925Snp if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) != 0 && 2178248925Snp strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) { 2179248925Snp char s[32]; 2180248925Snp 2181248925Snp snprintf(s, sizeof(s), "%s_%s", name_prefix, sc->cfg_file); 2182248925Snp cfg = firmware_get(s); 2183248925Snp if (cfg == NULL) { 2184248925Snp if (default_cfg != NULL) { 2185249376Snp device_printf(sc->dev, 2186249376Snp "unable to load module \"%s\" for " 2187249376Snp "configuration profile \"%s\", will use " 2188249376Snp "the default config file instead.\n", 2189249376Snp s, sc->cfg_file); 2190248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), 2191248925Snp "%s", DEFAULT_CF); 2192248925Snp } else { 2193249376Snp device_printf(sc->dev, 2194249376Snp "unable to load module \"%s\" for " 2195249376Snp "configuration profile \"%s\", will use " 2196249376Snp "the config file on the card's flash " 2197249376Snp "instead.\n", s, sc->cfg_file); 2198248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), 2199248925Snp "%s", FLASH_CF); 2200248925Snp } 2201248925Snp } 2202228561Snp } 2203222551Snp 2204248925Snp if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) == 0 && 2205248925Snp default_cfg == NULL) { 2206228561Snp device_printf(sc->dev, 2207248925Snp "default config file not available, will use the config " 2208248925Snp "file on the card's flash instead.\n"); 2209248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", FLASH_CF); 2210228561Snp } 2211228561Snp 2212248925Snp if (strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) { 2213248925Snp u_int cflen, i, n; 2214248925Snp const uint32_t *cfdata; 2215248925Snp uint32_t param, val, addr, off, mw_base, mw_aperture; 2216228561Snp 2217248925Snp KASSERT(cfg != NULL || default_cfg != NULL, 2218248925Snp ("%s: no config to upload", __func__)); 2219228561Snp 2220248925Snp /* 2221248925Snp * Ask the firmware where it wants us to upload the config file. 2222248925Snp */ 2223248925Snp param = FW_PARAM_DEV(CF); 2224248925Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 2225248925Snp if (rc != 0) { 2226248925Snp /* No support for config file? Shouldn't happen. */ 2227248925Snp device_printf(sc->dev, 2228248925Snp "failed to query config file location: %d.\n", rc); 2229248925Snp goto done; 2230248925Snp } 2231248925Snp mtype = G_FW_PARAMS_PARAM_Y(val); 2232248925Snp moff = G_FW_PARAMS_PARAM_Z(val) << 16; 2233228561Snp 2234248925Snp /* 2235248925Snp * XXX: sheer laziness. We deliberately added 4 bytes of 2236248925Snp * useless stuffing/comments at the end of the config file so 2237248925Snp * it's ok to simply throw away the last remaining bytes when 2238248925Snp * the config file is not an exact multiple of 4. This also 2239248925Snp * helps with the validate_mt_off_len check. 2240248925Snp */ 2241248925Snp if (cfg != NULL) { 2242248925Snp cflen = cfg->datasize & ~3; 2243248925Snp cfdata = cfg->data; 2244248925Snp } else { 2245248925Snp cflen = default_cfg->datasize & ~3; 2246248925Snp cfdata = default_cfg->data; 2247248925Snp } 2248222551Snp 2249248925Snp if (cflen > FLASH_CFG_MAX_SIZE) { 2250248925Snp device_printf(sc->dev, 2251248925Snp "config file too long (%d, max allowed is %d). " 2252248925Snp "Will try to use the config on the card, if any.\n", 2253248925Snp cflen, FLASH_CFG_MAX_SIZE); 2254248925Snp goto use_config_on_flash; 2255248925Snp } 2256218792Snp 2257248925Snp rc = validate_mt_off_len(sc, mtype, moff, cflen, &addr); 2258248925Snp if (rc != 0) { 2259248925Snp device_printf(sc->dev, 2260248925Snp "%s: addr (%d/0x%x) or len %d is not valid: %d. " 2261248925Snp "Will try to use the config on the card, if any.\n", 2262248925Snp __func__, mtype, moff, cflen, rc); 2263248925Snp goto use_config_on_flash; 2264248925Snp } 2265248925Snp 2266248925Snp memwin_info(sc, 2, &mw_base, &mw_aperture); 2267248925Snp while (cflen) { 2268248925Snp off = position_memwin(sc, 2, addr); 2269248925Snp n = min(cflen, mw_aperture - off); 2270248925Snp for (i = 0; i < n; i += 4) 2271248925Snp t4_write_reg(sc, mw_base + off + i, *cfdata++); 2272248925Snp cflen -= n; 2273248925Snp addr += n; 2274248925Snp } 2275248925Snp } else { 2276248925Snpuse_config_on_flash: 2277228561Snp mtype = FW_MEMTYPE_CF_FLASH; 2278248925Snp moff = t4_flash_cfg_addr(sc); 2279228561Snp } 2280228561Snp 2281228561Snp bzero(&caps, sizeof(caps)); 2282228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2283218792Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2284228561Snp caps.cfvalid_to_len16 = htobe32(F_FW_CAPS_CONFIG_CMD_CFVALID | 2285228561Snp V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) | 2286248925Snp V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(moff >> 16) | FW_LEN16(caps)); 2287228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 2288228561Snp if (rc != 0) { 2289228561Snp device_printf(sc->dev, 2290249376Snp "failed to pre-process config file: %d " 2291249376Snp "(mtype %d, moff 0x%x).\n", rc, mtype, moff); 2292248925Snp goto done; 2293228561Snp } 2294218792Snp 2295228561Snp finicsum = be32toh(caps.finicsum); 2296228561Snp cfcsum = be32toh(caps.cfcsum); 2297228561Snp if (finicsum != cfcsum) { 2298228561Snp device_printf(sc->dev, 2299228561Snp "WARNING: config file checksum mismatch: %08x %08x\n", 2300228561Snp finicsum, cfcsum); 2301228561Snp } 2302228561Snp sc->cfcsum = cfcsum; 2303218792Snp 2304228561Snp#define LIMIT_CAPS(x) do { \ 2305228561Snp caps.x &= htobe16(t4_##x##_allowed); \ 2306228561Snp sc->x = htobe16(caps.x); \ 2307228561Snp} while (0) 2308228561Snp 2309228561Snp /* 2310228561Snp * Let the firmware know what features will (not) be used so it can tune 2311228561Snp * things accordingly. 2312228561Snp */ 2313228561Snp LIMIT_CAPS(linkcaps); 2314228561Snp LIMIT_CAPS(niccaps); 2315228561Snp LIMIT_CAPS(toecaps); 2316228561Snp LIMIT_CAPS(rdmacaps); 2317228561Snp LIMIT_CAPS(iscsicaps); 2318228561Snp LIMIT_CAPS(fcoecaps); 2319228561Snp#undef LIMIT_CAPS 2320228561Snp 2321228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2322218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE); 2323228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 2324228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), NULL); 2325228561Snp if (rc != 0) { 2326228561Snp device_printf(sc->dev, 2327228561Snp "failed to process config file: %d.\n", rc); 2328228561Snp } 2329248925Snpdone: 2330248925Snp if (cfg != NULL) 2331248925Snp firmware_put(cfg, FIRMWARE_UNLOAD); 2332248925Snp return (rc); 2333218792Snp} 2334218792Snp 2335228561Snp/* 2336248925Snp * Retrieve parameters that are needed (or nice to have) very early. 2337228561Snp */ 2338218792Snpstatic int 2339228561Snpget_params__pre_init(struct adapter *sc) 2340218792Snp{ 2341218792Snp int rc; 2342228561Snp uint32_t param[2], val[2]; 2343228561Snp struct fw_devlog_cmd cmd; 2344228561Snp struct devlog_params *dlog = &sc->params.devlog; 2345218792Snp 2346228561Snp param[0] = FW_PARAM_DEV(PORTVEC); 2347228561Snp param[1] = FW_PARAM_DEV(CCLK); 2348228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 2349218792Snp if (rc != 0) { 2350218792Snp device_printf(sc->dev, 2351228561Snp "failed to query parameters (pre_init): %d.\n", rc); 2352228561Snp return (rc); 2353218792Snp } 2354218792Snp 2355218792Snp sc->params.portvec = val[0]; 2356240452Snp sc->params.nports = bitcount32(val[0]); 2357228561Snp sc->params.vpd.cclk = val[1]; 2358218792Snp 2359228561Snp /* Read device log parameters. */ 2360228561Snp bzero(&cmd, sizeof(cmd)); 2361228561Snp cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) | 2362228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2363228561Snp cmd.retval_len16 = htobe32(FW_LEN16(cmd)); 2364228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &cmd, sizeof(cmd), &cmd); 2365228561Snp if (rc != 0) { 2366228561Snp device_printf(sc->dev, 2367228561Snp "failed to get devlog parameters: %d.\n", rc); 2368228561Snp bzero(dlog, sizeof (*dlog)); 2369228561Snp rc = 0; /* devlog isn't critical for device operation */ 2370228561Snp } else { 2371228561Snp val[0] = be32toh(cmd.memtype_devlog_memaddr16_devlog); 2372228561Snp dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(val[0]); 2373228561Snp dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(val[0]) << 4; 2374228561Snp dlog->size = be32toh(cmd.memsize_devlog); 2375228561Snp } 2376228561Snp 2377228561Snp return (rc); 2378228561Snp} 2379228561Snp 2380228561Snp/* 2381228561Snp * Retrieve various parameters that are of interest to the driver. The device 2382228561Snp * has been initialized by the firmware at this point. 2383228561Snp */ 2384228561Snpstatic int 2385228561Snpget_params__post_init(struct adapter *sc) 2386228561Snp{ 2387228561Snp int rc; 2388228561Snp uint32_t param[7], val[7]; 2389228561Snp struct fw_caps_config_cmd caps; 2390228561Snp 2391228561Snp param[0] = FW_PARAM_PFVF(IQFLINT_START); 2392228561Snp param[1] = FW_PARAM_PFVF(EQ_START); 2393228561Snp param[2] = FW_PARAM_PFVF(FILTER_START); 2394228561Snp param[3] = FW_PARAM_PFVF(FILTER_END); 2395245434Snp param[4] = FW_PARAM_PFVF(L2T_START); 2396245434Snp param[5] = FW_PARAM_PFVF(L2T_END); 2397245434Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2398228561Snp if (rc != 0) { 2399228561Snp device_printf(sc->dev, 2400228561Snp "failed to query parameters (post_init): %d.\n", rc); 2401228561Snp return (rc); 2402228561Snp } 2403228561Snp 2404228561Snp sc->sge.iq_start = val[0]; 2405228561Snp sc->sge.eq_start = val[1]; 2406228561Snp sc->tids.ftid_base = val[2]; 2407228561Snp sc->tids.nftids = val[3] - val[2] + 1; 2408245434Snp sc->vres.l2t.start = val[4]; 2409245434Snp sc->vres.l2t.size = val[5] - val[4] + 1; 2410245434Snp KASSERT(sc->vres.l2t.size <= L2T_SIZE, 2411245434Snp ("%s: L2 table size (%u) larger than expected (%u)", 2412245434Snp __func__, sc->vres.l2t.size, L2T_SIZE)); 2413228561Snp 2414228561Snp /* get capabilites */ 2415228561Snp bzero(&caps, sizeof(caps)); 2416228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2417228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2418228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 2419228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 2420228561Snp if (rc != 0) { 2421228561Snp device_printf(sc->dev, 2422228561Snp "failed to get card capabilities: %d.\n", rc); 2423228561Snp return (rc); 2424228561Snp } 2425228561Snp 2426228561Snp if (caps.toecaps) { 2427218792Snp /* query offload-related parameters */ 2428228561Snp param[0] = FW_PARAM_DEV(NTID); 2429228561Snp param[1] = FW_PARAM_PFVF(SERVER_START); 2430228561Snp param[2] = FW_PARAM_PFVF(SERVER_END); 2431228561Snp param[3] = FW_PARAM_PFVF(TDDP_START); 2432228561Snp param[4] = FW_PARAM_PFVF(TDDP_END); 2433228561Snp param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 2434228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2435218792Snp if (rc != 0) { 2436218792Snp device_printf(sc->dev, 2437218792Snp "failed to query TOE parameters: %d.\n", rc); 2438228561Snp return (rc); 2439218792Snp } 2440218792Snp sc->tids.ntids = val[0]; 2441218792Snp sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS); 2442218792Snp sc->tids.stid_base = val[1]; 2443218792Snp sc->tids.nstids = val[2] - val[1] + 1; 2444218792Snp sc->vres.ddp.start = val[3]; 2445218792Snp sc->vres.ddp.size = val[4] - val[3] + 1; 2446218792Snp sc->params.ofldq_wr_cred = val[5]; 2447218792Snp sc->params.offload = 1; 2448218792Snp } 2449228561Snp if (caps.rdmacaps) { 2450228561Snp param[0] = FW_PARAM_PFVF(STAG_START); 2451228561Snp param[1] = FW_PARAM_PFVF(STAG_END); 2452228561Snp param[2] = FW_PARAM_PFVF(RQ_START); 2453228561Snp param[3] = FW_PARAM_PFVF(RQ_END); 2454228561Snp param[4] = FW_PARAM_PFVF(PBL_START); 2455228561Snp param[5] = FW_PARAM_PFVF(PBL_END); 2456228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2457218792Snp if (rc != 0) { 2458218792Snp device_printf(sc->dev, 2459228561Snp "failed to query RDMA parameters(1): %d.\n", rc); 2460228561Snp return (rc); 2461218792Snp } 2462218792Snp sc->vres.stag.start = val[0]; 2463218792Snp sc->vres.stag.size = val[1] - val[0] + 1; 2464218792Snp sc->vres.rq.start = val[2]; 2465218792Snp sc->vres.rq.size = val[3] - val[2] + 1; 2466218792Snp sc->vres.pbl.start = val[4]; 2467218792Snp sc->vres.pbl.size = val[5] - val[4] + 1; 2468228561Snp 2469228561Snp param[0] = FW_PARAM_PFVF(SQRQ_START); 2470228561Snp param[1] = FW_PARAM_PFVF(SQRQ_END); 2471228561Snp param[2] = FW_PARAM_PFVF(CQ_START); 2472228561Snp param[3] = FW_PARAM_PFVF(CQ_END); 2473228561Snp param[4] = FW_PARAM_PFVF(OCQ_START); 2474228561Snp param[5] = FW_PARAM_PFVF(OCQ_END); 2475228561Snp rc = -t4_query_params(sc, 0, 0, 0, 6, param, val); 2476228561Snp if (rc != 0) { 2477228561Snp device_printf(sc->dev, 2478228561Snp "failed to query RDMA parameters(2): %d.\n", rc); 2479228561Snp return (rc); 2480228561Snp } 2481228561Snp sc->vres.qp.start = val[0]; 2482228561Snp sc->vres.qp.size = val[1] - val[0] + 1; 2483228561Snp sc->vres.cq.start = val[2]; 2484228561Snp sc->vres.cq.size = val[3] - val[2] + 1; 2485228561Snp sc->vres.ocq.start = val[4]; 2486228561Snp sc->vres.ocq.size = val[5] - val[4] + 1; 2487218792Snp } 2488228561Snp if (caps.iscsicaps) { 2489228561Snp param[0] = FW_PARAM_PFVF(ISCSI_START); 2490228561Snp param[1] = FW_PARAM_PFVF(ISCSI_END); 2491228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 2492218792Snp if (rc != 0) { 2493218792Snp device_printf(sc->dev, 2494218792Snp "failed to query iSCSI parameters: %d.\n", rc); 2495228561Snp return (rc); 2496218792Snp } 2497218792Snp sc->vres.iscsi.start = val[0]; 2498218792Snp sc->vres.iscsi.size = val[1] - val[0] + 1; 2499218792Snp } 2500218792Snp 2501248925Snp /* 2502248925Snp * We've got the params we wanted to query via the firmware. Now grab 2503248925Snp * some others directly from the chip. 2504248925Snp */ 2505248925Snp rc = t4_read_chip_settings(sc); 2506228561Snp 2507218792Snp return (rc); 2508218792Snp} 2509218792Snp 2510247291Snpstatic int 2511247291Snpset_params__post_init(struct adapter *sc) 2512247291Snp{ 2513247291Snp uint32_t param, val; 2514247291Snp 2515249382Snp /* ask for encapsulated CPLs */ 2516247291Snp param = FW_PARAM_PFVF(CPLFW4MSG_ENCAP); 2517249382Snp val = 1; 2518249382Snp (void)t4_set_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 2519247291Snp 2520249382Snp return (0); 2521247291Snp} 2522247291Snp 2523228561Snp#undef FW_PARAM_PFVF 2524228561Snp#undef FW_PARAM_DEV 2525228561Snp 2526218792Snpstatic void 2527218792Snpt4_set_desc(struct adapter *sc) 2528218792Snp{ 2529218792Snp char buf[128]; 2530218792Snp struct adapter_params *p = &sc->params; 2531218792Snp 2532228561Snp snprintf(buf, sizeof(buf), "Chelsio %s %sNIC (rev %d), S/N:%s, E/C:%s", 2533248925Snp p->vpd.id, is_offload(sc) ? "R" : "", chip_rev(sc), p->vpd.sn, 2534248925Snp p->vpd.ec); 2535218792Snp 2536218792Snp device_set_desc_copy(sc->dev, buf); 2537218792Snp} 2538218792Snp 2539218792Snpstatic void 2540218792Snpbuild_medialist(struct port_info *pi) 2541218792Snp{ 2542218792Snp struct ifmedia *media = &pi->media; 2543218792Snp int data, m; 2544218792Snp 2545218792Snp PORT_LOCK(pi); 2546218792Snp 2547218792Snp ifmedia_removeall(media); 2548218792Snp 2549218792Snp m = IFM_ETHER | IFM_FDX; 2550218792Snp data = (pi->port_type << 8) | pi->mod_type; 2551218792Snp 2552218792Snp switch(pi->port_type) { 2553218792Snp case FW_PORT_TYPE_BT_XFI: 2554218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2555218792Snp break; 2556218792Snp 2557218792Snp case FW_PORT_TYPE_BT_XAUI: 2558218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2559218792Snp /* fall through */ 2560218792Snp 2561218792Snp case FW_PORT_TYPE_BT_SGMII: 2562218792Snp ifmedia_add(media, m | IFM_1000_T, data, NULL); 2563218792Snp ifmedia_add(media, m | IFM_100_TX, data, NULL); 2564218792Snp ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL); 2565218792Snp ifmedia_set(media, IFM_ETHER | IFM_AUTO); 2566218792Snp break; 2567218792Snp 2568218792Snp case FW_PORT_TYPE_CX4: 2569218792Snp ifmedia_add(media, m | IFM_10G_CX4, data, NULL); 2570218792Snp ifmedia_set(media, m | IFM_10G_CX4); 2571218792Snp break; 2572218792Snp 2573218792Snp case FW_PORT_TYPE_SFP: 2574218792Snp case FW_PORT_TYPE_FIBER_XFI: 2575218792Snp case FW_PORT_TYPE_FIBER_XAUI: 2576218792Snp switch (pi->mod_type) { 2577218792Snp 2578218792Snp case FW_PORT_MOD_TYPE_LR: 2579218792Snp ifmedia_add(media, m | IFM_10G_LR, data, NULL); 2580218792Snp ifmedia_set(media, m | IFM_10G_LR); 2581218792Snp break; 2582218792Snp 2583218792Snp case FW_PORT_MOD_TYPE_SR: 2584218792Snp ifmedia_add(media, m | IFM_10G_SR, data, NULL); 2585218792Snp ifmedia_set(media, m | IFM_10G_SR); 2586218792Snp break; 2587218792Snp 2588218792Snp case FW_PORT_MOD_TYPE_LRM: 2589218792Snp ifmedia_add(media, m | IFM_10G_LRM, data, NULL); 2590218792Snp ifmedia_set(media, m | IFM_10G_LRM); 2591218792Snp break; 2592218792Snp 2593218792Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2594218792Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2595218792Snp ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL); 2596218792Snp ifmedia_set(media, m | IFM_10G_TWINAX); 2597218792Snp break; 2598218792Snp 2599218792Snp case FW_PORT_MOD_TYPE_NONE: 2600218792Snp m &= ~IFM_FDX; 2601218792Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2602218792Snp ifmedia_set(media, m | IFM_NONE); 2603218792Snp break; 2604218792Snp 2605218792Snp case FW_PORT_MOD_TYPE_NA: 2606218792Snp case FW_PORT_MOD_TYPE_ER: 2607218792Snp default: 2608250092Snp device_printf(pi->dev, 2609250092Snp "unknown port_type (%d), mod_type (%d)\n", 2610250092Snp pi->port_type, pi->mod_type); 2611218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2612218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2613218792Snp break; 2614218792Snp } 2615218792Snp break; 2616218792Snp 2617250092Snp case FW_PORT_TYPE_QSFP: 2618250092Snp switch (pi->mod_type) { 2619250092Snp 2620250092Snp case FW_PORT_MOD_TYPE_LR: 2621250092Snp ifmedia_add(media, m | IFM_40G_LR4, data, NULL); 2622250092Snp ifmedia_set(media, m | IFM_40G_LR4); 2623250092Snp break; 2624250092Snp 2625250092Snp case FW_PORT_MOD_TYPE_SR: 2626250092Snp ifmedia_add(media, m | IFM_40G_SR4, data, NULL); 2627250092Snp ifmedia_set(media, m | IFM_40G_SR4); 2628250092Snp break; 2629250614Snp 2630250092Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2631250092Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2632250092Snp ifmedia_add(media, m | IFM_40G_CR4, data, NULL); 2633250092Snp ifmedia_set(media, m | IFM_40G_CR4); 2634250092Snp break; 2635250092Snp 2636250614Snp case FW_PORT_MOD_TYPE_NONE: 2637250614Snp m &= ~IFM_FDX; 2638250614Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2639250614Snp ifmedia_set(media, m | IFM_NONE); 2640250614Snp break; 2641250614Snp 2642250092Snp default: 2643250092Snp device_printf(pi->dev, 2644250092Snp "unknown port_type (%d), mod_type (%d)\n", 2645250092Snp pi->port_type, pi->mod_type); 2646250092Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2647250092Snp ifmedia_set(media, m | IFM_UNKNOWN); 2648250092Snp break; 2649250092Snp } 2650250092Snp break; 2651250092Snp 2652218792Snp default: 2653250092Snp device_printf(pi->dev, 2654250092Snp "unknown port_type (%d), mod_type (%d)\n", pi->port_type, 2655250092Snp pi->mod_type); 2656218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2657218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2658218792Snp break; 2659218792Snp } 2660218792Snp 2661218792Snp PORT_UNLOCK(pi); 2662218792Snp} 2663218792Snp 2664231172Snp#define FW_MAC_EXACT_CHUNK 7 2665231172Snp 2666218792Snp/* 2667218792Snp * Program the port's XGMAC based on parameters in ifnet. The caller also 2668218792Snp * indicates which parameters should be programmed (the rest are left alone). 2669218792Snp */ 2670218792Snpstatic int 2671218792Snpupdate_mac_settings(struct port_info *pi, int flags) 2672218792Snp{ 2673218792Snp int rc; 2674218792Snp struct ifnet *ifp = pi->ifp; 2675218792Snp struct adapter *sc = pi->adapter; 2676218792Snp int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1; 2677218792Snp 2678245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2679218792Snp KASSERT(flags, ("%s: not told what to update.", __func__)); 2680218792Snp 2681218792Snp if (flags & XGMAC_MTU) 2682218792Snp mtu = ifp->if_mtu; 2683218792Snp 2684218792Snp if (flags & XGMAC_PROMISC) 2685218792Snp promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0; 2686218792Snp 2687218792Snp if (flags & XGMAC_ALLMULTI) 2688218792Snp allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0; 2689218792Snp 2690218792Snp if (flags & XGMAC_VLANEX) 2691218792Snp vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0; 2692218792Snp 2693218792Snp rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, mtu, promisc, allmulti, 1, 2694218792Snp vlanex, false); 2695218792Snp if (rc) { 2696218792Snp if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, rc); 2697218792Snp return (rc); 2698218792Snp } 2699218792Snp 2700218792Snp if (flags & XGMAC_UCADDR) { 2701218792Snp uint8_t ucaddr[ETHER_ADDR_LEN]; 2702218792Snp 2703218792Snp bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr)); 2704218792Snp rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, 2705218792Snp ucaddr, true, true); 2706218792Snp if (rc < 0) { 2707218792Snp rc = -rc; 2708218792Snp if_printf(ifp, "change_mac failed: %d\n", rc); 2709218792Snp return (rc); 2710218792Snp } else { 2711218792Snp pi->xact_addr_filt = rc; 2712218792Snp rc = 0; 2713218792Snp } 2714218792Snp } 2715218792Snp 2716218792Snp if (flags & XGMAC_MCADDRS) { 2717231172Snp const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK]; 2718218792Snp int del = 1; 2719218792Snp uint64_t hash = 0; 2720218792Snp struct ifmultiaddr *ifma; 2721231172Snp int i = 0, j; 2722218792Snp 2723218792Snp if_maddr_rlock(ifp); 2724218792Snp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2725238054Snp if (ifma->ifma_addr->sa_family != AF_LINK) 2726218792Snp continue; 2727231172Snp mcaddr[i++] = 2728231172Snp LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 2729218792Snp 2730231172Snp if (i == FW_MAC_EXACT_CHUNK) { 2731231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2732231172Snp del, i, mcaddr, NULL, &hash, 0); 2733231172Snp if (rc < 0) { 2734231172Snp rc = -rc; 2735231172Snp for (j = 0; j < i; j++) { 2736231172Snp if_printf(ifp, 2737231172Snp "failed to add mc address" 2738231172Snp " %02x:%02x:%02x:" 2739231172Snp "%02x:%02x:%02x rc=%d\n", 2740231172Snp mcaddr[j][0], mcaddr[j][1], 2741231172Snp mcaddr[j][2], mcaddr[j][3], 2742231172Snp mcaddr[j][4], mcaddr[j][5], 2743231172Snp rc); 2744231172Snp } 2745231172Snp goto mcfail; 2746231172Snp } 2747231172Snp del = 0; 2748231172Snp i = 0; 2749231172Snp } 2750231172Snp } 2751231172Snp if (i > 0) { 2752231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2753231172Snp del, i, mcaddr, NULL, &hash, 0); 2754218792Snp if (rc < 0) { 2755218792Snp rc = -rc; 2756231172Snp for (j = 0; j < i; j++) { 2757231172Snp if_printf(ifp, 2758231172Snp "failed to add mc address" 2759231172Snp " %02x:%02x:%02x:" 2760231172Snp "%02x:%02x:%02x rc=%d\n", 2761231172Snp mcaddr[j][0], mcaddr[j][1], 2762231172Snp mcaddr[j][2], mcaddr[j][3], 2763231172Snp mcaddr[j][4], mcaddr[j][5], 2764231172Snp rc); 2765231172Snp } 2766218792Snp goto mcfail; 2767218792Snp } 2768218792Snp } 2769218792Snp 2770218792Snp rc = -t4_set_addr_hash(sc, sc->mbox, pi->viid, 0, hash, 0); 2771218792Snp if (rc != 0) 2772218792Snp if_printf(ifp, "failed to set mc address hash: %d", rc); 2773218792Snpmcfail: 2774218792Snp if_maddr_runlock(ifp); 2775218792Snp } 2776218792Snp 2777218792Snp return (rc); 2778218792Snp} 2779218792Snp 2780245274Snpint 2781245274Snpbegin_synchronized_op(struct adapter *sc, struct port_info *pi, int flags, 2782245274Snp char *wmesg) 2783218792Snp{ 2784245274Snp int rc, pri; 2785218792Snp 2786245274Snp#ifdef WITNESS 2787245274Snp /* the caller thinks it's ok to sleep, but is it really? */ 2788245274Snp if (flags & SLEEP_OK) 2789245274Snp pause("t4slptst", 1); 2790245274Snp#endif 2791218792Snp 2792245274Snp if (INTR_OK) 2793245274Snp pri = PCATCH; 2794245274Snp else 2795245274Snp pri = 0; 2796245274Snp 2797245274Snp ADAPTER_LOCK(sc); 2798245274Snp for (;;) { 2799245274Snp 2800245274Snp if (pi && IS_DOOMED(pi)) { 2801245274Snp rc = ENXIO; 2802245274Snp goto done; 2803245274Snp } 2804245274Snp 2805245274Snp if (!IS_BUSY(sc)) { 2806245274Snp rc = 0; 2807245274Snp break; 2808245274Snp } 2809245274Snp 2810245274Snp if (!(flags & SLEEP_OK)) { 2811245274Snp rc = EBUSY; 2812245274Snp goto done; 2813245274Snp } 2814245274Snp 2815245274Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, pri, wmesg, 0)) { 2816218792Snp rc = EINTR; 2817218792Snp goto done; 2818218792Snp } 2819218792Snp } 2820245274Snp 2821218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 2822218792Snp SET_BUSY(sc); 2823245274Snp#ifdef INVARIANTS 2824245274Snp sc->last_op = wmesg; 2825245274Snp sc->last_op_thr = curthread; 2826245274Snp#endif 2827218792Snp 2828245274Snpdone: 2829245274Snp if (!(flags & HOLD_LOCK) || rc) 2830245274Snp ADAPTER_UNLOCK(sc); 2831218792Snp 2832245274Snp return (rc); 2833245274Snp} 2834245274Snp 2835245274Snpvoid 2836245274Snpend_synchronized_op(struct adapter *sc, int flags) 2837245274Snp{ 2838245274Snp 2839245274Snp if (flags & LOCK_HELD) 2840245274Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 2841245274Snp else 2842245274Snp ADAPTER_LOCK(sc); 2843245274Snp 2844218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 2845218792Snp CLR_BUSY(sc); 2846245274Snp wakeup(&sc->flags); 2847218792Snp ADAPTER_UNLOCK(sc); 2848218792Snp} 2849218792Snp 2850218792Snpstatic int 2851218792Snpcxgbe_init_synchronized(struct port_info *pi) 2852218792Snp{ 2853218792Snp struct adapter *sc = pi->adapter; 2854218792Snp struct ifnet *ifp = pi->ifp; 2855228561Snp int rc = 0; 2856218792Snp 2857245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2858218792Snp 2859218792Snp if (isset(&sc->open_device_map, pi->port_id)) { 2860218792Snp KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, 2861218792Snp ("mismatch between open_device_map and if_drv_flags")); 2862218792Snp return (0); /* already running */ 2863218792Snp } 2864218792Snp 2865228561Snp if (!(sc->flags & FULL_INIT_DONE) && 2866228561Snp ((rc = adapter_full_init(sc)) != 0)) 2867218792Snp return (rc); /* error message displayed already */ 2868218792Snp 2869228561Snp if (!(pi->flags & PORT_INIT_DONE) && 2870228561Snp ((rc = port_full_init(pi)) != 0)) 2871228561Snp return (rc); /* error message displayed already */ 2872218792Snp 2873218792Snp rc = update_mac_settings(pi, XGMAC_ALL); 2874218792Snp if (rc) 2875218792Snp goto done; /* error message displayed already */ 2876218792Snp 2877218792Snp rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg); 2878218792Snp if (rc != 0) { 2879218792Snp if_printf(ifp, "start_link failed: %d\n", rc); 2880218792Snp goto done; 2881218792Snp } 2882218792Snp 2883218792Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true); 2884218792Snp if (rc != 0) { 2885218792Snp if_printf(ifp, "enable_vi failed: %d\n", rc); 2886218792Snp goto done; 2887218792Snp } 2888218792Snp 2889218792Snp /* all ok */ 2890218792Snp setbit(&sc->open_device_map, pi->port_id); 2891245274Snp PORT_LOCK(pi); 2892218792Snp ifp->if_drv_flags |= IFF_DRV_RUNNING; 2893245274Snp PORT_UNLOCK(pi); 2894218792Snp 2895218792Snp callout_reset(&pi->tick, hz, cxgbe_tick, pi); 2896218792Snpdone: 2897218792Snp if (rc != 0) 2898218792Snp cxgbe_uninit_synchronized(pi); 2899218792Snp 2900218792Snp return (rc); 2901218792Snp} 2902218792Snp 2903218792Snp/* 2904218792Snp * Idempotent. 2905218792Snp */ 2906218792Snpstatic int 2907218792Snpcxgbe_uninit_synchronized(struct port_info *pi) 2908218792Snp{ 2909218792Snp struct adapter *sc = pi->adapter; 2910218792Snp struct ifnet *ifp = pi->ifp; 2911218792Snp int rc; 2912218792Snp 2913245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2914218792Snp 2915218792Snp /* 2916228561Snp * Disable the VI so that all its data in either direction is discarded 2917228561Snp * by the MPS. Leave everything else (the queues, interrupts, and 1Hz 2918228561Snp * tick) intact as the TP can deliver negative advice or data that it's 2919228561Snp * holding in its RAM (for an offloaded connection) even after the VI is 2920228561Snp * disabled. 2921218792Snp */ 2922228561Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false); 2923228561Snp if (rc) { 2924228561Snp if_printf(ifp, "disable_vi failed: %d\n", rc); 2925228561Snp return (rc); 2926228561Snp } 2927228561Snp 2928218792Snp clrbit(&sc->open_device_map, pi->port_id); 2929245274Snp PORT_LOCK(pi); 2930228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2931245274Snp PORT_UNLOCK(pi); 2932218792Snp 2933218792Snp pi->link_cfg.link_ok = 0; 2934218792Snp pi->link_cfg.speed = 0; 2935218792Snp t4_os_link_changed(sc, pi->port_id, 0); 2936218792Snp 2937218792Snp return (0); 2938218792Snp} 2939218792Snp 2940240453Snp/* 2941240453Snp * It is ok for this function to fail midway and return right away. t4_detach 2942240453Snp * will walk the entire sc->irq list and clean up whatever is valid. 2943240453Snp */ 2944218792Snpstatic int 2945240453Snpsetup_intr_handlers(struct adapter *sc) 2946218792Snp{ 2947240453Snp int rc, rid, p, q; 2948222510Snp char s[8]; 2949222510Snp struct irq *irq; 2950228561Snp struct port_info *pi; 2951228561Snp struct sge_rxq *rxq; 2952237263Snp#ifdef TCP_OFFLOAD 2953228561Snp struct sge_ofld_rxq *ofld_rxq; 2954228561Snp#endif 2955218792Snp 2956218792Snp /* 2957218792Snp * Setup interrupts. 2958218792Snp */ 2959222510Snp irq = &sc->irq[0]; 2960222510Snp rid = sc->intr_type == INTR_INTX ? 0 : 1; 2961218792Snp if (sc->intr_count == 1) { 2962228561Snp KASSERT(!(sc->flags & INTR_DIRECT), 2963228561Snp ("%s: single interrupt && INTR_DIRECT?", __func__)); 2964222510Snp 2965240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_all, sc, "all"); 2966240453Snp if (rc != 0) 2967240453Snp return (rc); 2968218792Snp } else { 2969228561Snp /* Multiple interrupts. */ 2970228561Snp KASSERT(sc->intr_count >= T4_EXTRA_INTR + sc->params.nports, 2971228561Snp ("%s: too few intr.", __func__)); 2972228561Snp 2973228561Snp /* The first one is always error intr */ 2974240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_err, sc, "err"); 2975240453Snp if (rc != 0) 2976240453Snp return (rc); 2977222510Snp irq++; 2978222510Snp rid++; 2979218792Snp 2980228561Snp /* The second one is always the firmware event queue */ 2981240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_evt, &sc->sge.fwq, 2982240453Snp "evt"); 2983240453Snp if (rc != 0) 2984240453Snp return (rc); 2985228561Snp irq++; 2986228561Snp rid++; 2987222510Snp 2988228561Snp /* 2989228561Snp * Note that if INTR_DIRECT is not set then either the NIC rx 2990228561Snp * queues or (exclusive or) the TOE rx queueus will be taking 2991228561Snp * direct interrupts. 2992228561Snp * 2993228561Snp * There is no need to check for is_offload(sc) as nofldrxq 2994228561Snp * will be 0 if offload is disabled. 2995228561Snp */ 2996228561Snp for_each_port(sc, p) { 2997228561Snp pi = sc->port[p]; 2998222510Snp 2999237263Snp#ifdef TCP_OFFLOAD 3000228561Snp /* 3001228561Snp * Skip over the NIC queues if they aren't taking direct 3002228561Snp * interrupts. 3003228561Snp */ 3004228561Snp if (!(sc->flags & INTR_DIRECT) && 3005228561Snp pi->nofldrxq > pi->nrxq) 3006228561Snp goto ofld_queues; 3007228561Snp#endif 3008228561Snp rxq = &sc->sge.rxq[pi->first_rxq]; 3009228561Snp for (q = 0; q < pi->nrxq; q++, rxq++) { 3010228561Snp snprintf(s, sizeof(s), "%d.%d", p, q); 3011240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, rxq, 3012240453Snp s); 3013240453Snp if (rc != 0) 3014240453Snp return (rc); 3015222510Snp irq++; 3016222510Snp rid++; 3017218792Snp } 3018218792Snp 3019237263Snp#ifdef TCP_OFFLOAD 3020228561Snp /* 3021228561Snp * Skip over the offload queues if they aren't taking 3022228561Snp * direct interrupts. 3023228561Snp */ 3024228561Snp if (!(sc->flags & INTR_DIRECT)) 3025228561Snp continue; 3026228561Snpofld_queues: 3027228561Snp ofld_rxq = &sc->sge.ofld_rxq[pi->first_ofld_rxq]; 3028228561Snp for (q = 0; q < pi->nofldrxq; q++, ofld_rxq++) { 3029228561Snp snprintf(s, sizeof(s), "%d,%d", p, q); 3030240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, 3031240453Snp ofld_rxq, s); 3032240453Snp if (rc != 0) 3033240453Snp return (rc); 3034228561Snp irq++; 3035228561Snp rid++; 3036218792Snp } 3037228561Snp#endif 3038218792Snp } 3039218792Snp } 3040218792Snp 3041240453Snp return (0); 3042240453Snp} 3043240453Snp 3044240453Snpstatic int 3045240453Snpadapter_full_init(struct adapter *sc) 3046240453Snp{ 3047240453Snp int rc, i; 3048240453Snp 3049240453Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 3050240453Snp KASSERT((sc->flags & FULL_INIT_DONE) == 0, 3051240453Snp ("%s: FULL_INIT_DONE already", __func__)); 3052240453Snp 3053240453Snp /* 3054240453Snp * queues that belong to the adapter (not any particular port). 3055240453Snp */ 3056240453Snp rc = t4_setup_adapter_queues(sc); 3057240453Snp if (rc != 0) 3058240453Snp goto done; 3059240453Snp 3060240453Snp for (i = 0; i < nitems(sc->tq); i++) { 3061240453Snp sc->tq[i] = taskqueue_create("t4 taskq", M_NOWAIT, 3062240453Snp taskqueue_thread_enqueue, &sc->tq[i]); 3063240453Snp if (sc->tq[i] == NULL) { 3064240453Snp device_printf(sc->dev, 3065240453Snp "failed to allocate task queue %d\n", i); 3066240453Snp rc = ENOMEM; 3067240453Snp goto done; 3068240453Snp } 3069240453Snp taskqueue_start_threads(&sc->tq[i], 1, PI_NET, "%s tq%d", 3070240453Snp device_get_nameunit(sc->dev), i); 3071240453Snp } 3072240453Snp 3073218792Snp t4_intr_enable(sc); 3074218792Snp sc->flags |= FULL_INIT_DONE; 3075218792Snpdone: 3076218792Snp if (rc != 0) 3077228561Snp adapter_full_uninit(sc); 3078218792Snp 3079218792Snp return (rc); 3080218792Snp} 3081218792Snp 3082218792Snpstatic int 3083228561Snpadapter_full_uninit(struct adapter *sc) 3084218792Snp{ 3085218792Snp int i; 3086218792Snp 3087218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 3088218792Snp 3089220873Snp t4_teardown_adapter_queues(sc); 3090218792Snp 3091240452Snp for (i = 0; i < nitems(sc->tq) && sc->tq[i]; i++) { 3092228561Snp taskqueue_free(sc->tq[i]); 3093228561Snp sc->tq[i] = NULL; 3094228561Snp } 3095228561Snp 3096218792Snp sc->flags &= ~FULL_INIT_DONE; 3097218792Snp 3098218792Snp return (0); 3099218792Snp} 3100218792Snp 3101218792Snpstatic int 3102228561Snpport_full_init(struct port_info *pi) 3103228561Snp{ 3104228561Snp struct adapter *sc = pi->adapter; 3105228561Snp struct ifnet *ifp = pi->ifp; 3106228561Snp uint16_t *rss; 3107228561Snp struct sge_rxq *rxq; 3108228561Snp int rc, i; 3109228561Snp 3110245274Snp ASSERT_SYNCHRONIZED_OP(sc); 3111228561Snp KASSERT((pi->flags & PORT_INIT_DONE) == 0, 3112228561Snp ("%s: PORT_INIT_DONE already", __func__)); 3113228561Snp 3114228561Snp sysctl_ctx_init(&pi->ctx); 3115228561Snp pi->flags |= PORT_SYSCTL_CTX; 3116228561Snp 3117228561Snp /* 3118228561Snp * Allocate tx/rx/fl queues for this port. 3119228561Snp */ 3120228561Snp rc = t4_setup_port_queues(pi); 3121228561Snp if (rc != 0) 3122228561Snp goto done; /* error message displayed already */ 3123228561Snp 3124228561Snp /* 3125228561Snp * Setup RSS for this port. 3126228561Snp */ 3127228561Snp rss = malloc(pi->nrxq * sizeof (*rss), M_CXGBE, 3128228561Snp M_ZERO | M_WAITOK); 3129228561Snp for_each_rxq(pi, i, rxq) { 3130228561Snp rss[i] = rxq->iq.abs_id; 3131228561Snp } 3132228561Snp rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, 3133228561Snp pi->rss_size, rss, pi->nrxq); 3134228561Snp free(rss, M_CXGBE); 3135228561Snp if (rc != 0) { 3136228561Snp if_printf(ifp, "rss_config failed: %d\n", rc); 3137228561Snp goto done; 3138228561Snp } 3139228561Snp 3140228561Snp pi->flags |= PORT_INIT_DONE; 3141228561Snpdone: 3142228561Snp if (rc != 0) 3143228561Snp port_full_uninit(pi); 3144228561Snp 3145228561Snp return (rc); 3146228561Snp} 3147228561Snp 3148228561Snp/* 3149228561Snp * Idempotent. 3150228561Snp */ 3151228561Snpstatic int 3152228561Snpport_full_uninit(struct port_info *pi) 3153228561Snp{ 3154228561Snp struct adapter *sc = pi->adapter; 3155228561Snp int i; 3156228561Snp struct sge_rxq *rxq; 3157228561Snp struct sge_txq *txq; 3158237263Snp#ifdef TCP_OFFLOAD 3159228561Snp struct sge_ofld_rxq *ofld_rxq; 3160228561Snp struct sge_wrq *ofld_txq; 3161228561Snp#endif 3162228561Snp 3163228561Snp if (pi->flags & PORT_INIT_DONE) { 3164228561Snp 3165228561Snp /* Need to quiesce queues. XXX: ctrl queues? */ 3166228561Snp 3167228561Snp for_each_txq(pi, i, txq) { 3168228561Snp quiesce_eq(sc, &txq->eq); 3169228561Snp } 3170228561Snp 3171237263Snp#ifdef TCP_OFFLOAD 3172228561Snp for_each_ofld_txq(pi, i, ofld_txq) { 3173228561Snp quiesce_eq(sc, &ofld_txq->eq); 3174228561Snp } 3175228561Snp#endif 3176228561Snp 3177228561Snp for_each_rxq(pi, i, rxq) { 3178228561Snp quiesce_iq(sc, &rxq->iq); 3179228561Snp quiesce_fl(sc, &rxq->fl); 3180228561Snp } 3181228561Snp 3182237263Snp#ifdef TCP_OFFLOAD 3183228561Snp for_each_ofld_rxq(pi, i, ofld_rxq) { 3184228561Snp quiesce_iq(sc, &ofld_rxq->iq); 3185228561Snp quiesce_fl(sc, &ofld_rxq->fl); 3186228561Snp } 3187228561Snp#endif 3188228561Snp } 3189228561Snp 3190228561Snp t4_teardown_port_queues(pi); 3191228561Snp pi->flags &= ~PORT_INIT_DONE; 3192228561Snp 3193228561Snp return (0); 3194228561Snp} 3195228561Snp 3196228561Snpstatic void 3197228561Snpquiesce_eq(struct adapter *sc, struct sge_eq *eq) 3198228561Snp{ 3199228561Snp EQ_LOCK(eq); 3200228561Snp eq->flags |= EQ_DOOMED; 3201228561Snp 3202228561Snp /* 3203228561Snp * Wait for the response to a credit flush if one's 3204228561Snp * pending. 3205228561Snp */ 3206228561Snp while (eq->flags & EQ_CRFLUSHED) 3207228561Snp mtx_sleep(eq, &eq->eq_lock, 0, "crflush", 0); 3208228561Snp EQ_UNLOCK(eq); 3209228561Snp 3210228561Snp callout_drain(&eq->tx_callout); /* XXX: iffy */ 3211228561Snp pause("callout", 10); /* Still iffy */ 3212228561Snp 3213228561Snp taskqueue_drain(sc->tq[eq->tx_chan], &eq->tx_task); 3214228561Snp} 3215228561Snp 3216228561Snpstatic void 3217228561Snpquiesce_iq(struct adapter *sc, struct sge_iq *iq) 3218228561Snp{ 3219228561Snp (void) sc; /* unused */ 3220228561Snp 3221228561Snp /* Synchronize with the interrupt handler */ 3222228561Snp while (!atomic_cmpset_int(&iq->state, IQS_IDLE, IQS_DISABLED)) 3223228561Snp pause("iqfree", 1); 3224228561Snp} 3225228561Snp 3226228561Snpstatic void 3227228561Snpquiesce_fl(struct adapter *sc, struct sge_fl *fl) 3228228561Snp{ 3229228561Snp mtx_lock(&sc->sfl_lock); 3230228561Snp FL_LOCK(fl); 3231228561Snp fl->flags |= FL_DOOMED; 3232228561Snp FL_UNLOCK(fl); 3233228561Snp mtx_unlock(&sc->sfl_lock); 3234228561Snp 3235228561Snp callout_drain(&sc->sfl_callout); 3236228561Snp KASSERT((fl->flags & FL_STARVING) == 0, 3237228561Snp ("%s: still starving", __func__)); 3238228561Snp} 3239228561Snp 3240228561Snpstatic int 3241218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid, 3242228561Snp driver_intr_t *handler, void *arg, char *name) 3243218792Snp{ 3244218792Snp int rc; 3245218792Snp 3246218792Snp irq->rid = rid; 3247218792Snp irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid, 3248218792Snp RF_SHAREABLE | RF_ACTIVE); 3249218792Snp if (irq->res == NULL) { 3250218792Snp device_printf(sc->dev, 3251218792Snp "failed to allocate IRQ for rid %d, name %s.\n", rid, name); 3252218792Snp return (ENOMEM); 3253218792Snp } 3254218792Snp 3255218792Snp rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET, 3256218792Snp NULL, handler, arg, &irq->tag); 3257218792Snp if (rc != 0) { 3258218792Snp device_printf(sc->dev, 3259218792Snp "failed to setup interrupt for rid %d, name %s: %d\n", 3260218792Snp rid, name, rc); 3261218792Snp } else if (name) 3262218792Snp bus_describe_intr(sc->dev, irq->res, irq->tag, name); 3263218792Snp 3264218792Snp return (rc); 3265218792Snp} 3266218792Snp 3267218792Snpstatic int 3268218792Snpt4_free_irq(struct adapter *sc, struct irq *irq) 3269218792Snp{ 3270218792Snp if (irq->tag) 3271218792Snp bus_teardown_intr(sc->dev, irq->res, irq->tag); 3272218792Snp if (irq->res) 3273218792Snp bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res); 3274218792Snp 3275218792Snp bzero(irq, sizeof(*irq)); 3276218792Snp 3277218792Snp return (0); 3278218792Snp} 3279218792Snp 3280218792Snpstatic void 3281218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start, 3282218792Snp unsigned int end) 3283218792Snp{ 3284218792Snp uint32_t *p = (uint32_t *)(buf + start); 3285218792Snp 3286218792Snp for ( ; start <= end; start += sizeof(uint32_t)) 3287218792Snp *p++ = t4_read_reg(sc, start); 3288218792Snp} 3289218792Snp 3290218792Snpstatic void 3291218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf) 3292218792Snp{ 3293248925Snp int i, n; 3294248925Snp const unsigned int *reg_ranges; 3295248925Snp static const unsigned int t4_reg_ranges[] = { 3296218792Snp 0x1008, 0x1108, 3297218792Snp 0x1180, 0x11b4, 3298218792Snp 0x11fc, 0x123c, 3299218792Snp 0x1300, 0x173c, 3300218792Snp 0x1800, 0x18fc, 3301218792Snp 0x3000, 0x30d8, 3302218792Snp 0x30e0, 0x5924, 3303218792Snp 0x5960, 0x59d4, 3304218792Snp 0x5a00, 0x5af8, 3305218792Snp 0x6000, 0x6098, 3306218792Snp 0x6100, 0x6150, 3307218792Snp 0x6200, 0x6208, 3308218792Snp 0x6240, 0x6248, 3309218792Snp 0x6280, 0x6338, 3310218792Snp 0x6370, 0x638c, 3311218792Snp 0x6400, 0x643c, 3312218792Snp 0x6500, 0x6524, 3313218792Snp 0x6a00, 0x6a38, 3314218792Snp 0x6a60, 0x6a78, 3315218792Snp 0x6b00, 0x6b84, 3316218792Snp 0x6bf0, 0x6c84, 3317218792Snp 0x6cf0, 0x6d84, 3318218792Snp 0x6df0, 0x6e84, 3319218792Snp 0x6ef0, 0x6f84, 3320218792Snp 0x6ff0, 0x7084, 3321218792Snp 0x70f0, 0x7184, 3322218792Snp 0x71f0, 0x7284, 3323218792Snp 0x72f0, 0x7384, 3324218792Snp 0x73f0, 0x7450, 3325218792Snp 0x7500, 0x7530, 3326218792Snp 0x7600, 0x761c, 3327218792Snp 0x7680, 0x76cc, 3328218792Snp 0x7700, 0x7798, 3329218792Snp 0x77c0, 0x77fc, 3330218792Snp 0x7900, 0x79fc, 3331218792Snp 0x7b00, 0x7c38, 3332218792Snp 0x7d00, 0x7efc, 3333218792Snp 0x8dc0, 0x8e1c, 3334218792Snp 0x8e30, 0x8e78, 3335218792Snp 0x8ea0, 0x8f6c, 3336218792Snp 0x8fc0, 0x9074, 3337218792Snp 0x90fc, 0x90fc, 3338218792Snp 0x9400, 0x9458, 3339218792Snp 0x9600, 0x96bc, 3340218792Snp 0x9800, 0x9808, 3341218792Snp 0x9820, 0x983c, 3342218792Snp 0x9850, 0x9864, 3343218792Snp 0x9c00, 0x9c6c, 3344218792Snp 0x9c80, 0x9cec, 3345218792Snp 0x9d00, 0x9d6c, 3346218792Snp 0x9d80, 0x9dec, 3347218792Snp 0x9e00, 0x9e6c, 3348218792Snp 0x9e80, 0x9eec, 3349218792Snp 0x9f00, 0x9f6c, 3350218792Snp 0x9f80, 0x9fec, 3351218792Snp 0xd004, 0xd03c, 3352218792Snp 0xdfc0, 0xdfe0, 3353218792Snp 0xe000, 0xea7c, 3354218792Snp 0xf000, 0x11190, 3355237439Snp 0x19040, 0x1906c, 3356237439Snp 0x19078, 0x19080, 3357237439Snp 0x1908c, 0x19124, 3358218792Snp 0x19150, 0x191b0, 3359218792Snp 0x191d0, 0x191e8, 3360218792Snp 0x19238, 0x1924c, 3361218792Snp 0x193f8, 0x19474, 3362218792Snp 0x19490, 0x194f8, 3363218792Snp 0x19800, 0x19f30, 3364218792Snp 0x1a000, 0x1a06c, 3365218792Snp 0x1a0b0, 0x1a120, 3366218792Snp 0x1a128, 0x1a138, 3367218792Snp 0x1a190, 0x1a1c4, 3368218792Snp 0x1a1fc, 0x1a1fc, 3369218792Snp 0x1e040, 0x1e04c, 3370237439Snp 0x1e284, 0x1e28c, 3371218792Snp 0x1e2c0, 0x1e2c0, 3372218792Snp 0x1e2e0, 0x1e2e0, 3373218792Snp 0x1e300, 0x1e384, 3374218792Snp 0x1e3c0, 0x1e3c8, 3375218792Snp 0x1e440, 0x1e44c, 3376237439Snp 0x1e684, 0x1e68c, 3377218792Snp 0x1e6c0, 0x1e6c0, 3378218792Snp 0x1e6e0, 0x1e6e0, 3379218792Snp 0x1e700, 0x1e784, 3380218792Snp 0x1e7c0, 0x1e7c8, 3381218792Snp 0x1e840, 0x1e84c, 3382237439Snp 0x1ea84, 0x1ea8c, 3383218792Snp 0x1eac0, 0x1eac0, 3384218792Snp 0x1eae0, 0x1eae0, 3385218792Snp 0x1eb00, 0x1eb84, 3386218792Snp 0x1ebc0, 0x1ebc8, 3387218792Snp 0x1ec40, 0x1ec4c, 3388237439Snp 0x1ee84, 0x1ee8c, 3389218792Snp 0x1eec0, 0x1eec0, 3390218792Snp 0x1eee0, 0x1eee0, 3391218792Snp 0x1ef00, 0x1ef84, 3392218792Snp 0x1efc0, 0x1efc8, 3393218792Snp 0x1f040, 0x1f04c, 3394237439Snp 0x1f284, 0x1f28c, 3395218792Snp 0x1f2c0, 0x1f2c0, 3396218792Snp 0x1f2e0, 0x1f2e0, 3397218792Snp 0x1f300, 0x1f384, 3398218792Snp 0x1f3c0, 0x1f3c8, 3399218792Snp 0x1f440, 0x1f44c, 3400237439Snp 0x1f684, 0x1f68c, 3401218792Snp 0x1f6c0, 0x1f6c0, 3402218792Snp 0x1f6e0, 0x1f6e0, 3403218792Snp 0x1f700, 0x1f784, 3404218792Snp 0x1f7c0, 0x1f7c8, 3405218792Snp 0x1f840, 0x1f84c, 3406237439Snp 0x1fa84, 0x1fa8c, 3407218792Snp 0x1fac0, 0x1fac0, 3408218792Snp 0x1fae0, 0x1fae0, 3409218792Snp 0x1fb00, 0x1fb84, 3410218792Snp 0x1fbc0, 0x1fbc8, 3411218792Snp 0x1fc40, 0x1fc4c, 3412237439Snp 0x1fe84, 0x1fe8c, 3413218792Snp 0x1fec0, 0x1fec0, 3414218792Snp 0x1fee0, 0x1fee0, 3415218792Snp 0x1ff00, 0x1ff84, 3416218792Snp 0x1ffc0, 0x1ffc8, 3417218792Snp 0x20000, 0x2002c, 3418218792Snp 0x20100, 0x2013c, 3419218792Snp 0x20190, 0x201c8, 3420218792Snp 0x20200, 0x20318, 3421218792Snp 0x20400, 0x20528, 3422218792Snp 0x20540, 0x20614, 3423218792Snp 0x21000, 0x21040, 3424218792Snp 0x2104c, 0x21060, 3425218792Snp 0x210c0, 0x210ec, 3426218792Snp 0x21200, 0x21268, 3427218792Snp 0x21270, 0x21284, 3428218792Snp 0x212fc, 0x21388, 3429218792Snp 0x21400, 0x21404, 3430218792Snp 0x21500, 0x21518, 3431218792Snp 0x2152c, 0x2153c, 3432218792Snp 0x21550, 0x21554, 3433218792Snp 0x21600, 0x21600, 3434218792Snp 0x21608, 0x21628, 3435218792Snp 0x21630, 0x2163c, 3436218792Snp 0x21700, 0x2171c, 3437218792Snp 0x21780, 0x2178c, 3438218792Snp 0x21800, 0x21c38, 3439218792Snp 0x21c80, 0x21d7c, 3440218792Snp 0x21e00, 0x21e04, 3441218792Snp 0x22000, 0x2202c, 3442218792Snp 0x22100, 0x2213c, 3443218792Snp 0x22190, 0x221c8, 3444218792Snp 0x22200, 0x22318, 3445218792Snp 0x22400, 0x22528, 3446218792Snp 0x22540, 0x22614, 3447218792Snp 0x23000, 0x23040, 3448218792Snp 0x2304c, 0x23060, 3449218792Snp 0x230c0, 0x230ec, 3450218792Snp 0x23200, 0x23268, 3451218792Snp 0x23270, 0x23284, 3452218792Snp 0x232fc, 0x23388, 3453218792Snp 0x23400, 0x23404, 3454218792Snp 0x23500, 0x23518, 3455218792Snp 0x2352c, 0x2353c, 3456218792Snp 0x23550, 0x23554, 3457218792Snp 0x23600, 0x23600, 3458218792Snp 0x23608, 0x23628, 3459218792Snp 0x23630, 0x2363c, 3460218792Snp 0x23700, 0x2371c, 3461218792Snp 0x23780, 0x2378c, 3462218792Snp 0x23800, 0x23c38, 3463218792Snp 0x23c80, 0x23d7c, 3464218792Snp 0x23e00, 0x23e04, 3465218792Snp 0x24000, 0x2402c, 3466218792Snp 0x24100, 0x2413c, 3467218792Snp 0x24190, 0x241c8, 3468218792Snp 0x24200, 0x24318, 3469218792Snp 0x24400, 0x24528, 3470218792Snp 0x24540, 0x24614, 3471218792Snp 0x25000, 0x25040, 3472218792Snp 0x2504c, 0x25060, 3473218792Snp 0x250c0, 0x250ec, 3474218792Snp 0x25200, 0x25268, 3475218792Snp 0x25270, 0x25284, 3476218792Snp 0x252fc, 0x25388, 3477218792Snp 0x25400, 0x25404, 3478218792Snp 0x25500, 0x25518, 3479218792Snp 0x2552c, 0x2553c, 3480218792Snp 0x25550, 0x25554, 3481218792Snp 0x25600, 0x25600, 3482218792Snp 0x25608, 0x25628, 3483218792Snp 0x25630, 0x2563c, 3484218792Snp 0x25700, 0x2571c, 3485218792Snp 0x25780, 0x2578c, 3486218792Snp 0x25800, 0x25c38, 3487218792Snp 0x25c80, 0x25d7c, 3488218792Snp 0x25e00, 0x25e04, 3489218792Snp 0x26000, 0x2602c, 3490218792Snp 0x26100, 0x2613c, 3491218792Snp 0x26190, 0x261c8, 3492218792Snp 0x26200, 0x26318, 3493218792Snp 0x26400, 0x26528, 3494218792Snp 0x26540, 0x26614, 3495218792Snp 0x27000, 0x27040, 3496218792Snp 0x2704c, 0x27060, 3497218792Snp 0x270c0, 0x270ec, 3498218792Snp 0x27200, 0x27268, 3499218792Snp 0x27270, 0x27284, 3500218792Snp 0x272fc, 0x27388, 3501218792Snp 0x27400, 0x27404, 3502218792Snp 0x27500, 0x27518, 3503218792Snp 0x2752c, 0x2753c, 3504218792Snp 0x27550, 0x27554, 3505218792Snp 0x27600, 0x27600, 3506218792Snp 0x27608, 0x27628, 3507218792Snp 0x27630, 0x2763c, 3508218792Snp 0x27700, 0x2771c, 3509218792Snp 0x27780, 0x2778c, 3510218792Snp 0x27800, 0x27c38, 3511218792Snp 0x27c80, 0x27d7c, 3512218792Snp 0x27e00, 0x27e04 3513218792Snp }; 3514248925Snp static const unsigned int t5_reg_ranges[] = { 3515248925Snp 0x1008, 0x1148, 3516248925Snp 0x1180, 0x11b4, 3517248925Snp 0x11fc, 0x123c, 3518248925Snp 0x1280, 0x173c, 3519248925Snp 0x1800, 0x18fc, 3520248925Snp 0x3000, 0x3028, 3521248925Snp 0x3060, 0x30d8, 3522248925Snp 0x30e0, 0x30fc, 3523248925Snp 0x3140, 0x357c, 3524248925Snp 0x35a8, 0x35cc, 3525248925Snp 0x35ec, 0x35ec, 3526248925Snp 0x3600, 0x5624, 3527248925Snp 0x56cc, 0x575c, 3528248925Snp 0x580c, 0x5814, 3529248925Snp 0x5890, 0x58bc, 3530248925Snp 0x5940, 0x59dc, 3531248925Snp 0x59fc, 0x5a18, 3532248925Snp 0x5a60, 0x5a9c, 3533248925Snp 0x5b94, 0x5bfc, 3534248925Snp 0x6000, 0x6040, 3535248925Snp 0x6058, 0x614c, 3536248925Snp 0x7700, 0x7798, 3537248925Snp 0x77c0, 0x78fc, 3538248925Snp 0x7b00, 0x7c54, 3539248925Snp 0x7d00, 0x7efc, 3540248925Snp 0x8dc0, 0x8de0, 3541248925Snp 0x8df8, 0x8e84, 3542248925Snp 0x8ea0, 0x8f84, 3543248925Snp 0x8fc0, 0x90f8, 3544248925Snp 0x9400, 0x9470, 3545248925Snp 0x9600, 0x96f4, 3546248925Snp 0x9800, 0x9808, 3547248925Snp 0x9820, 0x983c, 3548248925Snp 0x9850, 0x9864, 3549248925Snp 0x9c00, 0x9c6c, 3550248925Snp 0x9c80, 0x9cec, 3551248925Snp 0x9d00, 0x9d6c, 3552248925Snp 0x9d80, 0x9dec, 3553248925Snp 0x9e00, 0x9e6c, 3554248925Snp 0x9e80, 0x9eec, 3555248925Snp 0x9f00, 0x9f6c, 3556248925Snp 0x9f80, 0xa020, 3557248925Snp 0xd004, 0xd03c, 3558248925Snp 0xdfc0, 0xdfe0, 3559248925Snp 0xe000, 0x11088, 3560248925Snp 0x1109c, 0x1117c, 3561248925Snp 0x11190, 0x11204, 3562248925Snp 0x19040, 0x1906c, 3563248925Snp 0x19078, 0x19080, 3564248925Snp 0x1908c, 0x19124, 3565248925Snp 0x19150, 0x191b0, 3566248925Snp 0x191d0, 0x191e8, 3567248925Snp 0x19238, 0x19290, 3568248925Snp 0x193f8, 0x19474, 3569248925Snp 0x19490, 0x194cc, 3570248925Snp 0x194f0, 0x194f8, 3571248925Snp 0x19c00, 0x19c60, 3572248925Snp 0x19c94, 0x19e10, 3573248925Snp 0x19e50, 0x19f34, 3574248925Snp 0x19f40, 0x19f50, 3575248925Snp 0x19f90, 0x19fe4, 3576248925Snp 0x1a000, 0x1a06c, 3577248925Snp 0x1a0b0, 0x1a120, 3578248925Snp 0x1a128, 0x1a138, 3579248925Snp 0x1a190, 0x1a1c4, 3580248925Snp 0x1a1fc, 0x1a1fc, 3581248925Snp 0x1e008, 0x1e00c, 3582248925Snp 0x1e040, 0x1e04c, 3583248925Snp 0x1e284, 0x1e290, 3584248925Snp 0x1e2c0, 0x1e2c0, 3585248925Snp 0x1e2e0, 0x1e2e0, 3586248925Snp 0x1e300, 0x1e384, 3587248925Snp 0x1e3c0, 0x1e3c8, 3588248925Snp 0x1e408, 0x1e40c, 3589248925Snp 0x1e440, 0x1e44c, 3590248925Snp 0x1e684, 0x1e690, 3591248925Snp 0x1e6c0, 0x1e6c0, 3592248925Snp 0x1e6e0, 0x1e6e0, 3593248925Snp 0x1e700, 0x1e784, 3594248925Snp 0x1e7c0, 0x1e7c8, 3595248925Snp 0x1e808, 0x1e80c, 3596248925Snp 0x1e840, 0x1e84c, 3597248925Snp 0x1ea84, 0x1ea90, 3598248925Snp 0x1eac0, 0x1eac0, 3599248925Snp 0x1eae0, 0x1eae0, 3600248925Snp 0x1eb00, 0x1eb84, 3601248925Snp 0x1ebc0, 0x1ebc8, 3602248925Snp 0x1ec08, 0x1ec0c, 3603248925Snp 0x1ec40, 0x1ec4c, 3604248925Snp 0x1ee84, 0x1ee90, 3605248925Snp 0x1eec0, 0x1eec0, 3606248925Snp 0x1eee0, 0x1eee0, 3607248925Snp 0x1ef00, 0x1ef84, 3608248925Snp 0x1efc0, 0x1efc8, 3609248925Snp 0x1f008, 0x1f00c, 3610248925Snp 0x1f040, 0x1f04c, 3611248925Snp 0x1f284, 0x1f290, 3612248925Snp 0x1f2c0, 0x1f2c0, 3613248925Snp 0x1f2e0, 0x1f2e0, 3614248925Snp 0x1f300, 0x1f384, 3615248925Snp 0x1f3c0, 0x1f3c8, 3616248925Snp 0x1f408, 0x1f40c, 3617248925Snp 0x1f440, 0x1f44c, 3618248925Snp 0x1f684, 0x1f690, 3619248925Snp 0x1f6c0, 0x1f6c0, 3620248925Snp 0x1f6e0, 0x1f6e0, 3621248925Snp 0x1f700, 0x1f784, 3622248925Snp 0x1f7c0, 0x1f7c8, 3623248925Snp 0x1f808, 0x1f80c, 3624248925Snp 0x1f840, 0x1f84c, 3625248925Snp 0x1fa84, 0x1fa90, 3626248925Snp 0x1fac0, 0x1fac0, 3627248925Snp 0x1fae0, 0x1fae0, 3628248925Snp 0x1fb00, 0x1fb84, 3629248925Snp 0x1fbc0, 0x1fbc8, 3630248925Snp 0x1fc08, 0x1fc0c, 3631248925Snp 0x1fc40, 0x1fc4c, 3632248925Snp 0x1fe84, 0x1fe90, 3633248925Snp 0x1fec0, 0x1fec0, 3634248925Snp 0x1fee0, 0x1fee0, 3635248925Snp 0x1ff00, 0x1ff84, 3636248925Snp 0x1ffc0, 0x1ffc8, 3637252312Snp 0x30000, 0x30030, 3638248925Snp 0x30100, 0x30144, 3639248925Snp 0x30190, 0x301d0, 3640248925Snp 0x30200, 0x30318, 3641248925Snp 0x30400, 0x3052c, 3642248925Snp 0x30540, 0x3061c, 3643248925Snp 0x30800, 0x30834, 3644248925Snp 0x308c0, 0x30908, 3645248925Snp 0x30910, 0x309ac, 3646252312Snp 0x30a00, 0x30a2c, 3647248925Snp 0x30a44, 0x30a50, 3648248925Snp 0x30a74, 0x30c24, 3649252312Snp 0x30d00, 0x30d00, 3650248925Snp 0x30d08, 0x30d14, 3651248925Snp 0x30d1c, 0x30d20, 3652248925Snp 0x30d3c, 0x30d50, 3653248925Snp 0x31200, 0x3120c, 3654248925Snp 0x31220, 0x31220, 3655248925Snp 0x31240, 0x31240, 3656252312Snp 0x31600, 0x3160c, 3657248925Snp 0x31a00, 0x31a1c, 3658252312Snp 0x31e00, 0x31e20, 3659248925Snp 0x31e38, 0x31e3c, 3660248925Snp 0x31e80, 0x31e80, 3661248925Snp 0x31e88, 0x31ea8, 3662248925Snp 0x31eb0, 0x31eb4, 3663248925Snp 0x31ec8, 0x31ed4, 3664248925Snp 0x31fb8, 0x32004, 3665252312Snp 0x32200, 0x32200, 3666252312Snp 0x32208, 0x32240, 3667252312Snp 0x32248, 0x32280, 3668252312Snp 0x32288, 0x322c0, 3669248925Snp 0x322c8, 0x322fc, 3670248925Snp 0x32600, 0x32630, 3671248925Snp 0x32a00, 0x32abc, 3672248925Snp 0x32b00, 0x32b70, 3673248925Snp 0x33000, 0x33048, 3674248925Snp 0x33060, 0x3309c, 3675248925Snp 0x330f0, 0x33148, 3676248925Snp 0x33160, 0x3319c, 3677248925Snp 0x331f0, 0x332e4, 3678248925Snp 0x332f8, 0x333e4, 3679248925Snp 0x333f8, 0x33448, 3680248925Snp 0x33460, 0x3349c, 3681248925Snp 0x334f0, 0x33548, 3682248925Snp 0x33560, 0x3359c, 3683248925Snp 0x335f0, 0x336e4, 3684248925Snp 0x336f8, 0x337e4, 3685248925Snp 0x337f8, 0x337fc, 3686248925Snp 0x33814, 0x33814, 3687248925Snp 0x3382c, 0x3382c, 3688248925Snp 0x33880, 0x3388c, 3689248925Snp 0x338e8, 0x338ec, 3690248925Snp 0x33900, 0x33948, 3691248925Snp 0x33960, 0x3399c, 3692248925Snp 0x339f0, 0x33ae4, 3693248925Snp 0x33af8, 0x33b10, 3694248925Snp 0x33b28, 0x33b28, 3695248925Snp 0x33b3c, 0x33b50, 3696248925Snp 0x33bf0, 0x33c10, 3697248925Snp 0x33c28, 0x33c28, 3698248925Snp 0x33c3c, 0x33c50, 3699248925Snp 0x33cf0, 0x33cfc, 3700252312Snp 0x34000, 0x34030, 3701248925Snp 0x34100, 0x34144, 3702248925Snp 0x34190, 0x341d0, 3703248925Snp 0x34200, 0x34318, 3704248925Snp 0x34400, 0x3452c, 3705248925Snp 0x34540, 0x3461c, 3706248925Snp 0x34800, 0x34834, 3707248925Snp 0x348c0, 0x34908, 3708248925Snp 0x34910, 0x349ac, 3709252312Snp 0x34a00, 0x34a2c, 3710248925Snp 0x34a44, 0x34a50, 3711248925Snp 0x34a74, 0x34c24, 3712252312Snp 0x34d00, 0x34d00, 3713248925Snp 0x34d08, 0x34d14, 3714248925Snp 0x34d1c, 0x34d20, 3715248925Snp 0x34d3c, 0x34d50, 3716248925Snp 0x35200, 0x3520c, 3717248925Snp 0x35220, 0x35220, 3718248925Snp 0x35240, 0x35240, 3719252312Snp 0x35600, 0x3560c, 3720248925Snp 0x35a00, 0x35a1c, 3721252312Snp 0x35e00, 0x35e20, 3722248925Snp 0x35e38, 0x35e3c, 3723248925Snp 0x35e80, 0x35e80, 3724248925Snp 0x35e88, 0x35ea8, 3725248925Snp 0x35eb0, 0x35eb4, 3726248925Snp 0x35ec8, 0x35ed4, 3727248925Snp 0x35fb8, 0x36004, 3728252312Snp 0x36200, 0x36200, 3729252312Snp 0x36208, 0x36240, 3730252312Snp 0x36248, 0x36280, 3731252312Snp 0x36288, 0x362c0, 3732248925Snp 0x362c8, 0x362fc, 3733248925Snp 0x36600, 0x36630, 3734248925Snp 0x36a00, 0x36abc, 3735248925Snp 0x36b00, 0x36b70, 3736248925Snp 0x37000, 0x37048, 3737248925Snp 0x37060, 0x3709c, 3738248925Snp 0x370f0, 0x37148, 3739248925Snp 0x37160, 0x3719c, 3740248925Snp 0x371f0, 0x372e4, 3741248925Snp 0x372f8, 0x373e4, 3742248925Snp 0x373f8, 0x37448, 3743248925Snp 0x37460, 0x3749c, 3744248925Snp 0x374f0, 0x37548, 3745248925Snp 0x37560, 0x3759c, 3746248925Snp 0x375f0, 0x376e4, 3747248925Snp 0x376f8, 0x377e4, 3748248925Snp 0x377f8, 0x377fc, 3749248925Snp 0x37814, 0x37814, 3750248925Snp 0x3782c, 0x3782c, 3751248925Snp 0x37880, 0x3788c, 3752248925Snp 0x378e8, 0x378ec, 3753248925Snp 0x37900, 0x37948, 3754248925Snp 0x37960, 0x3799c, 3755248925Snp 0x379f0, 0x37ae4, 3756248925Snp 0x37af8, 0x37b10, 3757248925Snp 0x37b28, 0x37b28, 3758248925Snp 0x37b3c, 0x37b50, 3759248925Snp 0x37bf0, 0x37c10, 3760248925Snp 0x37c28, 0x37c28, 3761248925Snp 0x37c3c, 0x37c50, 3762248925Snp 0x37cf0, 0x37cfc, 3763252312Snp 0x38000, 0x38030, 3764248925Snp 0x38100, 0x38144, 3765248925Snp 0x38190, 0x381d0, 3766248925Snp 0x38200, 0x38318, 3767248925Snp 0x38400, 0x3852c, 3768248925Snp 0x38540, 0x3861c, 3769248925Snp 0x38800, 0x38834, 3770248925Snp 0x388c0, 0x38908, 3771248925Snp 0x38910, 0x389ac, 3772252312Snp 0x38a00, 0x38a2c, 3773248925Snp 0x38a44, 0x38a50, 3774248925Snp 0x38a74, 0x38c24, 3775252312Snp 0x38d00, 0x38d00, 3776248925Snp 0x38d08, 0x38d14, 3777248925Snp 0x38d1c, 0x38d20, 3778248925Snp 0x38d3c, 0x38d50, 3779248925Snp 0x39200, 0x3920c, 3780248925Snp 0x39220, 0x39220, 3781248925Snp 0x39240, 0x39240, 3782252312Snp 0x39600, 0x3960c, 3783248925Snp 0x39a00, 0x39a1c, 3784252312Snp 0x39e00, 0x39e20, 3785248925Snp 0x39e38, 0x39e3c, 3786248925Snp 0x39e80, 0x39e80, 3787248925Snp 0x39e88, 0x39ea8, 3788248925Snp 0x39eb0, 0x39eb4, 3789248925Snp 0x39ec8, 0x39ed4, 3790248925Snp 0x39fb8, 0x3a004, 3791252312Snp 0x3a200, 0x3a200, 3792252312Snp 0x3a208, 0x3a240, 3793252312Snp 0x3a248, 0x3a280, 3794252312Snp 0x3a288, 0x3a2c0, 3795248925Snp 0x3a2c8, 0x3a2fc, 3796248925Snp 0x3a600, 0x3a630, 3797248925Snp 0x3aa00, 0x3aabc, 3798248925Snp 0x3ab00, 0x3ab70, 3799248925Snp 0x3b000, 0x3b048, 3800248925Snp 0x3b060, 0x3b09c, 3801248925Snp 0x3b0f0, 0x3b148, 3802248925Snp 0x3b160, 0x3b19c, 3803248925Snp 0x3b1f0, 0x3b2e4, 3804248925Snp 0x3b2f8, 0x3b3e4, 3805248925Snp 0x3b3f8, 0x3b448, 3806248925Snp 0x3b460, 0x3b49c, 3807248925Snp 0x3b4f0, 0x3b548, 3808248925Snp 0x3b560, 0x3b59c, 3809248925Snp 0x3b5f0, 0x3b6e4, 3810248925Snp 0x3b6f8, 0x3b7e4, 3811248925Snp 0x3b7f8, 0x3b7fc, 3812248925Snp 0x3b814, 0x3b814, 3813248925Snp 0x3b82c, 0x3b82c, 3814248925Snp 0x3b880, 0x3b88c, 3815248925Snp 0x3b8e8, 0x3b8ec, 3816248925Snp 0x3b900, 0x3b948, 3817248925Snp 0x3b960, 0x3b99c, 3818248925Snp 0x3b9f0, 0x3bae4, 3819248925Snp 0x3baf8, 0x3bb10, 3820248925Snp 0x3bb28, 0x3bb28, 3821248925Snp 0x3bb3c, 0x3bb50, 3822248925Snp 0x3bbf0, 0x3bc10, 3823248925Snp 0x3bc28, 0x3bc28, 3824248925Snp 0x3bc3c, 0x3bc50, 3825248925Snp 0x3bcf0, 0x3bcfc, 3826252312Snp 0x3c000, 0x3c030, 3827248925Snp 0x3c100, 0x3c144, 3828248925Snp 0x3c190, 0x3c1d0, 3829248925Snp 0x3c200, 0x3c318, 3830248925Snp 0x3c400, 0x3c52c, 3831248925Snp 0x3c540, 0x3c61c, 3832248925Snp 0x3c800, 0x3c834, 3833248925Snp 0x3c8c0, 0x3c908, 3834248925Snp 0x3c910, 0x3c9ac, 3835252312Snp 0x3ca00, 0x3ca2c, 3836248925Snp 0x3ca44, 0x3ca50, 3837248925Snp 0x3ca74, 0x3cc24, 3838252312Snp 0x3cd00, 0x3cd00, 3839248925Snp 0x3cd08, 0x3cd14, 3840248925Snp 0x3cd1c, 0x3cd20, 3841248925Snp 0x3cd3c, 0x3cd50, 3842248925Snp 0x3d200, 0x3d20c, 3843248925Snp 0x3d220, 0x3d220, 3844248925Snp 0x3d240, 0x3d240, 3845252312Snp 0x3d600, 0x3d60c, 3846248925Snp 0x3da00, 0x3da1c, 3847252312Snp 0x3de00, 0x3de20, 3848248925Snp 0x3de38, 0x3de3c, 3849248925Snp 0x3de80, 0x3de80, 3850248925Snp 0x3de88, 0x3dea8, 3851248925Snp 0x3deb0, 0x3deb4, 3852248925Snp 0x3dec8, 0x3ded4, 3853248925Snp 0x3dfb8, 0x3e004, 3854252312Snp 0x3e200, 0x3e200, 3855252312Snp 0x3e208, 0x3e240, 3856252312Snp 0x3e248, 0x3e280, 3857252312Snp 0x3e288, 0x3e2c0, 3858248925Snp 0x3e2c8, 0x3e2fc, 3859248925Snp 0x3e600, 0x3e630, 3860248925Snp 0x3ea00, 0x3eabc, 3861248925Snp 0x3eb00, 0x3eb70, 3862248925Snp 0x3f000, 0x3f048, 3863248925Snp 0x3f060, 0x3f09c, 3864248925Snp 0x3f0f0, 0x3f148, 3865248925Snp 0x3f160, 0x3f19c, 3866248925Snp 0x3f1f0, 0x3f2e4, 3867248925Snp 0x3f2f8, 0x3f3e4, 3868248925Snp 0x3f3f8, 0x3f448, 3869248925Snp 0x3f460, 0x3f49c, 3870248925Snp 0x3f4f0, 0x3f548, 3871248925Snp 0x3f560, 0x3f59c, 3872248925Snp 0x3f5f0, 0x3f6e4, 3873248925Snp 0x3f6f8, 0x3f7e4, 3874248925Snp 0x3f7f8, 0x3f7fc, 3875248925Snp 0x3f814, 0x3f814, 3876248925Snp 0x3f82c, 0x3f82c, 3877248925Snp 0x3f880, 0x3f88c, 3878248925Snp 0x3f8e8, 0x3f8ec, 3879248925Snp 0x3f900, 0x3f948, 3880248925Snp 0x3f960, 0x3f99c, 3881248925Snp 0x3f9f0, 0x3fae4, 3882248925Snp 0x3faf8, 0x3fb10, 3883248925Snp 0x3fb28, 0x3fb28, 3884248925Snp 0x3fb3c, 0x3fb50, 3885248925Snp 0x3fbf0, 0x3fc10, 3886248925Snp 0x3fc28, 0x3fc28, 3887248925Snp 0x3fc3c, 0x3fc50, 3888248925Snp 0x3fcf0, 0x3fcfc, 3889248925Snp 0x40000, 0x4000c, 3890248925Snp 0x40040, 0x40068, 3891248925Snp 0x4007c, 0x40144, 3892248925Snp 0x40180, 0x4018c, 3893248925Snp 0x40200, 0x40298, 3894248925Snp 0x402ac, 0x4033c, 3895248925Snp 0x403f8, 0x403fc, 3896252312Snp 0x41304, 0x413c4, 3897248925Snp 0x41400, 0x4141c, 3898248925Snp 0x41480, 0x414d0, 3899248925Snp 0x44000, 0x44078, 3900248925Snp 0x440c0, 0x44278, 3901248925Snp 0x442c0, 0x44478, 3902248925Snp 0x444c0, 0x44678, 3903248925Snp 0x446c0, 0x44878, 3904248925Snp 0x448c0, 0x449fc, 3905248925Snp 0x45000, 0x45068, 3906248925Snp 0x45080, 0x45084, 3907248925Snp 0x450a0, 0x450b0, 3908248925Snp 0x45200, 0x45268, 3909248925Snp 0x45280, 0x45284, 3910248925Snp 0x452a0, 0x452b0, 3911248925Snp 0x460c0, 0x460e4, 3912248925Snp 0x47000, 0x4708c, 3913248925Snp 0x47200, 0x47250, 3914248925Snp 0x47400, 0x47420, 3915248925Snp 0x47600, 0x47618, 3916248925Snp 0x47800, 0x47814, 3917248925Snp 0x48000, 0x4800c, 3918248925Snp 0x48040, 0x48068, 3919248925Snp 0x4807c, 0x48144, 3920248925Snp 0x48180, 0x4818c, 3921248925Snp 0x48200, 0x48298, 3922248925Snp 0x482ac, 0x4833c, 3923248925Snp 0x483f8, 0x483fc, 3924252312Snp 0x49304, 0x493c4, 3925248925Snp 0x49400, 0x4941c, 3926248925Snp 0x49480, 0x494d0, 3927248925Snp 0x4c000, 0x4c078, 3928248925Snp 0x4c0c0, 0x4c278, 3929248925Snp 0x4c2c0, 0x4c478, 3930248925Snp 0x4c4c0, 0x4c678, 3931248925Snp 0x4c6c0, 0x4c878, 3932248925Snp 0x4c8c0, 0x4c9fc, 3933248925Snp 0x4d000, 0x4d068, 3934248925Snp 0x4d080, 0x4d084, 3935248925Snp 0x4d0a0, 0x4d0b0, 3936248925Snp 0x4d200, 0x4d268, 3937248925Snp 0x4d280, 0x4d284, 3938248925Snp 0x4d2a0, 0x4d2b0, 3939248925Snp 0x4e0c0, 0x4e0e4, 3940248925Snp 0x4f000, 0x4f08c, 3941248925Snp 0x4f200, 0x4f250, 3942248925Snp 0x4f400, 0x4f420, 3943248925Snp 0x4f600, 0x4f618, 3944248925Snp 0x4f800, 0x4f814, 3945248925Snp 0x50000, 0x500cc, 3946248925Snp 0x50400, 0x50400, 3947248925Snp 0x50800, 0x508cc, 3948248925Snp 0x50c00, 0x50c00, 3949248925Snp 0x51000, 0x5101c, 3950248925Snp 0x51300, 0x51308, 3951248925Snp }; 3952218792Snp 3953248925Snp if (is_t4(sc)) { 3954248925Snp reg_ranges = &t4_reg_ranges[0]; 3955248925Snp n = nitems(t4_reg_ranges); 3956248925Snp } else { 3957248925Snp reg_ranges = &t5_reg_ranges[0]; 3958248925Snp n = nitems(t5_reg_ranges); 3959248925Snp } 3960248925Snp 3961248925Snp regs->version = chip_id(sc) | chip_rev(sc) << 10; 3962248925Snp for (i = 0; i < n; i += 2) 3963218792Snp reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]); 3964218792Snp} 3965218792Snp 3966218792Snpstatic void 3967218792Snpcxgbe_tick(void *arg) 3968218792Snp{ 3969218792Snp struct port_info *pi = arg; 3970218792Snp struct ifnet *ifp = pi->ifp; 3971218792Snp struct sge_txq *txq; 3972218792Snp int i, drops; 3973218792Snp struct port_stats *s = &pi->stats; 3974218792Snp 3975218792Snp PORT_LOCK(pi); 3976218792Snp if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 3977218792Snp PORT_UNLOCK(pi); 3978218792Snp return; /* without scheduling another callout */ 3979218792Snp } 3980218792Snp 3981218792Snp t4_get_port_stats(pi->adapter, pi->tx_chan, s); 3982218792Snp 3983228561Snp ifp->if_opackets = s->tx_frames - s->tx_pause; 3984228561Snp ifp->if_ipackets = s->rx_frames - s->rx_pause; 3985228561Snp ifp->if_obytes = s->tx_octets - s->tx_pause * 64; 3986228561Snp ifp->if_ibytes = s->rx_octets - s->rx_pause * 64; 3987228561Snp ifp->if_omcasts = s->tx_mcast_frames - s->tx_pause; 3988228561Snp ifp->if_imcasts = s->rx_mcast_frames - s->rx_pause; 3989218792Snp ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 + 3990239259Snp s->rx_ovflow3 + s->rx_trunc0 + s->rx_trunc1 + s->rx_trunc2 + 3991239259Snp s->rx_trunc3; 3992218792Snp 3993218792Snp drops = s->tx_drop; 3994218792Snp for_each_txq(pi, i, txq) 3995220873Snp drops += txq->br->br_drops; 3996218792Snp ifp->if_snd.ifq_drops = drops; 3997218792Snp 3998218792Snp ifp->if_oerrors = s->tx_error_frames; 3999218792Snp ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long + 4000218792Snp s->rx_fcs_err + s->rx_len_err; 4001218792Snp 4002218792Snp callout_schedule(&pi->tick, hz); 4003218792Snp PORT_UNLOCK(pi); 4004218792Snp} 4005218792Snp 4006237263Snpstatic void 4007237263Snpcxgbe_vlan_config(void *arg, struct ifnet *ifp, uint16_t vid) 4008237263Snp{ 4009237263Snp struct ifnet *vlan; 4010237263Snp 4011241494Snp if (arg != ifp || ifp->if_type != IFT_ETHER) 4012237263Snp return; 4013237263Snp 4014237263Snp vlan = VLAN_DEVAT(ifp, vid); 4015237263Snp VLAN_SETCOOKIE(vlan, ifp); 4016237263Snp} 4017237263Snp 4018218792Snpstatic int 4019228561Snpcpl_not_handled(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 4020228561Snp{ 4021237263Snp 4022228561Snp#ifdef INVARIANTS 4023237263Snp panic("%s: opcode 0x%02x on iq %p with payload %p", 4024228561Snp __func__, rss->opcode, iq, m); 4025228561Snp#else 4026239336Snp log(LOG_ERR, "%s: opcode 0x%02x on iq %p with payload %p\n", 4027228561Snp __func__, rss->opcode, iq, m); 4028228561Snp m_freem(m); 4029228561Snp#endif 4030228561Snp return (EDOOFUS); 4031228561Snp} 4032228561Snp 4033228561Snpint 4034228561Snpt4_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h) 4035228561Snp{ 4036228561Snp uintptr_t *loc, new; 4037228561Snp 4038240452Snp if (opcode >= nitems(sc->cpl_handler)) 4039228561Snp return (EINVAL); 4040228561Snp 4041228561Snp new = h ? (uintptr_t)h : (uintptr_t)cpl_not_handled; 4042228561Snp loc = (uintptr_t *) &sc->cpl_handler[opcode]; 4043228561Snp atomic_store_rel_ptr(loc, new); 4044228561Snp 4045228561Snp return (0); 4046228561Snp} 4047228561Snp 4048228561Snpstatic int 4049237263Snpan_not_handled(struct sge_iq *iq, const struct rsp_ctrl *ctrl) 4050237263Snp{ 4051237263Snp 4052237263Snp#ifdef INVARIANTS 4053237263Snp panic("%s: async notification on iq %p (ctrl %p)", __func__, iq, ctrl); 4054237263Snp#else 4055239336Snp log(LOG_ERR, "%s: async notification on iq %p (ctrl %p)\n", 4056237263Snp __func__, iq, ctrl); 4057237263Snp#endif 4058237263Snp return (EDOOFUS); 4059237263Snp} 4060237263Snp 4061237263Snpint 4062237263Snpt4_register_an_handler(struct adapter *sc, an_handler_t h) 4063237263Snp{ 4064237263Snp uintptr_t *loc, new; 4065237263Snp 4066237263Snp new = h ? (uintptr_t)h : (uintptr_t)an_not_handled; 4067237263Snp loc = (uintptr_t *) &sc->an_handler; 4068237263Snp atomic_store_rel_ptr(loc, new); 4069237263Snp 4070237263Snp return (0); 4071237263Snp} 4072237263Snp 4073237263Snpstatic int 4074239336Snpfw_msg_not_handled(struct adapter *sc, const __be64 *rpl) 4075239336Snp{ 4076241733Sed const struct cpl_fw6_msg *cpl = 4077241733Sed __containerof(rpl, struct cpl_fw6_msg, data[0]); 4078239336Snp 4079239336Snp#ifdef INVARIANTS 4080239336Snp panic("%s: fw_msg type %d", __func__, cpl->type); 4081239336Snp#else 4082239336Snp log(LOG_ERR, "%s: fw_msg type %d\n", __func__, cpl->type); 4083239336Snp#endif 4084239336Snp return (EDOOFUS); 4085239336Snp} 4086239336Snp 4087239336Snpint 4088239336Snpt4_register_fw_msg_handler(struct adapter *sc, int type, fw_msg_handler_t h) 4089239336Snp{ 4090239336Snp uintptr_t *loc, new; 4091239336Snp 4092240452Snp if (type >= nitems(sc->fw_msg_handler)) 4093239336Snp return (EINVAL); 4094239336Snp 4095247291Snp /* 4096247291Snp * These are dispatched by the handler for FW{4|6}_CPL_MSG using the CPL 4097247291Snp * handler dispatch table. Reject any attempt to install a handler for 4098247291Snp * this subtype. 4099247291Snp */ 4100247291Snp if (type == FW_TYPE_RSSCPL || type == FW6_TYPE_RSSCPL) 4101247291Snp return (EINVAL); 4102247291Snp 4103239336Snp new = h ? (uintptr_t)h : (uintptr_t)fw_msg_not_handled; 4104239336Snp loc = (uintptr_t *) &sc->fw_msg_handler[type]; 4105239336Snp atomic_store_rel_ptr(loc, new); 4106239336Snp 4107239336Snp return (0); 4108239336Snp} 4109239336Snp 4110239336Snpstatic int 4111218792Snpt4_sysctls(struct adapter *sc) 4112218792Snp{ 4113218792Snp struct sysctl_ctx_list *ctx; 4114218792Snp struct sysctl_oid *oid; 4115228561Snp struct sysctl_oid_list *children, *c0; 4116228561Snp static char *caps[] = { 4117228561Snp "\20\1PPP\2QFC\3DCBX", /* caps[0] linkcaps */ 4118228561Snp "\20\1NIC\2VM\3IDS\4UM\5UM_ISGL", /* caps[1] niccaps */ 4119228561Snp "\20\1TOE", /* caps[2] toecaps */ 4120228561Snp "\20\1RDDP\2RDMAC", /* caps[3] rdmacaps */ 4121228561Snp "\20\1INITIATOR_PDU\2TARGET_PDU" /* caps[4] iscsicaps */ 4122228561Snp "\3INITIATOR_CNXOFLD\4TARGET_CNXOFLD" 4123228561Snp "\5INITIATOR_SSNOFLD\6TARGET_SSNOFLD", 4124228561Snp "\20\1INITIATOR\2TARGET\3CTRL_OFLD" /* caps[5] fcoecaps */ 4125228561Snp }; 4126249392Snp static char *doorbells = {"\20\1UDB\2WCWR\3UDBWC\4KDB"}; 4127218792Snp 4128218792Snp ctx = device_get_sysctl_ctx(sc->dev); 4129228561Snp 4130228561Snp /* 4131228561Snp * dev.t4nex.X. 4132228561Snp */ 4133218792Snp oid = device_get_sysctl_tree(sc->dev); 4134228561Snp c0 = children = SYSCTL_CHILDREN(oid); 4135218792Snp 4136248925Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, NULL, 4137248925Snp sc->params.nports, "# of ports"); 4138218792Snp 4139218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD, 4140248925Snp NULL, chip_rev(sc), "chip hardware revision"); 4141218792Snp 4142218792Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 4143218792Snp CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 4144218792Snp 4145228561Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "cf", 4146245936Snp CTLFLAG_RD, &sc->cfg_file, 0, "configuration file"); 4147218792Snp 4148248925Snp SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cfcsum", CTLFLAG_RD, NULL, 4149248925Snp sc->cfcsum, "config file checksum"); 4150228561Snp 4151248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "doorbells", 4152248925Snp CTLTYPE_STRING | CTLFLAG_RD, doorbells, sc->doorbells, 4153248925Snp sysctl_bitfield, "A", "available doorbells"); 4154248925Snp 4155228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkcaps", 4156228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[0], sc->linkcaps, 4157228561Snp sysctl_bitfield, "A", "available link capabilities"); 4158228561Snp 4159228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "niccaps", 4160228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[1], sc->niccaps, 4161228561Snp sysctl_bitfield, "A", "available NIC capabilities"); 4162228561Snp 4163228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "toecaps", 4164228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[2], sc->toecaps, 4165228561Snp sysctl_bitfield, "A", "available TCP offload capabilities"); 4166228561Snp 4167228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdmacaps", 4168228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[3], sc->rdmacaps, 4169228561Snp sysctl_bitfield, "A", "available RDMA capabilities"); 4170228561Snp 4171228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "iscsicaps", 4172228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[4], sc->iscsicaps, 4173228561Snp sysctl_bitfield, "A", "available iSCSI capabilities"); 4174228561Snp 4175228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoecaps", 4176228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[5], sc->fcoecaps, 4177228561Snp sysctl_bitfield, "A", "available FCoE capabilities"); 4178228561Snp 4179248925Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, NULL, 4180248925Snp sc->params.vpd.cclk, "core clock frequency (in KHz)"); 4181218792Snp 4182219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers", 4183228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.timer_val, 4184228561Snp sizeof(sc->sge.timer_val), sysctl_int_array, "A", 4185228561Snp "interrupt holdoff timer values (us)"); 4186218792Snp 4187219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts", 4188228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.counter_val, 4189228561Snp sizeof(sc->sge.counter_val), sysctl_int_array, "A", 4190228561Snp "interrupt holdoff packet counter values"); 4191218792Snp 4192252469Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nfilters", CTLFLAG_RD, 4193252469Snp NULL, sc->tids.nftids, "number of filters"); 4194252469Snp 4195231115Snp#ifdef SBUF_DRAIN 4196228561Snp /* 4197228561Snp * dev.t4nex.X.misc. Marked CTLFLAG_SKIP to avoid information overload. 4198228561Snp */ 4199228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "misc", 4200228561Snp CTLFLAG_RD | CTLFLAG_SKIP, NULL, 4201228561Snp "logs and miscellaneous information"); 4202228561Snp children = SYSCTL_CHILDREN(oid); 4203228561Snp 4204228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cctrl", 4205228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4206228561Snp sysctl_cctrl, "A", "congestion control"); 4207228561Snp 4208247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp0", 4209247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4210247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 0 (TP0)"); 4211247122Snp 4212247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp1", 4213247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 1, 4214247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 1 (TP1)"); 4215247122Snp 4216247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ulp", 4217247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 2, 4218247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 2 (ULP)"); 4219247122Snp 4220247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge0", 4221247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 3, 4222247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 3 (SGE0)"); 4223247122Snp 4224247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge1", 4225247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 4, 4226247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 4 (SGE1)"); 4227247122Snp 4228247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ncsi", 4229247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 5, 4230247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 5 (NCSI)"); 4231247122Snp 4232247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_la", 4233247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4234247122Snp sysctl_cim_la, "A", "CIM logic analyzer"); 4235247122Snp 4236251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ma_la", 4237251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4238251213Snp sysctl_cim_ma_la, "A", "CIM MA logic analyzer"); 4239251213Snp 4240247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp0", 4241247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0 + CIM_NUM_IBQ, 4242247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 0 (ULP0)"); 4243247122Snp 4244247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp1", 4245247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 1 + CIM_NUM_IBQ, 4246247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 1 (ULP1)"); 4247247122Snp 4248247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp2", 4249247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 2 + CIM_NUM_IBQ, 4250247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 2 (ULP2)"); 4251247122Snp 4252247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp3", 4253247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 3 + CIM_NUM_IBQ, 4254247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 3 (ULP3)"); 4255247122Snp 4256247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge", 4257247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 4 + CIM_NUM_IBQ, 4258247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 4 (SGE)"); 4259247122Snp 4260247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ncsi", 4261247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 5 + CIM_NUM_IBQ, 4262247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 5 (NCSI)"); 4263247122Snp 4264248925Snp if (is_t5(sc)) { 4265248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge0_rx", 4266248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 6 + CIM_NUM_IBQ, 4267248925Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 6 (SGE0-RX)"); 4268248925Snp 4269248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge1_rx", 4270248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 7 + CIM_NUM_IBQ, 4271248925Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 7 (SGE1-RX)"); 4272248925Snp } 4273248925Snp 4274251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_pif_la", 4275251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4276251213Snp sysctl_cim_pif_la, "A", "CIM PIF logic analyzer"); 4277251213Snp 4278247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_qcfg", 4279247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4280247122Snp sysctl_cim_qcfg, "A", "CIM queue configuration"); 4281247122Snp 4282228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats", 4283228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4284228561Snp sysctl_cpl_stats, "A", "CPL statistics"); 4285228561Snp 4286228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ddp_stats", 4287228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4288228561Snp sysctl_ddp_stats, "A", "DDP statistics"); 4289228561Snp 4290222551Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog", 4291222551Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4292228561Snp sysctl_devlog, "A", "firmware's device log"); 4293222551Snp 4294228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoe_stats", 4295228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4296228561Snp sysctl_fcoe_stats, "A", "FCoE statistics"); 4297228561Snp 4298228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hw_sched", 4299228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4300228561Snp sysctl_hw_sched, "A", "hardware scheduler "); 4301228561Snp 4302228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "l2t", 4303228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4304228561Snp sysctl_l2t, "A", "hardware L2 table"); 4305228561Snp 4306228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats", 4307228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4308228561Snp sysctl_lb_stats, "A", "loopback statistics"); 4309228561Snp 4310228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "meminfo", 4311228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4312228561Snp sysctl_meminfo, "A", "memory regions"); 4313228561Snp 4314251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "mps_tcam", 4315251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4316251213Snp sysctl_mps_tcam, "A", "MPS TCAM entries"); 4317251213Snp 4318228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "path_mtus", 4319228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4320228561Snp sysctl_path_mtus, "A", "path MTUs"); 4321228561Snp 4322228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pm_stats", 4323228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4324228561Snp sysctl_pm_stats, "A", "PM statistics"); 4325228561Snp 4326228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_stats", 4327228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4328228561Snp sysctl_rdma_stats, "A", "RDMA statistics"); 4329228561Snp 4330228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tcp_stats", 4331228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4332228561Snp sysctl_tcp_stats, "A", "TCP statistics"); 4333228561Snp 4334228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tids", 4335228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4336228561Snp sysctl_tids, "A", "TID information"); 4337228561Snp 4338228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_err_stats", 4339228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4340228561Snp sysctl_tp_err_stats, "A", "TP error statistics"); 4341228561Snp 4342251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_la", 4343251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4344251213Snp sysctl_tp_la, "A", "TP logic analyzer"); 4345251213Snp 4346228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_rate", 4347228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4348228561Snp sysctl_tx_rate, "A", "Tx rate"); 4349248925Snp 4350251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ulprx_la", 4351251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4352251213Snp sysctl_ulprx_la, "A", "ULPRX logic analyzer"); 4353251213Snp 4354248925Snp if (is_t5(sc)) { 4355249392Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "wcwr_stats", 4356248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4357249392Snp sysctl_wcwr_stats, "A", "write combined work requests"); 4358248925Snp } 4359231115Snp#endif 4360228561Snp 4361237263Snp#ifdef TCP_OFFLOAD 4362228561Snp if (is_offload(sc)) { 4363228561Snp /* 4364228561Snp * dev.t4nex.X.toe. 4365228561Snp */ 4366228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "toe", CTLFLAG_RD, 4367228561Snp NULL, "TOE parameters"); 4368228561Snp children = SYSCTL_CHILDREN(oid); 4369228561Snp 4370228561Snp sc->tt.sndbuf = 256 * 1024; 4371228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "sndbuf", CTLFLAG_RW, 4372228561Snp &sc->tt.sndbuf, 0, "max hardware send buffer size"); 4373228561Snp 4374228561Snp sc->tt.ddp = 0; 4375228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp", CTLFLAG_RW, 4376228561Snp &sc->tt.ddp, 0, "DDP allowed"); 4377239341Snp 4378239341Snp sc->tt.indsz = G_INDICATESIZE(t4_read_reg(sc, A_TP_PARA_REG5)); 4379228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "indsz", CTLFLAG_RW, 4380228561Snp &sc->tt.indsz, 0, "DDP max indicate size allowed"); 4381239341Snp 4382239341Snp sc->tt.ddp_thres = 4383239341Snp G_RXCOALESCESIZE(t4_read_reg(sc, A_TP_PARA_REG2)); 4384228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp_thres", CTLFLAG_RW, 4385228561Snp &sc->tt.ddp_thres, 0, "DDP threshold"); 4386228561Snp } 4387228561Snp#endif 4388228561Snp 4389228561Snp 4390218792Snp return (0); 4391218792Snp} 4392218792Snp 4393218792Snpstatic int 4394218792Snpcxgbe_sysctls(struct port_info *pi) 4395218792Snp{ 4396218792Snp struct sysctl_ctx_list *ctx; 4397218792Snp struct sysctl_oid *oid; 4398218792Snp struct sysctl_oid_list *children; 4399218792Snp 4400218792Snp ctx = device_get_sysctl_ctx(pi->dev); 4401218792Snp 4402218792Snp /* 4403218792Snp * dev.cxgbe.X. 4404218792Snp */ 4405218792Snp oid = device_get_sysctl_tree(pi->dev); 4406218792Snp children = SYSCTL_CHILDREN(oid); 4407218792Snp 4408218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD, 4409218792Snp &pi->nrxq, 0, "# of rx queues"); 4410218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD, 4411218792Snp &pi->ntxq, 0, "# of tx queues"); 4412218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD, 4413218792Snp &pi->first_rxq, 0, "index of first rx queue"); 4414218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD, 4415218792Snp &pi->first_txq, 0, "index of first tx queue"); 4416218792Snp 4417237263Snp#ifdef TCP_OFFLOAD 4418228561Snp if (is_offload(pi->adapter)) { 4419228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldrxq", CTLFLAG_RD, 4420228561Snp &pi->nofldrxq, 0, 4421228561Snp "# of rx queues for offloaded TCP connections"); 4422228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldtxq", CTLFLAG_RD, 4423228561Snp &pi->nofldtxq, 0, 4424228561Snp "# of tx queues for offloaded TCP connections"); 4425228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_rxq", 4426228561Snp CTLFLAG_RD, &pi->first_ofld_rxq, 0, 4427228561Snp "index of first TOE rx queue"); 4428228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_txq", 4429228561Snp CTLFLAG_RD, &pi->first_ofld_txq, 0, 4430228561Snp "index of first TOE tx queue"); 4431228561Snp } 4432228561Snp#endif 4433228561Snp 4434218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx", 4435218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I", 4436218792Snp "holdoff timer index"); 4437218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx", 4438218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I", 4439218792Snp "holdoff packet counter index"); 4440218792Snp 4441218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq", 4442218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I", 4443218792Snp "rx queue size"); 4444218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq", 4445218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I", 4446218792Snp "tx queue size"); 4447218792Snp 4448218792Snp /* 4449218792Snp * dev.cxgbe.X.stats. 4450218792Snp */ 4451218792Snp oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, 4452218792Snp NULL, "port statistics"); 4453218792Snp children = SYSCTL_CHILDREN(oid); 4454218792Snp 4455218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \ 4456218792Snp SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \ 4457218792Snp CTLTYPE_U64 | CTLFLAG_RD, pi->adapter, reg, \ 4458218792Snp sysctl_handle_t4_reg64, "QU", desc) 4459218792Snp 4460218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames", 4461218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L)); 4462218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames", 4463218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L)); 4464218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames", 4465218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L)); 4466218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames", 4467218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L)); 4468218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames", 4469218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L)); 4470218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames", 4471218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L)); 4472218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_64", 4473218792Snp "# of tx frames in this range", 4474218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L)); 4475218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127", 4476218792Snp "# of tx frames in this range", 4477218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L)); 4478218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255", 4479218792Snp "# of tx frames in this range", 4480218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L)); 4481218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511", 4482218792Snp "# of tx frames in this range", 4483218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L)); 4484218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023", 4485218792Snp "# of tx frames in this range", 4486218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L)); 4487218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518", 4488218792Snp "# of tx frames in this range", 4489218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L)); 4490218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max", 4491218792Snp "# of tx frames in this range", 4492218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L)); 4493218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames", 4494218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L)); 4495218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted", 4496218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L)); 4497218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted", 4498218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L)); 4499218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted", 4500218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L)); 4501218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted", 4502218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L)); 4503218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted", 4504218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L)); 4505218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted", 4506218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L)); 4507218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted", 4508218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L)); 4509218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted", 4510218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L)); 4511218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted", 4512218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L)); 4513218792Snp 4514218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames", 4515218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L)); 4516218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames", 4517218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L)); 4518218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames", 4519218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L)); 4520218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames", 4521218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L)); 4522218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames", 4523218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L)); 4524218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU", 4525218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L)); 4526218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames", 4527218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L)); 4528218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err", 4529218792Snp "# of frames received with bad FCS", 4530218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L)); 4531218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_len_err", 4532218792Snp "# of frames received with length error", 4533218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L)); 4534218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors", 4535218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L)); 4536218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received", 4537218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L)); 4538218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_64", 4539218792Snp "# of rx frames in this range", 4540218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L)); 4541218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127", 4542218792Snp "# of rx frames in this range", 4543218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L)); 4544218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255", 4545218792Snp "# of rx frames in this range", 4546218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L)); 4547218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511", 4548218792Snp "# of rx frames in this range", 4549218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L)); 4550218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023", 4551218792Snp "# of rx frames in this range", 4552218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L)); 4553218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518", 4554218792Snp "# of rx frames in this range", 4555218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L)); 4556218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max", 4557218792Snp "# of rx frames in this range", 4558218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L)); 4559218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received", 4560218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L)); 4561218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received", 4562218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L)); 4563218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received", 4564218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L)); 4565218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received", 4566218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L)); 4567218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received", 4568218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L)); 4569218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received", 4570218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L)); 4571218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received", 4572218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L)); 4573218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received", 4574218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L)); 4575218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received", 4576218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L)); 4577218792Snp 4578218792Snp#undef SYSCTL_ADD_T4_REG64 4579218792Snp 4580218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \ 4581218792Snp SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \ 4582218792Snp &pi->stats.name, desc) 4583218792Snp 4584218792Snp /* We get these from port_stats and they may be stale by upto 1s */ 4585218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0, 4586218792Snp "# drops due to buffer-group 0 overflows"); 4587218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1, 4588218792Snp "# drops due to buffer-group 1 overflows"); 4589218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2, 4590218792Snp "# drops due to buffer-group 2 overflows"); 4591218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3, 4592218792Snp "# drops due to buffer-group 3 overflows"); 4593218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc0, 4594218792Snp "# of buffer-group 0 truncated packets"); 4595218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc1, 4596218792Snp "# of buffer-group 1 truncated packets"); 4597218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc2, 4598218792Snp "# of buffer-group 2 truncated packets"); 4599218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc3, 4600218792Snp "# of buffer-group 3 truncated packets"); 4601218792Snp 4602218792Snp#undef SYSCTL_ADD_T4_PORTSTAT 4603218792Snp 4604218792Snp return (0); 4605218792Snp} 4606218792Snp 4607218792Snpstatic int 4608219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS) 4609219436Snp{ 4610219436Snp int rc, *i; 4611219436Snp struct sbuf sb; 4612219436Snp 4613219436Snp sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); 4614219436Snp for (i = arg1; arg2; arg2 -= sizeof(int), i++) 4615219436Snp sbuf_printf(&sb, "%d ", *i); 4616219436Snp sbuf_trim(&sb); 4617219436Snp sbuf_finish(&sb); 4618219436Snp rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 4619219436Snp sbuf_delete(&sb); 4620219436Snp return (rc); 4621219436Snp} 4622219436Snp 4623219436Snpstatic int 4624228561Snpsysctl_bitfield(SYSCTL_HANDLER_ARGS) 4625228561Snp{ 4626228561Snp int rc; 4627228561Snp struct sbuf *sb; 4628228561Snp 4629228561Snp rc = sysctl_wire_old_buffer(req, 0); 4630228561Snp if (rc != 0) 4631228561Snp return(rc); 4632228561Snp 4633228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 4634228561Snp if (sb == NULL) 4635228561Snp return (ENOMEM); 4636228561Snp 4637228561Snp sbuf_printf(sb, "%b", (int)arg2, (char *)arg1); 4638228561Snp rc = sbuf_finish(sb); 4639228561Snp sbuf_delete(sb); 4640228561Snp 4641228561Snp return (rc); 4642228561Snp} 4643228561Snp 4644228561Snpstatic int 4645218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS) 4646218792Snp{ 4647218792Snp struct port_info *pi = arg1; 4648218792Snp struct adapter *sc = pi->adapter; 4649218792Snp int idx, rc, i; 4650245274Snp struct sge_rxq *rxq; 4651245274Snp uint8_t v; 4652218792Snp 4653218792Snp idx = pi->tmr_idx; 4654218792Snp 4655218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 4656218792Snp if (rc != 0 || req->newptr == NULL) 4657218792Snp return (rc); 4658218792Snp 4659218792Snp if (idx < 0 || idx >= SGE_NTIMERS) 4660218792Snp return (EINVAL); 4661218792Snp 4662245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4663245274Snp "t4tmr"); 4664245274Snp if (rc) 4665245274Snp return (rc); 4666228561Snp 4667245274Snp v = V_QINTR_TIMER_IDX(idx) | V_QINTR_CNT_EN(pi->pktc_idx != -1); 4668245274Snp for_each_rxq(pi, i, rxq) { 4669228561Snp#ifdef atomic_store_rel_8 4670245274Snp atomic_store_rel_8(&rxq->iq.intr_params, v); 4671228561Snp#else 4672245274Snp rxq->iq.intr_params = v; 4673228561Snp#endif 4674218792Snp } 4675245274Snp pi->tmr_idx = idx; 4676218792Snp 4677245274Snp end_synchronized_op(sc, LOCK_HELD); 4678245274Snp return (0); 4679218792Snp} 4680218792Snp 4681218792Snpstatic int 4682218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS) 4683218792Snp{ 4684218792Snp struct port_info *pi = arg1; 4685218792Snp struct adapter *sc = pi->adapter; 4686218792Snp int idx, rc; 4687218792Snp 4688218792Snp idx = pi->pktc_idx; 4689218792Snp 4690218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 4691218792Snp if (rc != 0 || req->newptr == NULL) 4692218792Snp return (rc); 4693218792Snp 4694218792Snp if (idx < -1 || idx >= SGE_NCOUNTERS) 4695218792Snp return (EINVAL); 4696218792Snp 4697245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4698245274Snp "t4pktc"); 4699245274Snp if (rc) 4700245274Snp return (rc); 4701245274Snp 4702245274Snp if (pi->flags & PORT_INIT_DONE) 4703228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 4704245274Snp else 4705218792Snp pi->pktc_idx = idx; 4706218792Snp 4707245274Snp end_synchronized_op(sc, LOCK_HELD); 4708218792Snp return (rc); 4709218792Snp} 4710218792Snp 4711218792Snpstatic int 4712218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS) 4713218792Snp{ 4714218792Snp struct port_info *pi = arg1; 4715218792Snp struct adapter *sc = pi->adapter; 4716218792Snp int qsize, rc; 4717218792Snp 4718218792Snp qsize = pi->qsize_rxq; 4719218792Snp 4720218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 4721218792Snp if (rc != 0 || req->newptr == NULL) 4722218792Snp return (rc); 4723218792Snp 4724218792Snp if (qsize < 128 || (qsize & 7)) 4725218792Snp return (EINVAL); 4726218792Snp 4727245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4728245274Snp "t4rxqs"); 4729245274Snp if (rc) 4730245274Snp return (rc); 4731245274Snp 4732245274Snp if (pi->flags & PORT_INIT_DONE) 4733228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 4734245274Snp else 4735218792Snp pi->qsize_rxq = qsize; 4736218792Snp 4737245274Snp end_synchronized_op(sc, LOCK_HELD); 4738218792Snp return (rc); 4739218792Snp} 4740218792Snp 4741218792Snpstatic int 4742218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS) 4743218792Snp{ 4744218792Snp struct port_info *pi = arg1; 4745218792Snp struct adapter *sc = pi->adapter; 4746218792Snp int qsize, rc; 4747218792Snp 4748218792Snp qsize = pi->qsize_txq; 4749218792Snp 4750218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 4751218792Snp if (rc != 0 || req->newptr == NULL) 4752218792Snp return (rc); 4753218792Snp 4754245274Snp /* bufring size must be powerof2 */ 4755245274Snp if (qsize < 128 || !powerof2(qsize)) 4756218792Snp return (EINVAL); 4757218792Snp 4758245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4759245274Snp "t4txqs"); 4760245274Snp if (rc) 4761245274Snp return (rc); 4762245274Snp 4763245274Snp if (pi->flags & PORT_INIT_DONE) 4764228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 4765245274Snp else 4766218792Snp pi->qsize_txq = qsize; 4767218792Snp 4768245274Snp end_synchronized_op(sc, LOCK_HELD); 4769218792Snp return (rc); 4770218792Snp} 4771218792Snp 4772218792Snpstatic int 4773218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS) 4774218792Snp{ 4775218792Snp struct adapter *sc = arg1; 4776218792Snp int reg = arg2; 4777218792Snp uint64_t val; 4778218792Snp 4779218792Snp val = t4_read_reg64(sc, reg); 4780218792Snp 4781218792Snp return (sysctl_handle_64(oidp, &val, 0, req)); 4782218792Snp} 4783218792Snp 4784231115Snp#ifdef SBUF_DRAIN 4785228561Snpstatic int 4786228561Snpsysctl_cctrl(SYSCTL_HANDLER_ARGS) 4787228561Snp{ 4788228561Snp struct adapter *sc = arg1; 4789228561Snp struct sbuf *sb; 4790228561Snp int rc, i; 4791228561Snp uint16_t incr[NMTUS][NCCTRL_WIN]; 4792228561Snp static const char *dec_fac[] = { 4793228561Snp "0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875", 4794228561Snp "0.9375" 4795228561Snp }; 4796228561Snp 4797228561Snp rc = sysctl_wire_old_buffer(req, 0); 4798228561Snp if (rc != 0) 4799228561Snp return (rc); 4800228561Snp 4801228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 4802228561Snp if (sb == NULL) 4803228561Snp return (ENOMEM); 4804228561Snp 4805228561Snp t4_read_cong_tbl(sc, incr); 4806228561Snp 4807228561Snp for (i = 0; i < NCCTRL_WIN; ++i) { 4808228561Snp sbuf_printf(sb, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i, 4809228561Snp incr[0][i], incr[1][i], incr[2][i], incr[3][i], incr[4][i], 4810228561Snp incr[5][i], incr[6][i], incr[7][i]); 4811228561Snp sbuf_printf(sb, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n", 4812228561Snp incr[8][i], incr[9][i], incr[10][i], incr[11][i], 4813228561Snp incr[12][i], incr[13][i], incr[14][i], incr[15][i], 4814228561Snp sc->params.a_wnd[i], dec_fac[sc->params.b_wnd[i]]); 4815228561Snp } 4816228561Snp 4817228561Snp rc = sbuf_finish(sb); 4818228561Snp sbuf_delete(sb); 4819228561Snp 4820228561Snp return (rc); 4821228561Snp} 4822228561Snp 4823248925Snpstatic const char *qname[CIM_NUM_IBQ + CIM_NUM_OBQ_T5] = { 4824247122Snp "TP0", "TP1", "ULP", "SGE0", "SGE1", "NC-SI", /* ibq's */ 4825248925Snp "ULP0", "ULP1", "ULP2", "ULP3", "SGE", "NC-SI", /* obq's */ 4826248925Snp "SGE0-RX", "SGE1-RX" /* additional obq's (T5 onwards) */ 4827247122Snp}; 4828247122Snp 4829228561Snpstatic int 4830247122Snpsysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS) 4831247122Snp{ 4832247122Snp struct adapter *sc = arg1; 4833247122Snp struct sbuf *sb; 4834247122Snp int rc, i, n, qid = arg2; 4835247122Snp uint32_t *buf, *p; 4836247122Snp char *qtype; 4837248925Snp u_int cim_num_obq = is_t4(sc) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5; 4838247122Snp 4839248925Snp KASSERT(qid >= 0 && qid < CIM_NUM_IBQ + cim_num_obq, 4840247122Snp ("%s: bad qid %d\n", __func__, qid)); 4841247122Snp 4842247122Snp if (qid < CIM_NUM_IBQ) { 4843247122Snp /* inbound queue */ 4844247122Snp qtype = "IBQ"; 4845247122Snp n = 4 * CIM_IBQ_SIZE; 4846247122Snp buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); 4847247122Snp rc = t4_read_cim_ibq(sc, qid, buf, n); 4848247122Snp } else { 4849247122Snp /* outbound queue */ 4850247122Snp qtype = "OBQ"; 4851247122Snp qid -= CIM_NUM_IBQ; 4852248925Snp n = 4 * cim_num_obq * CIM_OBQ_SIZE; 4853247122Snp buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); 4854247122Snp rc = t4_read_cim_obq(sc, qid, buf, n); 4855247122Snp } 4856247122Snp 4857247122Snp if (rc < 0) { 4858247122Snp rc = -rc; 4859247122Snp goto done; 4860247122Snp } 4861247122Snp n = rc * sizeof(uint32_t); /* rc has # of words actually read */ 4862247122Snp 4863247122Snp rc = sysctl_wire_old_buffer(req, 0); 4864247122Snp if (rc != 0) 4865247122Snp goto done; 4866247122Snp 4867248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req); 4868247122Snp if (sb == NULL) { 4869247122Snp rc = ENOMEM; 4870247122Snp goto done; 4871247122Snp } 4872247122Snp 4873247122Snp sbuf_printf(sb, "%s%d %s", qtype , qid, qname[arg2]); 4874247122Snp for (i = 0, p = buf; i < n; i += 16, p += 4) 4875247122Snp sbuf_printf(sb, "\n%#06x: %08x %08x %08x %08x", i, p[0], p[1], 4876247122Snp p[2], p[3]); 4877247122Snp 4878247122Snp rc = sbuf_finish(sb); 4879247122Snp sbuf_delete(sb); 4880247122Snpdone: 4881247122Snp free(buf, M_CXGBE); 4882247122Snp return (rc); 4883247122Snp} 4884247122Snp 4885247122Snpstatic int 4886247122Snpsysctl_cim_la(SYSCTL_HANDLER_ARGS) 4887247122Snp{ 4888247122Snp struct adapter *sc = arg1; 4889247122Snp u_int cfg; 4890247122Snp struct sbuf *sb; 4891247122Snp uint32_t *buf, *p; 4892247122Snp int rc; 4893247122Snp 4894247122Snp rc = -t4_cim_read(sc, A_UP_UP_DBG_LA_CFG, 1, &cfg); 4895247122Snp if (rc != 0) 4896247122Snp return (rc); 4897247122Snp 4898247122Snp rc = sysctl_wire_old_buffer(req, 0); 4899247122Snp if (rc != 0) 4900247122Snp return (rc); 4901247122Snp 4902247122Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 4903247122Snp if (sb == NULL) 4904247122Snp return (ENOMEM); 4905247122Snp 4906247122Snp buf = malloc(sc->params.cim_la_size * sizeof(uint32_t), M_CXGBE, 4907247122Snp M_ZERO | M_WAITOK); 4908247122Snp 4909247122Snp rc = -t4_cim_read_la(sc, buf, NULL); 4910247122Snp if (rc != 0) 4911247122Snp goto done; 4912247122Snp 4913247122Snp sbuf_printf(sb, "Status Data PC%s", 4914247122Snp cfg & F_UPDBGLACAPTPCONLY ? "" : 4915247122Snp " LS0Stat LS0Addr LS0Data"); 4916247122Snp 4917247122Snp KASSERT((sc->params.cim_la_size & 7) == 0, 4918247122Snp ("%s: p will walk off the end of buf", __func__)); 4919247122Snp 4920247122Snp for (p = buf; p < &buf[sc->params.cim_la_size]; p += 8) { 4921247122Snp if (cfg & F_UPDBGLACAPTPCONLY) { 4922247122Snp sbuf_printf(sb, "\n %02x %08x %08x", p[5] & 0xff, 4923247122Snp p[6], p[7]); 4924247122Snp sbuf_printf(sb, "\n %02x %02x%06x %02x%06x", 4925247122Snp (p[3] >> 8) & 0xff, p[3] & 0xff, p[4] >> 8, 4926247122Snp p[4] & 0xff, p[5] >> 8); 4927247122Snp sbuf_printf(sb, "\n %02x %x%07x %x%07x", 4928247122Snp (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, 4929247122Snp p[1] & 0xf, p[2] >> 4); 4930247122Snp } else { 4931247122Snp sbuf_printf(sb, 4932247122Snp "\n %02x %x%07x %x%07x %08x %08x " 4933247122Snp "%08x%08x%08x%08x", 4934247122Snp (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, 4935247122Snp p[1] & 0xf, p[2] >> 4, p[2] & 0xf, p[3], p[4], p[5], 4936247122Snp p[6], p[7]); 4937247122Snp } 4938247122Snp } 4939247122Snp 4940247122Snp rc = sbuf_finish(sb); 4941247122Snp sbuf_delete(sb); 4942247122Snpdone: 4943247122Snp free(buf, M_CXGBE); 4944247122Snp return (rc); 4945247122Snp} 4946247122Snp 4947247122Snpstatic int 4948251213Snpsysctl_cim_ma_la(SYSCTL_HANDLER_ARGS) 4949251213Snp{ 4950251213Snp struct adapter *sc = arg1; 4951251213Snp u_int i; 4952251213Snp struct sbuf *sb; 4953251213Snp uint32_t *buf, *p; 4954251213Snp int rc; 4955251213Snp 4956251213Snp rc = sysctl_wire_old_buffer(req, 0); 4957251213Snp if (rc != 0) 4958251213Snp return (rc); 4959251213Snp 4960251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 4961251213Snp if (sb == NULL) 4962251213Snp return (ENOMEM); 4963251213Snp 4964251213Snp buf = malloc(2 * CIM_MALA_SIZE * 5 * sizeof(uint32_t), M_CXGBE, 4965251213Snp M_ZERO | M_WAITOK); 4966251213Snp 4967251213Snp t4_cim_read_ma_la(sc, buf, buf + 5 * CIM_MALA_SIZE); 4968251213Snp p = buf; 4969251213Snp 4970251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) { 4971251213Snp sbuf_printf(sb, "\n%02x%08x%08x%08x%08x", p[4], p[3], p[2], 4972251213Snp p[1], p[0]); 4973251213Snp } 4974251213Snp 4975251213Snp sbuf_printf(sb, "\n\nCnt ID Tag UE Data RDY VLD"); 4976251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) { 4977251213Snp sbuf_printf(sb, "\n%3u %2u %x %u %08x%08x %u %u", 4978251213Snp (p[2] >> 10) & 0xff, (p[2] >> 7) & 7, 4979251213Snp (p[2] >> 3) & 0xf, (p[2] >> 2) & 1, 4980251213Snp (p[1] >> 2) | ((p[2] & 3) << 30), 4981251213Snp (p[0] >> 2) | ((p[1] & 3) << 30), (p[0] >> 1) & 1, 4982251213Snp p[0] & 1); 4983251213Snp } 4984251213Snp 4985251213Snp rc = sbuf_finish(sb); 4986251213Snp sbuf_delete(sb); 4987251213Snp free(buf, M_CXGBE); 4988251213Snp return (rc); 4989251213Snp} 4990251213Snp 4991251213Snpstatic int 4992251213Snpsysctl_cim_pif_la(SYSCTL_HANDLER_ARGS) 4993251213Snp{ 4994251213Snp struct adapter *sc = arg1; 4995251213Snp u_int i; 4996251213Snp struct sbuf *sb; 4997251213Snp uint32_t *buf, *p; 4998251213Snp int rc; 4999251213Snp 5000251213Snp rc = sysctl_wire_old_buffer(req, 0); 5001251213Snp if (rc != 0) 5002251213Snp return (rc); 5003251213Snp 5004251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5005251213Snp if (sb == NULL) 5006251213Snp return (ENOMEM); 5007251213Snp 5008251213Snp buf = malloc(2 * CIM_PIFLA_SIZE * 6 * sizeof(uint32_t), M_CXGBE, 5009251213Snp M_ZERO | M_WAITOK); 5010251213Snp 5011251213Snp t4_cim_read_pif_la(sc, buf, buf + 6 * CIM_PIFLA_SIZE, NULL, NULL); 5012251213Snp p = buf; 5013251213Snp 5014251213Snp sbuf_printf(sb, "Cntl ID DataBE Addr Data"); 5015251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 6) { 5016251213Snp sbuf_printf(sb, "\n %02x %02x %04x %08x %08x%08x%08x%08x", 5017251213Snp (p[5] >> 22) & 0xff, (p[5] >> 16) & 0x3f, p[5] & 0xffff, 5018251213Snp p[4], p[3], p[2], p[1], p[0]); 5019251213Snp } 5020251213Snp 5021251213Snp sbuf_printf(sb, "\n\nCntl ID Data"); 5022251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 6) { 5023251213Snp sbuf_printf(sb, "\n %02x %02x %08x%08x%08x%08x", 5024251213Snp (p[4] >> 6) & 0xff, p[4] & 0x3f, p[3], p[2], p[1], p[0]); 5025251213Snp } 5026251213Snp 5027251213Snp rc = sbuf_finish(sb); 5028251213Snp sbuf_delete(sb); 5029251213Snp free(buf, M_CXGBE); 5030251213Snp return (rc); 5031251213Snp} 5032251213Snp 5033251213Snpstatic int 5034247122Snpsysctl_cim_qcfg(SYSCTL_HANDLER_ARGS) 5035247122Snp{ 5036247122Snp struct adapter *sc = arg1; 5037247122Snp struct sbuf *sb; 5038247122Snp int rc, i; 5039248925Snp uint16_t base[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; 5040248925Snp uint16_t size[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; 5041247122Snp uint16_t thres[CIM_NUM_IBQ]; 5042248925Snp uint32_t obq_wr[2 * CIM_NUM_OBQ_T5], *wr = obq_wr; 5043248925Snp uint32_t stat[4 * (CIM_NUM_IBQ + CIM_NUM_OBQ_T5)], *p = stat; 5044248925Snp u_int cim_num_obq, ibq_rdaddr, obq_rdaddr, nq; 5045247122Snp 5046248925Snp if (is_t4(sc)) { 5047248925Snp cim_num_obq = CIM_NUM_OBQ; 5048248925Snp ibq_rdaddr = A_UP_IBQ_0_RDADDR; 5049248925Snp obq_rdaddr = A_UP_OBQ_0_REALADDR; 5050248925Snp } else { 5051248925Snp cim_num_obq = CIM_NUM_OBQ_T5; 5052248925Snp ibq_rdaddr = A_UP_IBQ_0_SHADOW_RDADDR; 5053248925Snp obq_rdaddr = A_UP_OBQ_0_SHADOW_REALADDR; 5054248925Snp } 5055248925Snp nq = CIM_NUM_IBQ + cim_num_obq; 5056248925Snp 5057248925Snp rc = -t4_cim_read(sc, ibq_rdaddr, 4 * nq, stat); 5058247122Snp if (rc == 0) 5059248925Snp rc = -t4_cim_read(sc, obq_rdaddr, 2 * cim_num_obq, obq_wr); 5060247122Snp if (rc != 0) 5061247122Snp return (rc); 5062247122Snp 5063247122Snp t4_read_cimq_cfg(sc, base, size, thres); 5064247122Snp 5065247122Snp rc = sysctl_wire_old_buffer(req, 0); 5066247122Snp if (rc != 0) 5067247122Snp return (rc); 5068247122Snp 5069248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req); 5070247122Snp if (sb == NULL) 5071247122Snp return (ENOMEM); 5072247122Snp 5073247122Snp sbuf_printf(sb, "Queue Base Size Thres RdPtr WrPtr SOP EOP Avail"); 5074247122Snp 5075247122Snp for (i = 0; i < CIM_NUM_IBQ; i++, p += 4) 5076248925Snp sbuf_printf(sb, "\n%7s %5x %5u %5u %6x %4x %4u %4u %5u", 5077247122Snp qname[i], base[i], size[i], thres[i], G_IBQRDADDR(p[0]), 5078247122Snp G_IBQWRADDR(p[1]), G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), 5079247122Snp G_QUEREMFLITS(p[2]) * 16); 5080248925Snp for ( ; i < nq; i++, p += 4, wr += 2) 5081248925Snp sbuf_printf(sb, "\n%7s %5x %5u %12x %4x %4u %4u %5u", qname[i], 5082247122Snp base[i], size[i], G_QUERDADDR(p[0]) & 0x3fff, 5083247122Snp wr[0] - base[i], G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), 5084247122Snp G_QUEREMFLITS(p[2]) * 16); 5085247122Snp 5086247122Snp rc = sbuf_finish(sb); 5087247122Snp sbuf_delete(sb); 5088247122Snp 5089247122Snp return (rc); 5090247122Snp} 5091247122Snp 5092247122Snpstatic int 5093228561Snpsysctl_cpl_stats(SYSCTL_HANDLER_ARGS) 5094228561Snp{ 5095228561Snp struct adapter *sc = arg1; 5096228561Snp struct sbuf *sb; 5097228561Snp int rc; 5098228561Snp struct tp_cpl_stats stats; 5099228561Snp 5100228561Snp rc = sysctl_wire_old_buffer(req, 0); 5101228561Snp if (rc != 0) 5102228561Snp return (rc); 5103228561Snp 5104228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5105228561Snp if (sb == NULL) 5106228561Snp return (ENOMEM); 5107228561Snp 5108228561Snp t4_tp_get_cpl_stats(sc, &stats); 5109228561Snp 5110228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 5111228561Snp "channel 3\n"); 5112228561Snp sbuf_printf(sb, "CPL requests: %10u %10u %10u %10u\n", 5113228561Snp stats.req[0], stats.req[1], stats.req[2], stats.req[3]); 5114228561Snp sbuf_printf(sb, "CPL responses: %10u %10u %10u %10u", 5115228561Snp stats.rsp[0], stats.rsp[1], stats.rsp[2], stats.rsp[3]); 5116228561Snp 5117228561Snp rc = sbuf_finish(sb); 5118228561Snp sbuf_delete(sb); 5119228561Snp 5120228561Snp return (rc); 5121228561Snp} 5122228561Snp 5123228561Snpstatic int 5124228561Snpsysctl_ddp_stats(SYSCTL_HANDLER_ARGS) 5125228561Snp{ 5126228561Snp struct adapter *sc = arg1; 5127228561Snp struct sbuf *sb; 5128228561Snp int rc; 5129228561Snp struct tp_usm_stats stats; 5130228561Snp 5131228561Snp rc = sysctl_wire_old_buffer(req, 0); 5132228561Snp if (rc != 0) 5133228561Snp return(rc); 5134228561Snp 5135228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5136228561Snp if (sb == NULL) 5137228561Snp return (ENOMEM); 5138228561Snp 5139228561Snp t4_get_usm_stats(sc, &stats); 5140228561Snp 5141228561Snp sbuf_printf(sb, "Frames: %u\n", stats.frames); 5142228561Snp sbuf_printf(sb, "Octets: %ju\n", stats.octets); 5143228561Snp sbuf_printf(sb, "Drops: %u", stats.drops); 5144228561Snp 5145228561Snp rc = sbuf_finish(sb); 5146228561Snp sbuf_delete(sb); 5147228561Snp 5148228561Snp return (rc); 5149228561Snp} 5150228561Snp 5151222551Snpconst char *devlog_level_strings[] = { 5152222551Snp [FW_DEVLOG_LEVEL_EMERG] = "EMERG", 5153222551Snp [FW_DEVLOG_LEVEL_CRIT] = "CRIT", 5154222551Snp [FW_DEVLOG_LEVEL_ERR] = "ERR", 5155222551Snp [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", 5156222551Snp [FW_DEVLOG_LEVEL_INFO] = "INFO", 5157222551Snp [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" 5158222551Snp}; 5159222551Snp 5160222551Snpconst char *devlog_facility_strings[] = { 5161222551Snp [FW_DEVLOG_FACILITY_CORE] = "CORE", 5162222551Snp [FW_DEVLOG_FACILITY_SCHED] = "SCHED", 5163222551Snp [FW_DEVLOG_FACILITY_TIMER] = "TIMER", 5164222551Snp [FW_DEVLOG_FACILITY_RES] = "RES", 5165222551Snp [FW_DEVLOG_FACILITY_HW] = "HW", 5166222551Snp [FW_DEVLOG_FACILITY_FLR] = "FLR", 5167222551Snp [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", 5168222551Snp [FW_DEVLOG_FACILITY_PHY] = "PHY", 5169222551Snp [FW_DEVLOG_FACILITY_MAC] = "MAC", 5170222551Snp [FW_DEVLOG_FACILITY_PORT] = "PORT", 5171222551Snp [FW_DEVLOG_FACILITY_VI] = "VI", 5172222551Snp [FW_DEVLOG_FACILITY_FILTER] = "FILTER", 5173222551Snp [FW_DEVLOG_FACILITY_ACL] = "ACL", 5174222551Snp [FW_DEVLOG_FACILITY_TM] = "TM", 5175222551Snp [FW_DEVLOG_FACILITY_QFC] = "QFC", 5176222551Snp [FW_DEVLOG_FACILITY_DCB] = "DCB", 5177222551Snp [FW_DEVLOG_FACILITY_ETH] = "ETH", 5178222551Snp [FW_DEVLOG_FACILITY_OFLD] = "OFLD", 5179222551Snp [FW_DEVLOG_FACILITY_RI] = "RI", 5180222551Snp [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", 5181222551Snp [FW_DEVLOG_FACILITY_FCOE] = "FCOE", 5182222551Snp [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", 5183222551Snp [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE" 5184222551Snp}; 5185222551Snp 5186222551Snpstatic int 5187222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS) 5188222551Snp{ 5189222551Snp struct adapter *sc = arg1; 5190222551Snp struct devlog_params *dparams = &sc->params.devlog; 5191222551Snp struct fw_devlog_e *buf, *e; 5192222551Snp int i, j, rc, nentries, first = 0; 5193222551Snp struct sbuf *sb; 5194222551Snp uint64_t ftstamp = UINT64_MAX; 5195222551Snp 5196248925Snp if (dparams->start == 0) { 5197248925Snp dparams->memtype = 0; 5198248925Snp dparams->start = 0x84000; 5199248925Snp dparams->size = 32768; 5200248925Snp } 5201222551Snp 5202222551Snp nentries = dparams->size / sizeof(struct fw_devlog_e); 5203222551Snp 5204222551Snp buf = malloc(dparams->size, M_CXGBE, M_NOWAIT); 5205222551Snp if (buf == NULL) 5206222551Snp return (ENOMEM); 5207222551Snp 5208222551Snp rc = -t4_mem_read(sc, dparams->memtype, dparams->start, dparams->size, 5209222551Snp (void *)buf); 5210222551Snp if (rc != 0) 5211222551Snp goto done; 5212222551Snp 5213222551Snp for (i = 0; i < nentries; i++) { 5214222551Snp e = &buf[i]; 5215222551Snp 5216222551Snp if (e->timestamp == 0) 5217222551Snp break; /* end */ 5218222551Snp 5219222551Snp e->timestamp = be64toh(e->timestamp); 5220222551Snp e->seqno = be32toh(e->seqno); 5221222551Snp for (j = 0; j < 8; j++) 5222222551Snp e->params[j] = be32toh(e->params[j]); 5223222551Snp 5224222551Snp if (e->timestamp < ftstamp) { 5225222551Snp ftstamp = e->timestamp; 5226222551Snp first = i; 5227222551Snp } 5228222551Snp } 5229222551Snp 5230222551Snp if (buf[first].timestamp == 0) 5231222551Snp goto done; /* nothing in the log */ 5232222551Snp 5233222551Snp rc = sysctl_wire_old_buffer(req, 0); 5234222551Snp if (rc != 0) 5235222551Snp goto done; 5236222551Snp 5237222551Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5238228561Snp if (sb == NULL) { 5239228561Snp rc = ENOMEM; 5240228561Snp goto done; 5241228561Snp } 5242228561Snp sbuf_printf(sb, "%10s %15s %8s %8s %s\n", 5243222551Snp "Seq#", "Tstamp", "Level", "Facility", "Message"); 5244222551Snp 5245222551Snp i = first; 5246222551Snp do { 5247222551Snp e = &buf[i]; 5248222551Snp if (e->timestamp == 0) 5249222551Snp break; /* end */ 5250222551Snp 5251222551Snp sbuf_printf(sb, "%10d %15ju %8s %8s ", 5252222551Snp e->seqno, e->timestamp, 5253240452Snp (e->level < nitems(devlog_level_strings) ? 5254222551Snp devlog_level_strings[e->level] : "UNKNOWN"), 5255240452Snp (e->facility < nitems(devlog_facility_strings) ? 5256222551Snp devlog_facility_strings[e->facility] : "UNKNOWN")); 5257222551Snp sbuf_printf(sb, e->fmt, e->params[0], e->params[1], 5258222551Snp e->params[2], e->params[3], e->params[4], 5259222551Snp e->params[5], e->params[6], e->params[7]); 5260222551Snp 5261222551Snp if (++i == nentries) 5262222551Snp i = 0; 5263222551Snp } while (i != first); 5264222551Snp 5265222551Snp rc = sbuf_finish(sb); 5266222551Snp sbuf_delete(sb); 5267222551Snpdone: 5268222551Snp free(buf, M_CXGBE); 5269222551Snp return (rc); 5270222551Snp} 5271222551Snp 5272228561Snpstatic int 5273228561Snpsysctl_fcoe_stats(SYSCTL_HANDLER_ARGS) 5274228561Snp{ 5275228561Snp struct adapter *sc = arg1; 5276228561Snp struct sbuf *sb; 5277228561Snp int rc; 5278228561Snp struct tp_fcoe_stats stats[4]; 5279228561Snp 5280228561Snp rc = sysctl_wire_old_buffer(req, 0); 5281228561Snp if (rc != 0) 5282228561Snp return (rc); 5283228561Snp 5284228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5285228561Snp if (sb == NULL) 5286228561Snp return (ENOMEM); 5287228561Snp 5288228561Snp t4_get_fcoe_stats(sc, 0, &stats[0]); 5289228561Snp t4_get_fcoe_stats(sc, 1, &stats[1]); 5290228561Snp t4_get_fcoe_stats(sc, 2, &stats[2]); 5291228561Snp t4_get_fcoe_stats(sc, 3, &stats[3]); 5292228561Snp 5293228561Snp sbuf_printf(sb, " channel 0 channel 1 " 5294228561Snp "channel 2 channel 3\n"); 5295228561Snp sbuf_printf(sb, "octetsDDP: %16ju %16ju %16ju %16ju\n", 5296228561Snp stats[0].octetsDDP, stats[1].octetsDDP, stats[2].octetsDDP, 5297228561Snp stats[3].octetsDDP); 5298228561Snp sbuf_printf(sb, "framesDDP: %16u %16u %16u %16u\n", stats[0].framesDDP, 5299228561Snp stats[1].framesDDP, stats[2].framesDDP, stats[3].framesDDP); 5300228561Snp sbuf_printf(sb, "framesDrop: %16u %16u %16u %16u", 5301228561Snp stats[0].framesDrop, stats[1].framesDrop, stats[2].framesDrop, 5302228561Snp stats[3].framesDrop); 5303228561Snp 5304228561Snp rc = sbuf_finish(sb); 5305228561Snp sbuf_delete(sb); 5306228561Snp 5307228561Snp return (rc); 5308228561Snp} 5309228561Snp 5310228561Snpstatic int 5311228561Snpsysctl_hw_sched(SYSCTL_HANDLER_ARGS) 5312228561Snp{ 5313228561Snp struct adapter *sc = arg1; 5314228561Snp struct sbuf *sb; 5315228561Snp int rc, i; 5316228561Snp unsigned int map, kbps, ipg, mode; 5317228561Snp unsigned int pace_tab[NTX_SCHED]; 5318228561Snp 5319228561Snp rc = sysctl_wire_old_buffer(req, 0); 5320228561Snp if (rc != 0) 5321228561Snp return (rc); 5322228561Snp 5323228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5324228561Snp if (sb == NULL) 5325228561Snp return (ENOMEM); 5326228561Snp 5327228561Snp map = t4_read_reg(sc, A_TP_TX_MOD_QUEUE_REQ_MAP); 5328228561Snp mode = G_TIMERMODE(t4_read_reg(sc, A_TP_MOD_CONFIG)); 5329228561Snp t4_read_pace_tbl(sc, pace_tab); 5330228561Snp 5331228561Snp sbuf_printf(sb, "Scheduler Mode Channel Rate (Kbps) " 5332228561Snp "Class IPG (0.1 ns) Flow IPG (us)"); 5333228561Snp 5334228561Snp for (i = 0; i < NTX_SCHED; ++i, map >>= 2) { 5335228561Snp t4_get_tx_sched(sc, i, &kbps, &ipg); 5336228561Snp sbuf_printf(sb, "\n %u %-5s %u ", i, 5337228561Snp (mode & (1 << i)) ? "flow" : "class", map & 3); 5338228561Snp if (kbps) 5339228561Snp sbuf_printf(sb, "%9u ", kbps); 5340228561Snp else 5341228561Snp sbuf_printf(sb, " disabled "); 5342228561Snp 5343228561Snp if (ipg) 5344228561Snp sbuf_printf(sb, "%13u ", ipg); 5345228561Snp else 5346228561Snp sbuf_printf(sb, " disabled "); 5347228561Snp 5348228561Snp if (pace_tab[i]) 5349228561Snp sbuf_printf(sb, "%10u", pace_tab[i]); 5350228561Snp else 5351228561Snp sbuf_printf(sb, " disabled"); 5352228561Snp } 5353228561Snp 5354228561Snp rc = sbuf_finish(sb); 5355228561Snp sbuf_delete(sb); 5356228561Snp 5357228561Snp return (rc); 5358228561Snp} 5359228561Snp 5360228561Snpstatic int 5361228561Snpsysctl_lb_stats(SYSCTL_HANDLER_ARGS) 5362228561Snp{ 5363228561Snp struct adapter *sc = arg1; 5364228561Snp struct sbuf *sb; 5365228561Snp int rc, i, j; 5366228561Snp uint64_t *p0, *p1; 5367228561Snp struct lb_port_stats s[2]; 5368228561Snp static const char *stat_name[] = { 5369228561Snp "OctetsOK:", "FramesOK:", "BcastFrames:", "McastFrames:", 5370228561Snp "UcastFrames:", "ErrorFrames:", "Frames64:", "Frames65To127:", 5371228561Snp "Frames128To255:", "Frames256To511:", "Frames512To1023:", 5372228561Snp "Frames1024To1518:", "Frames1519ToMax:", "FramesDropped:", 5373228561Snp "BG0FramesDropped:", "BG1FramesDropped:", "BG2FramesDropped:", 5374228561Snp "BG3FramesDropped:", "BG0FramesTrunc:", "BG1FramesTrunc:", 5375228561Snp "BG2FramesTrunc:", "BG3FramesTrunc:" 5376228561Snp }; 5377228561Snp 5378228561Snp rc = sysctl_wire_old_buffer(req, 0); 5379228561Snp if (rc != 0) 5380228561Snp return (rc); 5381228561Snp 5382228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5383228561Snp if (sb == NULL) 5384228561Snp return (ENOMEM); 5385228561Snp 5386228561Snp memset(s, 0, sizeof(s)); 5387228561Snp 5388228561Snp for (i = 0; i < 4; i += 2) { 5389228561Snp t4_get_lb_stats(sc, i, &s[0]); 5390228561Snp t4_get_lb_stats(sc, i + 1, &s[1]); 5391228561Snp 5392228561Snp p0 = &s[0].octets; 5393228561Snp p1 = &s[1].octets; 5394228561Snp sbuf_printf(sb, "%s Loopback %u" 5395228561Snp " Loopback %u", i == 0 ? "" : "\n", i, i + 1); 5396228561Snp 5397240452Snp for (j = 0; j < nitems(stat_name); j++) 5398228561Snp sbuf_printf(sb, "\n%-17s %20ju %20ju", stat_name[j], 5399228561Snp *p0++, *p1++); 5400228561Snp } 5401228561Snp 5402228561Snp rc = sbuf_finish(sb); 5403228561Snp sbuf_delete(sb); 5404228561Snp 5405228561Snp return (rc); 5406228561Snp} 5407228561Snp 5408228561Snpstruct mem_desc { 5409228561Snp unsigned int base; 5410228561Snp unsigned int limit; 5411228561Snp unsigned int idx; 5412228561Snp}; 5413228561Snp 5414228561Snpstatic int 5415228561Snpmem_desc_cmp(const void *a, const void *b) 5416228561Snp{ 5417228561Snp return ((const struct mem_desc *)a)->base - 5418228561Snp ((const struct mem_desc *)b)->base; 5419228561Snp} 5420228561Snp 5421228561Snpstatic void 5422228561Snpmem_region_show(struct sbuf *sb, const char *name, unsigned int from, 5423228561Snp unsigned int to) 5424228561Snp{ 5425228561Snp unsigned int size; 5426228561Snp 5427228561Snp size = to - from + 1; 5428228561Snp if (size == 0) 5429228561Snp return; 5430228561Snp 5431228561Snp /* XXX: need humanize_number(3) in libkern for a more readable 'size' */ 5432228561Snp sbuf_printf(sb, "%-15s %#x-%#x [%u]\n", name, from, to, size); 5433228561Snp} 5434228561Snp 5435228561Snpstatic int 5436228561Snpsysctl_meminfo(SYSCTL_HANDLER_ARGS) 5437228561Snp{ 5438228561Snp struct adapter *sc = arg1; 5439228561Snp struct sbuf *sb; 5440228561Snp int rc, i, n; 5441248925Snp uint32_t lo, hi, used, alloc; 5442248925Snp static const char *memory[] = {"EDC0:", "EDC1:", "MC:", "MC0:", "MC1:"}; 5443228561Snp static const char *region[] = { 5444228561Snp "DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:", 5445228561Snp "Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:", 5446228561Snp "Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:", 5447228561Snp "TDDP region:", "TPT region:", "STAG region:", "RQ region:", 5448248925Snp "RQUDP region:", "PBL region:", "TXPBL region:", 5449248925Snp "DBVFIFO region:", "ULPRX state:", "ULPTX state:", 5450248925Snp "On-chip queues:" 5451228561Snp }; 5452248925Snp struct mem_desc avail[4]; 5453240452Snp struct mem_desc mem[nitems(region) + 3]; /* up to 3 holes */ 5454228561Snp struct mem_desc *md = mem; 5455228561Snp 5456228561Snp rc = sysctl_wire_old_buffer(req, 0); 5457228561Snp if (rc != 0) 5458228561Snp return (rc); 5459228561Snp 5460228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5461228561Snp if (sb == NULL) 5462228561Snp return (ENOMEM); 5463228561Snp 5464240452Snp for (i = 0; i < nitems(mem); i++) { 5465228561Snp mem[i].limit = 0; 5466228561Snp mem[i].idx = i; 5467228561Snp } 5468228561Snp 5469228561Snp /* Find and sort the populated memory ranges */ 5470228561Snp i = 0; 5471228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 5472228561Snp if (lo & F_EDRAM0_ENABLE) { 5473228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 5474228561Snp avail[i].base = G_EDRAM0_BASE(hi) << 20; 5475228561Snp avail[i].limit = avail[i].base + (G_EDRAM0_SIZE(hi) << 20); 5476228561Snp avail[i].idx = 0; 5477228561Snp i++; 5478228561Snp } 5479228561Snp if (lo & F_EDRAM1_ENABLE) { 5480228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 5481228561Snp avail[i].base = G_EDRAM1_BASE(hi) << 20; 5482228561Snp avail[i].limit = avail[i].base + (G_EDRAM1_SIZE(hi) << 20); 5483228561Snp avail[i].idx = 1; 5484228561Snp i++; 5485228561Snp } 5486228561Snp if (lo & F_EXT_MEM_ENABLE) { 5487228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 5488228561Snp avail[i].base = G_EXT_MEM_BASE(hi) << 20; 5489248925Snp avail[i].limit = avail[i].base + 5490248925Snp (G_EXT_MEM_SIZE(hi) << 20); 5491248925Snp avail[i].idx = is_t4(sc) ? 2 : 3; /* Call it MC for T4 */ 5492228561Snp i++; 5493228561Snp } 5494248925Snp if (!is_t4(sc) && lo & F_EXT_MEM1_ENABLE) { 5495248925Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 5496248925Snp avail[i].base = G_EXT_MEM1_BASE(hi) << 20; 5497248925Snp avail[i].limit = avail[i].base + 5498248925Snp (G_EXT_MEM1_SIZE(hi) << 20); 5499248925Snp avail[i].idx = 4; 5500248925Snp i++; 5501248925Snp } 5502228561Snp if (!i) /* no memory available */ 5503228561Snp return 0; 5504228561Snp qsort(avail, i, sizeof(struct mem_desc), mem_desc_cmp); 5505228561Snp 5506228561Snp (md++)->base = t4_read_reg(sc, A_SGE_DBQ_CTXT_BADDR); 5507228561Snp (md++)->base = t4_read_reg(sc, A_SGE_IMSG_CTXT_BADDR); 5508228561Snp (md++)->base = t4_read_reg(sc, A_SGE_FLM_CACHE_BADDR); 5509228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 5510228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_BASE); 5511228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TIMER_BASE); 5512228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_RX_FLST_BASE); 5513228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_TX_FLST_BASE); 5514228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_PS_FLST_BASE); 5515228561Snp 5516228561Snp /* the next few have explicit upper bounds */ 5517228561Snp md->base = t4_read_reg(sc, A_TP_PMM_TX_BASE); 5518228561Snp md->limit = md->base - 1 + 5519228561Snp t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE) * 5520228561Snp G_PMTXMAXPAGE(t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE)); 5521228561Snp md++; 5522228561Snp 5523228561Snp md->base = t4_read_reg(sc, A_TP_PMM_RX_BASE); 5524228561Snp md->limit = md->base - 1 + 5525228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) * 5526228561Snp G_PMRXMAXPAGE(t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE)); 5527228561Snp md++; 5528228561Snp 5529228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 5530228561Snp hi = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4; 5531228561Snp md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE); 5532228561Snp md->limit = (sc->tids.ntids - hi) * 16 + md->base - 1; 5533228561Snp } else { 5534228561Snp md->base = 0; 5535240452Snp md->idx = nitems(region); /* hide it */ 5536228561Snp } 5537228561Snp md++; 5538228561Snp 5539228561Snp#define ulp_region(reg) \ 5540228561Snp md->base = t4_read_reg(sc, A_ULP_ ## reg ## _LLIMIT);\ 5541228561Snp (md++)->limit = t4_read_reg(sc, A_ULP_ ## reg ## _ULIMIT) 5542228561Snp 5543228561Snp ulp_region(RX_ISCSI); 5544228561Snp ulp_region(RX_TDDP); 5545228561Snp ulp_region(TX_TPT); 5546228561Snp ulp_region(RX_STAG); 5547228561Snp ulp_region(RX_RQ); 5548228561Snp ulp_region(RX_RQUDP); 5549228561Snp ulp_region(RX_PBL); 5550228561Snp ulp_region(TX_PBL); 5551228561Snp#undef ulp_region 5552228561Snp 5553248925Snp md->base = 0; 5554248925Snp md->idx = nitems(region); 5555248925Snp if (!is_t4(sc) && t4_read_reg(sc, A_SGE_CONTROL2) & F_VFIFO_ENABLE) { 5556248925Snp md->base = G_BASEADDR(t4_read_reg(sc, A_SGE_DBVFIFO_BADDR)); 5557248925Snp md->limit = md->base + (G_DBVFIFO_SIZE((t4_read_reg(sc, 5558248925Snp A_SGE_DBVFIFO_SIZE))) << 2) - 1; 5559248925Snp } 5560248925Snp md++; 5561248925Snp 5562228561Snp md->base = t4_read_reg(sc, A_ULP_RX_CTX_BASE); 5563228561Snp md->limit = md->base + sc->tids.ntids - 1; 5564228561Snp md++; 5565228561Snp md->base = t4_read_reg(sc, A_ULP_TX_ERR_TABLE_BASE); 5566228561Snp md->limit = md->base + sc->tids.ntids - 1; 5567228561Snp md++; 5568228561Snp 5569228561Snp md->base = sc->vres.ocq.start; 5570228561Snp if (sc->vres.ocq.size) 5571228561Snp md->limit = md->base + sc->vres.ocq.size - 1; 5572228561Snp else 5573240452Snp md->idx = nitems(region); /* hide it */ 5574228561Snp md++; 5575228561Snp 5576228561Snp /* add any address-space holes, there can be up to 3 */ 5577228561Snp for (n = 0; n < i - 1; n++) 5578228561Snp if (avail[n].limit < avail[n + 1].base) 5579228561Snp (md++)->base = avail[n].limit; 5580228561Snp if (avail[n].limit) 5581228561Snp (md++)->base = avail[n].limit; 5582228561Snp 5583228561Snp n = md - mem; 5584228561Snp qsort(mem, n, sizeof(struct mem_desc), mem_desc_cmp); 5585228561Snp 5586228561Snp for (lo = 0; lo < i; lo++) 5587228561Snp mem_region_show(sb, memory[avail[lo].idx], avail[lo].base, 5588228561Snp avail[lo].limit - 1); 5589228561Snp 5590228561Snp sbuf_printf(sb, "\n"); 5591228561Snp for (i = 0; i < n; i++) { 5592240452Snp if (mem[i].idx >= nitems(region)) 5593228561Snp continue; /* skip holes */ 5594228561Snp if (!mem[i].limit) 5595228561Snp mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0; 5596228561Snp mem_region_show(sb, region[mem[i].idx], mem[i].base, 5597228561Snp mem[i].limit); 5598228561Snp } 5599228561Snp 5600228561Snp sbuf_printf(sb, "\n"); 5601228561Snp lo = t4_read_reg(sc, A_CIM_SDRAM_BASE_ADDR); 5602228561Snp hi = t4_read_reg(sc, A_CIM_SDRAM_ADDR_SIZE) + lo - 1; 5603228561Snp mem_region_show(sb, "uP RAM:", lo, hi); 5604228561Snp 5605228561Snp lo = t4_read_reg(sc, A_CIM_EXTMEM2_BASE_ADDR); 5606228561Snp hi = t4_read_reg(sc, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1; 5607228561Snp mem_region_show(sb, "uP Extmem2:", lo, hi); 5608228561Snp 5609228561Snp lo = t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE); 5610228561Snp sbuf_printf(sb, "\n%u Rx pages of size %uKiB for %u channels\n", 5611228561Snp G_PMRXMAXPAGE(lo), 5612228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) >> 10, 5613228561Snp (lo & F_PMRXNUMCHN) ? 2 : 1); 5614228561Snp 5615228561Snp lo = t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE); 5616228561Snp hi = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE); 5617228561Snp sbuf_printf(sb, "%u Tx pages of size %u%ciB for %u channels\n", 5618228561Snp G_PMTXMAXPAGE(lo), 5619228561Snp hi >= (1 << 20) ? (hi >> 20) : (hi >> 10), 5620228561Snp hi >= (1 << 20) ? 'M' : 'K', 1 << G_PMTXNUMCHN(lo)); 5621228561Snp sbuf_printf(sb, "%u p-structs\n", 5622228561Snp t4_read_reg(sc, A_TP_CMM_MM_MAX_PSTRUCT)); 5623228561Snp 5624228561Snp for (i = 0; i < 4; i++) { 5625228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV0 + i * 4); 5626248925Snp if (is_t4(sc)) { 5627248925Snp used = G_USED(lo); 5628248925Snp alloc = G_ALLOC(lo); 5629248925Snp } else { 5630248925Snp used = G_T5_USED(lo); 5631248925Snp alloc = G_T5_ALLOC(lo); 5632248925Snp } 5633228561Snp sbuf_printf(sb, "\nPort %d using %u pages out of %u allocated", 5634248925Snp i, used, alloc); 5635228561Snp } 5636228561Snp for (i = 0; i < 4; i++) { 5637228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV4 + i * 4); 5638248925Snp if (is_t4(sc)) { 5639248925Snp used = G_USED(lo); 5640248925Snp alloc = G_ALLOC(lo); 5641248925Snp } else { 5642248925Snp used = G_T5_USED(lo); 5643248925Snp alloc = G_T5_ALLOC(lo); 5644248925Snp } 5645228561Snp sbuf_printf(sb, 5646228561Snp "\nLoopback %d using %u pages out of %u allocated", 5647248925Snp i, used, alloc); 5648228561Snp } 5649228561Snp 5650228561Snp rc = sbuf_finish(sb); 5651228561Snp sbuf_delete(sb); 5652228561Snp 5653228561Snp return (rc); 5654228561Snp} 5655228561Snp 5656251213Snpstatic inline void 5657251213Snptcamxy2valmask(uint64_t x, uint64_t y, uint8_t *addr, uint64_t *mask) 5658251213Snp{ 5659251213Snp *mask = x | y; 5660251213Snp y = htobe64(y); 5661251213Snp memcpy(addr, (char *)&y + 2, ETHER_ADDR_LEN); 5662251213Snp} 5663251213Snp 5664228561Snpstatic int 5665251213Snpsysctl_mps_tcam(SYSCTL_HANDLER_ARGS) 5666251213Snp{ 5667251213Snp struct adapter *sc = arg1; 5668251213Snp struct sbuf *sb; 5669251213Snp int rc, i, n; 5670251213Snp 5671251213Snp rc = sysctl_wire_old_buffer(req, 0); 5672251213Snp if (rc != 0) 5673251213Snp return (rc); 5674251213Snp 5675251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5676251213Snp if (sb == NULL) 5677251213Snp return (ENOMEM); 5678251213Snp 5679251213Snp sbuf_printf(sb, 5680251213Snp "Idx Ethernet address Mask Vld Ports PF" 5681251213Snp " VF Replication P0 P1 P2 P3 ML"); 5682251213Snp n = is_t4(sc) ? NUM_MPS_CLS_SRAM_L_INSTANCES : 5683251213Snp NUM_MPS_T5_CLS_SRAM_L_INSTANCES; 5684251213Snp for (i = 0; i < n; i++) { 5685251213Snp uint64_t tcamx, tcamy, mask; 5686251213Snp uint32_t cls_lo, cls_hi; 5687251213Snp uint8_t addr[ETHER_ADDR_LEN]; 5688251213Snp 5689251213Snp tcamy = t4_read_reg64(sc, MPS_CLS_TCAM_Y_L(i)); 5690251213Snp tcamx = t4_read_reg64(sc, MPS_CLS_TCAM_X_L(i)); 5691251213Snp cls_lo = t4_read_reg(sc, MPS_CLS_SRAM_L(i)); 5692251213Snp cls_hi = t4_read_reg(sc, MPS_CLS_SRAM_H(i)); 5693251213Snp 5694251213Snp if (tcamx & tcamy) 5695251213Snp continue; 5696251213Snp 5697251213Snp tcamxy2valmask(tcamx, tcamy, addr, &mask); 5698251213Snp sbuf_printf(sb, "\n%3u %02x:%02x:%02x:%02x:%02x:%02x %012jx" 5699251213Snp " %c %#x%4u%4d", i, addr[0], addr[1], addr[2], 5700251213Snp addr[3], addr[4], addr[5], (uintmax_t)mask, 5701251213Snp (cls_lo & F_SRAM_VLD) ? 'Y' : 'N', 5702251213Snp G_PORTMAP(cls_hi), G_PF(cls_lo), 5703251213Snp (cls_lo & F_VF_VALID) ? G_VF(cls_lo) : -1); 5704251213Snp 5705251213Snp if (cls_lo & F_REPLICATE) { 5706251213Snp struct fw_ldst_cmd ldst_cmd; 5707251213Snp 5708251213Snp memset(&ldst_cmd, 0, sizeof(ldst_cmd)); 5709251213Snp ldst_cmd.op_to_addrspace = 5710251213Snp htobe32(V_FW_CMD_OP(FW_LDST_CMD) | 5711251213Snp F_FW_CMD_REQUEST | F_FW_CMD_READ | 5712251213Snp V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MPS)); 5713251213Snp ldst_cmd.cycles_to_len16 = htobe32(FW_LEN16(ldst_cmd)); 5714251213Snp ldst_cmd.u.mps.fid_ctl = 5715251213Snp htobe16(V_FW_LDST_CMD_FID(FW_LDST_MPS_RPLC) | 5716251213Snp V_FW_LDST_CMD_CTL(i)); 5717251213Snp 5718251213Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, 5719251213Snp "t4mps"); 5720251213Snp if (rc) 5721251213Snp break; 5722251213Snp rc = -t4_wr_mbox(sc, sc->mbox, &ldst_cmd, 5723251213Snp sizeof(ldst_cmd), &ldst_cmd); 5724251213Snp end_synchronized_op(sc, 0); 5725251213Snp 5726251213Snp if (rc != 0) { 5727251213Snp sbuf_printf(sb, 5728251213Snp " ------------ error %3u ------------", rc); 5729251213Snp rc = 0; 5730251213Snp } else { 5731251213Snp sbuf_printf(sb, " %08x %08x %08x %08x", 5732251213Snp be32toh(ldst_cmd.u.mps.rplc127_96), 5733251213Snp be32toh(ldst_cmd.u.mps.rplc95_64), 5734251213Snp be32toh(ldst_cmd.u.mps.rplc63_32), 5735251213Snp be32toh(ldst_cmd.u.mps.rplc31_0)); 5736251213Snp } 5737251213Snp } else 5738251213Snp sbuf_printf(sb, "%36s", ""); 5739251213Snp 5740251213Snp sbuf_printf(sb, "%4u%3u%3u%3u %#3x", G_SRAM_PRIO0(cls_lo), 5741251213Snp G_SRAM_PRIO1(cls_lo), G_SRAM_PRIO2(cls_lo), 5742251213Snp G_SRAM_PRIO3(cls_lo), (cls_lo >> S_MULTILISTEN0) & 0xf); 5743251213Snp } 5744251213Snp 5745251213Snp if (rc) 5746251213Snp (void) sbuf_finish(sb); 5747251213Snp else 5748251213Snp rc = sbuf_finish(sb); 5749251213Snp sbuf_delete(sb); 5750251213Snp 5751251213Snp return (rc); 5752251213Snp} 5753251213Snp 5754251213Snpstatic int 5755228561Snpsysctl_path_mtus(SYSCTL_HANDLER_ARGS) 5756228561Snp{ 5757228561Snp struct adapter *sc = arg1; 5758228561Snp struct sbuf *sb; 5759228561Snp int rc; 5760228561Snp uint16_t mtus[NMTUS]; 5761228561Snp 5762228561Snp rc = sysctl_wire_old_buffer(req, 0); 5763228561Snp if (rc != 0) 5764228561Snp return (rc); 5765228561Snp 5766228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5767228561Snp if (sb == NULL) 5768228561Snp return (ENOMEM); 5769228561Snp 5770228561Snp t4_read_mtu_tbl(sc, mtus, NULL); 5771228561Snp 5772228561Snp sbuf_printf(sb, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", 5773228561Snp mtus[0], mtus[1], mtus[2], mtus[3], mtus[4], mtus[5], mtus[6], 5774228561Snp mtus[7], mtus[8], mtus[9], mtus[10], mtus[11], mtus[12], mtus[13], 5775228561Snp mtus[14], mtus[15]); 5776228561Snp 5777228561Snp rc = sbuf_finish(sb); 5778228561Snp sbuf_delete(sb); 5779228561Snp 5780228561Snp return (rc); 5781228561Snp} 5782228561Snp 5783228561Snpstatic int 5784228561Snpsysctl_pm_stats(SYSCTL_HANDLER_ARGS) 5785228561Snp{ 5786228561Snp struct adapter *sc = arg1; 5787228561Snp struct sbuf *sb; 5788228561Snp int rc, i; 5789228561Snp uint32_t tx_cnt[PM_NSTATS], rx_cnt[PM_NSTATS]; 5790228561Snp uint64_t tx_cyc[PM_NSTATS], rx_cyc[PM_NSTATS]; 5791228561Snp static const char *pm_stats[] = { 5792228561Snp "Read:", "Write bypass:", "Write mem:", "Flush:", "FIFO wait:" 5793228561Snp }; 5794228561Snp 5795228561Snp rc = sysctl_wire_old_buffer(req, 0); 5796228561Snp if (rc != 0) 5797228561Snp return (rc); 5798228561Snp 5799228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5800228561Snp if (sb == NULL) 5801228561Snp return (ENOMEM); 5802228561Snp 5803228561Snp t4_pmtx_get_stats(sc, tx_cnt, tx_cyc); 5804228561Snp t4_pmrx_get_stats(sc, rx_cnt, rx_cyc); 5805228561Snp 5806228561Snp sbuf_printf(sb, " Tx count Tx cycles " 5807228561Snp "Rx count Rx cycles"); 5808228561Snp for (i = 0; i < PM_NSTATS; i++) 5809228561Snp sbuf_printf(sb, "\n%-13s %10u %20ju %10u %20ju", 5810228561Snp pm_stats[i], tx_cnt[i], tx_cyc[i], rx_cnt[i], rx_cyc[i]); 5811228561Snp 5812228561Snp rc = sbuf_finish(sb); 5813228561Snp sbuf_delete(sb); 5814228561Snp 5815228561Snp return (rc); 5816228561Snp} 5817228561Snp 5818228561Snpstatic int 5819228561Snpsysctl_rdma_stats(SYSCTL_HANDLER_ARGS) 5820228561Snp{ 5821228561Snp struct adapter *sc = arg1; 5822228561Snp struct sbuf *sb; 5823228561Snp int rc; 5824228561Snp struct tp_rdma_stats stats; 5825228561Snp 5826228561Snp rc = sysctl_wire_old_buffer(req, 0); 5827228561Snp if (rc != 0) 5828228561Snp return (rc); 5829228561Snp 5830228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5831228561Snp if (sb == NULL) 5832228561Snp return (ENOMEM); 5833228561Snp 5834228561Snp t4_tp_get_rdma_stats(sc, &stats); 5835228561Snp sbuf_printf(sb, "NoRQEModDefferals: %u\n", stats.rqe_dfr_mod); 5836228561Snp sbuf_printf(sb, "NoRQEPktDefferals: %u", stats.rqe_dfr_pkt); 5837228561Snp 5838228561Snp rc = sbuf_finish(sb); 5839228561Snp sbuf_delete(sb); 5840228561Snp 5841228561Snp return (rc); 5842228561Snp} 5843228561Snp 5844228561Snpstatic int 5845228561Snpsysctl_tcp_stats(SYSCTL_HANDLER_ARGS) 5846228561Snp{ 5847228561Snp struct adapter *sc = arg1; 5848228561Snp struct sbuf *sb; 5849228561Snp int rc; 5850228561Snp struct tp_tcp_stats v4, v6; 5851228561Snp 5852228561Snp rc = sysctl_wire_old_buffer(req, 0); 5853228561Snp if (rc != 0) 5854228561Snp return (rc); 5855228561Snp 5856228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5857228561Snp if (sb == NULL) 5858228561Snp return (ENOMEM); 5859228561Snp 5860228561Snp t4_tp_get_tcp_stats(sc, &v4, &v6); 5861228561Snp sbuf_printf(sb, 5862228561Snp " IP IPv6\n"); 5863228561Snp sbuf_printf(sb, "OutRsts: %20u %20u\n", 5864228561Snp v4.tcpOutRsts, v6.tcpOutRsts); 5865228561Snp sbuf_printf(sb, "InSegs: %20ju %20ju\n", 5866228561Snp v4.tcpInSegs, v6.tcpInSegs); 5867228561Snp sbuf_printf(sb, "OutSegs: %20ju %20ju\n", 5868228561Snp v4.tcpOutSegs, v6.tcpOutSegs); 5869228561Snp sbuf_printf(sb, "RetransSegs: %20ju %20ju", 5870228561Snp v4.tcpRetransSegs, v6.tcpRetransSegs); 5871228561Snp 5872228561Snp rc = sbuf_finish(sb); 5873228561Snp sbuf_delete(sb); 5874228561Snp 5875228561Snp return (rc); 5876228561Snp} 5877228561Snp 5878228561Snpstatic int 5879228561Snpsysctl_tids(SYSCTL_HANDLER_ARGS) 5880228561Snp{ 5881228561Snp struct adapter *sc = arg1; 5882228561Snp struct sbuf *sb; 5883228561Snp int rc; 5884228561Snp struct tid_info *t = &sc->tids; 5885228561Snp 5886228561Snp rc = sysctl_wire_old_buffer(req, 0); 5887228561Snp if (rc != 0) 5888228561Snp return (rc); 5889228561Snp 5890228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5891228561Snp if (sb == NULL) 5892228561Snp return (ENOMEM); 5893228561Snp 5894228561Snp if (t->natids) { 5895228561Snp sbuf_printf(sb, "ATID range: 0-%u, in use: %u\n", t->natids - 1, 5896228561Snp t->atids_in_use); 5897228561Snp } 5898228561Snp 5899228561Snp if (t->ntids) { 5900228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 5901228561Snp uint32_t b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4; 5902228561Snp 5903228561Snp if (b) { 5904228561Snp sbuf_printf(sb, "TID range: 0-%u, %u-%u", b - 1, 5905228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 5906228561Snp t->ntids - 1); 5907228561Snp } else { 5908228561Snp sbuf_printf(sb, "TID range: %u-%u", 5909228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 5910228561Snp t->ntids - 1); 5911228561Snp } 5912228561Snp } else 5913228561Snp sbuf_printf(sb, "TID range: 0-%u", t->ntids - 1); 5914228561Snp sbuf_printf(sb, ", in use: %u\n", 5915228561Snp atomic_load_acq_int(&t->tids_in_use)); 5916228561Snp } 5917228561Snp 5918228561Snp if (t->nstids) { 5919228561Snp sbuf_printf(sb, "STID range: %u-%u, in use: %u\n", t->stid_base, 5920228561Snp t->stid_base + t->nstids - 1, t->stids_in_use); 5921228561Snp } 5922228561Snp 5923228561Snp if (t->nftids) { 5924228561Snp sbuf_printf(sb, "FTID range: %u-%u\n", t->ftid_base, 5925228561Snp t->ftid_base + t->nftids - 1); 5926228561Snp } 5927228561Snp 5928228561Snp sbuf_printf(sb, "HW TID usage: %u IP users, %u IPv6 users", 5929228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV4), 5930228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV6)); 5931228561Snp 5932228561Snp rc = sbuf_finish(sb); 5933228561Snp sbuf_delete(sb); 5934228561Snp 5935228561Snp return (rc); 5936228561Snp} 5937228561Snp 5938228561Snpstatic int 5939228561Snpsysctl_tp_err_stats(SYSCTL_HANDLER_ARGS) 5940228561Snp{ 5941228561Snp struct adapter *sc = arg1; 5942228561Snp struct sbuf *sb; 5943228561Snp int rc; 5944228561Snp struct tp_err_stats stats; 5945228561Snp 5946228561Snp rc = sysctl_wire_old_buffer(req, 0); 5947228561Snp if (rc != 0) 5948228561Snp return (rc); 5949228561Snp 5950228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5951228561Snp if (sb == NULL) 5952228561Snp return (ENOMEM); 5953228561Snp 5954228561Snp t4_tp_get_err_stats(sc, &stats); 5955228561Snp 5956228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 5957228561Snp "channel 3\n"); 5958228561Snp sbuf_printf(sb, "macInErrs: %10u %10u %10u %10u\n", 5959228561Snp stats.macInErrs[0], stats.macInErrs[1], stats.macInErrs[2], 5960228561Snp stats.macInErrs[3]); 5961228561Snp sbuf_printf(sb, "hdrInErrs: %10u %10u %10u %10u\n", 5962228561Snp stats.hdrInErrs[0], stats.hdrInErrs[1], stats.hdrInErrs[2], 5963228561Snp stats.hdrInErrs[3]); 5964228561Snp sbuf_printf(sb, "tcpInErrs: %10u %10u %10u %10u\n", 5965228561Snp stats.tcpInErrs[0], stats.tcpInErrs[1], stats.tcpInErrs[2], 5966228561Snp stats.tcpInErrs[3]); 5967228561Snp sbuf_printf(sb, "tcp6InErrs: %10u %10u %10u %10u\n", 5968228561Snp stats.tcp6InErrs[0], stats.tcp6InErrs[1], stats.tcp6InErrs[2], 5969228561Snp stats.tcp6InErrs[3]); 5970228561Snp sbuf_printf(sb, "tnlCongDrops: %10u %10u %10u %10u\n", 5971228561Snp stats.tnlCongDrops[0], stats.tnlCongDrops[1], stats.tnlCongDrops[2], 5972228561Snp stats.tnlCongDrops[3]); 5973228561Snp sbuf_printf(sb, "tnlTxDrops: %10u %10u %10u %10u\n", 5974228561Snp stats.tnlTxDrops[0], stats.tnlTxDrops[1], stats.tnlTxDrops[2], 5975228561Snp stats.tnlTxDrops[3]); 5976228561Snp sbuf_printf(sb, "ofldVlanDrops: %10u %10u %10u %10u\n", 5977228561Snp stats.ofldVlanDrops[0], stats.ofldVlanDrops[1], 5978228561Snp stats.ofldVlanDrops[2], stats.ofldVlanDrops[3]); 5979228561Snp sbuf_printf(sb, "ofldChanDrops: %10u %10u %10u %10u\n\n", 5980228561Snp stats.ofldChanDrops[0], stats.ofldChanDrops[1], 5981228561Snp stats.ofldChanDrops[2], stats.ofldChanDrops[3]); 5982228561Snp sbuf_printf(sb, "ofldNoNeigh: %u\nofldCongDefer: %u", 5983228561Snp stats.ofldNoNeigh, stats.ofldCongDefer); 5984228561Snp 5985228561Snp rc = sbuf_finish(sb); 5986228561Snp sbuf_delete(sb); 5987228561Snp 5988228561Snp return (rc); 5989228561Snp} 5990228561Snp 5991251213Snpstruct field_desc { 5992251213Snp const char *name; 5993251213Snp u_int start; 5994251213Snp u_int width; 5995251213Snp}; 5996251213Snp 5997251213Snpstatic void 5998251213Snpfield_desc_show(struct sbuf *sb, uint64_t v, const struct field_desc *f) 5999251213Snp{ 6000251213Snp char buf[32]; 6001251213Snp int line_size = 0; 6002251213Snp 6003251213Snp while (f->name) { 6004251213Snp uint64_t mask = (1ULL << f->width) - 1; 6005251213Snp int len = snprintf(buf, sizeof(buf), "%s: %ju", f->name, 6006251213Snp ((uintmax_t)v >> f->start) & mask); 6007251213Snp 6008251213Snp if (line_size + len >= 79) { 6009251213Snp line_size = 8; 6010251213Snp sbuf_printf(sb, "\n "); 6011251213Snp } 6012251213Snp sbuf_printf(sb, "%s ", buf); 6013251213Snp line_size += len + 1; 6014251213Snp f++; 6015251213Snp } 6016251213Snp sbuf_printf(sb, "\n"); 6017251213Snp} 6018251213Snp 6019251213Snpstatic struct field_desc tp_la0[] = { 6020251213Snp { "RcfOpCodeOut", 60, 4 }, 6021251213Snp { "State", 56, 4 }, 6022251213Snp { "WcfState", 52, 4 }, 6023251213Snp { "RcfOpcSrcOut", 50, 2 }, 6024251213Snp { "CRxError", 49, 1 }, 6025251213Snp { "ERxError", 48, 1 }, 6026251213Snp { "SanityFailed", 47, 1 }, 6027251213Snp { "SpuriousMsg", 46, 1 }, 6028251213Snp { "FlushInputMsg", 45, 1 }, 6029251213Snp { "FlushInputCpl", 44, 1 }, 6030251213Snp { "RssUpBit", 43, 1 }, 6031251213Snp { "RssFilterHit", 42, 1 }, 6032251213Snp { "Tid", 32, 10 }, 6033251213Snp { "InitTcb", 31, 1 }, 6034251213Snp { "LineNumber", 24, 7 }, 6035251213Snp { "Emsg", 23, 1 }, 6036251213Snp { "EdataOut", 22, 1 }, 6037251213Snp { "Cmsg", 21, 1 }, 6038251213Snp { "CdataOut", 20, 1 }, 6039251213Snp { "EreadPdu", 19, 1 }, 6040251213Snp { "CreadPdu", 18, 1 }, 6041251213Snp { "TunnelPkt", 17, 1 }, 6042251213Snp { "RcfPeerFin", 16, 1 }, 6043251213Snp { "RcfReasonOut", 12, 4 }, 6044251213Snp { "TxCchannel", 10, 2 }, 6045251213Snp { "RcfTxChannel", 8, 2 }, 6046251213Snp { "RxEchannel", 6, 2 }, 6047251213Snp { "RcfRxChannel", 5, 1 }, 6048251213Snp { "RcfDataOutSrdy", 4, 1 }, 6049251213Snp { "RxDvld", 3, 1 }, 6050251213Snp { "RxOoDvld", 2, 1 }, 6051251213Snp { "RxCongestion", 1, 1 }, 6052251213Snp { "TxCongestion", 0, 1 }, 6053251213Snp { NULL } 6054251213Snp}; 6055251213Snp 6056251213Snpstatic struct field_desc tp_la1[] = { 6057251213Snp { "CplCmdIn", 56, 8 }, 6058251213Snp { "CplCmdOut", 48, 8 }, 6059251213Snp { "ESynOut", 47, 1 }, 6060251213Snp { "EAckOut", 46, 1 }, 6061251213Snp { "EFinOut", 45, 1 }, 6062251213Snp { "ERstOut", 44, 1 }, 6063251213Snp { "SynIn", 43, 1 }, 6064251213Snp { "AckIn", 42, 1 }, 6065251213Snp { "FinIn", 41, 1 }, 6066251213Snp { "RstIn", 40, 1 }, 6067251213Snp { "DataIn", 39, 1 }, 6068251213Snp { "DataInVld", 38, 1 }, 6069251213Snp { "PadIn", 37, 1 }, 6070251213Snp { "RxBufEmpty", 36, 1 }, 6071251213Snp { "RxDdp", 35, 1 }, 6072251213Snp { "RxFbCongestion", 34, 1 }, 6073251213Snp { "TxFbCongestion", 33, 1 }, 6074251213Snp { "TxPktSumSrdy", 32, 1 }, 6075251213Snp { "RcfUlpType", 28, 4 }, 6076251213Snp { "Eread", 27, 1 }, 6077251213Snp { "Ebypass", 26, 1 }, 6078251213Snp { "Esave", 25, 1 }, 6079251213Snp { "Static0", 24, 1 }, 6080251213Snp { "Cread", 23, 1 }, 6081251213Snp { "Cbypass", 22, 1 }, 6082251213Snp { "Csave", 21, 1 }, 6083251213Snp { "CPktOut", 20, 1 }, 6084251213Snp { "RxPagePoolFull", 18, 2 }, 6085251213Snp { "RxLpbkPkt", 17, 1 }, 6086251213Snp { "TxLpbkPkt", 16, 1 }, 6087251213Snp { "RxVfValid", 15, 1 }, 6088251213Snp { "SynLearned", 14, 1 }, 6089251213Snp { "SetDelEntry", 13, 1 }, 6090251213Snp { "SetInvEntry", 12, 1 }, 6091251213Snp { "CpcmdDvld", 11, 1 }, 6092251213Snp { "CpcmdSave", 10, 1 }, 6093251213Snp { "RxPstructsFull", 8, 2 }, 6094251213Snp { "EpcmdDvld", 7, 1 }, 6095251213Snp { "EpcmdFlush", 6, 1 }, 6096251213Snp { "EpcmdTrimPrefix", 5, 1 }, 6097251213Snp { "EpcmdTrimPostfix", 4, 1 }, 6098251213Snp { "ERssIp4Pkt", 3, 1 }, 6099251213Snp { "ERssIp6Pkt", 2, 1 }, 6100251213Snp { "ERssTcpUdpPkt", 1, 1 }, 6101251213Snp { "ERssFceFipPkt", 0, 1 }, 6102251213Snp { NULL } 6103251213Snp}; 6104251213Snp 6105251213Snpstatic struct field_desc tp_la2[] = { 6106251213Snp { "CplCmdIn", 56, 8 }, 6107251213Snp { "MpsVfVld", 55, 1 }, 6108251213Snp { "MpsPf", 52, 3 }, 6109251213Snp { "MpsVf", 44, 8 }, 6110251213Snp { "SynIn", 43, 1 }, 6111251213Snp { "AckIn", 42, 1 }, 6112251213Snp { "FinIn", 41, 1 }, 6113251213Snp { "RstIn", 40, 1 }, 6114251213Snp { "DataIn", 39, 1 }, 6115251213Snp { "DataInVld", 38, 1 }, 6116251213Snp { "PadIn", 37, 1 }, 6117251213Snp { "RxBufEmpty", 36, 1 }, 6118251213Snp { "RxDdp", 35, 1 }, 6119251213Snp { "RxFbCongestion", 34, 1 }, 6120251213Snp { "TxFbCongestion", 33, 1 }, 6121251213Snp { "TxPktSumSrdy", 32, 1 }, 6122251213Snp { "RcfUlpType", 28, 4 }, 6123251213Snp { "Eread", 27, 1 }, 6124251213Snp { "Ebypass", 26, 1 }, 6125251213Snp { "Esave", 25, 1 }, 6126251213Snp { "Static0", 24, 1 }, 6127251213Snp { "Cread", 23, 1 }, 6128251213Snp { "Cbypass", 22, 1 }, 6129251213Snp { "Csave", 21, 1 }, 6130251213Snp { "CPktOut", 20, 1 }, 6131251213Snp { "RxPagePoolFull", 18, 2 }, 6132251213Snp { "RxLpbkPkt", 17, 1 }, 6133251213Snp { "TxLpbkPkt", 16, 1 }, 6134251213Snp { "RxVfValid", 15, 1 }, 6135251213Snp { "SynLearned", 14, 1 }, 6136251213Snp { "SetDelEntry", 13, 1 }, 6137251213Snp { "SetInvEntry", 12, 1 }, 6138251213Snp { "CpcmdDvld", 11, 1 }, 6139251213Snp { "CpcmdSave", 10, 1 }, 6140251213Snp { "RxPstructsFull", 8, 2 }, 6141251213Snp { "EpcmdDvld", 7, 1 }, 6142251213Snp { "EpcmdFlush", 6, 1 }, 6143251213Snp { "EpcmdTrimPrefix", 5, 1 }, 6144251213Snp { "EpcmdTrimPostfix", 4, 1 }, 6145251213Snp { "ERssIp4Pkt", 3, 1 }, 6146251213Snp { "ERssIp6Pkt", 2, 1 }, 6147251213Snp { "ERssTcpUdpPkt", 1, 1 }, 6148251213Snp { "ERssFceFipPkt", 0, 1 }, 6149251213Snp { NULL } 6150251213Snp}; 6151251213Snp 6152251213Snpstatic void 6153251213Snptp_la_show(struct sbuf *sb, uint64_t *p, int idx) 6154251213Snp{ 6155251213Snp 6156251213Snp field_desc_show(sb, *p, tp_la0); 6157251213Snp} 6158251213Snp 6159251213Snpstatic void 6160251213Snptp_la_show2(struct sbuf *sb, uint64_t *p, int idx) 6161251213Snp{ 6162251213Snp 6163251213Snp if (idx) 6164251213Snp sbuf_printf(sb, "\n"); 6165251213Snp field_desc_show(sb, p[0], tp_la0); 6166251213Snp if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) 6167251213Snp field_desc_show(sb, p[1], tp_la0); 6168251213Snp} 6169251213Snp 6170251213Snpstatic void 6171251213Snptp_la_show3(struct sbuf *sb, uint64_t *p, int idx) 6172251213Snp{ 6173251213Snp 6174251213Snp if (idx) 6175251213Snp sbuf_printf(sb, "\n"); 6176251213Snp field_desc_show(sb, p[0], tp_la0); 6177251213Snp if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) 6178251213Snp field_desc_show(sb, p[1], (p[0] & (1 << 17)) ? tp_la2 : tp_la1); 6179251213Snp} 6180251213Snp 6181228561Snpstatic int 6182251213Snpsysctl_tp_la(SYSCTL_HANDLER_ARGS) 6183251213Snp{ 6184251213Snp struct adapter *sc = arg1; 6185251213Snp struct sbuf *sb; 6186251213Snp uint64_t *buf, *p; 6187251213Snp int rc; 6188251213Snp u_int i, inc; 6189251213Snp void (*show_func)(struct sbuf *, uint64_t *, int); 6190251213Snp 6191251213Snp rc = sysctl_wire_old_buffer(req, 0); 6192251213Snp if (rc != 0) 6193251213Snp return (rc); 6194251213Snp 6195251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6196251213Snp if (sb == NULL) 6197251213Snp return (ENOMEM); 6198251213Snp 6199251213Snp buf = malloc(TPLA_SIZE * sizeof(uint64_t), M_CXGBE, M_ZERO | M_WAITOK); 6200251213Snp 6201251213Snp t4_tp_read_la(sc, buf, NULL); 6202251213Snp p = buf; 6203251213Snp 6204251213Snp switch (G_DBGLAMODE(t4_read_reg(sc, A_TP_DBG_LA_CONFIG))) { 6205251213Snp case 2: 6206251213Snp inc = 2; 6207251213Snp show_func = tp_la_show2; 6208251213Snp break; 6209251213Snp case 3: 6210251213Snp inc = 2; 6211251213Snp show_func = tp_la_show3; 6212251213Snp break; 6213251213Snp default: 6214251213Snp inc = 1; 6215251213Snp show_func = tp_la_show; 6216251213Snp } 6217251213Snp 6218251213Snp for (i = 0; i < TPLA_SIZE / inc; i++, p += inc) 6219251213Snp (*show_func)(sb, p, i); 6220251213Snp 6221251213Snp rc = sbuf_finish(sb); 6222251213Snp sbuf_delete(sb); 6223251213Snp free(buf, M_CXGBE); 6224251213Snp return (rc); 6225251213Snp} 6226251213Snp 6227251213Snpstatic int 6228228561Snpsysctl_tx_rate(SYSCTL_HANDLER_ARGS) 6229228561Snp{ 6230228561Snp struct adapter *sc = arg1; 6231228561Snp struct sbuf *sb; 6232228561Snp int rc; 6233228561Snp u64 nrate[NCHAN], orate[NCHAN]; 6234228561Snp 6235228561Snp rc = sysctl_wire_old_buffer(req, 0); 6236228561Snp if (rc != 0) 6237228561Snp return (rc); 6238228561Snp 6239228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6240228561Snp if (sb == NULL) 6241228561Snp return (ENOMEM); 6242228561Snp 6243228561Snp t4_get_chan_txrate(sc, nrate, orate); 6244228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 6245228561Snp "channel 3\n"); 6246228561Snp sbuf_printf(sb, "NIC B/s: %10ju %10ju %10ju %10ju\n", 6247228561Snp nrate[0], nrate[1], nrate[2], nrate[3]); 6248228561Snp sbuf_printf(sb, "Offload B/s: %10ju %10ju %10ju %10ju", 6249228561Snp orate[0], orate[1], orate[2], orate[3]); 6250228561Snp 6251228561Snp rc = sbuf_finish(sb); 6252228561Snp sbuf_delete(sb); 6253228561Snp 6254228561Snp return (rc); 6255228561Snp} 6256248925Snp 6257248925Snpstatic int 6258251213Snpsysctl_ulprx_la(SYSCTL_HANDLER_ARGS) 6259251213Snp{ 6260251213Snp struct adapter *sc = arg1; 6261251213Snp struct sbuf *sb; 6262251213Snp uint32_t *buf, *p; 6263251213Snp int rc, i; 6264251213Snp 6265251213Snp rc = sysctl_wire_old_buffer(req, 0); 6266251213Snp if (rc != 0) 6267251213Snp return (rc); 6268251213Snp 6269251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6270251213Snp if (sb == NULL) 6271251213Snp return (ENOMEM); 6272251213Snp 6273251213Snp buf = malloc(ULPRX_LA_SIZE * 8 * sizeof(uint32_t), M_CXGBE, 6274251213Snp M_ZERO | M_WAITOK); 6275251213Snp 6276251213Snp t4_ulprx_read_la(sc, buf); 6277251213Snp p = buf; 6278251213Snp 6279251213Snp sbuf_printf(sb, " Pcmd Type Message" 6280251213Snp " Data"); 6281251213Snp for (i = 0; i < ULPRX_LA_SIZE; i++, p += 8) { 6282251213Snp sbuf_printf(sb, "\n%08x%08x %4x %08x %08x%08x%08x%08x", 6283251213Snp p[1], p[0], p[2], p[3], p[7], p[6], p[5], p[4]); 6284251213Snp } 6285251213Snp 6286251213Snp rc = sbuf_finish(sb); 6287251213Snp sbuf_delete(sb); 6288251213Snp free(buf, M_CXGBE); 6289251213Snp return (rc); 6290251213Snp} 6291251213Snp 6292251213Snpstatic int 6293249392Snpsysctl_wcwr_stats(SYSCTL_HANDLER_ARGS) 6294248925Snp{ 6295248925Snp struct adapter *sc = arg1; 6296248925Snp struct sbuf *sb; 6297248925Snp int rc, v; 6298248925Snp 6299248925Snp rc = sysctl_wire_old_buffer(req, 0); 6300248925Snp if (rc != 0) 6301248925Snp return (rc); 6302248925Snp 6303248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6304248925Snp if (sb == NULL) 6305248925Snp return (ENOMEM); 6306248925Snp 6307248925Snp v = t4_read_reg(sc, A_SGE_STAT_CFG); 6308248925Snp if (G_STATSOURCE_T5(v) == 7) { 6309248925Snp if (G_STATMODE(v) == 0) { 6310249383Snp sbuf_printf(sb, "total %d, incomplete %d", 6311248925Snp t4_read_reg(sc, A_SGE_STAT_TOTAL), 6312248925Snp t4_read_reg(sc, A_SGE_STAT_MATCH)); 6313248925Snp } else if (G_STATMODE(v) == 1) { 6314249383Snp sbuf_printf(sb, "total %d, data overflow %d", 6315248925Snp t4_read_reg(sc, A_SGE_STAT_TOTAL), 6316248925Snp t4_read_reg(sc, A_SGE_STAT_MATCH)); 6317248925Snp } 6318248925Snp } 6319248925Snp rc = sbuf_finish(sb); 6320248925Snp sbuf_delete(sb); 6321248925Snp 6322248925Snp return (rc); 6323248925Snp} 6324231115Snp#endif 6325228561Snp 6326219286Snpstatic inline void 6327219286Snptxq_start(struct ifnet *ifp, struct sge_txq *txq) 6328219286Snp{ 6329219286Snp struct buf_ring *br; 6330219286Snp struct mbuf *m; 6331219286Snp 6332219286Snp TXQ_LOCK_ASSERT_OWNED(txq); 6333219286Snp 6334220873Snp br = txq->br; 6335219286Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 6336219286Snp if (m) 6337219286Snp t4_eth_tx(ifp, txq, m); 6338219286Snp} 6339219286Snp 6340219286Snpvoid 6341228561Snpt4_tx_callout(void *arg) 6342219286Snp{ 6343228561Snp struct sge_eq *eq = arg; 6344228561Snp struct adapter *sc; 6345219286Snp 6346228561Snp if (EQ_TRYLOCK(eq) == 0) 6347228561Snp goto reschedule; 6348228561Snp 6349228561Snp if (eq->flags & EQ_STALLED && !can_resume_tx(eq)) { 6350228561Snp EQ_UNLOCK(eq); 6351228561Snpreschedule: 6352228561Snp if (__predict_true(!(eq->flags && EQ_DOOMED))) 6353228561Snp callout_schedule(&eq->tx_callout, 1); 6354228561Snp return; 6355228561Snp } 6356228561Snp 6357228561Snp EQ_LOCK_ASSERT_OWNED(eq); 6358228561Snp 6359228561Snp if (__predict_true((eq->flags & EQ_DOOMED) == 0)) { 6360228561Snp 6361228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 6362228561Snp struct sge_txq *txq = arg; 6363228561Snp struct port_info *pi = txq->ifp->if_softc; 6364228561Snp 6365228561Snp sc = pi->adapter; 6366228561Snp } else { 6367228561Snp struct sge_wrq *wrq = arg; 6368228561Snp 6369228561Snp sc = wrq->adapter; 6370228561Snp } 6371228561Snp 6372228561Snp taskqueue_enqueue(sc->tq[eq->tx_chan], &eq->tx_task); 6373228561Snp } 6374228561Snp 6375228561Snp EQ_UNLOCK(eq); 6376228561Snp} 6377228561Snp 6378228561Snpvoid 6379228561Snpt4_tx_task(void *arg, int count) 6380228561Snp{ 6381228561Snp struct sge_eq *eq = arg; 6382228561Snp 6383228561Snp EQ_LOCK(eq); 6384228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 6385228561Snp struct sge_txq *txq = arg; 6386220649Snp txq_start(txq->ifp, txq); 6387228561Snp } else { 6388228561Snp struct sge_wrq *wrq = arg; 6389228561Snp t4_wrq_tx_locked(wrq->adapter, wrq, NULL); 6390228561Snp } 6391228561Snp EQ_UNLOCK(eq); 6392219286Snp} 6393219286Snp 6394221474Snpstatic uint32_t 6395221474Snpfconf_to_mode(uint32_t fconf) 6396221474Snp{ 6397221474Snp uint32_t mode; 6398221474Snp 6399221474Snp mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR | 6400221474Snp T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT; 6401221474Snp 6402221474Snp if (fconf & F_FRAGMENTATION) 6403221474Snp mode |= T4_FILTER_IP_FRAGMENT; 6404221474Snp 6405221474Snp if (fconf & F_MPSHITTYPE) 6406221474Snp mode |= T4_FILTER_MPS_HIT_TYPE; 6407221474Snp 6408221474Snp if (fconf & F_MACMATCH) 6409221474Snp mode |= T4_FILTER_MAC_IDX; 6410221474Snp 6411221474Snp if (fconf & F_ETHERTYPE) 6412221474Snp mode |= T4_FILTER_ETH_TYPE; 6413221474Snp 6414221474Snp if (fconf & F_PROTOCOL) 6415221474Snp mode |= T4_FILTER_IP_PROTO; 6416221474Snp 6417221474Snp if (fconf & F_TOS) 6418221474Snp mode |= T4_FILTER_IP_TOS; 6419221474Snp 6420221474Snp if (fconf & F_VLAN) 6421228561Snp mode |= T4_FILTER_VLAN; 6422221474Snp 6423221474Snp if (fconf & F_VNIC_ID) 6424228561Snp mode |= T4_FILTER_VNIC; 6425221474Snp 6426221474Snp if (fconf & F_PORT) 6427221474Snp mode |= T4_FILTER_PORT; 6428221474Snp 6429221474Snp if (fconf & F_FCOE) 6430221474Snp mode |= T4_FILTER_FCoE; 6431221474Snp 6432221474Snp return (mode); 6433221474Snp} 6434221474Snp 6435221474Snpstatic uint32_t 6436221474Snpmode_to_fconf(uint32_t mode) 6437221474Snp{ 6438221474Snp uint32_t fconf = 0; 6439221474Snp 6440221474Snp if (mode & T4_FILTER_IP_FRAGMENT) 6441221474Snp fconf |= F_FRAGMENTATION; 6442221474Snp 6443221474Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 6444221474Snp fconf |= F_MPSHITTYPE; 6445221474Snp 6446221474Snp if (mode & T4_FILTER_MAC_IDX) 6447221474Snp fconf |= F_MACMATCH; 6448221474Snp 6449221474Snp if (mode & T4_FILTER_ETH_TYPE) 6450221474Snp fconf |= F_ETHERTYPE; 6451221474Snp 6452221474Snp if (mode & T4_FILTER_IP_PROTO) 6453221474Snp fconf |= F_PROTOCOL; 6454221474Snp 6455221474Snp if (mode & T4_FILTER_IP_TOS) 6456221474Snp fconf |= F_TOS; 6457221474Snp 6458228561Snp if (mode & T4_FILTER_VLAN) 6459221474Snp fconf |= F_VLAN; 6460221474Snp 6461228561Snp if (mode & T4_FILTER_VNIC) 6462221474Snp fconf |= F_VNIC_ID; 6463221474Snp 6464221474Snp if (mode & T4_FILTER_PORT) 6465221474Snp fconf |= F_PORT; 6466221474Snp 6467221474Snp if (mode & T4_FILTER_FCoE) 6468221474Snp fconf |= F_FCOE; 6469221474Snp 6470221474Snp return (fconf); 6471221474Snp} 6472221474Snp 6473221474Snpstatic uint32_t 6474221474Snpfspec_to_fconf(struct t4_filter_specification *fs) 6475221474Snp{ 6476221474Snp uint32_t fconf = 0; 6477221474Snp 6478221474Snp if (fs->val.frag || fs->mask.frag) 6479221474Snp fconf |= F_FRAGMENTATION; 6480221474Snp 6481221474Snp if (fs->val.matchtype || fs->mask.matchtype) 6482221474Snp fconf |= F_MPSHITTYPE; 6483221474Snp 6484221474Snp if (fs->val.macidx || fs->mask.macidx) 6485221474Snp fconf |= F_MACMATCH; 6486221474Snp 6487221474Snp if (fs->val.ethtype || fs->mask.ethtype) 6488221474Snp fconf |= F_ETHERTYPE; 6489221474Snp 6490221474Snp if (fs->val.proto || fs->mask.proto) 6491221474Snp fconf |= F_PROTOCOL; 6492221474Snp 6493221474Snp if (fs->val.tos || fs->mask.tos) 6494221474Snp fconf |= F_TOS; 6495221474Snp 6496228561Snp if (fs->val.vlan_vld || fs->mask.vlan_vld) 6497221474Snp fconf |= F_VLAN; 6498221474Snp 6499228561Snp if (fs->val.vnic_vld || fs->mask.vnic_vld) 6500221474Snp fconf |= F_VNIC_ID; 6501221474Snp 6502221474Snp if (fs->val.iport || fs->mask.iport) 6503221474Snp fconf |= F_PORT; 6504221474Snp 6505221474Snp if (fs->val.fcoe || fs->mask.fcoe) 6506221474Snp fconf |= F_FCOE; 6507221474Snp 6508221474Snp return (fconf); 6509221474Snp} 6510221474Snp 6511221474Snpstatic int 6512221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode) 6513221474Snp{ 6514245274Snp int rc; 6515221474Snp uint32_t fconf; 6516221474Snp 6517245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 6518245274Snp "t4getfm"); 6519245274Snp if (rc) 6520245274Snp return (rc); 6521245274Snp 6522221474Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1, 6523221474Snp A_TP_VLAN_PRI_MAP); 6524221474Snp 6525228561Snp if (sc->filter_mode != fconf) { 6526228561Snp log(LOG_WARNING, "%s: cached filter mode out of sync %x %x.\n", 6527228561Snp device_get_nameunit(sc->dev), sc->filter_mode, fconf); 6528228561Snp sc->filter_mode = fconf; 6529228561Snp } 6530221474Snp 6531228561Snp *mode = fconf_to_mode(sc->filter_mode); 6532228561Snp 6533245274Snp end_synchronized_op(sc, LOCK_HELD); 6534221474Snp return (0); 6535221474Snp} 6536221474Snp 6537221474Snpstatic int 6538221474Snpset_filter_mode(struct adapter *sc, uint32_t mode) 6539221474Snp{ 6540221474Snp uint32_t fconf; 6541221474Snp int rc; 6542221474Snp 6543221474Snp fconf = mode_to_fconf(mode); 6544221474Snp 6545245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 6546245274Snp "t4setfm"); 6547245274Snp if (rc) 6548245274Snp return (rc); 6549221474Snp 6550221474Snp if (sc->tids.ftids_in_use > 0) { 6551221474Snp rc = EBUSY; 6552221474Snp goto done; 6553221474Snp } 6554221474Snp 6555237263Snp#ifdef TCP_OFFLOAD 6556228561Snp if (sc->offload_map) { 6557228561Snp rc = EBUSY; 6558228561Snp goto done; 6559228561Snp } 6560228561Snp#endif 6561228561Snp 6562228561Snp#ifdef notyet 6563221474Snp rc = -t4_set_filter_mode(sc, fconf); 6564228561Snp if (rc == 0) 6565228561Snp sc->filter_mode = fconf; 6566228561Snp#else 6567228561Snp rc = ENOTSUP; 6568228561Snp#endif 6569228561Snp 6570221474Snpdone: 6571245274Snp end_synchronized_op(sc, LOCK_HELD); 6572221474Snp return (rc); 6573221474Snp} 6574221474Snp 6575222552Snpstatic inline uint64_t 6576222552Snpget_filter_hits(struct adapter *sc, uint32_t fid) 6577222552Snp{ 6578248925Snp uint32_t mw_base, off, tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 6579222552Snp uint64_t hits; 6580222552Snp 6581248925Snp memwin_info(sc, 0, &mw_base, NULL); 6582248925Snp off = position_memwin(sc, 0, 6583222552Snp tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE); 6584251358Snp if (is_t4(sc)) { 6585251358Snp hits = t4_read_reg64(sc, mw_base + off + 16); 6586251358Snp hits = be64toh(hits); 6587251358Snp } else { 6588251358Snp hits = t4_read_reg(sc, mw_base + off + 24); 6589251358Snp hits = be32toh(hits); 6590251358Snp } 6591222552Snp 6592251358Snp return (hits); 6593222552Snp} 6594222552Snp 6595221474Snpstatic int 6596221474Snpget_filter(struct adapter *sc, struct t4_filter *t) 6597221474Snp{ 6598245274Snp int i, rc, nfilters = sc->tids.nftids; 6599221474Snp struct filter_entry *f; 6600221474Snp 6601245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 6602245274Snp "t4getf"); 6603245274Snp if (rc) 6604245274Snp return (rc); 6605221474Snp 6606221474Snp if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL || 6607221474Snp t->idx >= nfilters) { 6608221474Snp t->idx = 0xffffffff; 6609245274Snp goto done; 6610221474Snp } 6611221474Snp 6612221474Snp f = &sc->tids.ftid_tab[t->idx]; 6613221474Snp for (i = t->idx; i < nfilters; i++, f++) { 6614221474Snp if (f->valid) { 6615221474Snp t->idx = i; 6616222509Snp t->l2tidx = f->l2t ? f->l2t->idx : 0; 6617222509Snp t->smtidx = f->smtidx; 6618222552Snp if (f->fs.hitcnts) 6619222552Snp t->hits = get_filter_hits(sc, t->idx); 6620222552Snp else 6621222552Snp t->hits = UINT64_MAX; 6622221474Snp t->fs = f->fs; 6623221474Snp 6624245274Snp goto done; 6625221474Snp } 6626221474Snp } 6627221474Snp 6628221474Snp t->idx = 0xffffffff; 6629245274Snpdone: 6630245274Snp end_synchronized_op(sc, LOCK_HELD); 6631221474Snp return (0); 6632221474Snp} 6633221474Snp 6634221474Snpstatic int 6635221474Snpset_filter(struct adapter *sc, struct t4_filter *t) 6636221474Snp{ 6637221474Snp unsigned int nfilters, nports; 6638221474Snp struct filter_entry *f; 6639245274Snp int i, rc; 6640221474Snp 6641245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setf"); 6642245274Snp if (rc) 6643245274Snp return (rc); 6644221474Snp 6645221474Snp nfilters = sc->tids.nftids; 6646221474Snp nports = sc->params.nports; 6647221474Snp 6648245274Snp if (nfilters == 0) { 6649245274Snp rc = ENOTSUP; 6650245274Snp goto done; 6651245274Snp } 6652221474Snp 6653245274Snp if (!(sc->flags & FULL_INIT_DONE)) { 6654245274Snp rc = EAGAIN; 6655245274Snp goto done; 6656245274Snp } 6657221474Snp 6658245274Snp if (t->idx >= nfilters) { 6659245274Snp rc = EINVAL; 6660245274Snp goto done; 6661245274Snp } 6662221474Snp 6663221474Snp /* Validate against the global filter mode */ 6664245274Snp if ((sc->filter_mode | fspec_to_fconf(&t->fs)) != sc->filter_mode) { 6665245274Snp rc = E2BIG; 6666245274Snp goto done; 6667245274Snp } 6668221474Snp 6669245274Snp if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) { 6670245274Snp rc = EINVAL; 6671245274Snp goto done; 6672245274Snp } 6673221474Snp 6674245274Snp if (t->fs.val.iport >= nports) { 6675245274Snp rc = EINVAL; 6676245274Snp goto done; 6677245274Snp } 6678221474Snp 6679221474Snp /* Can't specify an iq if not steering to it */ 6680245274Snp if (!t->fs.dirsteer && t->fs.iq) { 6681245274Snp rc = EINVAL; 6682245274Snp goto done; 6683245274Snp } 6684221474Snp 6685221474Snp /* IPv6 filter idx must be 4 aligned */ 6686221474Snp if (t->fs.type == 1 && 6687245274Snp ((t->idx & 0x3) || t->idx + 4 >= nfilters)) { 6688245274Snp rc = EINVAL; 6689245274Snp goto done; 6690245274Snp } 6691221474Snp 6692221474Snp if (sc->tids.ftid_tab == NULL) { 6693221474Snp KASSERT(sc->tids.ftids_in_use == 0, 6694221474Snp ("%s: no memory allocated but filters_in_use > 0", 6695221474Snp __func__)); 6696221474Snp 6697221474Snp sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) * 6698221474Snp nfilters, M_CXGBE, M_NOWAIT | M_ZERO); 6699245274Snp if (sc->tids.ftid_tab == NULL) { 6700245274Snp rc = ENOMEM; 6701245274Snp goto done; 6702245274Snp } 6703245274Snp mtx_init(&sc->tids.ftid_lock, "T4 filters", 0, MTX_DEF); 6704221474Snp } 6705221474Snp 6706221474Snp for (i = 0; i < 4; i++) { 6707221474Snp f = &sc->tids.ftid_tab[t->idx + i]; 6708221474Snp 6709245274Snp if (f->pending || f->valid) { 6710245274Snp rc = EBUSY; 6711245274Snp goto done; 6712245274Snp } 6713245274Snp if (f->locked) { 6714245274Snp rc = EPERM; 6715245274Snp goto done; 6716245274Snp } 6717221474Snp 6718221474Snp if (t->fs.type == 0) 6719221474Snp break; 6720221474Snp } 6721221474Snp 6722221474Snp f = &sc->tids.ftid_tab[t->idx]; 6723221474Snp f->fs = t->fs; 6724221474Snp 6725245274Snp rc = set_filter_wr(sc, t->idx); 6726245274Snpdone: 6727245274Snp end_synchronized_op(sc, 0); 6728245274Snp 6729245274Snp if (rc == 0) { 6730245274Snp mtx_lock(&sc->tids.ftid_lock); 6731245274Snp for (;;) { 6732245274Snp if (f->pending == 0) { 6733245274Snp rc = f->valid ? 0 : EIO; 6734245274Snp break; 6735245274Snp } 6736245274Snp 6737245274Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 6738245274Snp PCATCH, "t4setfw", 0)) { 6739245274Snp rc = EINPROGRESS; 6740245274Snp break; 6741245274Snp } 6742245274Snp } 6743245274Snp mtx_unlock(&sc->tids.ftid_lock); 6744245274Snp } 6745245274Snp return (rc); 6746221474Snp} 6747221474Snp 6748221474Snpstatic int 6749221474Snpdel_filter(struct adapter *sc, struct t4_filter *t) 6750221474Snp{ 6751221474Snp unsigned int nfilters; 6752221474Snp struct filter_entry *f; 6753245274Snp int rc; 6754221474Snp 6755245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4delf"); 6756245274Snp if (rc) 6757245274Snp return (rc); 6758221474Snp 6759221474Snp nfilters = sc->tids.nftids; 6760221474Snp 6761245274Snp if (nfilters == 0) { 6762245274Snp rc = ENOTSUP; 6763245274Snp goto done; 6764245274Snp } 6765221474Snp 6766221474Snp if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 || 6767245274Snp t->idx >= nfilters) { 6768245274Snp rc = EINVAL; 6769245274Snp goto done; 6770245274Snp } 6771221474Snp 6772245274Snp if (!(sc->flags & FULL_INIT_DONE)) { 6773245274Snp rc = EAGAIN; 6774245274Snp goto done; 6775245274Snp } 6776221474Snp 6777221474Snp f = &sc->tids.ftid_tab[t->idx]; 6778221474Snp 6779245274Snp if (f->pending) { 6780245274Snp rc = EBUSY; 6781245274Snp goto done; 6782245274Snp } 6783245274Snp if (f->locked) { 6784245274Snp rc = EPERM; 6785245274Snp goto done; 6786245274Snp } 6787221474Snp 6788221474Snp if (f->valid) { 6789221474Snp t->fs = f->fs; /* extra info for the caller */ 6790245274Snp rc = del_filter_wr(sc, t->idx); 6791221474Snp } 6792221474Snp 6793245274Snpdone: 6794245274Snp end_synchronized_op(sc, 0); 6795245274Snp 6796245274Snp if (rc == 0) { 6797245274Snp mtx_lock(&sc->tids.ftid_lock); 6798245274Snp for (;;) { 6799245274Snp if (f->pending == 0) { 6800245274Snp rc = f->valid ? EIO : 0; 6801245274Snp break; 6802245274Snp } 6803245274Snp 6804245274Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 6805245274Snp PCATCH, "t4delfw", 0)) { 6806245274Snp rc = EINPROGRESS; 6807245274Snp break; 6808245274Snp } 6809245274Snp } 6810245274Snp mtx_unlock(&sc->tids.ftid_lock); 6811245274Snp } 6812245274Snp 6813245274Snp return (rc); 6814221474Snp} 6815221474Snp 6816221474Snpstatic void 6817222509Snpclear_filter(struct filter_entry *f) 6818221474Snp{ 6819222509Snp if (f->l2t) 6820222509Snp t4_l2t_release(f->l2t); 6821222509Snp 6822221474Snp bzero(f, sizeof (*f)); 6823221474Snp} 6824221474Snp 6825221474Snpstatic int 6826221474Snpset_filter_wr(struct adapter *sc, int fidx) 6827221474Snp{ 6828221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 6829237263Snp struct wrqe *wr; 6830221474Snp struct fw_filter_wr *fwr; 6831221474Snp unsigned int ftid; 6832221474Snp 6833245274Snp ASSERT_SYNCHRONIZED_OP(sc); 6834221474Snp 6835222509Snp if (f->fs.newdmac || f->fs.newvlan) { 6836222509Snp /* This filter needs an L2T entry; allocate one. */ 6837222509Snp f->l2t = t4_l2t_alloc_switching(sc->l2t); 6838222509Snp if (f->l2t == NULL) 6839222509Snp return (EAGAIN); 6840222509Snp if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport, 6841222509Snp f->fs.dmac)) { 6842222509Snp t4_l2t_release(f->l2t); 6843222509Snp f->l2t = NULL; 6844222509Snp return (ENOMEM); 6845222509Snp } 6846222509Snp } 6847221474Snp 6848221474Snp ftid = sc->tids.ftid_base + fidx; 6849221474Snp 6850237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 6851237263Snp if (wr == NULL) 6852221474Snp return (ENOMEM); 6853221474Snp 6854237263Snp fwr = wrtod(wr); 6855221474Snp bzero(fwr, sizeof (*fwr)); 6856221474Snp 6857221474Snp fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR)); 6858221474Snp fwr->len16_pkd = htobe32(FW_LEN16(*fwr)); 6859221474Snp fwr->tid_to_iq = 6860221474Snp htobe32(V_FW_FILTER_WR_TID(ftid) | 6861221474Snp V_FW_FILTER_WR_RQTYPE(f->fs.type) | 6862221474Snp V_FW_FILTER_WR_NOREPLY(0) | 6863221474Snp V_FW_FILTER_WR_IQ(f->fs.iq)); 6864221474Snp fwr->del_filter_to_l2tix = 6865221474Snp htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) | 6866221474Snp V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) | 6867221474Snp V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) | 6868221474Snp V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) | 6869221474Snp V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) | 6870221474Snp V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) | 6871221474Snp V_FW_FILTER_WR_DMAC(f->fs.newdmac) | 6872221474Snp V_FW_FILTER_WR_SMAC(f->fs.newsmac) | 6873221474Snp V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT || 6874221474Snp f->fs.newvlan == VLAN_REWRITE) | 6875221474Snp V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE || 6876221474Snp f->fs.newvlan == VLAN_REWRITE) | 6877221474Snp V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) | 6878221474Snp V_FW_FILTER_WR_TXCHAN(f->fs.eport) | 6879221474Snp V_FW_FILTER_WR_PRIO(f->fs.prio) | 6880222509Snp V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0)); 6881221474Snp fwr->ethtype = htobe16(f->fs.val.ethtype); 6882221474Snp fwr->ethtypem = htobe16(f->fs.mask.ethtype); 6883221474Snp fwr->frag_to_ovlan_vldm = 6884221474Snp (V_FW_FILTER_WR_FRAG(f->fs.val.frag) | 6885221474Snp V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) | 6886228561Snp V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) | 6887228561Snp V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.vnic_vld) | 6888228561Snp V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) | 6889228561Snp V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.vnic_vld)); 6890221474Snp fwr->smac_sel = 0; 6891221474Snp fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) | 6892228561Snp V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id)); 6893221474Snp fwr->maci_to_matchtypem = 6894221474Snp htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) | 6895221474Snp V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) | 6896221474Snp V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) | 6897221474Snp V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) | 6898221474Snp V_FW_FILTER_WR_PORT(f->fs.val.iport) | 6899221474Snp V_FW_FILTER_WR_PORTM(f->fs.mask.iport) | 6900221474Snp V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) | 6901221474Snp V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype)); 6902221474Snp fwr->ptcl = f->fs.val.proto; 6903221474Snp fwr->ptclm = f->fs.mask.proto; 6904221474Snp fwr->ttyp = f->fs.val.tos; 6905221474Snp fwr->ttypm = f->fs.mask.tos; 6906228561Snp fwr->ivlan = htobe16(f->fs.val.vlan); 6907228561Snp fwr->ivlanm = htobe16(f->fs.mask.vlan); 6908228561Snp fwr->ovlan = htobe16(f->fs.val.vnic); 6909228561Snp fwr->ovlanm = htobe16(f->fs.mask.vnic); 6910221474Snp bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip)); 6911221474Snp bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm)); 6912221474Snp bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip)); 6913221474Snp bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm)); 6914221474Snp fwr->lp = htobe16(f->fs.val.dport); 6915221474Snp fwr->lpm = htobe16(f->fs.mask.dport); 6916221474Snp fwr->fp = htobe16(f->fs.val.sport); 6917221474Snp fwr->fpm = htobe16(f->fs.mask.sport); 6918221474Snp if (f->fs.newsmac) 6919221474Snp bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma)); 6920221474Snp 6921221474Snp f->pending = 1; 6922221474Snp sc->tids.ftids_in_use++; 6923228561Snp 6924237263Snp t4_wrq_tx(sc, wr); 6925228561Snp return (0); 6926221474Snp} 6927221474Snp 6928221474Snpstatic int 6929221474Snpdel_filter_wr(struct adapter *sc, int fidx) 6930221474Snp{ 6931221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 6932237263Snp struct wrqe *wr; 6933221474Snp struct fw_filter_wr *fwr; 6934228561Snp unsigned int ftid; 6935221474Snp 6936221474Snp ftid = sc->tids.ftid_base + fidx; 6937221474Snp 6938237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 6939237263Snp if (wr == NULL) 6940221474Snp return (ENOMEM); 6941237263Snp fwr = wrtod(wr); 6942221474Snp bzero(fwr, sizeof (*fwr)); 6943221474Snp 6944228561Snp t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id); 6945221474Snp 6946221474Snp f->pending = 1; 6947237263Snp t4_wrq_tx(sc, wr); 6948228561Snp return (0); 6949221474Snp} 6950221474Snp 6951239338Snpint 6952239338Snpt4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 6953221474Snp{ 6954228561Snp struct adapter *sc = iq->adapter; 6955228561Snp const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1); 6956221474Snp unsigned int idx = GET_TID(rpl); 6957221474Snp 6958228561Snp KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__, 6959228561Snp rss->opcode)); 6960228561Snp 6961221474Snp if (idx >= sc->tids.ftid_base && 6962221474Snp (idx -= sc->tids.ftid_base) < sc->tids.nftids) { 6963221474Snp unsigned int rc = G_COOKIE(rpl->cookie); 6964221474Snp struct filter_entry *f = &sc->tids.ftid_tab[idx]; 6965221474Snp 6966245274Snp mtx_lock(&sc->tids.ftid_lock); 6967228561Snp if (rc == FW_FILTER_WR_FLT_ADDED) { 6968245274Snp KASSERT(f->pending, ("%s: filter[%u] isn't pending.", 6969245274Snp __func__, idx)); 6970221474Snp f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff; 6971221474Snp f->pending = 0; /* asynchronous setup completed */ 6972221474Snp f->valid = 1; 6973231120Snp } else { 6974231120Snp if (rc != FW_FILTER_WR_FLT_DELETED) { 6975231120Snp /* Add or delete failed, display an error */ 6976231120Snp log(LOG_ERR, 6977231120Snp "filter %u setup failed with error %u\n", 6978231120Snp idx, rc); 6979231120Snp } 6980228561Snp 6981231120Snp clear_filter(f); 6982231120Snp sc->tids.ftids_in_use--; 6983221474Snp } 6984245274Snp wakeup(&sc->tids.ftid_tab); 6985245274Snp mtx_unlock(&sc->tids.ftid_lock); 6986221474Snp } 6987228561Snp 6988228561Snp return (0); 6989221474Snp} 6990221474Snp 6991222973Snpstatic int 6992222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt) 6993222973Snp{ 6994245274Snp int rc; 6995222973Snp 6996222973Snp if (cntxt->cid > M_CTXTQID) 6997245274Snp return (EINVAL); 6998222973Snp 6999222973Snp if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS && 7000222973Snp cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM) 7001245274Snp return (EINVAL); 7002222973Snp 7003246575Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ctxt"); 7004246575Snp if (rc) 7005246575Snp return (rc); 7006246575Snp 7007222973Snp if (sc->flags & FW_OK) { 7008246575Snp rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id, 7009246575Snp &cntxt->data[0]); 7010246575Snp if (rc == 0) 7011246575Snp goto done; 7012222973Snp } 7013222973Snp 7014245274Snp /* 7015245274Snp * Read via firmware failed or wasn't even attempted. Read directly via 7016245274Snp * the backdoor. 7017245274Snp */ 7018246575Snp rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id, &cntxt->data[0]); 7019246575Snpdone: 7020246575Snp end_synchronized_op(sc, 0); 7021245274Snp return (rc); 7022245274Snp} 7023222973Snp 7024245274Snpstatic int 7025245274Snpload_fw(struct adapter *sc, struct t4_data *fw) 7026245274Snp{ 7027245274Snp int rc; 7028245274Snp uint8_t *fw_data; 7029245274Snp 7030245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ldfw"); 7031245274Snp if (rc) 7032245274Snp return (rc); 7033245274Snp 7034245274Snp if (sc->flags & FULL_INIT_DONE) { 7035245274Snp rc = EBUSY; 7036245274Snp goto done; 7037222973Snp } 7038222973Snp 7039245274Snp fw_data = malloc(fw->len, M_CXGBE, M_WAITOK); 7040245274Snp if (fw_data == NULL) { 7041245274Snp rc = ENOMEM; 7042245274Snp goto done; 7043245274Snp } 7044245274Snp 7045245274Snp rc = copyin(fw->data, fw_data, fw->len); 7046245274Snp if (rc == 0) 7047245274Snp rc = -t4_load_fw(sc, fw_data, fw->len); 7048245274Snp 7049245274Snp free(fw_data, M_CXGBE); 7050245274Snpdone: 7051245274Snp end_synchronized_op(sc, 0); 7052222973Snp return (rc); 7053222973Snp} 7054222973Snp 7055228561Snpstatic int 7056248925Snpread_card_mem(struct adapter *sc, int win, struct t4_mem_range *mr) 7057228561Snp{ 7058248925Snp uint32_t addr, off, remaining, i, n; 7059228561Snp uint32_t *buf, *b; 7060248925Snp uint32_t mw_base, mw_aperture; 7061228561Snp int rc; 7062248925Snp uint8_t *dst; 7063228561Snp 7064248925Snp rc = validate_mem_range(sc, mr->addr, mr->len); 7065248925Snp if (rc != 0) 7066248925Snp return (rc); 7067228561Snp 7068248925Snp memwin_info(sc, win, &mw_base, &mw_aperture); 7069248925Snp buf = b = malloc(min(mr->len, mw_aperture), M_CXGBE, M_WAITOK); 7070248925Snp addr = mr->addr; 7071228561Snp remaining = mr->len; 7072248925Snp dst = (void *)mr->data; 7073228561Snp 7074228561Snp while (remaining) { 7075248925Snp off = position_memwin(sc, win, addr); 7076228561Snp 7077228561Snp /* number of bytes that we'll copy in the inner loop */ 7078248925Snp n = min(remaining, mw_aperture - off); 7079248925Snp for (i = 0; i < n; i += 4) 7080248925Snp *b++ = t4_read_reg(sc, mw_base + off + i); 7081228561Snp 7082248925Snp rc = copyout(buf, dst, n); 7083248925Snp if (rc != 0) 7084248925Snp break; 7085228561Snp 7086248925Snp b = buf; 7087248925Snp dst += n; 7088248925Snp remaining -= n; 7089248925Snp addr += n; 7090228561Snp } 7091228561Snp 7092228561Snp free(buf, M_CXGBE); 7093228561Snp return (rc); 7094228561Snp} 7095228561Snp 7096241399Snpstatic int 7097241399Snpread_i2c(struct adapter *sc, struct t4_i2c_data *i2cd) 7098241399Snp{ 7099241399Snp int rc; 7100241399Snp 7101241399Snp if (i2cd->len == 0 || i2cd->port_id >= sc->params.nports) 7102241399Snp return (EINVAL); 7103241399Snp 7104241399Snp if (i2cd->len > 1) { 7105241399Snp /* XXX: need fw support for longer reads in one go */ 7106241399Snp return (ENOTSUP); 7107241399Snp } 7108241399Snp 7109245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4i2crd"); 7110245274Snp if (rc) 7111245274Snp return (rc); 7112241399Snp rc = -t4_i2c_rd(sc, sc->mbox, i2cd->port_id, i2cd->dev_addr, 7113241399Snp i2cd->offset, &i2cd->data[0]); 7114245274Snp end_synchronized_op(sc, 0); 7115241399Snp 7116241399Snp return (rc); 7117241399Snp} 7118241399Snp 7119218792Snpint 7120218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap) 7121218792Snp{ 7122222102Snp int i; 7123218792Snp 7124222102Snp return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0); 7125218792Snp} 7126218792Snp 7127218792Snpint 7128218792Snpt4_os_pci_save_state(struct adapter *sc) 7129218792Snp{ 7130218792Snp device_t dev; 7131218792Snp struct pci_devinfo *dinfo; 7132218792Snp 7133218792Snp dev = sc->dev; 7134218792Snp dinfo = device_get_ivars(dev); 7135218792Snp 7136218792Snp pci_cfg_save(dev, dinfo, 0); 7137218792Snp return (0); 7138218792Snp} 7139218792Snp 7140218792Snpint 7141218792Snpt4_os_pci_restore_state(struct adapter *sc) 7142218792Snp{ 7143218792Snp device_t dev; 7144218792Snp struct pci_devinfo *dinfo; 7145218792Snp 7146218792Snp dev = sc->dev; 7147218792Snp dinfo = device_get_ivars(dev); 7148218792Snp 7149218792Snp pci_cfg_restore(dev, dinfo); 7150218792Snp return (0); 7151218792Snp} 7152219299Snp 7153218792Snpvoid 7154218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx) 7155218792Snp{ 7156218792Snp struct port_info *pi = sc->port[idx]; 7157218792Snp static const char *mod_str[] = { 7158220232Snp NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM" 7159218792Snp }; 7160218792Snp 7161218792Snp if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 7162218792Snp if_printf(pi->ifp, "transceiver unplugged.\n"); 7163220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) 7164220232Snp if_printf(pi->ifp, "unknown transceiver inserted.\n"); 7165220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) 7166220232Snp if_printf(pi->ifp, "unsupported transceiver inserted.\n"); 7167240452Snp else if (pi->mod_type > 0 && pi->mod_type < nitems(mod_str)) { 7168218792Snp if_printf(pi->ifp, "%s transceiver inserted.\n", 7169218792Snp mod_str[pi->mod_type]); 7170219299Snp } else { 7171219299Snp if_printf(pi->ifp, "transceiver (type %d) inserted.\n", 7172219299Snp pi->mod_type); 7173219299Snp } 7174218792Snp} 7175218792Snp 7176218792Snpvoid 7177218792Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat) 7178218792Snp{ 7179218792Snp struct port_info *pi = sc->port[idx]; 7180218792Snp struct ifnet *ifp = pi->ifp; 7181218792Snp 7182218792Snp if (link_stat) { 7183218792Snp ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed); 7184218792Snp if_link_state_change(ifp, LINK_STATE_UP); 7185218792Snp } else 7186218792Snp if_link_state_change(ifp, LINK_STATE_DOWN); 7187218792Snp} 7188218792Snp 7189228561Snpvoid 7190228561Snpt4_iterate(void (*func)(struct adapter *, void *), void *arg) 7191228561Snp{ 7192228561Snp struct adapter *sc; 7193228561Snp 7194228561Snp mtx_lock(&t4_list_lock); 7195228561Snp SLIST_FOREACH(sc, &t4_list, link) { 7196228561Snp /* 7197228561Snp * func should not make any assumptions about what state sc is 7198228561Snp * in - the only guarantee is that sc->sc_lock is a valid lock. 7199228561Snp */ 7200228561Snp func(sc, arg); 7201228561Snp } 7202228561Snp mtx_unlock(&t4_list_lock); 7203228561Snp} 7204228561Snp 7205218792Snpstatic int 7206218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td) 7207218792Snp{ 7208218792Snp return (0); 7209218792Snp} 7210218792Snp 7211218792Snpstatic int 7212218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td) 7213218792Snp{ 7214218792Snp return (0); 7215218792Snp} 7216218792Snp 7217218792Snpstatic int 7218218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag, 7219218792Snp struct thread *td) 7220218792Snp{ 7221218792Snp int rc; 7222218792Snp struct adapter *sc = dev->si_drv1; 7223218792Snp 7224218792Snp rc = priv_check(td, PRIV_DRIVER); 7225218792Snp if (rc != 0) 7226218792Snp return (rc); 7227218792Snp 7228218792Snp switch (cmd) { 7229220410Snp case CHELSIO_T4_GETREG: { 7230220410Snp struct t4_reg *edata = (struct t4_reg *)data; 7231220410Snp 7232218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 7233218792Snp return (EFAULT); 7234220410Snp 7235220410Snp if (edata->size == 4) 7236220410Snp edata->val = t4_read_reg(sc, edata->addr); 7237220410Snp else if (edata->size == 8) 7238220410Snp edata->val = t4_read_reg64(sc, edata->addr); 7239220410Snp else 7240220410Snp return (EINVAL); 7241220410Snp 7242218792Snp break; 7243218792Snp } 7244220410Snp case CHELSIO_T4_SETREG: { 7245220410Snp struct t4_reg *edata = (struct t4_reg *)data; 7246220410Snp 7247218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 7248218792Snp return (EFAULT); 7249220410Snp 7250220410Snp if (edata->size == 4) { 7251220410Snp if (edata->val & 0xffffffff00000000) 7252220410Snp return (EINVAL); 7253220410Snp t4_write_reg(sc, edata->addr, (uint32_t) edata->val); 7254220410Snp } else if (edata->size == 8) 7255220410Snp t4_write_reg64(sc, edata->addr, edata->val); 7256220410Snp else 7257220410Snp return (EINVAL); 7258218792Snp break; 7259218792Snp } 7260218792Snp case CHELSIO_T4_REGDUMP: { 7261218792Snp struct t4_regdump *regs = (struct t4_regdump *)data; 7262248925Snp int reglen = is_t4(sc) ? T4_REGDUMP_SIZE : T5_REGDUMP_SIZE; 7263218792Snp uint8_t *buf; 7264218792Snp 7265218792Snp if (regs->len < reglen) { 7266218792Snp regs->len = reglen; /* hint to the caller */ 7267218792Snp return (ENOBUFS); 7268218792Snp } 7269218792Snp 7270218792Snp regs->len = reglen; 7271218792Snp buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO); 7272218792Snp t4_get_regs(sc, regs, buf); 7273218792Snp rc = copyout(buf, regs->data, reglen); 7274218792Snp free(buf, M_CXGBE); 7275218792Snp break; 7276218792Snp } 7277221474Snp case CHELSIO_T4_GET_FILTER_MODE: 7278221474Snp rc = get_filter_mode(sc, (uint32_t *)data); 7279221474Snp break; 7280221474Snp case CHELSIO_T4_SET_FILTER_MODE: 7281221474Snp rc = set_filter_mode(sc, *(uint32_t *)data); 7282221474Snp break; 7283221474Snp case CHELSIO_T4_GET_FILTER: 7284221474Snp rc = get_filter(sc, (struct t4_filter *)data); 7285221474Snp break; 7286221474Snp case CHELSIO_T4_SET_FILTER: 7287221474Snp rc = set_filter(sc, (struct t4_filter *)data); 7288221474Snp break; 7289221474Snp case CHELSIO_T4_DEL_FILTER: 7290221474Snp rc = del_filter(sc, (struct t4_filter *)data); 7291221474Snp break; 7292222973Snp case CHELSIO_T4_GET_SGE_CONTEXT: 7293222973Snp rc = get_sge_context(sc, (struct t4_sge_context *)data); 7294222973Snp break; 7295245274Snp case CHELSIO_T4_LOAD_FW: 7296245274Snp rc = load_fw(sc, (struct t4_data *)data); 7297228561Snp break; 7298228561Snp case CHELSIO_T4_GET_MEM: 7299248925Snp rc = read_card_mem(sc, 2, (struct t4_mem_range *)data); 7300228561Snp break; 7301241399Snp case CHELSIO_T4_GET_I2C: 7302241399Snp rc = read_i2c(sc, (struct t4_i2c_data *)data); 7303241399Snp break; 7304241409Snp case CHELSIO_T4_CLEAR_STATS: { 7305245518Snp int i; 7306241409Snp u_int port_id = *(uint32_t *)data; 7307245518Snp struct port_info *pi; 7308241409Snp 7309241409Snp if (port_id >= sc->params.nports) 7310241409Snp return (EINVAL); 7311241409Snp 7312245518Snp /* MAC stats */ 7313241409Snp t4_clr_port_stats(sc, port_id); 7314245518Snp 7315245518Snp pi = sc->port[port_id]; 7316245518Snp if (pi->flags & PORT_INIT_DONE) { 7317245518Snp struct sge_rxq *rxq; 7318245518Snp struct sge_txq *txq; 7319245518Snp struct sge_wrq *wrq; 7320245518Snp 7321245518Snp for_each_rxq(pi, i, rxq) { 7322245518Snp#if defined(INET) || defined(INET6) 7323245518Snp rxq->lro.lro_queued = 0; 7324245518Snp rxq->lro.lro_flushed = 0; 7325245518Snp#endif 7326245518Snp rxq->rxcsum = 0; 7327245518Snp rxq->vlan_extraction = 0; 7328245518Snp } 7329245518Snp 7330245518Snp for_each_txq(pi, i, txq) { 7331245518Snp txq->txcsum = 0; 7332245518Snp txq->tso_wrs = 0; 7333245518Snp txq->vlan_insertion = 0; 7334245518Snp txq->imm_wrs = 0; 7335245518Snp txq->sgl_wrs = 0; 7336245518Snp txq->txpkt_wrs = 0; 7337245518Snp txq->txpkts_wrs = 0; 7338245518Snp txq->txpkts_pkts = 0; 7339246093Snp txq->br->br_drops = 0; 7340245518Snp txq->no_dmamap = 0; 7341245518Snp txq->no_desc = 0; 7342245518Snp } 7343245518Snp 7344245518Snp#ifdef TCP_OFFLOAD 7345245518Snp /* nothing to clear for each ofld_rxq */ 7346245518Snp 7347245518Snp for_each_ofld_txq(pi, i, wrq) { 7348245518Snp wrq->tx_wrs = 0; 7349245518Snp wrq->no_desc = 0; 7350245518Snp } 7351245518Snp#endif 7352245518Snp wrq = &sc->sge.ctrlq[pi->port_id]; 7353245518Snp wrq->tx_wrs = 0; 7354245518Snp wrq->no_desc = 0; 7355245518Snp } 7356241409Snp break; 7357241409Snp } 7358218792Snp default: 7359218792Snp rc = EINVAL; 7360218792Snp } 7361218792Snp 7362218792Snp return (rc); 7363218792Snp} 7364218792Snp 7365237263Snp#ifdef TCP_OFFLOAD 7366219392Snpstatic int 7367228561Snptoe_capability(struct port_info *pi, int enable) 7368228561Snp{ 7369228561Snp int rc; 7370228561Snp struct adapter *sc = pi->adapter; 7371228561Snp 7372245274Snp ASSERT_SYNCHRONIZED_OP(sc); 7373228561Snp 7374228561Snp if (!is_offload(sc)) 7375228561Snp return (ENODEV); 7376228561Snp 7377228561Snp if (enable) { 7378237263Snp if (!(sc->flags & FULL_INIT_DONE)) { 7379245274Snp rc = cxgbe_init_synchronized(pi); 7380245274Snp if (rc) 7381245274Snp return (rc); 7382237263Snp } 7383237263Snp 7384228561Snp if (isset(&sc->offload_map, pi->port_id)) 7385228561Snp return (0); 7386228561Snp 7387237263Snp if (!(sc->flags & TOM_INIT_DONE)) { 7388237263Snp rc = t4_activate_uld(sc, ULD_TOM); 7389237263Snp if (rc == EAGAIN) { 7390237263Snp log(LOG_WARNING, 7391237263Snp "You must kldload t4_tom.ko before trying " 7392237263Snp "to enable TOE on a cxgbe interface.\n"); 7393237263Snp } 7394228561Snp if (rc != 0) 7395228561Snp return (rc); 7396237263Snp KASSERT(sc->tom_softc != NULL, 7397237263Snp ("%s: TOM activated but softc NULL", __func__)); 7398237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 7399237263Snp ("%s: TOM activated but flag not set", __func__)); 7400228561Snp } 7401228561Snp 7402228561Snp setbit(&sc->offload_map, pi->port_id); 7403228561Snp } else { 7404228561Snp if (!isset(&sc->offload_map, pi->port_id)) 7405228561Snp return (0); 7406228561Snp 7407237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 7408237263Snp ("%s: TOM never initialized?", __func__)); 7409228561Snp clrbit(&sc->offload_map, pi->port_id); 7410228561Snp } 7411228561Snp 7412228561Snp return (0); 7413228561Snp} 7414228561Snp 7415228561Snp/* 7416228561Snp * Add an upper layer driver to the global list. 7417228561Snp */ 7418228561Snpint 7419228561Snpt4_register_uld(struct uld_info *ui) 7420228561Snp{ 7421228561Snp int rc = 0; 7422228561Snp struct uld_info *u; 7423228561Snp 7424228561Snp mtx_lock(&t4_uld_list_lock); 7425228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 7426228561Snp if (u->uld_id == ui->uld_id) { 7427228561Snp rc = EEXIST; 7428228561Snp goto done; 7429228561Snp } 7430228561Snp } 7431228561Snp 7432228561Snp SLIST_INSERT_HEAD(&t4_uld_list, ui, link); 7433228561Snp ui->refcount = 0; 7434228561Snpdone: 7435228561Snp mtx_unlock(&t4_uld_list_lock); 7436228561Snp return (rc); 7437228561Snp} 7438228561Snp 7439228561Snpint 7440228561Snpt4_unregister_uld(struct uld_info *ui) 7441228561Snp{ 7442228561Snp int rc = EINVAL; 7443228561Snp struct uld_info *u; 7444228561Snp 7445228561Snp mtx_lock(&t4_uld_list_lock); 7446228561Snp 7447228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 7448228561Snp if (u == ui) { 7449228561Snp if (ui->refcount > 0) { 7450228561Snp rc = EBUSY; 7451228561Snp goto done; 7452228561Snp } 7453228561Snp 7454228561Snp SLIST_REMOVE(&t4_uld_list, ui, uld_info, link); 7455228561Snp rc = 0; 7456228561Snp goto done; 7457228561Snp } 7458228561Snp } 7459228561Snpdone: 7460228561Snp mtx_unlock(&t4_uld_list_lock); 7461228561Snp return (rc); 7462228561Snp} 7463228561Snp 7464237263Snpint 7465237263Snpt4_activate_uld(struct adapter *sc, int id) 7466228561Snp{ 7467228561Snp int rc = EAGAIN; 7468228561Snp struct uld_info *ui; 7469228561Snp 7470245274Snp ASSERT_SYNCHRONIZED_OP(sc); 7471245274Snp 7472228561Snp mtx_lock(&t4_uld_list_lock); 7473228561Snp 7474228561Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 7475228561Snp if (ui->uld_id == id) { 7476237263Snp rc = ui->activate(sc); 7477237263Snp if (rc == 0) 7478228561Snp ui->refcount++; 7479228561Snp goto done; 7480228561Snp } 7481228561Snp } 7482228561Snpdone: 7483228561Snp mtx_unlock(&t4_uld_list_lock); 7484228561Snp 7485228561Snp return (rc); 7486228561Snp} 7487228561Snp 7488237263Snpint 7489237263Snpt4_deactivate_uld(struct adapter *sc, int id) 7490228561Snp{ 7491237263Snp int rc = EINVAL; 7492237263Snp struct uld_info *ui; 7493228561Snp 7494245274Snp ASSERT_SYNCHRONIZED_OP(sc); 7495245274Snp 7496228561Snp mtx_lock(&t4_uld_list_lock); 7497228561Snp 7498237263Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 7499237263Snp if (ui->uld_id == id) { 7500237263Snp rc = ui->deactivate(sc); 7501237263Snp if (rc == 0) 7502237263Snp ui->refcount--; 7503237263Snp goto done; 7504237263Snp } 7505228561Snp } 7506228561Snpdone: 7507228561Snp mtx_unlock(&t4_uld_list_lock); 7508228561Snp 7509228561Snp return (rc); 7510228561Snp} 7511228561Snp#endif 7512228561Snp 7513228561Snp/* 7514228561Snp * Come up with reasonable defaults for some of the tunables, provided they're 7515228561Snp * not set by the user (in which case we'll use the values as is). 7516228561Snp */ 7517228561Snpstatic void 7518228561Snptweak_tunables(void) 7519228561Snp{ 7520228561Snp int nc = mp_ncpus; /* our snapshot of the number of CPUs */ 7521228561Snp 7522228561Snp if (t4_ntxq10g < 1) 7523228561Snp t4_ntxq10g = min(nc, NTXQ_10G); 7524228561Snp 7525228561Snp if (t4_ntxq1g < 1) 7526228561Snp t4_ntxq1g = min(nc, NTXQ_1G); 7527228561Snp 7528228561Snp if (t4_nrxq10g < 1) 7529228561Snp t4_nrxq10g = min(nc, NRXQ_10G); 7530228561Snp 7531228561Snp if (t4_nrxq1g < 1) 7532228561Snp t4_nrxq1g = min(nc, NRXQ_1G); 7533228561Snp 7534237263Snp#ifdef TCP_OFFLOAD 7535228561Snp if (t4_nofldtxq10g < 1) 7536228561Snp t4_nofldtxq10g = min(nc, NOFLDTXQ_10G); 7537228561Snp 7538228561Snp if (t4_nofldtxq1g < 1) 7539228561Snp t4_nofldtxq1g = min(nc, NOFLDTXQ_1G); 7540228561Snp 7541228561Snp if (t4_nofldrxq10g < 1) 7542228561Snp t4_nofldrxq10g = min(nc, NOFLDRXQ_10G); 7543228561Snp 7544228561Snp if (t4_nofldrxq1g < 1) 7545228561Snp t4_nofldrxq1g = min(nc, NOFLDRXQ_1G); 7546238028Snp 7547238028Snp if (t4_toecaps_allowed == -1) 7548238028Snp t4_toecaps_allowed = FW_CAPS_CONFIG_TOE; 7549238028Snp#else 7550238028Snp if (t4_toecaps_allowed == -1) 7551238028Snp t4_toecaps_allowed = 0; 7552228561Snp#endif 7553228561Snp 7554228561Snp if (t4_tmr_idx_10g < 0 || t4_tmr_idx_10g >= SGE_NTIMERS) 7555228561Snp t4_tmr_idx_10g = TMR_IDX_10G; 7556228561Snp 7557228561Snp if (t4_pktc_idx_10g < -1 || t4_pktc_idx_10g >= SGE_NCOUNTERS) 7558228561Snp t4_pktc_idx_10g = PKTC_IDX_10G; 7559228561Snp 7560228561Snp if (t4_tmr_idx_1g < 0 || t4_tmr_idx_1g >= SGE_NTIMERS) 7561228561Snp t4_tmr_idx_1g = TMR_IDX_1G; 7562228561Snp 7563228561Snp if (t4_pktc_idx_1g < -1 || t4_pktc_idx_1g >= SGE_NCOUNTERS) 7564228561Snp t4_pktc_idx_1g = PKTC_IDX_1G; 7565228561Snp 7566228561Snp if (t4_qsize_txq < 128) 7567228561Snp t4_qsize_txq = 128; 7568228561Snp 7569228561Snp if (t4_qsize_rxq < 128) 7570228561Snp t4_qsize_rxq = 128; 7571228561Snp while (t4_qsize_rxq & 7) 7572228561Snp t4_qsize_rxq++; 7573228561Snp 7574228561Snp t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX; 7575228561Snp} 7576228561Snp 7577228561Snpstatic int 7578249370Snpmod_event(module_t mod, int cmd, void *arg) 7579219392Snp{ 7580228561Snp int rc = 0; 7581249370Snp static int loaded = 0; 7582219392Snp 7583228561Snp switch (cmd) { 7584228561Snp case MOD_LOAD: 7585249370Snp if (atomic_fetchadd_int(&loaded, 1)) 7586249370Snp break; 7587219392Snp t4_sge_modload(); 7588228561Snp mtx_init(&t4_list_lock, "T4 adapters", 0, MTX_DEF); 7589228561Snp SLIST_INIT(&t4_list); 7590237263Snp#ifdef TCP_OFFLOAD 7591228561Snp mtx_init(&t4_uld_list_lock, "T4 ULDs", 0, MTX_DEF); 7592228561Snp SLIST_INIT(&t4_uld_list); 7593228561Snp#endif 7594228561Snp tweak_tunables(); 7595228561Snp break; 7596219392Snp 7597228561Snp case MOD_UNLOAD: 7598249370Snp if (atomic_fetchadd_int(&loaded, -1) > 1) 7599249370Snp break; 7600237263Snp#ifdef TCP_OFFLOAD 7601228561Snp mtx_lock(&t4_uld_list_lock); 7602228561Snp if (!SLIST_EMPTY(&t4_uld_list)) { 7603228561Snp rc = EBUSY; 7604228561Snp mtx_unlock(&t4_uld_list_lock); 7605228561Snp break; 7606228561Snp } 7607228561Snp mtx_unlock(&t4_uld_list_lock); 7608228561Snp mtx_destroy(&t4_uld_list_lock); 7609228561Snp#endif 7610228561Snp mtx_lock(&t4_list_lock); 7611228561Snp if (!SLIST_EMPTY(&t4_list)) { 7612228561Snp rc = EBUSY; 7613228561Snp mtx_unlock(&t4_list_lock); 7614228561Snp break; 7615228561Snp } 7616228561Snp mtx_unlock(&t4_list_lock); 7617228561Snp mtx_destroy(&t4_list_lock); 7618228561Snp break; 7619228561Snp } 7620228561Snp 7621228561Snp return (rc); 7622219392Snp} 7623219392Snp 7624248925Snpstatic devclass_t t4_devclass, t5_devclass; 7625248925Snpstatic devclass_t cxgbe_devclass, cxl_devclass; 7626218792Snp 7627249370SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, mod_event, 0); 7628218792SnpMODULE_VERSION(t4nex, 1); 7629250697SkibMODULE_DEPEND(t4nex, firmware, 1, 1, 1); 7630218792Snp 7631249370SnpDRIVER_MODULE(t5nex, pci, t5_driver, t5_devclass, mod_event, 0); 7632248925SnpMODULE_VERSION(t5nex, 1); 7633250697SkibMODULE_DEPEND(t5nex, firmware, 1, 1, 1); 7634248925Snp 7635218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0); 7636218792SnpMODULE_VERSION(cxgbe, 1); 7637248925Snp 7638248925SnpDRIVER_MODULE(cxl, t5nex, cxl_driver, cxl_devclass, 0, 0); 7639248925SnpMODULE_VERSION(cxl, 1); 7640