t4_main.c revision 251213
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 251213 2013-06-01 02:07:37Z 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/* 1915249376Snp * The firmware in the KLD is usable and can be installed. But should it be? 1916249376Snp * This routine explains itself in detail if it indicates the KLD firmware 1917249376Snp * should be 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 KASSERT(t4_fw_install != 0, ("%s: Can't install; shouldn't be asked " 1925249376Snp "to evaluate if install is a good idea.", __func__)); 1926249376Snp 1927249376Snp if (!card_fw_usable) { 1928249376Snp reason = "incompatible or unusable"; 1929249376Snp goto install; 1930249376Snp } 1931249376Snp 1932249376Snp if (k > c) { 1933249376Snp reason = "older than the version bundled with this driver"; 1934249376Snp goto install; 1935249376Snp } 1936249376Snp 1937249376Snp if (t4_fw_install == 2 && k != c) { 1938249376Snp reason = "different than the version bundled with this driver"; 1939249376Snp goto install; 1940249376Snp } 1941249376Snp 1942249376Snp return (0); 1943249376Snp 1944249376Snpinstall: 1945249376Snp device_printf(sc->dev, "firmware on card (%u.%u.%u.%u) is %s, " 1946249376Snp "installing firmware %u.%u.%u.%u on card.\n", 1947249376Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 1948249376Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), reason, 1949249376Snp G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k), 1950249376Snp G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k)); 1951249376Snp 1952249376Snp return (1); 1953249376Snp} 1954249376Snp/* 1955248925Snp * Establish contact with the firmware and determine if we are the master driver 1956248925Snp * or not, and whether we are responsible for chip initialization. 1957218792Snp */ 1958218792Snpstatic int 1959218792Snpprep_firmware(struct adapter *sc) 1960218792Snp{ 1961248925Snp const struct firmware *fw = NULL, *default_cfg; 1962248925Snp int rc, pf, card_fw_usable, kld_fw_usable, need_fw_reset = 1; 1963218792Snp enum dev_state state; 1964248925Snp struct fw_info *fw_info; 1965248925Snp struct fw_hdr *card_fw; /* fw on the card */ 1966248925Snp const struct fw_hdr *kld_fw; /* fw in the KLD */ 1967248925Snp const struct fw_hdr *drv_fw; /* fw header the driver was compiled 1968248925Snp against */ 1969218792Snp 1970248925Snp /* Contact firmware. */ 1971248925Snp rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state); 1972248925Snp if (rc < 0 || state == DEV_STATE_ERR) { 1973248925Snp rc = -rc; 1974248925Snp device_printf(sc->dev, 1975248925Snp "failed to connect to the firmware: %d, %d.\n", rc, state); 1976248925Snp return (rc); 1977248925Snp } 1978248925Snp pf = rc; 1979248925Snp if (pf == sc->mbox) 1980248925Snp sc->flags |= MASTER_PF; 1981248925Snp else if (state == DEV_STATE_UNINIT) { 1982248925Snp /* 1983248925Snp * We didn't get to be the master so we definitely won't be 1984248925Snp * configuring the chip. It's a bug if someone else hasn't 1985248925Snp * configured it already. 1986248925Snp */ 1987248925Snp device_printf(sc->dev, "couldn't be master(%d), " 1988248925Snp "device not already initialized either(%d).\n", rc, state); 1989248925Snp return (EDOOFUS); 1990248925Snp } 1991228561Snp 1992248925Snp /* This is the firmware whose headers the driver was compiled against */ 1993248925Snp fw_info = find_fw_info(chip_id(sc)); 1994248925Snp if (fw_info == NULL) { 1995248925Snp device_printf(sc->dev, 1996248925Snp "unable to look up firmware information for chip %d.\n", 1997248925Snp chip_id(sc)); 1998248925Snp return (EINVAL); 1999248925Snp } 2000248925Snp drv_fw = &fw_info->fw_hdr; 2001248925Snp 2002248925Snp /* 2003248925Snp * The firmware KLD contains many modules. The KLD name is also the 2004248925Snp * name of the module that contains the default config file. 2005248925Snp */ 2006248925Snp default_cfg = firmware_get(fw_info->kld_name); 2007248925Snp 2008247347Snp /* Read the header of the firmware on the card */ 2009247347Snp card_fw = malloc(sizeof(*card_fw), M_CXGBE, M_ZERO | M_WAITOK); 2010247347Snp rc = -t4_read_flash(sc, FLASH_FW_START, 2011247347Snp sizeof (*card_fw) / sizeof (uint32_t), (uint32_t *)card_fw, 1); 2012247347Snp if (rc == 0) 2013248925Snp card_fw_usable = fw_compatible(drv_fw, (const void*)card_fw); 2014247347Snp else { 2015247347Snp device_printf(sc->dev, 2016247347Snp "Unable to read card's firmware header: %d\n", rc); 2017247347Snp card_fw_usable = 0; 2018247347Snp } 2019218792Snp 2020247347Snp /* This is the firmware in the KLD */ 2021248925Snp fw = firmware_get(fw_info->fw_mod_name); 2022247347Snp if (fw != NULL) { 2023247347Snp kld_fw = (const void *)fw->data; 2024248925Snp kld_fw_usable = fw_compatible(drv_fw, kld_fw); 2025247347Snp } else { 2026247347Snp kld_fw = NULL; 2027247347Snp kld_fw_usable = 0; 2028247347Snp } 2029219287Snp 2030248925Snp if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver && 2031248925Snp (!kld_fw_usable || kld_fw->fw_ver == drv_fw->fw_ver || 2032248925Snp t4_fw_install == 0)) { 2033248925Snp /* 2034248925Snp * Common case: the firmware on the card is an exact match and 2035248925Snp * the KLD is an exact match too, or the KLD is 2036248925Snp * absent/incompatible, or we're prohibited from using it. Note 2037248925Snp * that t4_fw_install = 2 is ignored here -- use cxgbetool 2038248925Snp * loadfw if you want to reinstall the same firmware as the one 2039248925Snp * on the card. 2040248925Snp */ 2041248925Snp } else if (kld_fw_usable && state == DEV_STATE_UNINIT && 2042249376Snp should_install_kld_fw(sc, card_fw_usable, be32toh(kld_fw->fw_ver), 2043249376Snp be32toh(card_fw->fw_ver))) { 2044219287Snp 2045250221Snp rc = -t4_fw_upgrade(sc, sc->mbox, fw->data, fw->datasize, 0); 2046247347Snp if (rc != 0) { 2047247347Snp device_printf(sc->dev, 2048247347Snp "failed to install firmware: %d\n", rc); 2049228561Snp goto done; 2050219287Snp } 2051219287Snp 2052247347Snp /* Installed successfully, update the cached header too. */ 2053247347Snp memcpy(card_fw, kld_fw, sizeof(*card_fw)); 2054247347Snp card_fw_usable = 1; 2055248925Snp need_fw_reset = 0; /* already reset as part of load_fw */ 2056247347Snp } 2057219287Snp 2058247347Snp if (!card_fw_usable) { 2059248925Snp uint32_t d, c, k; 2060247347Snp 2061248925Snp d = ntohl(drv_fw->fw_ver); 2062247347Snp c = ntohl(card_fw->fw_ver); 2063247347Snp k = kld_fw ? ntohl(kld_fw->fw_ver) : 0; 2064247347Snp 2065247347Snp device_printf(sc->dev, "Cannot find a usable firmware: " 2066248925Snp "fw_install %d, chip state %d, " 2067248925Snp "driver compiled with %d.%d.%d.%d, " 2068247347Snp "card has %d.%d.%d.%d, KLD has %d.%d.%d.%d\n", 2069248925Snp t4_fw_install, state, 2070248925Snp G_FW_HDR_FW_VER_MAJOR(d), G_FW_HDR_FW_VER_MINOR(d), 2071248925Snp G_FW_HDR_FW_VER_MICRO(d), G_FW_HDR_FW_VER_BUILD(d), 2072247347Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 2073247347Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), 2074247347Snp G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k), 2075247347Snp G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k)); 2076248925Snp rc = EINVAL; 2077247347Snp goto done; 2078218792Snp } 2079218792Snp 2080247347Snp /* We're using whatever's on the card and it's known to be good. */ 2081247347Snp sc->params.fw_vers = ntohl(card_fw->fw_ver); 2082247347Snp snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u", 2083247347Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 2084247347Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 2085247347Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 2086247347Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 2087247347Snp 2088218792Snp /* Reset device */ 2089248925Snp if (need_fw_reset && 2090248925Snp (rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST)) != 0) { 2091218792Snp device_printf(sc->dev, "firmware reset failed: %d.\n", rc); 2092218792Snp if (rc != ETIMEDOUT && rc != EIO) 2093218792Snp t4_fw_bye(sc, sc->mbox); 2094228561Snp goto done; 2095218792Snp } 2096248925Snp sc->flags |= FW_OK; 2097218792Snp 2098248925Snp rc = get_params__pre_init(sc); 2099248925Snp if (rc != 0) 2100248925Snp goto done; /* error message displayed already */ 2101248925Snp 2102228561Snp /* Partition adapter resources as specified in the config file. */ 2103248925Snp if (state == DEV_STATE_UNINIT) { 2104228561Snp 2105248925Snp KASSERT(sc->flags & MASTER_PF, 2106248925Snp ("%s: trying to change chip settings when not master.", 2107248925Snp __func__)); 2108228561Snp 2109248925Snp rc = partition_resources(sc, default_cfg, fw_info->kld_name); 2110228561Snp if (rc != 0) 2111228561Snp goto done; /* error message displayed already */ 2112248925Snp 2113248925Snp t4_tweak_chip_settings(sc); 2114248925Snp 2115248925Snp /* get basic stuff going */ 2116248925Snp rc = -t4_fw_initialize(sc, sc->mbox); 2117248925Snp if (rc != 0) { 2118248925Snp device_printf(sc->dev, "fw init failed: %d.\n", rc); 2119248925Snp goto done; 2120248925Snp } 2121245936Snp } else { 2122248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "pf%d", pf); 2123248925Snp sc->cfcsum = 0; 2124228561Snp } 2125228561Snp 2126228561Snpdone: 2127247347Snp free(card_fw, M_CXGBE); 2128228561Snp if (fw != NULL) 2129228561Snp firmware_put(fw, FIRMWARE_UNLOAD); 2130228561Snp if (default_cfg != NULL) 2131228561Snp firmware_put(default_cfg, FIRMWARE_UNLOAD); 2132228561Snp 2133228561Snp return (rc); 2134218792Snp} 2135218792Snp 2136228561Snp#define FW_PARAM_DEV(param) \ 2137228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ 2138228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) 2139228561Snp#define FW_PARAM_PFVF(param) \ 2140228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ 2141228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)) 2142228561Snp 2143228561Snp/* 2144248925Snp * Partition chip resources for use between various PFs, VFs, etc. 2145228561Snp */ 2146218792Snpstatic int 2147248925Snppartition_resources(struct adapter *sc, const struct firmware *default_cfg, 2148248925Snp const char *name_prefix) 2149222551Snp{ 2150248925Snp const struct firmware *cfg = NULL; 2151248925Snp int rc = 0; 2152248925Snp struct fw_caps_config_cmd caps; 2153248925Snp uint32_t mtype, moff, finicsum, cfcsum; 2154222551Snp 2155248925Snp /* 2156248925Snp * Figure out what configuration file to use. Pick the default config 2157248925Snp * file for the card if the user hasn't specified one explicitly. 2158248925Snp */ 2159248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", t4_cfg_file); 2160248925Snp if (strncmp(t4_cfg_file, DEFAULT_CF, sizeof(t4_cfg_file)) == 0) { 2161248925Snp /* Card specific overrides go here. */ 2162248925Snp if (pci_get_device(sc->dev) == 0x440a) 2163248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), UWIRE_CF); 2164249376Snp if (is_fpga(sc)) 2165249376Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), FPGA_CF); 2166222551Snp } 2167222551Snp 2168248925Snp /* 2169248925Snp * We need to load another module if the profile is anything except 2170248925Snp * "default" or "flash". 2171248925Snp */ 2172248925Snp if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) != 0 && 2173248925Snp strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) { 2174248925Snp char s[32]; 2175248925Snp 2176248925Snp snprintf(s, sizeof(s), "%s_%s", name_prefix, sc->cfg_file); 2177248925Snp cfg = firmware_get(s); 2178248925Snp if (cfg == NULL) { 2179248925Snp if (default_cfg != NULL) { 2180249376Snp device_printf(sc->dev, 2181249376Snp "unable to load module \"%s\" for " 2182249376Snp "configuration profile \"%s\", will use " 2183249376Snp "the default config file instead.\n", 2184249376Snp s, sc->cfg_file); 2185248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), 2186248925Snp "%s", DEFAULT_CF); 2187248925Snp } else { 2188249376Snp device_printf(sc->dev, 2189249376Snp "unable to load module \"%s\" for " 2190249376Snp "configuration profile \"%s\", will use " 2191249376Snp "the config file on the card's flash " 2192249376Snp "instead.\n", s, sc->cfg_file); 2193248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), 2194248925Snp "%s", FLASH_CF); 2195248925Snp } 2196248925Snp } 2197228561Snp } 2198222551Snp 2199248925Snp if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) == 0 && 2200248925Snp default_cfg == NULL) { 2201228561Snp device_printf(sc->dev, 2202248925Snp "default config file not available, will use the config " 2203248925Snp "file on the card's flash instead.\n"); 2204248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", FLASH_CF); 2205228561Snp } 2206228561Snp 2207248925Snp if (strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) { 2208248925Snp u_int cflen, i, n; 2209248925Snp const uint32_t *cfdata; 2210248925Snp uint32_t param, val, addr, off, mw_base, mw_aperture; 2211228561Snp 2212248925Snp KASSERT(cfg != NULL || default_cfg != NULL, 2213248925Snp ("%s: no config to upload", __func__)); 2214228561Snp 2215248925Snp /* 2216248925Snp * Ask the firmware where it wants us to upload the config file. 2217248925Snp */ 2218248925Snp param = FW_PARAM_DEV(CF); 2219248925Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 2220248925Snp if (rc != 0) { 2221248925Snp /* No support for config file? Shouldn't happen. */ 2222248925Snp device_printf(sc->dev, 2223248925Snp "failed to query config file location: %d.\n", rc); 2224248925Snp goto done; 2225248925Snp } 2226248925Snp mtype = G_FW_PARAMS_PARAM_Y(val); 2227248925Snp moff = G_FW_PARAMS_PARAM_Z(val) << 16; 2228228561Snp 2229248925Snp /* 2230248925Snp * XXX: sheer laziness. We deliberately added 4 bytes of 2231248925Snp * useless stuffing/comments at the end of the config file so 2232248925Snp * it's ok to simply throw away the last remaining bytes when 2233248925Snp * the config file is not an exact multiple of 4. This also 2234248925Snp * helps with the validate_mt_off_len check. 2235248925Snp */ 2236248925Snp if (cfg != NULL) { 2237248925Snp cflen = cfg->datasize & ~3; 2238248925Snp cfdata = cfg->data; 2239248925Snp } else { 2240248925Snp cflen = default_cfg->datasize & ~3; 2241248925Snp cfdata = default_cfg->data; 2242248925Snp } 2243222551Snp 2244248925Snp if (cflen > FLASH_CFG_MAX_SIZE) { 2245248925Snp device_printf(sc->dev, 2246248925Snp "config file too long (%d, max allowed is %d). " 2247248925Snp "Will try to use the config on the card, if any.\n", 2248248925Snp cflen, FLASH_CFG_MAX_SIZE); 2249248925Snp goto use_config_on_flash; 2250248925Snp } 2251218792Snp 2252248925Snp rc = validate_mt_off_len(sc, mtype, moff, cflen, &addr); 2253248925Snp if (rc != 0) { 2254248925Snp device_printf(sc->dev, 2255248925Snp "%s: addr (%d/0x%x) or len %d is not valid: %d. " 2256248925Snp "Will try to use the config on the card, if any.\n", 2257248925Snp __func__, mtype, moff, cflen, rc); 2258248925Snp goto use_config_on_flash; 2259248925Snp } 2260248925Snp 2261248925Snp memwin_info(sc, 2, &mw_base, &mw_aperture); 2262248925Snp while (cflen) { 2263248925Snp off = position_memwin(sc, 2, addr); 2264248925Snp n = min(cflen, mw_aperture - off); 2265248925Snp for (i = 0; i < n; i += 4) 2266248925Snp t4_write_reg(sc, mw_base + off + i, *cfdata++); 2267248925Snp cflen -= n; 2268248925Snp addr += n; 2269248925Snp } 2270248925Snp } else { 2271248925Snpuse_config_on_flash: 2272228561Snp mtype = FW_MEMTYPE_CF_FLASH; 2273248925Snp moff = t4_flash_cfg_addr(sc); 2274228561Snp } 2275228561Snp 2276228561Snp bzero(&caps, sizeof(caps)); 2277228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2278218792Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2279228561Snp caps.cfvalid_to_len16 = htobe32(F_FW_CAPS_CONFIG_CMD_CFVALID | 2280228561Snp V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) | 2281248925Snp V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(moff >> 16) | FW_LEN16(caps)); 2282228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 2283228561Snp if (rc != 0) { 2284228561Snp device_printf(sc->dev, 2285249376Snp "failed to pre-process config file: %d " 2286249376Snp "(mtype %d, moff 0x%x).\n", rc, mtype, moff); 2287248925Snp goto done; 2288228561Snp } 2289218792Snp 2290228561Snp finicsum = be32toh(caps.finicsum); 2291228561Snp cfcsum = be32toh(caps.cfcsum); 2292228561Snp if (finicsum != cfcsum) { 2293228561Snp device_printf(sc->dev, 2294228561Snp "WARNING: config file checksum mismatch: %08x %08x\n", 2295228561Snp finicsum, cfcsum); 2296228561Snp } 2297228561Snp sc->cfcsum = cfcsum; 2298218792Snp 2299228561Snp#define LIMIT_CAPS(x) do { \ 2300228561Snp caps.x &= htobe16(t4_##x##_allowed); \ 2301228561Snp sc->x = htobe16(caps.x); \ 2302228561Snp} while (0) 2303228561Snp 2304228561Snp /* 2305228561Snp * Let the firmware know what features will (not) be used so it can tune 2306228561Snp * things accordingly. 2307228561Snp */ 2308228561Snp LIMIT_CAPS(linkcaps); 2309228561Snp LIMIT_CAPS(niccaps); 2310228561Snp LIMIT_CAPS(toecaps); 2311228561Snp LIMIT_CAPS(rdmacaps); 2312228561Snp LIMIT_CAPS(iscsicaps); 2313228561Snp LIMIT_CAPS(fcoecaps); 2314228561Snp#undef LIMIT_CAPS 2315228561Snp 2316228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2317218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE); 2318228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 2319228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), NULL); 2320228561Snp if (rc != 0) { 2321228561Snp device_printf(sc->dev, 2322228561Snp "failed to process config file: %d.\n", rc); 2323228561Snp } 2324248925Snpdone: 2325248925Snp if (cfg != NULL) 2326248925Snp firmware_put(cfg, FIRMWARE_UNLOAD); 2327248925Snp return (rc); 2328218792Snp} 2329218792Snp 2330228561Snp/* 2331248925Snp * Retrieve parameters that are needed (or nice to have) very early. 2332228561Snp */ 2333218792Snpstatic int 2334228561Snpget_params__pre_init(struct adapter *sc) 2335218792Snp{ 2336218792Snp int rc; 2337228561Snp uint32_t param[2], val[2]; 2338228561Snp struct fw_devlog_cmd cmd; 2339228561Snp struct devlog_params *dlog = &sc->params.devlog; 2340218792Snp 2341228561Snp param[0] = FW_PARAM_DEV(PORTVEC); 2342228561Snp param[1] = FW_PARAM_DEV(CCLK); 2343228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 2344218792Snp if (rc != 0) { 2345218792Snp device_printf(sc->dev, 2346228561Snp "failed to query parameters (pre_init): %d.\n", rc); 2347228561Snp return (rc); 2348218792Snp } 2349218792Snp 2350218792Snp sc->params.portvec = val[0]; 2351240452Snp sc->params.nports = bitcount32(val[0]); 2352228561Snp sc->params.vpd.cclk = val[1]; 2353218792Snp 2354228561Snp /* Read device log parameters. */ 2355228561Snp bzero(&cmd, sizeof(cmd)); 2356228561Snp cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) | 2357228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2358228561Snp cmd.retval_len16 = htobe32(FW_LEN16(cmd)); 2359228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &cmd, sizeof(cmd), &cmd); 2360228561Snp if (rc != 0) { 2361228561Snp device_printf(sc->dev, 2362228561Snp "failed to get devlog parameters: %d.\n", rc); 2363228561Snp bzero(dlog, sizeof (*dlog)); 2364228561Snp rc = 0; /* devlog isn't critical for device operation */ 2365228561Snp } else { 2366228561Snp val[0] = be32toh(cmd.memtype_devlog_memaddr16_devlog); 2367228561Snp dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(val[0]); 2368228561Snp dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(val[0]) << 4; 2369228561Snp dlog->size = be32toh(cmd.memsize_devlog); 2370228561Snp } 2371228561Snp 2372228561Snp return (rc); 2373228561Snp} 2374228561Snp 2375228561Snp/* 2376228561Snp * Retrieve various parameters that are of interest to the driver. The device 2377228561Snp * has been initialized by the firmware at this point. 2378228561Snp */ 2379228561Snpstatic int 2380228561Snpget_params__post_init(struct adapter *sc) 2381228561Snp{ 2382228561Snp int rc; 2383228561Snp uint32_t param[7], val[7]; 2384228561Snp struct fw_caps_config_cmd caps; 2385228561Snp 2386228561Snp param[0] = FW_PARAM_PFVF(IQFLINT_START); 2387228561Snp param[1] = FW_PARAM_PFVF(EQ_START); 2388228561Snp param[2] = FW_PARAM_PFVF(FILTER_START); 2389228561Snp param[3] = FW_PARAM_PFVF(FILTER_END); 2390245434Snp param[4] = FW_PARAM_PFVF(L2T_START); 2391245434Snp param[5] = FW_PARAM_PFVF(L2T_END); 2392245434Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2393228561Snp if (rc != 0) { 2394228561Snp device_printf(sc->dev, 2395228561Snp "failed to query parameters (post_init): %d.\n", rc); 2396228561Snp return (rc); 2397228561Snp } 2398228561Snp 2399228561Snp sc->sge.iq_start = val[0]; 2400228561Snp sc->sge.eq_start = val[1]; 2401228561Snp sc->tids.ftid_base = val[2]; 2402228561Snp sc->tids.nftids = val[3] - val[2] + 1; 2403245434Snp sc->vres.l2t.start = val[4]; 2404245434Snp sc->vres.l2t.size = val[5] - val[4] + 1; 2405245434Snp KASSERT(sc->vres.l2t.size <= L2T_SIZE, 2406245434Snp ("%s: L2 table size (%u) larger than expected (%u)", 2407245434Snp __func__, sc->vres.l2t.size, L2T_SIZE)); 2408228561Snp 2409228561Snp /* get capabilites */ 2410228561Snp bzero(&caps, sizeof(caps)); 2411228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2412228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2413228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 2414228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 2415228561Snp if (rc != 0) { 2416228561Snp device_printf(sc->dev, 2417228561Snp "failed to get card capabilities: %d.\n", rc); 2418228561Snp return (rc); 2419228561Snp } 2420228561Snp 2421228561Snp if (caps.toecaps) { 2422218792Snp /* query offload-related parameters */ 2423228561Snp param[0] = FW_PARAM_DEV(NTID); 2424228561Snp param[1] = FW_PARAM_PFVF(SERVER_START); 2425228561Snp param[2] = FW_PARAM_PFVF(SERVER_END); 2426228561Snp param[3] = FW_PARAM_PFVF(TDDP_START); 2427228561Snp param[4] = FW_PARAM_PFVF(TDDP_END); 2428228561Snp param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 2429228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2430218792Snp if (rc != 0) { 2431218792Snp device_printf(sc->dev, 2432218792Snp "failed to query TOE parameters: %d.\n", rc); 2433228561Snp return (rc); 2434218792Snp } 2435218792Snp sc->tids.ntids = val[0]; 2436218792Snp sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS); 2437218792Snp sc->tids.stid_base = val[1]; 2438218792Snp sc->tids.nstids = val[2] - val[1] + 1; 2439218792Snp sc->vres.ddp.start = val[3]; 2440218792Snp sc->vres.ddp.size = val[4] - val[3] + 1; 2441218792Snp sc->params.ofldq_wr_cred = val[5]; 2442218792Snp sc->params.offload = 1; 2443218792Snp } 2444228561Snp if (caps.rdmacaps) { 2445228561Snp param[0] = FW_PARAM_PFVF(STAG_START); 2446228561Snp param[1] = FW_PARAM_PFVF(STAG_END); 2447228561Snp param[2] = FW_PARAM_PFVF(RQ_START); 2448228561Snp param[3] = FW_PARAM_PFVF(RQ_END); 2449228561Snp param[4] = FW_PARAM_PFVF(PBL_START); 2450228561Snp param[5] = FW_PARAM_PFVF(PBL_END); 2451228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2452218792Snp if (rc != 0) { 2453218792Snp device_printf(sc->dev, 2454228561Snp "failed to query RDMA parameters(1): %d.\n", rc); 2455228561Snp return (rc); 2456218792Snp } 2457218792Snp sc->vres.stag.start = val[0]; 2458218792Snp sc->vres.stag.size = val[1] - val[0] + 1; 2459218792Snp sc->vres.rq.start = val[2]; 2460218792Snp sc->vres.rq.size = val[3] - val[2] + 1; 2461218792Snp sc->vres.pbl.start = val[4]; 2462218792Snp sc->vres.pbl.size = val[5] - val[4] + 1; 2463228561Snp 2464228561Snp param[0] = FW_PARAM_PFVF(SQRQ_START); 2465228561Snp param[1] = FW_PARAM_PFVF(SQRQ_END); 2466228561Snp param[2] = FW_PARAM_PFVF(CQ_START); 2467228561Snp param[3] = FW_PARAM_PFVF(CQ_END); 2468228561Snp param[4] = FW_PARAM_PFVF(OCQ_START); 2469228561Snp param[5] = FW_PARAM_PFVF(OCQ_END); 2470228561Snp rc = -t4_query_params(sc, 0, 0, 0, 6, param, val); 2471228561Snp if (rc != 0) { 2472228561Snp device_printf(sc->dev, 2473228561Snp "failed to query RDMA parameters(2): %d.\n", rc); 2474228561Snp return (rc); 2475228561Snp } 2476228561Snp sc->vres.qp.start = val[0]; 2477228561Snp sc->vres.qp.size = val[1] - val[0] + 1; 2478228561Snp sc->vres.cq.start = val[2]; 2479228561Snp sc->vres.cq.size = val[3] - val[2] + 1; 2480228561Snp sc->vres.ocq.start = val[4]; 2481228561Snp sc->vres.ocq.size = val[5] - val[4] + 1; 2482218792Snp } 2483228561Snp if (caps.iscsicaps) { 2484228561Snp param[0] = FW_PARAM_PFVF(ISCSI_START); 2485228561Snp param[1] = FW_PARAM_PFVF(ISCSI_END); 2486228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 2487218792Snp if (rc != 0) { 2488218792Snp device_printf(sc->dev, 2489218792Snp "failed to query iSCSI parameters: %d.\n", rc); 2490228561Snp return (rc); 2491218792Snp } 2492218792Snp sc->vres.iscsi.start = val[0]; 2493218792Snp sc->vres.iscsi.size = val[1] - val[0] + 1; 2494218792Snp } 2495218792Snp 2496248925Snp /* 2497248925Snp * We've got the params we wanted to query via the firmware. Now grab 2498248925Snp * some others directly from the chip. 2499248925Snp */ 2500248925Snp rc = t4_read_chip_settings(sc); 2501228561Snp 2502218792Snp return (rc); 2503218792Snp} 2504218792Snp 2505247291Snpstatic int 2506247291Snpset_params__post_init(struct adapter *sc) 2507247291Snp{ 2508247291Snp uint32_t param, val; 2509247291Snp 2510249382Snp /* ask for encapsulated CPLs */ 2511247291Snp param = FW_PARAM_PFVF(CPLFW4MSG_ENCAP); 2512249382Snp val = 1; 2513249382Snp (void)t4_set_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 2514247291Snp 2515249382Snp return (0); 2516247291Snp} 2517247291Snp 2518228561Snp#undef FW_PARAM_PFVF 2519228561Snp#undef FW_PARAM_DEV 2520228561Snp 2521218792Snpstatic void 2522218792Snpt4_set_desc(struct adapter *sc) 2523218792Snp{ 2524218792Snp char buf[128]; 2525218792Snp struct adapter_params *p = &sc->params; 2526218792Snp 2527228561Snp snprintf(buf, sizeof(buf), "Chelsio %s %sNIC (rev %d), S/N:%s, E/C:%s", 2528248925Snp p->vpd.id, is_offload(sc) ? "R" : "", chip_rev(sc), p->vpd.sn, 2529248925Snp p->vpd.ec); 2530218792Snp 2531218792Snp device_set_desc_copy(sc->dev, buf); 2532218792Snp} 2533218792Snp 2534218792Snpstatic void 2535218792Snpbuild_medialist(struct port_info *pi) 2536218792Snp{ 2537218792Snp struct ifmedia *media = &pi->media; 2538218792Snp int data, m; 2539218792Snp 2540218792Snp PORT_LOCK(pi); 2541218792Snp 2542218792Snp ifmedia_removeall(media); 2543218792Snp 2544218792Snp m = IFM_ETHER | IFM_FDX; 2545218792Snp data = (pi->port_type << 8) | pi->mod_type; 2546218792Snp 2547218792Snp switch(pi->port_type) { 2548218792Snp case FW_PORT_TYPE_BT_XFI: 2549218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2550218792Snp break; 2551218792Snp 2552218792Snp case FW_PORT_TYPE_BT_XAUI: 2553218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2554218792Snp /* fall through */ 2555218792Snp 2556218792Snp case FW_PORT_TYPE_BT_SGMII: 2557218792Snp ifmedia_add(media, m | IFM_1000_T, data, NULL); 2558218792Snp ifmedia_add(media, m | IFM_100_TX, data, NULL); 2559218792Snp ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL); 2560218792Snp ifmedia_set(media, IFM_ETHER | IFM_AUTO); 2561218792Snp break; 2562218792Snp 2563218792Snp case FW_PORT_TYPE_CX4: 2564218792Snp ifmedia_add(media, m | IFM_10G_CX4, data, NULL); 2565218792Snp ifmedia_set(media, m | IFM_10G_CX4); 2566218792Snp break; 2567218792Snp 2568218792Snp case FW_PORT_TYPE_SFP: 2569218792Snp case FW_PORT_TYPE_FIBER_XFI: 2570218792Snp case FW_PORT_TYPE_FIBER_XAUI: 2571218792Snp switch (pi->mod_type) { 2572218792Snp 2573218792Snp case FW_PORT_MOD_TYPE_LR: 2574218792Snp ifmedia_add(media, m | IFM_10G_LR, data, NULL); 2575218792Snp ifmedia_set(media, m | IFM_10G_LR); 2576218792Snp break; 2577218792Snp 2578218792Snp case FW_PORT_MOD_TYPE_SR: 2579218792Snp ifmedia_add(media, m | IFM_10G_SR, data, NULL); 2580218792Snp ifmedia_set(media, m | IFM_10G_SR); 2581218792Snp break; 2582218792Snp 2583218792Snp case FW_PORT_MOD_TYPE_LRM: 2584218792Snp ifmedia_add(media, m | IFM_10G_LRM, data, NULL); 2585218792Snp ifmedia_set(media, m | IFM_10G_LRM); 2586218792Snp break; 2587218792Snp 2588218792Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2589218792Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2590218792Snp ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL); 2591218792Snp ifmedia_set(media, m | IFM_10G_TWINAX); 2592218792Snp break; 2593218792Snp 2594218792Snp case FW_PORT_MOD_TYPE_NONE: 2595218792Snp m &= ~IFM_FDX; 2596218792Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2597218792Snp ifmedia_set(media, m | IFM_NONE); 2598218792Snp break; 2599218792Snp 2600218792Snp case FW_PORT_MOD_TYPE_NA: 2601218792Snp case FW_PORT_MOD_TYPE_ER: 2602218792Snp default: 2603250092Snp device_printf(pi->dev, 2604250092Snp "unknown port_type (%d), mod_type (%d)\n", 2605250092Snp pi->port_type, pi->mod_type); 2606218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2607218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2608218792Snp break; 2609218792Snp } 2610218792Snp break; 2611218792Snp 2612250092Snp case FW_PORT_TYPE_QSFP: 2613250092Snp switch (pi->mod_type) { 2614250092Snp 2615250092Snp case FW_PORT_MOD_TYPE_LR: 2616250092Snp ifmedia_add(media, m | IFM_40G_LR4, data, NULL); 2617250092Snp ifmedia_set(media, m | IFM_40G_LR4); 2618250092Snp break; 2619250092Snp 2620250092Snp case FW_PORT_MOD_TYPE_SR: 2621250092Snp ifmedia_add(media, m | IFM_40G_SR4, data, NULL); 2622250092Snp ifmedia_set(media, m | IFM_40G_SR4); 2623250092Snp break; 2624250614Snp 2625250092Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2626250092Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2627250092Snp ifmedia_add(media, m | IFM_40G_CR4, data, NULL); 2628250092Snp ifmedia_set(media, m | IFM_40G_CR4); 2629250092Snp break; 2630250092Snp 2631250614Snp case FW_PORT_MOD_TYPE_NONE: 2632250614Snp m &= ~IFM_FDX; 2633250614Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2634250614Snp ifmedia_set(media, m | IFM_NONE); 2635250614Snp break; 2636250614Snp 2637250092Snp default: 2638250092Snp device_printf(pi->dev, 2639250092Snp "unknown port_type (%d), mod_type (%d)\n", 2640250092Snp pi->port_type, pi->mod_type); 2641250092Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2642250092Snp ifmedia_set(media, m | IFM_UNKNOWN); 2643250092Snp break; 2644250092Snp } 2645250092Snp break; 2646250092Snp 2647218792Snp default: 2648250092Snp device_printf(pi->dev, 2649250092Snp "unknown port_type (%d), mod_type (%d)\n", pi->port_type, 2650250092Snp pi->mod_type); 2651218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2652218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2653218792Snp break; 2654218792Snp } 2655218792Snp 2656218792Snp PORT_UNLOCK(pi); 2657218792Snp} 2658218792Snp 2659231172Snp#define FW_MAC_EXACT_CHUNK 7 2660231172Snp 2661218792Snp/* 2662218792Snp * Program the port's XGMAC based on parameters in ifnet. The caller also 2663218792Snp * indicates which parameters should be programmed (the rest are left alone). 2664218792Snp */ 2665218792Snpstatic int 2666218792Snpupdate_mac_settings(struct port_info *pi, int flags) 2667218792Snp{ 2668218792Snp int rc; 2669218792Snp struct ifnet *ifp = pi->ifp; 2670218792Snp struct adapter *sc = pi->adapter; 2671218792Snp int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1; 2672218792Snp 2673245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2674218792Snp KASSERT(flags, ("%s: not told what to update.", __func__)); 2675218792Snp 2676218792Snp if (flags & XGMAC_MTU) 2677218792Snp mtu = ifp->if_mtu; 2678218792Snp 2679218792Snp if (flags & XGMAC_PROMISC) 2680218792Snp promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0; 2681218792Snp 2682218792Snp if (flags & XGMAC_ALLMULTI) 2683218792Snp allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0; 2684218792Snp 2685218792Snp if (flags & XGMAC_VLANEX) 2686218792Snp vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0; 2687218792Snp 2688218792Snp rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, mtu, promisc, allmulti, 1, 2689218792Snp vlanex, false); 2690218792Snp if (rc) { 2691218792Snp if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, rc); 2692218792Snp return (rc); 2693218792Snp } 2694218792Snp 2695218792Snp if (flags & XGMAC_UCADDR) { 2696218792Snp uint8_t ucaddr[ETHER_ADDR_LEN]; 2697218792Snp 2698218792Snp bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr)); 2699218792Snp rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, 2700218792Snp ucaddr, true, true); 2701218792Snp if (rc < 0) { 2702218792Snp rc = -rc; 2703218792Snp if_printf(ifp, "change_mac failed: %d\n", rc); 2704218792Snp return (rc); 2705218792Snp } else { 2706218792Snp pi->xact_addr_filt = rc; 2707218792Snp rc = 0; 2708218792Snp } 2709218792Snp } 2710218792Snp 2711218792Snp if (flags & XGMAC_MCADDRS) { 2712231172Snp const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK]; 2713218792Snp int del = 1; 2714218792Snp uint64_t hash = 0; 2715218792Snp struct ifmultiaddr *ifma; 2716231172Snp int i = 0, j; 2717218792Snp 2718218792Snp if_maddr_rlock(ifp); 2719218792Snp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2720238054Snp if (ifma->ifma_addr->sa_family != AF_LINK) 2721218792Snp continue; 2722231172Snp mcaddr[i++] = 2723231172Snp LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 2724218792Snp 2725231172Snp if (i == FW_MAC_EXACT_CHUNK) { 2726231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2727231172Snp del, i, mcaddr, NULL, &hash, 0); 2728231172Snp if (rc < 0) { 2729231172Snp rc = -rc; 2730231172Snp for (j = 0; j < i; j++) { 2731231172Snp if_printf(ifp, 2732231172Snp "failed to add mc address" 2733231172Snp " %02x:%02x:%02x:" 2734231172Snp "%02x:%02x:%02x rc=%d\n", 2735231172Snp mcaddr[j][0], mcaddr[j][1], 2736231172Snp mcaddr[j][2], mcaddr[j][3], 2737231172Snp mcaddr[j][4], mcaddr[j][5], 2738231172Snp rc); 2739231172Snp } 2740231172Snp goto mcfail; 2741231172Snp } 2742231172Snp del = 0; 2743231172Snp i = 0; 2744231172Snp } 2745231172Snp } 2746231172Snp if (i > 0) { 2747231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2748231172Snp del, i, mcaddr, NULL, &hash, 0); 2749218792Snp if (rc < 0) { 2750218792Snp rc = -rc; 2751231172Snp for (j = 0; j < i; j++) { 2752231172Snp if_printf(ifp, 2753231172Snp "failed to add mc address" 2754231172Snp " %02x:%02x:%02x:" 2755231172Snp "%02x:%02x:%02x rc=%d\n", 2756231172Snp mcaddr[j][0], mcaddr[j][1], 2757231172Snp mcaddr[j][2], mcaddr[j][3], 2758231172Snp mcaddr[j][4], mcaddr[j][5], 2759231172Snp rc); 2760231172Snp } 2761218792Snp goto mcfail; 2762218792Snp } 2763218792Snp } 2764218792Snp 2765218792Snp rc = -t4_set_addr_hash(sc, sc->mbox, pi->viid, 0, hash, 0); 2766218792Snp if (rc != 0) 2767218792Snp if_printf(ifp, "failed to set mc address hash: %d", rc); 2768218792Snpmcfail: 2769218792Snp if_maddr_runlock(ifp); 2770218792Snp } 2771218792Snp 2772218792Snp return (rc); 2773218792Snp} 2774218792Snp 2775245274Snpint 2776245274Snpbegin_synchronized_op(struct adapter *sc, struct port_info *pi, int flags, 2777245274Snp char *wmesg) 2778218792Snp{ 2779245274Snp int rc, pri; 2780218792Snp 2781245274Snp#ifdef WITNESS 2782245274Snp /* the caller thinks it's ok to sleep, but is it really? */ 2783245274Snp if (flags & SLEEP_OK) 2784245274Snp pause("t4slptst", 1); 2785245274Snp#endif 2786218792Snp 2787245274Snp if (INTR_OK) 2788245274Snp pri = PCATCH; 2789245274Snp else 2790245274Snp pri = 0; 2791245274Snp 2792245274Snp ADAPTER_LOCK(sc); 2793245274Snp for (;;) { 2794245274Snp 2795245274Snp if (pi && IS_DOOMED(pi)) { 2796245274Snp rc = ENXIO; 2797245274Snp goto done; 2798245274Snp } 2799245274Snp 2800245274Snp if (!IS_BUSY(sc)) { 2801245274Snp rc = 0; 2802245274Snp break; 2803245274Snp } 2804245274Snp 2805245274Snp if (!(flags & SLEEP_OK)) { 2806245274Snp rc = EBUSY; 2807245274Snp goto done; 2808245274Snp } 2809245274Snp 2810245274Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, pri, wmesg, 0)) { 2811218792Snp rc = EINTR; 2812218792Snp goto done; 2813218792Snp } 2814218792Snp } 2815245274Snp 2816218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 2817218792Snp SET_BUSY(sc); 2818245274Snp#ifdef INVARIANTS 2819245274Snp sc->last_op = wmesg; 2820245274Snp sc->last_op_thr = curthread; 2821245274Snp#endif 2822218792Snp 2823245274Snpdone: 2824245274Snp if (!(flags & HOLD_LOCK) || rc) 2825245274Snp ADAPTER_UNLOCK(sc); 2826218792Snp 2827245274Snp return (rc); 2828245274Snp} 2829245274Snp 2830245274Snpvoid 2831245274Snpend_synchronized_op(struct adapter *sc, int flags) 2832245274Snp{ 2833245274Snp 2834245274Snp if (flags & LOCK_HELD) 2835245274Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 2836245274Snp else 2837245274Snp ADAPTER_LOCK(sc); 2838245274Snp 2839218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 2840218792Snp CLR_BUSY(sc); 2841245274Snp wakeup(&sc->flags); 2842218792Snp ADAPTER_UNLOCK(sc); 2843218792Snp} 2844218792Snp 2845218792Snpstatic int 2846218792Snpcxgbe_init_synchronized(struct port_info *pi) 2847218792Snp{ 2848218792Snp struct adapter *sc = pi->adapter; 2849218792Snp struct ifnet *ifp = pi->ifp; 2850228561Snp int rc = 0; 2851218792Snp 2852245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2853218792Snp 2854218792Snp if (isset(&sc->open_device_map, pi->port_id)) { 2855218792Snp KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, 2856218792Snp ("mismatch between open_device_map and if_drv_flags")); 2857218792Snp return (0); /* already running */ 2858218792Snp } 2859218792Snp 2860228561Snp if (!(sc->flags & FULL_INIT_DONE) && 2861228561Snp ((rc = adapter_full_init(sc)) != 0)) 2862218792Snp return (rc); /* error message displayed already */ 2863218792Snp 2864228561Snp if (!(pi->flags & PORT_INIT_DONE) && 2865228561Snp ((rc = port_full_init(pi)) != 0)) 2866228561Snp return (rc); /* error message displayed already */ 2867218792Snp 2868218792Snp rc = update_mac_settings(pi, XGMAC_ALL); 2869218792Snp if (rc) 2870218792Snp goto done; /* error message displayed already */ 2871218792Snp 2872218792Snp rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg); 2873218792Snp if (rc != 0) { 2874218792Snp if_printf(ifp, "start_link failed: %d\n", rc); 2875218792Snp goto done; 2876218792Snp } 2877218792Snp 2878218792Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true); 2879218792Snp if (rc != 0) { 2880218792Snp if_printf(ifp, "enable_vi failed: %d\n", rc); 2881218792Snp goto done; 2882218792Snp } 2883218792Snp 2884218792Snp /* all ok */ 2885218792Snp setbit(&sc->open_device_map, pi->port_id); 2886245274Snp PORT_LOCK(pi); 2887218792Snp ifp->if_drv_flags |= IFF_DRV_RUNNING; 2888245274Snp PORT_UNLOCK(pi); 2889218792Snp 2890218792Snp callout_reset(&pi->tick, hz, cxgbe_tick, pi); 2891218792Snpdone: 2892218792Snp if (rc != 0) 2893218792Snp cxgbe_uninit_synchronized(pi); 2894218792Snp 2895218792Snp return (rc); 2896218792Snp} 2897218792Snp 2898218792Snp/* 2899218792Snp * Idempotent. 2900218792Snp */ 2901218792Snpstatic int 2902218792Snpcxgbe_uninit_synchronized(struct port_info *pi) 2903218792Snp{ 2904218792Snp struct adapter *sc = pi->adapter; 2905218792Snp struct ifnet *ifp = pi->ifp; 2906218792Snp int rc; 2907218792Snp 2908245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2909218792Snp 2910218792Snp /* 2911228561Snp * Disable the VI so that all its data in either direction is discarded 2912228561Snp * by the MPS. Leave everything else (the queues, interrupts, and 1Hz 2913228561Snp * tick) intact as the TP can deliver negative advice or data that it's 2914228561Snp * holding in its RAM (for an offloaded connection) even after the VI is 2915228561Snp * disabled. 2916218792Snp */ 2917228561Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false); 2918228561Snp if (rc) { 2919228561Snp if_printf(ifp, "disable_vi failed: %d\n", rc); 2920228561Snp return (rc); 2921228561Snp } 2922228561Snp 2923218792Snp clrbit(&sc->open_device_map, pi->port_id); 2924245274Snp PORT_LOCK(pi); 2925228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2926245274Snp PORT_UNLOCK(pi); 2927218792Snp 2928218792Snp pi->link_cfg.link_ok = 0; 2929218792Snp pi->link_cfg.speed = 0; 2930218792Snp t4_os_link_changed(sc, pi->port_id, 0); 2931218792Snp 2932218792Snp return (0); 2933218792Snp} 2934218792Snp 2935240453Snp/* 2936240453Snp * It is ok for this function to fail midway and return right away. t4_detach 2937240453Snp * will walk the entire sc->irq list and clean up whatever is valid. 2938240453Snp */ 2939218792Snpstatic int 2940240453Snpsetup_intr_handlers(struct adapter *sc) 2941218792Snp{ 2942240453Snp int rc, rid, p, q; 2943222510Snp char s[8]; 2944222510Snp struct irq *irq; 2945228561Snp struct port_info *pi; 2946228561Snp struct sge_rxq *rxq; 2947237263Snp#ifdef TCP_OFFLOAD 2948228561Snp struct sge_ofld_rxq *ofld_rxq; 2949228561Snp#endif 2950218792Snp 2951218792Snp /* 2952218792Snp * Setup interrupts. 2953218792Snp */ 2954222510Snp irq = &sc->irq[0]; 2955222510Snp rid = sc->intr_type == INTR_INTX ? 0 : 1; 2956218792Snp if (sc->intr_count == 1) { 2957228561Snp KASSERT(!(sc->flags & INTR_DIRECT), 2958228561Snp ("%s: single interrupt && INTR_DIRECT?", __func__)); 2959222510Snp 2960240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_all, sc, "all"); 2961240453Snp if (rc != 0) 2962240453Snp return (rc); 2963218792Snp } else { 2964228561Snp /* Multiple interrupts. */ 2965228561Snp KASSERT(sc->intr_count >= T4_EXTRA_INTR + sc->params.nports, 2966228561Snp ("%s: too few intr.", __func__)); 2967228561Snp 2968228561Snp /* The first one is always error intr */ 2969240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_err, sc, "err"); 2970240453Snp if (rc != 0) 2971240453Snp return (rc); 2972222510Snp irq++; 2973222510Snp rid++; 2974218792Snp 2975228561Snp /* The second one is always the firmware event queue */ 2976240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_evt, &sc->sge.fwq, 2977240453Snp "evt"); 2978240453Snp if (rc != 0) 2979240453Snp return (rc); 2980228561Snp irq++; 2981228561Snp rid++; 2982222510Snp 2983228561Snp /* 2984228561Snp * Note that if INTR_DIRECT is not set then either the NIC rx 2985228561Snp * queues or (exclusive or) the TOE rx queueus will be taking 2986228561Snp * direct interrupts. 2987228561Snp * 2988228561Snp * There is no need to check for is_offload(sc) as nofldrxq 2989228561Snp * will be 0 if offload is disabled. 2990228561Snp */ 2991228561Snp for_each_port(sc, p) { 2992228561Snp pi = sc->port[p]; 2993222510Snp 2994237263Snp#ifdef TCP_OFFLOAD 2995228561Snp /* 2996228561Snp * Skip over the NIC queues if they aren't taking direct 2997228561Snp * interrupts. 2998228561Snp */ 2999228561Snp if (!(sc->flags & INTR_DIRECT) && 3000228561Snp pi->nofldrxq > pi->nrxq) 3001228561Snp goto ofld_queues; 3002228561Snp#endif 3003228561Snp rxq = &sc->sge.rxq[pi->first_rxq]; 3004228561Snp for (q = 0; q < pi->nrxq; q++, rxq++) { 3005228561Snp snprintf(s, sizeof(s), "%d.%d", p, q); 3006240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, rxq, 3007240453Snp s); 3008240453Snp if (rc != 0) 3009240453Snp return (rc); 3010222510Snp irq++; 3011222510Snp rid++; 3012218792Snp } 3013218792Snp 3014237263Snp#ifdef TCP_OFFLOAD 3015228561Snp /* 3016228561Snp * Skip over the offload queues if they aren't taking 3017228561Snp * direct interrupts. 3018228561Snp */ 3019228561Snp if (!(sc->flags & INTR_DIRECT)) 3020228561Snp continue; 3021228561Snpofld_queues: 3022228561Snp ofld_rxq = &sc->sge.ofld_rxq[pi->first_ofld_rxq]; 3023228561Snp for (q = 0; q < pi->nofldrxq; q++, ofld_rxq++) { 3024228561Snp snprintf(s, sizeof(s), "%d,%d", p, q); 3025240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, 3026240453Snp ofld_rxq, s); 3027240453Snp if (rc != 0) 3028240453Snp return (rc); 3029228561Snp irq++; 3030228561Snp rid++; 3031218792Snp } 3032228561Snp#endif 3033218792Snp } 3034218792Snp } 3035218792Snp 3036240453Snp return (0); 3037240453Snp} 3038240453Snp 3039240453Snpstatic int 3040240453Snpadapter_full_init(struct adapter *sc) 3041240453Snp{ 3042240453Snp int rc, i; 3043240453Snp 3044240453Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 3045240453Snp KASSERT((sc->flags & FULL_INIT_DONE) == 0, 3046240453Snp ("%s: FULL_INIT_DONE already", __func__)); 3047240453Snp 3048240453Snp /* 3049240453Snp * queues that belong to the adapter (not any particular port). 3050240453Snp */ 3051240453Snp rc = t4_setup_adapter_queues(sc); 3052240453Snp if (rc != 0) 3053240453Snp goto done; 3054240453Snp 3055240453Snp for (i = 0; i < nitems(sc->tq); i++) { 3056240453Snp sc->tq[i] = taskqueue_create("t4 taskq", M_NOWAIT, 3057240453Snp taskqueue_thread_enqueue, &sc->tq[i]); 3058240453Snp if (sc->tq[i] == NULL) { 3059240453Snp device_printf(sc->dev, 3060240453Snp "failed to allocate task queue %d\n", i); 3061240453Snp rc = ENOMEM; 3062240453Snp goto done; 3063240453Snp } 3064240453Snp taskqueue_start_threads(&sc->tq[i], 1, PI_NET, "%s tq%d", 3065240453Snp device_get_nameunit(sc->dev), i); 3066240453Snp } 3067240453Snp 3068218792Snp t4_intr_enable(sc); 3069218792Snp sc->flags |= FULL_INIT_DONE; 3070218792Snpdone: 3071218792Snp if (rc != 0) 3072228561Snp adapter_full_uninit(sc); 3073218792Snp 3074218792Snp return (rc); 3075218792Snp} 3076218792Snp 3077218792Snpstatic int 3078228561Snpadapter_full_uninit(struct adapter *sc) 3079218792Snp{ 3080218792Snp int i; 3081218792Snp 3082218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 3083218792Snp 3084220873Snp t4_teardown_adapter_queues(sc); 3085218792Snp 3086240452Snp for (i = 0; i < nitems(sc->tq) && sc->tq[i]; i++) { 3087228561Snp taskqueue_free(sc->tq[i]); 3088228561Snp sc->tq[i] = NULL; 3089228561Snp } 3090228561Snp 3091218792Snp sc->flags &= ~FULL_INIT_DONE; 3092218792Snp 3093218792Snp return (0); 3094218792Snp} 3095218792Snp 3096218792Snpstatic int 3097228561Snpport_full_init(struct port_info *pi) 3098228561Snp{ 3099228561Snp struct adapter *sc = pi->adapter; 3100228561Snp struct ifnet *ifp = pi->ifp; 3101228561Snp uint16_t *rss; 3102228561Snp struct sge_rxq *rxq; 3103228561Snp int rc, i; 3104228561Snp 3105245274Snp ASSERT_SYNCHRONIZED_OP(sc); 3106228561Snp KASSERT((pi->flags & PORT_INIT_DONE) == 0, 3107228561Snp ("%s: PORT_INIT_DONE already", __func__)); 3108228561Snp 3109228561Snp sysctl_ctx_init(&pi->ctx); 3110228561Snp pi->flags |= PORT_SYSCTL_CTX; 3111228561Snp 3112228561Snp /* 3113228561Snp * Allocate tx/rx/fl queues for this port. 3114228561Snp */ 3115228561Snp rc = t4_setup_port_queues(pi); 3116228561Snp if (rc != 0) 3117228561Snp goto done; /* error message displayed already */ 3118228561Snp 3119228561Snp /* 3120228561Snp * Setup RSS for this port. 3121228561Snp */ 3122228561Snp rss = malloc(pi->nrxq * sizeof (*rss), M_CXGBE, 3123228561Snp M_ZERO | M_WAITOK); 3124228561Snp for_each_rxq(pi, i, rxq) { 3125228561Snp rss[i] = rxq->iq.abs_id; 3126228561Snp } 3127228561Snp rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, 3128228561Snp pi->rss_size, rss, pi->nrxq); 3129228561Snp free(rss, M_CXGBE); 3130228561Snp if (rc != 0) { 3131228561Snp if_printf(ifp, "rss_config failed: %d\n", rc); 3132228561Snp goto done; 3133228561Snp } 3134228561Snp 3135228561Snp pi->flags |= PORT_INIT_DONE; 3136228561Snpdone: 3137228561Snp if (rc != 0) 3138228561Snp port_full_uninit(pi); 3139228561Snp 3140228561Snp return (rc); 3141228561Snp} 3142228561Snp 3143228561Snp/* 3144228561Snp * Idempotent. 3145228561Snp */ 3146228561Snpstatic int 3147228561Snpport_full_uninit(struct port_info *pi) 3148228561Snp{ 3149228561Snp struct adapter *sc = pi->adapter; 3150228561Snp int i; 3151228561Snp struct sge_rxq *rxq; 3152228561Snp struct sge_txq *txq; 3153237263Snp#ifdef TCP_OFFLOAD 3154228561Snp struct sge_ofld_rxq *ofld_rxq; 3155228561Snp struct sge_wrq *ofld_txq; 3156228561Snp#endif 3157228561Snp 3158228561Snp if (pi->flags & PORT_INIT_DONE) { 3159228561Snp 3160228561Snp /* Need to quiesce queues. XXX: ctrl queues? */ 3161228561Snp 3162228561Snp for_each_txq(pi, i, txq) { 3163228561Snp quiesce_eq(sc, &txq->eq); 3164228561Snp } 3165228561Snp 3166237263Snp#ifdef TCP_OFFLOAD 3167228561Snp for_each_ofld_txq(pi, i, ofld_txq) { 3168228561Snp quiesce_eq(sc, &ofld_txq->eq); 3169228561Snp } 3170228561Snp#endif 3171228561Snp 3172228561Snp for_each_rxq(pi, i, rxq) { 3173228561Snp quiesce_iq(sc, &rxq->iq); 3174228561Snp quiesce_fl(sc, &rxq->fl); 3175228561Snp } 3176228561Snp 3177237263Snp#ifdef TCP_OFFLOAD 3178228561Snp for_each_ofld_rxq(pi, i, ofld_rxq) { 3179228561Snp quiesce_iq(sc, &ofld_rxq->iq); 3180228561Snp quiesce_fl(sc, &ofld_rxq->fl); 3181228561Snp } 3182228561Snp#endif 3183228561Snp } 3184228561Snp 3185228561Snp t4_teardown_port_queues(pi); 3186228561Snp pi->flags &= ~PORT_INIT_DONE; 3187228561Snp 3188228561Snp return (0); 3189228561Snp} 3190228561Snp 3191228561Snpstatic void 3192228561Snpquiesce_eq(struct adapter *sc, struct sge_eq *eq) 3193228561Snp{ 3194228561Snp EQ_LOCK(eq); 3195228561Snp eq->flags |= EQ_DOOMED; 3196228561Snp 3197228561Snp /* 3198228561Snp * Wait for the response to a credit flush if one's 3199228561Snp * pending. 3200228561Snp */ 3201228561Snp while (eq->flags & EQ_CRFLUSHED) 3202228561Snp mtx_sleep(eq, &eq->eq_lock, 0, "crflush", 0); 3203228561Snp EQ_UNLOCK(eq); 3204228561Snp 3205228561Snp callout_drain(&eq->tx_callout); /* XXX: iffy */ 3206228561Snp pause("callout", 10); /* Still iffy */ 3207228561Snp 3208228561Snp taskqueue_drain(sc->tq[eq->tx_chan], &eq->tx_task); 3209228561Snp} 3210228561Snp 3211228561Snpstatic void 3212228561Snpquiesce_iq(struct adapter *sc, struct sge_iq *iq) 3213228561Snp{ 3214228561Snp (void) sc; /* unused */ 3215228561Snp 3216228561Snp /* Synchronize with the interrupt handler */ 3217228561Snp while (!atomic_cmpset_int(&iq->state, IQS_IDLE, IQS_DISABLED)) 3218228561Snp pause("iqfree", 1); 3219228561Snp} 3220228561Snp 3221228561Snpstatic void 3222228561Snpquiesce_fl(struct adapter *sc, struct sge_fl *fl) 3223228561Snp{ 3224228561Snp mtx_lock(&sc->sfl_lock); 3225228561Snp FL_LOCK(fl); 3226228561Snp fl->flags |= FL_DOOMED; 3227228561Snp FL_UNLOCK(fl); 3228228561Snp mtx_unlock(&sc->sfl_lock); 3229228561Snp 3230228561Snp callout_drain(&sc->sfl_callout); 3231228561Snp KASSERT((fl->flags & FL_STARVING) == 0, 3232228561Snp ("%s: still starving", __func__)); 3233228561Snp} 3234228561Snp 3235228561Snpstatic int 3236218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid, 3237228561Snp driver_intr_t *handler, void *arg, char *name) 3238218792Snp{ 3239218792Snp int rc; 3240218792Snp 3241218792Snp irq->rid = rid; 3242218792Snp irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid, 3243218792Snp RF_SHAREABLE | RF_ACTIVE); 3244218792Snp if (irq->res == NULL) { 3245218792Snp device_printf(sc->dev, 3246218792Snp "failed to allocate IRQ for rid %d, name %s.\n", rid, name); 3247218792Snp return (ENOMEM); 3248218792Snp } 3249218792Snp 3250218792Snp rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET, 3251218792Snp NULL, handler, arg, &irq->tag); 3252218792Snp if (rc != 0) { 3253218792Snp device_printf(sc->dev, 3254218792Snp "failed to setup interrupt for rid %d, name %s: %d\n", 3255218792Snp rid, name, rc); 3256218792Snp } else if (name) 3257218792Snp bus_describe_intr(sc->dev, irq->res, irq->tag, name); 3258218792Snp 3259218792Snp return (rc); 3260218792Snp} 3261218792Snp 3262218792Snpstatic int 3263218792Snpt4_free_irq(struct adapter *sc, struct irq *irq) 3264218792Snp{ 3265218792Snp if (irq->tag) 3266218792Snp bus_teardown_intr(sc->dev, irq->res, irq->tag); 3267218792Snp if (irq->res) 3268218792Snp bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res); 3269218792Snp 3270218792Snp bzero(irq, sizeof(*irq)); 3271218792Snp 3272218792Snp return (0); 3273218792Snp} 3274218792Snp 3275218792Snpstatic void 3276218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start, 3277218792Snp unsigned int end) 3278218792Snp{ 3279218792Snp uint32_t *p = (uint32_t *)(buf + start); 3280218792Snp 3281218792Snp for ( ; start <= end; start += sizeof(uint32_t)) 3282218792Snp *p++ = t4_read_reg(sc, start); 3283218792Snp} 3284218792Snp 3285218792Snpstatic void 3286218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf) 3287218792Snp{ 3288248925Snp int i, n; 3289248925Snp const unsigned int *reg_ranges; 3290248925Snp static const unsigned int t4_reg_ranges[] = { 3291218792Snp 0x1008, 0x1108, 3292218792Snp 0x1180, 0x11b4, 3293218792Snp 0x11fc, 0x123c, 3294218792Snp 0x1300, 0x173c, 3295218792Snp 0x1800, 0x18fc, 3296218792Snp 0x3000, 0x30d8, 3297218792Snp 0x30e0, 0x5924, 3298218792Snp 0x5960, 0x59d4, 3299218792Snp 0x5a00, 0x5af8, 3300218792Snp 0x6000, 0x6098, 3301218792Snp 0x6100, 0x6150, 3302218792Snp 0x6200, 0x6208, 3303218792Snp 0x6240, 0x6248, 3304218792Snp 0x6280, 0x6338, 3305218792Snp 0x6370, 0x638c, 3306218792Snp 0x6400, 0x643c, 3307218792Snp 0x6500, 0x6524, 3308218792Snp 0x6a00, 0x6a38, 3309218792Snp 0x6a60, 0x6a78, 3310218792Snp 0x6b00, 0x6b84, 3311218792Snp 0x6bf0, 0x6c84, 3312218792Snp 0x6cf0, 0x6d84, 3313218792Snp 0x6df0, 0x6e84, 3314218792Snp 0x6ef0, 0x6f84, 3315218792Snp 0x6ff0, 0x7084, 3316218792Snp 0x70f0, 0x7184, 3317218792Snp 0x71f0, 0x7284, 3318218792Snp 0x72f0, 0x7384, 3319218792Snp 0x73f0, 0x7450, 3320218792Snp 0x7500, 0x7530, 3321218792Snp 0x7600, 0x761c, 3322218792Snp 0x7680, 0x76cc, 3323218792Snp 0x7700, 0x7798, 3324218792Snp 0x77c0, 0x77fc, 3325218792Snp 0x7900, 0x79fc, 3326218792Snp 0x7b00, 0x7c38, 3327218792Snp 0x7d00, 0x7efc, 3328218792Snp 0x8dc0, 0x8e1c, 3329218792Snp 0x8e30, 0x8e78, 3330218792Snp 0x8ea0, 0x8f6c, 3331218792Snp 0x8fc0, 0x9074, 3332218792Snp 0x90fc, 0x90fc, 3333218792Snp 0x9400, 0x9458, 3334218792Snp 0x9600, 0x96bc, 3335218792Snp 0x9800, 0x9808, 3336218792Snp 0x9820, 0x983c, 3337218792Snp 0x9850, 0x9864, 3338218792Snp 0x9c00, 0x9c6c, 3339218792Snp 0x9c80, 0x9cec, 3340218792Snp 0x9d00, 0x9d6c, 3341218792Snp 0x9d80, 0x9dec, 3342218792Snp 0x9e00, 0x9e6c, 3343218792Snp 0x9e80, 0x9eec, 3344218792Snp 0x9f00, 0x9f6c, 3345218792Snp 0x9f80, 0x9fec, 3346218792Snp 0xd004, 0xd03c, 3347218792Snp 0xdfc0, 0xdfe0, 3348218792Snp 0xe000, 0xea7c, 3349218792Snp 0xf000, 0x11190, 3350237439Snp 0x19040, 0x1906c, 3351237439Snp 0x19078, 0x19080, 3352237439Snp 0x1908c, 0x19124, 3353218792Snp 0x19150, 0x191b0, 3354218792Snp 0x191d0, 0x191e8, 3355218792Snp 0x19238, 0x1924c, 3356218792Snp 0x193f8, 0x19474, 3357218792Snp 0x19490, 0x194f8, 3358218792Snp 0x19800, 0x19f30, 3359218792Snp 0x1a000, 0x1a06c, 3360218792Snp 0x1a0b0, 0x1a120, 3361218792Snp 0x1a128, 0x1a138, 3362218792Snp 0x1a190, 0x1a1c4, 3363218792Snp 0x1a1fc, 0x1a1fc, 3364218792Snp 0x1e040, 0x1e04c, 3365237439Snp 0x1e284, 0x1e28c, 3366218792Snp 0x1e2c0, 0x1e2c0, 3367218792Snp 0x1e2e0, 0x1e2e0, 3368218792Snp 0x1e300, 0x1e384, 3369218792Snp 0x1e3c0, 0x1e3c8, 3370218792Snp 0x1e440, 0x1e44c, 3371237439Snp 0x1e684, 0x1e68c, 3372218792Snp 0x1e6c0, 0x1e6c0, 3373218792Snp 0x1e6e0, 0x1e6e0, 3374218792Snp 0x1e700, 0x1e784, 3375218792Snp 0x1e7c0, 0x1e7c8, 3376218792Snp 0x1e840, 0x1e84c, 3377237439Snp 0x1ea84, 0x1ea8c, 3378218792Snp 0x1eac0, 0x1eac0, 3379218792Snp 0x1eae0, 0x1eae0, 3380218792Snp 0x1eb00, 0x1eb84, 3381218792Snp 0x1ebc0, 0x1ebc8, 3382218792Snp 0x1ec40, 0x1ec4c, 3383237439Snp 0x1ee84, 0x1ee8c, 3384218792Snp 0x1eec0, 0x1eec0, 3385218792Snp 0x1eee0, 0x1eee0, 3386218792Snp 0x1ef00, 0x1ef84, 3387218792Snp 0x1efc0, 0x1efc8, 3388218792Snp 0x1f040, 0x1f04c, 3389237439Snp 0x1f284, 0x1f28c, 3390218792Snp 0x1f2c0, 0x1f2c0, 3391218792Snp 0x1f2e0, 0x1f2e0, 3392218792Snp 0x1f300, 0x1f384, 3393218792Snp 0x1f3c0, 0x1f3c8, 3394218792Snp 0x1f440, 0x1f44c, 3395237439Snp 0x1f684, 0x1f68c, 3396218792Snp 0x1f6c0, 0x1f6c0, 3397218792Snp 0x1f6e0, 0x1f6e0, 3398218792Snp 0x1f700, 0x1f784, 3399218792Snp 0x1f7c0, 0x1f7c8, 3400218792Snp 0x1f840, 0x1f84c, 3401237439Snp 0x1fa84, 0x1fa8c, 3402218792Snp 0x1fac0, 0x1fac0, 3403218792Snp 0x1fae0, 0x1fae0, 3404218792Snp 0x1fb00, 0x1fb84, 3405218792Snp 0x1fbc0, 0x1fbc8, 3406218792Snp 0x1fc40, 0x1fc4c, 3407237439Snp 0x1fe84, 0x1fe8c, 3408218792Snp 0x1fec0, 0x1fec0, 3409218792Snp 0x1fee0, 0x1fee0, 3410218792Snp 0x1ff00, 0x1ff84, 3411218792Snp 0x1ffc0, 0x1ffc8, 3412218792Snp 0x20000, 0x2002c, 3413218792Snp 0x20100, 0x2013c, 3414218792Snp 0x20190, 0x201c8, 3415218792Snp 0x20200, 0x20318, 3416218792Snp 0x20400, 0x20528, 3417218792Snp 0x20540, 0x20614, 3418218792Snp 0x21000, 0x21040, 3419218792Snp 0x2104c, 0x21060, 3420218792Snp 0x210c0, 0x210ec, 3421218792Snp 0x21200, 0x21268, 3422218792Snp 0x21270, 0x21284, 3423218792Snp 0x212fc, 0x21388, 3424218792Snp 0x21400, 0x21404, 3425218792Snp 0x21500, 0x21518, 3426218792Snp 0x2152c, 0x2153c, 3427218792Snp 0x21550, 0x21554, 3428218792Snp 0x21600, 0x21600, 3429218792Snp 0x21608, 0x21628, 3430218792Snp 0x21630, 0x2163c, 3431218792Snp 0x21700, 0x2171c, 3432218792Snp 0x21780, 0x2178c, 3433218792Snp 0x21800, 0x21c38, 3434218792Snp 0x21c80, 0x21d7c, 3435218792Snp 0x21e00, 0x21e04, 3436218792Snp 0x22000, 0x2202c, 3437218792Snp 0x22100, 0x2213c, 3438218792Snp 0x22190, 0x221c8, 3439218792Snp 0x22200, 0x22318, 3440218792Snp 0x22400, 0x22528, 3441218792Snp 0x22540, 0x22614, 3442218792Snp 0x23000, 0x23040, 3443218792Snp 0x2304c, 0x23060, 3444218792Snp 0x230c0, 0x230ec, 3445218792Snp 0x23200, 0x23268, 3446218792Snp 0x23270, 0x23284, 3447218792Snp 0x232fc, 0x23388, 3448218792Snp 0x23400, 0x23404, 3449218792Snp 0x23500, 0x23518, 3450218792Snp 0x2352c, 0x2353c, 3451218792Snp 0x23550, 0x23554, 3452218792Snp 0x23600, 0x23600, 3453218792Snp 0x23608, 0x23628, 3454218792Snp 0x23630, 0x2363c, 3455218792Snp 0x23700, 0x2371c, 3456218792Snp 0x23780, 0x2378c, 3457218792Snp 0x23800, 0x23c38, 3458218792Snp 0x23c80, 0x23d7c, 3459218792Snp 0x23e00, 0x23e04, 3460218792Snp 0x24000, 0x2402c, 3461218792Snp 0x24100, 0x2413c, 3462218792Snp 0x24190, 0x241c8, 3463218792Snp 0x24200, 0x24318, 3464218792Snp 0x24400, 0x24528, 3465218792Snp 0x24540, 0x24614, 3466218792Snp 0x25000, 0x25040, 3467218792Snp 0x2504c, 0x25060, 3468218792Snp 0x250c0, 0x250ec, 3469218792Snp 0x25200, 0x25268, 3470218792Snp 0x25270, 0x25284, 3471218792Snp 0x252fc, 0x25388, 3472218792Snp 0x25400, 0x25404, 3473218792Snp 0x25500, 0x25518, 3474218792Snp 0x2552c, 0x2553c, 3475218792Snp 0x25550, 0x25554, 3476218792Snp 0x25600, 0x25600, 3477218792Snp 0x25608, 0x25628, 3478218792Snp 0x25630, 0x2563c, 3479218792Snp 0x25700, 0x2571c, 3480218792Snp 0x25780, 0x2578c, 3481218792Snp 0x25800, 0x25c38, 3482218792Snp 0x25c80, 0x25d7c, 3483218792Snp 0x25e00, 0x25e04, 3484218792Snp 0x26000, 0x2602c, 3485218792Snp 0x26100, 0x2613c, 3486218792Snp 0x26190, 0x261c8, 3487218792Snp 0x26200, 0x26318, 3488218792Snp 0x26400, 0x26528, 3489218792Snp 0x26540, 0x26614, 3490218792Snp 0x27000, 0x27040, 3491218792Snp 0x2704c, 0x27060, 3492218792Snp 0x270c0, 0x270ec, 3493218792Snp 0x27200, 0x27268, 3494218792Snp 0x27270, 0x27284, 3495218792Snp 0x272fc, 0x27388, 3496218792Snp 0x27400, 0x27404, 3497218792Snp 0x27500, 0x27518, 3498218792Snp 0x2752c, 0x2753c, 3499218792Snp 0x27550, 0x27554, 3500218792Snp 0x27600, 0x27600, 3501218792Snp 0x27608, 0x27628, 3502218792Snp 0x27630, 0x2763c, 3503218792Snp 0x27700, 0x2771c, 3504218792Snp 0x27780, 0x2778c, 3505218792Snp 0x27800, 0x27c38, 3506218792Snp 0x27c80, 0x27d7c, 3507218792Snp 0x27e00, 0x27e04 3508218792Snp }; 3509248925Snp static const unsigned int t5_reg_ranges[] = { 3510248925Snp 0x1008, 0x1148, 3511248925Snp 0x1180, 0x11b4, 3512248925Snp 0x11fc, 0x123c, 3513248925Snp 0x1280, 0x173c, 3514248925Snp 0x1800, 0x18fc, 3515248925Snp 0x3000, 0x3028, 3516248925Snp 0x3060, 0x30d8, 3517248925Snp 0x30e0, 0x30fc, 3518248925Snp 0x3140, 0x357c, 3519248925Snp 0x35a8, 0x35cc, 3520248925Snp 0x35ec, 0x35ec, 3521248925Snp 0x3600, 0x5624, 3522248925Snp 0x56cc, 0x575c, 3523248925Snp 0x580c, 0x5814, 3524248925Snp 0x5890, 0x58bc, 3525248925Snp 0x5940, 0x59dc, 3526248925Snp 0x59fc, 0x5a18, 3527248925Snp 0x5a60, 0x5a9c, 3528248925Snp 0x5b94, 0x5bfc, 3529248925Snp 0x6000, 0x6040, 3530248925Snp 0x6058, 0x614c, 3531248925Snp 0x7700, 0x7798, 3532248925Snp 0x77c0, 0x78fc, 3533248925Snp 0x7b00, 0x7c54, 3534248925Snp 0x7d00, 0x7efc, 3535248925Snp 0x8dc0, 0x8de0, 3536248925Snp 0x8df8, 0x8e84, 3537248925Snp 0x8ea0, 0x8f84, 3538248925Snp 0x8fc0, 0x90f8, 3539248925Snp 0x9400, 0x9470, 3540248925Snp 0x9600, 0x96f4, 3541248925Snp 0x9800, 0x9808, 3542248925Snp 0x9820, 0x983c, 3543248925Snp 0x9850, 0x9864, 3544248925Snp 0x9c00, 0x9c6c, 3545248925Snp 0x9c80, 0x9cec, 3546248925Snp 0x9d00, 0x9d6c, 3547248925Snp 0x9d80, 0x9dec, 3548248925Snp 0x9e00, 0x9e6c, 3549248925Snp 0x9e80, 0x9eec, 3550248925Snp 0x9f00, 0x9f6c, 3551248925Snp 0x9f80, 0xa020, 3552248925Snp 0xd004, 0xd03c, 3553248925Snp 0xdfc0, 0xdfe0, 3554248925Snp 0xe000, 0x11088, 3555248925Snp 0x1109c, 0x1117c, 3556248925Snp 0x11190, 0x11204, 3557248925Snp 0x19040, 0x1906c, 3558248925Snp 0x19078, 0x19080, 3559248925Snp 0x1908c, 0x19124, 3560248925Snp 0x19150, 0x191b0, 3561248925Snp 0x191d0, 0x191e8, 3562248925Snp 0x19238, 0x19290, 3563248925Snp 0x193f8, 0x19474, 3564248925Snp 0x19490, 0x194cc, 3565248925Snp 0x194f0, 0x194f8, 3566248925Snp 0x19c00, 0x19c60, 3567248925Snp 0x19c94, 0x19e10, 3568248925Snp 0x19e50, 0x19f34, 3569248925Snp 0x19f40, 0x19f50, 3570248925Snp 0x19f90, 0x19fe4, 3571248925Snp 0x1a000, 0x1a06c, 3572248925Snp 0x1a0b0, 0x1a120, 3573248925Snp 0x1a128, 0x1a138, 3574248925Snp 0x1a190, 0x1a1c4, 3575248925Snp 0x1a1fc, 0x1a1fc, 3576248925Snp 0x1e008, 0x1e00c, 3577248925Snp 0x1e040, 0x1e04c, 3578248925Snp 0x1e284, 0x1e290, 3579248925Snp 0x1e2c0, 0x1e2c0, 3580248925Snp 0x1e2e0, 0x1e2e0, 3581248925Snp 0x1e300, 0x1e384, 3582248925Snp 0x1e3c0, 0x1e3c8, 3583248925Snp 0x1e408, 0x1e40c, 3584248925Snp 0x1e440, 0x1e44c, 3585248925Snp 0x1e684, 0x1e690, 3586248925Snp 0x1e6c0, 0x1e6c0, 3587248925Snp 0x1e6e0, 0x1e6e0, 3588248925Snp 0x1e700, 0x1e784, 3589248925Snp 0x1e7c0, 0x1e7c8, 3590248925Snp 0x1e808, 0x1e80c, 3591248925Snp 0x1e840, 0x1e84c, 3592248925Snp 0x1ea84, 0x1ea90, 3593248925Snp 0x1eac0, 0x1eac0, 3594248925Snp 0x1eae0, 0x1eae0, 3595248925Snp 0x1eb00, 0x1eb84, 3596248925Snp 0x1ebc0, 0x1ebc8, 3597248925Snp 0x1ec08, 0x1ec0c, 3598248925Snp 0x1ec40, 0x1ec4c, 3599248925Snp 0x1ee84, 0x1ee90, 3600248925Snp 0x1eec0, 0x1eec0, 3601248925Snp 0x1eee0, 0x1eee0, 3602248925Snp 0x1ef00, 0x1ef84, 3603248925Snp 0x1efc0, 0x1efc8, 3604248925Snp 0x1f008, 0x1f00c, 3605248925Snp 0x1f040, 0x1f04c, 3606248925Snp 0x1f284, 0x1f290, 3607248925Snp 0x1f2c0, 0x1f2c0, 3608248925Snp 0x1f2e0, 0x1f2e0, 3609248925Snp 0x1f300, 0x1f384, 3610248925Snp 0x1f3c0, 0x1f3c8, 3611248925Snp 0x1f408, 0x1f40c, 3612248925Snp 0x1f440, 0x1f44c, 3613248925Snp 0x1f684, 0x1f690, 3614248925Snp 0x1f6c0, 0x1f6c0, 3615248925Snp 0x1f6e0, 0x1f6e0, 3616248925Snp 0x1f700, 0x1f784, 3617248925Snp 0x1f7c0, 0x1f7c8, 3618248925Snp 0x1f808, 0x1f80c, 3619248925Snp 0x1f840, 0x1f84c, 3620248925Snp 0x1fa84, 0x1fa90, 3621248925Snp 0x1fac0, 0x1fac0, 3622248925Snp 0x1fae0, 0x1fae0, 3623248925Snp 0x1fb00, 0x1fb84, 3624248925Snp 0x1fbc0, 0x1fbc8, 3625248925Snp 0x1fc08, 0x1fc0c, 3626248925Snp 0x1fc40, 0x1fc4c, 3627248925Snp 0x1fe84, 0x1fe90, 3628248925Snp 0x1fec0, 0x1fec0, 3629248925Snp 0x1fee0, 0x1fee0, 3630248925Snp 0x1ff00, 0x1ff84, 3631248925Snp 0x1ffc0, 0x1ffc8, 3632248925Snp 0x30000, 0x30040, 3633248925Snp 0x30100, 0x30144, 3634248925Snp 0x30190, 0x301d0, 3635248925Snp 0x30200, 0x30318, 3636248925Snp 0x30400, 0x3052c, 3637248925Snp 0x30540, 0x3061c, 3638248925Snp 0x30800, 0x30834, 3639248925Snp 0x308c0, 0x30908, 3640248925Snp 0x30910, 0x309ac, 3641248925Snp 0x30a00, 0x30a04, 3642248925Snp 0x30a0c, 0x30a2c, 3643248925Snp 0x30a44, 0x30a50, 3644248925Snp 0x30a74, 0x30c24, 3645248925Snp 0x30d08, 0x30d14, 3646248925Snp 0x30d1c, 0x30d20, 3647248925Snp 0x30d3c, 0x30d50, 3648248925Snp 0x31200, 0x3120c, 3649248925Snp 0x31220, 0x31220, 3650248925Snp 0x31240, 0x31240, 3651248925Snp 0x31600, 0x31600, 3652248925Snp 0x31608, 0x3160c, 3653248925Snp 0x31a00, 0x31a1c, 3654248925Snp 0x31e04, 0x31e20, 3655248925Snp 0x31e38, 0x31e3c, 3656248925Snp 0x31e80, 0x31e80, 3657248925Snp 0x31e88, 0x31ea8, 3658248925Snp 0x31eb0, 0x31eb4, 3659248925Snp 0x31ec8, 0x31ed4, 3660248925Snp 0x31fb8, 0x32004, 3661248925Snp 0x32208, 0x3223c, 3662248925Snp 0x32248, 0x3227c, 3663248925Snp 0x32288, 0x322bc, 3664248925Snp 0x322c8, 0x322fc, 3665248925Snp 0x32600, 0x32630, 3666248925Snp 0x32a00, 0x32abc, 3667248925Snp 0x32b00, 0x32b70, 3668248925Snp 0x33000, 0x33048, 3669248925Snp 0x33060, 0x3309c, 3670248925Snp 0x330f0, 0x33148, 3671248925Snp 0x33160, 0x3319c, 3672248925Snp 0x331f0, 0x332e4, 3673248925Snp 0x332f8, 0x333e4, 3674248925Snp 0x333f8, 0x33448, 3675248925Snp 0x33460, 0x3349c, 3676248925Snp 0x334f0, 0x33548, 3677248925Snp 0x33560, 0x3359c, 3678248925Snp 0x335f0, 0x336e4, 3679248925Snp 0x336f8, 0x337e4, 3680248925Snp 0x337f8, 0x337fc, 3681248925Snp 0x33814, 0x33814, 3682248925Snp 0x3382c, 0x3382c, 3683248925Snp 0x33880, 0x3388c, 3684248925Snp 0x338e8, 0x338ec, 3685248925Snp 0x33900, 0x33948, 3686248925Snp 0x33960, 0x3399c, 3687248925Snp 0x339f0, 0x33ae4, 3688248925Snp 0x33af8, 0x33b10, 3689248925Snp 0x33b28, 0x33b28, 3690248925Snp 0x33b3c, 0x33b50, 3691248925Snp 0x33bf0, 0x33c10, 3692248925Snp 0x33c28, 0x33c28, 3693248925Snp 0x33c3c, 0x33c50, 3694248925Snp 0x33cf0, 0x33cfc, 3695248925Snp 0x34000, 0x34040, 3696248925Snp 0x34100, 0x34144, 3697248925Snp 0x34190, 0x341d0, 3698248925Snp 0x34200, 0x34318, 3699248925Snp 0x34400, 0x3452c, 3700248925Snp 0x34540, 0x3461c, 3701248925Snp 0x34800, 0x34834, 3702248925Snp 0x348c0, 0x34908, 3703248925Snp 0x34910, 0x349ac, 3704248925Snp 0x34a00, 0x34a04, 3705248925Snp 0x34a0c, 0x34a2c, 3706248925Snp 0x34a44, 0x34a50, 3707248925Snp 0x34a74, 0x34c24, 3708248925Snp 0x34d08, 0x34d14, 3709248925Snp 0x34d1c, 0x34d20, 3710248925Snp 0x34d3c, 0x34d50, 3711248925Snp 0x35200, 0x3520c, 3712248925Snp 0x35220, 0x35220, 3713248925Snp 0x35240, 0x35240, 3714248925Snp 0x35600, 0x35600, 3715248925Snp 0x35608, 0x3560c, 3716248925Snp 0x35a00, 0x35a1c, 3717248925Snp 0x35e04, 0x35e20, 3718248925Snp 0x35e38, 0x35e3c, 3719248925Snp 0x35e80, 0x35e80, 3720248925Snp 0x35e88, 0x35ea8, 3721248925Snp 0x35eb0, 0x35eb4, 3722248925Snp 0x35ec8, 0x35ed4, 3723248925Snp 0x35fb8, 0x36004, 3724248925Snp 0x36208, 0x3623c, 3725248925Snp 0x36248, 0x3627c, 3726248925Snp 0x36288, 0x362bc, 3727248925Snp 0x362c8, 0x362fc, 3728248925Snp 0x36600, 0x36630, 3729248925Snp 0x36a00, 0x36abc, 3730248925Snp 0x36b00, 0x36b70, 3731248925Snp 0x37000, 0x37048, 3732248925Snp 0x37060, 0x3709c, 3733248925Snp 0x370f0, 0x37148, 3734248925Snp 0x37160, 0x3719c, 3735248925Snp 0x371f0, 0x372e4, 3736248925Snp 0x372f8, 0x373e4, 3737248925Snp 0x373f8, 0x37448, 3738248925Snp 0x37460, 0x3749c, 3739248925Snp 0x374f0, 0x37548, 3740248925Snp 0x37560, 0x3759c, 3741248925Snp 0x375f0, 0x376e4, 3742248925Snp 0x376f8, 0x377e4, 3743248925Snp 0x377f8, 0x377fc, 3744248925Snp 0x37814, 0x37814, 3745248925Snp 0x3782c, 0x3782c, 3746248925Snp 0x37880, 0x3788c, 3747248925Snp 0x378e8, 0x378ec, 3748248925Snp 0x37900, 0x37948, 3749248925Snp 0x37960, 0x3799c, 3750248925Snp 0x379f0, 0x37ae4, 3751248925Snp 0x37af8, 0x37b10, 3752248925Snp 0x37b28, 0x37b28, 3753248925Snp 0x37b3c, 0x37b50, 3754248925Snp 0x37bf0, 0x37c10, 3755248925Snp 0x37c28, 0x37c28, 3756248925Snp 0x37c3c, 0x37c50, 3757248925Snp 0x37cf0, 0x37cfc, 3758248925Snp 0x38000, 0x38040, 3759248925Snp 0x38100, 0x38144, 3760248925Snp 0x38190, 0x381d0, 3761248925Snp 0x38200, 0x38318, 3762248925Snp 0x38400, 0x3852c, 3763248925Snp 0x38540, 0x3861c, 3764248925Snp 0x38800, 0x38834, 3765248925Snp 0x388c0, 0x38908, 3766248925Snp 0x38910, 0x389ac, 3767248925Snp 0x38a00, 0x38a04, 3768248925Snp 0x38a0c, 0x38a2c, 3769248925Snp 0x38a44, 0x38a50, 3770248925Snp 0x38a74, 0x38c24, 3771248925Snp 0x38d08, 0x38d14, 3772248925Snp 0x38d1c, 0x38d20, 3773248925Snp 0x38d3c, 0x38d50, 3774248925Snp 0x39200, 0x3920c, 3775248925Snp 0x39220, 0x39220, 3776248925Snp 0x39240, 0x39240, 3777248925Snp 0x39600, 0x39600, 3778248925Snp 0x39608, 0x3960c, 3779248925Snp 0x39a00, 0x39a1c, 3780248925Snp 0x39e04, 0x39e20, 3781248925Snp 0x39e38, 0x39e3c, 3782248925Snp 0x39e80, 0x39e80, 3783248925Snp 0x39e88, 0x39ea8, 3784248925Snp 0x39eb0, 0x39eb4, 3785248925Snp 0x39ec8, 0x39ed4, 3786248925Snp 0x39fb8, 0x3a004, 3787248925Snp 0x3a208, 0x3a23c, 3788248925Snp 0x3a248, 0x3a27c, 3789248925Snp 0x3a288, 0x3a2bc, 3790248925Snp 0x3a2c8, 0x3a2fc, 3791248925Snp 0x3a600, 0x3a630, 3792248925Snp 0x3aa00, 0x3aabc, 3793248925Snp 0x3ab00, 0x3ab70, 3794248925Snp 0x3b000, 0x3b048, 3795248925Snp 0x3b060, 0x3b09c, 3796248925Snp 0x3b0f0, 0x3b148, 3797248925Snp 0x3b160, 0x3b19c, 3798248925Snp 0x3b1f0, 0x3b2e4, 3799248925Snp 0x3b2f8, 0x3b3e4, 3800248925Snp 0x3b3f8, 0x3b448, 3801248925Snp 0x3b460, 0x3b49c, 3802248925Snp 0x3b4f0, 0x3b548, 3803248925Snp 0x3b560, 0x3b59c, 3804248925Snp 0x3b5f0, 0x3b6e4, 3805248925Snp 0x3b6f8, 0x3b7e4, 3806248925Snp 0x3b7f8, 0x3b7fc, 3807248925Snp 0x3b814, 0x3b814, 3808248925Snp 0x3b82c, 0x3b82c, 3809248925Snp 0x3b880, 0x3b88c, 3810248925Snp 0x3b8e8, 0x3b8ec, 3811248925Snp 0x3b900, 0x3b948, 3812248925Snp 0x3b960, 0x3b99c, 3813248925Snp 0x3b9f0, 0x3bae4, 3814248925Snp 0x3baf8, 0x3bb10, 3815248925Snp 0x3bb28, 0x3bb28, 3816248925Snp 0x3bb3c, 0x3bb50, 3817248925Snp 0x3bbf0, 0x3bc10, 3818248925Snp 0x3bc28, 0x3bc28, 3819248925Snp 0x3bc3c, 0x3bc50, 3820248925Snp 0x3bcf0, 0x3bcfc, 3821248925Snp 0x3c000, 0x3c040, 3822248925Snp 0x3c100, 0x3c144, 3823248925Snp 0x3c190, 0x3c1d0, 3824248925Snp 0x3c200, 0x3c318, 3825248925Snp 0x3c400, 0x3c52c, 3826248925Snp 0x3c540, 0x3c61c, 3827248925Snp 0x3c800, 0x3c834, 3828248925Snp 0x3c8c0, 0x3c908, 3829248925Snp 0x3c910, 0x3c9ac, 3830248925Snp 0x3ca00, 0x3ca04, 3831248925Snp 0x3ca0c, 0x3ca2c, 3832248925Snp 0x3ca44, 0x3ca50, 3833248925Snp 0x3ca74, 0x3cc24, 3834248925Snp 0x3cd08, 0x3cd14, 3835248925Snp 0x3cd1c, 0x3cd20, 3836248925Snp 0x3cd3c, 0x3cd50, 3837248925Snp 0x3d200, 0x3d20c, 3838248925Snp 0x3d220, 0x3d220, 3839248925Snp 0x3d240, 0x3d240, 3840248925Snp 0x3d600, 0x3d600, 3841248925Snp 0x3d608, 0x3d60c, 3842248925Snp 0x3da00, 0x3da1c, 3843248925Snp 0x3de04, 0x3de20, 3844248925Snp 0x3de38, 0x3de3c, 3845248925Snp 0x3de80, 0x3de80, 3846248925Snp 0x3de88, 0x3dea8, 3847248925Snp 0x3deb0, 0x3deb4, 3848248925Snp 0x3dec8, 0x3ded4, 3849248925Snp 0x3dfb8, 0x3e004, 3850248925Snp 0x3e208, 0x3e23c, 3851248925Snp 0x3e248, 0x3e27c, 3852248925Snp 0x3e288, 0x3e2bc, 3853248925Snp 0x3e2c8, 0x3e2fc, 3854248925Snp 0x3e600, 0x3e630, 3855248925Snp 0x3ea00, 0x3eabc, 3856248925Snp 0x3eb00, 0x3eb70, 3857248925Snp 0x3f000, 0x3f048, 3858248925Snp 0x3f060, 0x3f09c, 3859248925Snp 0x3f0f0, 0x3f148, 3860248925Snp 0x3f160, 0x3f19c, 3861248925Snp 0x3f1f0, 0x3f2e4, 3862248925Snp 0x3f2f8, 0x3f3e4, 3863248925Snp 0x3f3f8, 0x3f448, 3864248925Snp 0x3f460, 0x3f49c, 3865248925Snp 0x3f4f0, 0x3f548, 3866248925Snp 0x3f560, 0x3f59c, 3867248925Snp 0x3f5f0, 0x3f6e4, 3868248925Snp 0x3f6f8, 0x3f7e4, 3869248925Snp 0x3f7f8, 0x3f7fc, 3870248925Snp 0x3f814, 0x3f814, 3871248925Snp 0x3f82c, 0x3f82c, 3872248925Snp 0x3f880, 0x3f88c, 3873248925Snp 0x3f8e8, 0x3f8ec, 3874248925Snp 0x3f900, 0x3f948, 3875248925Snp 0x3f960, 0x3f99c, 3876248925Snp 0x3f9f0, 0x3fae4, 3877248925Snp 0x3faf8, 0x3fb10, 3878248925Snp 0x3fb28, 0x3fb28, 3879248925Snp 0x3fb3c, 0x3fb50, 3880248925Snp 0x3fbf0, 0x3fc10, 3881248925Snp 0x3fc28, 0x3fc28, 3882248925Snp 0x3fc3c, 0x3fc50, 3883248925Snp 0x3fcf0, 0x3fcfc, 3884248925Snp 0x40000, 0x4000c, 3885248925Snp 0x40040, 0x40068, 3886248925Snp 0x4007c, 0x40144, 3887248925Snp 0x40180, 0x4018c, 3888248925Snp 0x40200, 0x40298, 3889248925Snp 0x402ac, 0x4033c, 3890248925Snp 0x403f8, 0x403fc, 3891248925Snp 0x41300, 0x413c4, 3892248925Snp 0x41400, 0x4141c, 3893248925Snp 0x41480, 0x414d0, 3894248925Snp 0x44000, 0x44078, 3895248925Snp 0x440c0, 0x44278, 3896248925Snp 0x442c0, 0x44478, 3897248925Snp 0x444c0, 0x44678, 3898248925Snp 0x446c0, 0x44878, 3899248925Snp 0x448c0, 0x449fc, 3900248925Snp 0x45000, 0x45068, 3901248925Snp 0x45080, 0x45084, 3902248925Snp 0x450a0, 0x450b0, 3903248925Snp 0x45200, 0x45268, 3904248925Snp 0x45280, 0x45284, 3905248925Snp 0x452a0, 0x452b0, 3906248925Snp 0x460c0, 0x460e4, 3907248925Snp 0x47000, 0x4708c, 3908248925Snp 0x47200, 0x47250, 3909248925Snp 0x47400, 0x47420, 3910248925Snp 0x47600, 0x47618, 3911248925Snp 0x47800, 0x47814, 3912248925Snp 0x48000, 0x4800c, 3913248925Snp 0x48040, 0x48068, 3914248925Snp 0x4807c, 0x48144, 3915248925Snp 0x48180, 0x4818c, 3916248925Snp 0x48200, 0x48298, 3917248925Snp 0x482ac, 0x4833c, 3918248925Snp 0x483f8, 0x483fc, 3919248925Snp 0x49300, 0x493c4, 3920248925Snp 0x49400, 0x4941c, 3921248925Snp 0x49480, 0x494d0, 3922248925Snp 0x4c000, 0x4c078, 3923248925Snp 0x4c0c0, 0x4c278, 3924248925Snp 0x4c2c0, 0x4c478, 3925248925Snp 0x4c4c0, 0x4c678, 3926248925Snp 0x4c6c0, 0x4c878, 3927248925Snp 0x4c8c0, 0x4c9fc, 3928248925Snp 0x4d000, 0x4d068, 3929248925Snp 0x4d080, 0x4d084, 3930248925Snp 0x4d0a0, 0x4d0b0, 3931248925Snp 0x4d200, 0x4d268, 3932248925Snp 0x4d280, 0x4d284, 3933248925Snp 0x4d2a0, 0x4d2b0, 3934248925Snp 0x4e0c0, 0x4e0e4, 3935248925Snp 0x4f000, 0x4f08c, 3936248925Snp 0x4f200, 0x4f250, 3937248925Snp 0x4f400, 0x4f420, 3938248925Snp 0x4f600, 0x4f618, 3939248925Snp 0x4f800, 0x4f814, 3940248925Snp 0x50000, 0x500cc, 3941248925Snp 0x50400, 0x50400, 3942248925Snp 0x50800, 0x508cc, 3943248925Snp 0x50c00, 0x50c00, 3944248925Snp 0x51000, 0x5101c, 3945248925Snp 0x51300, 0x51308, 3946248925Snp }; 3947218792Snp 3948248925Snp if (is_t4(sc)) { 3949248925Snp reg_ranges = &t4_reg_ranges[0]; 3950248925Snp n = nitems(t4_reg_ranges); 3951248925Snp } else { 3952248925Snp reg_ranges = &t5_reg_ranges[0]; 3953248925Snp n = nitems(t5_reg_ranges); 3954248925Snp } 3955248925Snp 3956248925Snp regs->version = chip_id(sc) | chip_rev(sc) << 10; 3957248925Snp for (i = 0; i < n; i += 2) 3958218792Snp reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]); 3959218792Snp} 3960218792Snp 3961218792Snpstatic void 3962218792Snpcxgbe_tick(void *arg) 3963218792Snp{ 3964218792Snp struct port_info *pi = arg; 3965218792Snp struct ifnet *ifp = pi->ifp; 3966218792Snp struct sge_txq *txq; 3967218792Snp int i, drops; 3968218792Snp struct port_stats *s = &pi->stats; 3969218792Snp 3970218792Snp PORT_LOCK(pi); 3971218792Snp if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 3972218792Snp PORT_UNLOCK(pi); 3973218792Snp return; /* without scheduling another callout */ 3974218792Snp } 3975218792Snp 3976218792Snp t4_get_port_stats(pi->adapter, pi->tx_chan, s); 3977218792Snp 3978228561Snp ifp->if_opackets = s->tx_frames - s->tx_pause; 3979228561Snp ifp->if_ipackets = s->rx_frames - s->rx_pause; 3980228561Snp ifp->if_obytes = s->tx_octets - s->tx_pause * 64; 3981228561Snp ifp->if_ibytes = s->rx_octets - s->rx_pause * 64; 3982228561Snp ifp->if_omcasts = s->tx_mcast_frames - s->tx_pause; 3983228561Snp ifp->if_imcasts = s->rx_mcast_frames - s->rx_pause; 3984218792Snp ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 + 3985239259Snp s->rx_ovflow3 + s->rx_trunc0 + s->rx_trunc1 + s->rx_trunc2 + 3986239259Snp s->rx_trunc3; 3987218792Snp 3988218792Snp drops = s->tx_drop; 3989218792Snp for_each_txq(pi, i, txq) 3990220873Snp drops += txq->br->br_drops; 3991218792Snp ifp->if_snd.ifq_drops = drops; 3992218792Snp 3993218792Snp ifp->if_oerrors = s->tx_error_frames; 3994218792Snp ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long + 3995218792Snp s->rx_fcs_err + s->rx_len_err; 3996218792Snp 3997218792Snp callout_schedule(&pi->tick, hz); 3998218792Snp PORT_UNLOCK(pi); 3999218792Snp} 4000218792Snp 4001237263Snpstatic void 4002237263Snpcxgbe_vlan_config(void *arg, struct ifnet *ifp, uint16_t vid) 4003237263Snp{ 4004237263Snp struct ifnet *vlan; 4005237263Snp 4006241494Snp if (arg != ifp || ifp->if_type != IFT_ETHER) 4007237263Snp return; 4008237263Snp 4009237263Snp vlan = VLAN_DEVAT(ifp, vid); 4010237263Snp VLAN_SETCOOKIE(vlan, ifp); 4011237263Snp} 4012237263Snp 4013218792Snpstatic int 4014228561Snpcpl_not_handled(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 4015228561Snp{ 4016237263Snp 4017228561Snp#ifdef INVARIANTS 4018237263Snp panic("%s: opcode 0x%02x on iq %p with payload %p", 4019228561Snp __func__, rss->opcode, iq, m); 4020228561Snp#else 4021239336Snp log(LOG_ERR, "%s: opcode 0x%02x on iq %p with payload %p\n", 4022228561Snp __func__, rss->opcode, iq, m); 4023228561Snp m_freem(m); 4024228561Snp#endif 4025228561Snp return (EDOOFUS); 4026228561Snp} 4027228561Snp 4028228561Snpint 4029228561Snpt4_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h) 4030228561Snp{ 4031228561Snp uintptr_t *loc, new; 4032228561Snp 4033240452Snp if (opcode >= nitems(sc->cpl_handler)) 4034228561Snp return (EINVAL); 4035228561Snp 4036228561Snp new = h ? (uintptr_t)h : (uintptr_t)cpl_not_handled; 4037228561Snp loc = (uintptr_t *) &sc->cpl_handler[opcode]; 4038228561Snp atomic_store_rel_ptr(loc, new); 4039228561Snp 4040228561Snp return (0); 4041228561Snp} 4042228561Snp 4043228561Snpstatic int 4044237263Snpan_not_handled(struct sge_iq *iq, const struct rsp_ctrl *ctrl) 4045237263Snp{ 4046237263Snp 4047237263Snp#ifdef INVARIANTS 4048237263Snp panic("%s: async notification on iq %p (ctrl %p)", __func__, iq, ctrl); 4049237263Snp#else 4050239336Snp log(LOG_ERR, "%s: async notification on iq %p (ctrl %p)\n", 4051237263Snp __func__, iq, ctrl); 4052237263Snp#endif 4053237263Snp return (EDOOFUS); 4054237263Snp} 4055237263Snp 4056237263Snpint 4057237263Snpt4_register_an_handler(struct adapter *sc, an_handler_t h) 4058237263Snp{ 4059237263Snp uintptr_t *loc, new; 4060237263Snp 4061237263Snp new = h ? (uintptr_t)h : (uintptr_t)an_not_handled; 4062237263Snp loc = (uintptr_t *) &sc->an_handler; 4063237263Snp atomic_store_rel_ptr(loc, new); 4064237263Snp 4065237263Snp return (0); 4066237263Snp} 4067237263Snp 4068237263Snpstatic int 4069239336Snpfw_msg_not_handled(struct adapter *sc, const __be64 *rpl) 4070239336Snp{ 4071241733Sed const struct cpl_fw6_msg *cpl = 4072241733Sed __containerof(rpl, struct cpl_fw6_msg, data[0]); 4073239336Snp 4074239336Snp#ifdef INVARIANTS 4075239336Snp panic("%s: fw_msg type %d", __func__, cpl->type); 4076239336Snp#else 4077239336Snp log(LOG_ERR, "%s: fw_msg type %d\n", __func__, cpl->type); 4078239336Snp#endif 4079239336Snp return (EDOOFUS); 4080239336Snp} 4081239336Snp 4082239336Snpint 4083239336Snpt4_register_fw_msg_handler(struct adapter *sc, int type, fw_msg_handler_t h) 4084239336Snp{ 4085239336Snp uintptr_t *loc, new; 4086239336Snp 4087240452Snp if (type >= nitems(sc->fw_msg_handler)) 4088239336Snp return (EINVAL); 4089239336Snp 4090247291Snp /* 4091247291Snp * These are dispatched by the handler for FW{4|6}_CPL_MSG using the CPL 4092247291Snp * handler dispatch table. Reject any attempt to install a handler for 4093247291Snp * this subtype. 4094247291Snp */ 4095247291Snp if (type == FW_TYPE_RSSCPL || type == FW6_TYPE_RSSCPL) 4096247291Snp return (EINVAL); 4097247291Snp 4098239336Snp new = h ? (uintptr_t)h : (uintptr_t)fw_msg_not_handled; 4099239336Snp loc = (uintptr_t *) &sc->fw_msg_handler[type]; 4100239336Snp atomic_store_rel_ptr(loc, new); 4101239336Snp 4102239336Snp return (0); 4103239336Snp} 4104239336Snp 4105239336Snpstatic int 4106218792Snpt4_sysctls(struct adapter *sc) 4107218792Snp{ 4108218792Snp struct sysctl_ctx_list *ctx; 4109218792Snp struct sysctl_oid *oid; 4110228561Snp struct sysctl_oid_list *children, *c0; 4111228561Snp static char *caps[] = { 4112228561Snp "\20\1PPP\2QFC\3DCBX", /* caps[0] linkcaps */ 4113228561Snp "\20\1NIC\2VM\3IDS\4UM\5UM_ISGL", /* caps[1] niccaps */ 4114228561Snp "\20\1TOE", /* caps[2] toecaps */ 4115228561Snp "\20\1RDDP\2RDMAC", /* caps[3] rdmacaps */ 4116228561Snp "\20\1INITIATOR_PDU\2TARGET_PDU" /* caps[4] iscsicaps */ 4117228561Snp "\3INITIATOR_CNXOFLD\4TARGET_CNXOFLD" 4118228561Snp "\5INITIATOR_SSNOFLD\6TARGET_SSNOFLD", 4119228561Snp "\20\1INITIATOR\2TARGET\3CTRL_OFLD" /* caps[5] fcoecaps */ 4120228561Snp }; 4121249392Snp static char *doorbells = {"\20\1UDB\2WCWR\3UDBWC\4KDB"}; 4122218792Snp 4123218792Snp ctx = device_get_sysctl_ctx(sc->dev); 4124228561Snp 4125228561Snp /* 4126228561Snp * dev.t4nex.X. 4127228561Snp */ 4128218792Snp oid = device_get_sysctl_tree(sc->dev); 4129228561Snp c0 = children = SYSCTL_CHILDREN(oid); 4130218792Snp 4131248925Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, NULL, 4132248925Snp sc->params.nports, "# of ports"); 4133218792Snp 4134218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD, 4135248925Snp NULL, chip_rev(sc), "chip hardware revision"); 4136218792Snp 4137218792Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 4138218792Snp CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 4139218792Snp 4140228561Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "cf", 4141245936Snp CTLFLAG_RD, &sc->cfg_file, 0, "configuration file"); 4142218792Snp 4143248925Snp SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cfcsum", CTLFLAG_RD, NULL, 4144248925Snp sc->cfcsum, "config file checksum"); 4145228561Snp 4146248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "doorbells", 4147248925Snp CTLTYPE_STRING | CTLFLAG_RD, doorbells, sc->doorbells, 4148248925Snp sysctl_bitfield, "A", "available doorbells"); 4149248925Snp 4150228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkcaps", 4151228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[0], sc->linkcaps, 4152228561Snp sysctl_bitfield, "A", "available link capabilities"); 4153228561Snp 4154228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "niccaps", 4155228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[1], sc->niccaps, 4156228561Snp sysctl_bitfield, "A", "available NIC capabilities"); 4157228561Snp 4158228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "toecaps", 4159228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[2], sc->toecaps, 4160228561Snp sysctl_bitfield, "A", "available TCP offload capabilities"); 4161228561Snp 4162228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdmacaps", 4163228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[3], sc->rdmacaps, 4164228561Snp sysctl_bitfield, "A", "available RDMA capabilities"); 4165228561Snp 4166228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "iscsicaps", 4167228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[4], sc->iscsicaps, 4168228561Snp sysctl_bitfield, "A", "available iSCSI capabilities"); 4169228561Snp 4170228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoecaps", 4171228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[5], sc->fcoecaps, 4172228561Snp sysctl_bitfield, "A", "available FCoE capabilities"); 4173228561Snp 4174248925Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, NULL, 4175248925Snp sc->params.vpd.cclk, "core clock frequency (in KHz)"); 4176218792Snp 4177219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers", 4178228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.timer_val, 4179228561Snp sizeof(sc->sge.timer_val), sysctl_int_array, "A", 4180228561Snp "interrupt holdoff timer values (us)"); 4181218792Snp 4182219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts", 4183228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.counter_val, 4184228561Snp sizeof(sc->sge.counter_val), sysctl_int_array, "A", 4185228561Snp "interrupt holdoff packet counter values"); 4186218792Snp 4187231115Snp#ifdef SBUF_DRAIN 4188228561Snp /* 4189228561Snp * dev.t4nex.X.misc. Marked CTLFLAG_SKIP to avoid information overload. 4190228561Snp */ 4191228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "misc", 4192228561Snp CTLFLAG_RD | CTLFLAG_SKIP, NULL, 4193228561Snp "logs and miscellaneous information"); 4194228561Snp children = SYSCTL_CHILDREN(oid); 4195228561Snp 4196228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cctrl", 4197228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4198228561Snp sysctl_cctrl, "A", "congestion control"); 4199228561Snp 4200247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp0", 4201247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4202247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 0 (TP0)"); 4203247122Snp 4204247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp1", 4205247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 1, 4206247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 1 (TP1)"); 4207247122Snp 4208247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ulp", 4209247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 2, 4210247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 2 (ULP)"); 4211247122Snp 4212247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge0", 4213247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 3, 4214247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 3 (SGE0)"); 4215247122Snp 4216247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge1", 4217247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 4, 4218247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 4 (SGE1)"); 4219247122Snp 4220247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ncsi", 4221247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 5, 4222247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 5 (NCSI)"); 4223247122Snp 4224247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_la", 4225247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4226247122Snp sysctl_cim_la, "A", "CIM logic analyzer"); 4227247122Snp 4228251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ma_la", 4229251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4230251213Snp sysctl_cim_ma_la, "A", "CIM MA logic analyzer"); 4231251213Snp 4232247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp0", 4233247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0 + CIM_NUM_IBQ, 4234247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 0 (ULP0)"); 4235247122Snp 4236247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp1", 4237247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 1 + CIM_NUM_IBQ, 4238247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 1 (ULP1)"); 4239247122Snp 4240247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp2", 4241247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 2 + CIM_NUM_IBQ, 4242247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 2 (ULP2)"); 4243247122Snp 4244247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp3", 4245247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 3 + CIM_NUM_IBQ, 4246247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 3 (ULP3)"); 4247247122Snp 4248247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge", 4249247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 4 + CIM_NUM_IBQ, 4250247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 4 (SGE)"); 4251247122Snp 4252247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ncsi", 4253247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 5 + CIM_NUM_IBQ, 4254247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 5 (NCSI)"); 4255247122Snp 4256248925Snp if (is_t5(sc)) { 4257248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge0_rx", 4258248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 6 + CIM_NUM_IBQ, 4259248925Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 6 (SGE0-RX)"); 4260248925Snp 4261248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge1_rx", 4262248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 7 + CIM_NUM_IBQ, 4263248925Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 7 (SGE1-RX)"); 4264248925Snp } 4265248925Snp 4266251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_pif_la", 4267251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4268251213Snp sysctl_cim_pif_la, "A", "CIM PIF logic analyzer"); 4269251213Snp 4270247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_qcfg", 4271247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4272247122Snp sysctl_cim_qcfg, "A", "CIM queue configuration"); 4273247122Snp 4274228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats", 4275228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4276228561Snp sysctl_cpl_stats, "A", "CPL statistics"); 4277228561Snp 4278228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ddp_stats", 4279228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4280228561Snp sysctl_ddp_stats, "A", "DDP statistics"); 4281228561Snp 4282222551Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog", 4283222551Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4284228561Snp sysctl_devlog, "A", "firmware's device log"); 4285222551Snp 4286228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoe_stats", 4287228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4288228561Snp sysctl_fcoe_stats, "A", "FCoE statistics"); 4289228561Snp 4290228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hw_sched", 4291228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4292228561Snp sysctl_hw_sched, "A", "hardware scheduler "); 4293228561Snp 4294228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "l2t", 4295228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4296228561Snp sysctl_l2t, "A", "hardware L2 table"); 4297228561Snp 4298228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats", 4299228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4300228561Snp sysctl_lb_stats, "A", "loopback statistics"); 4301228561Snp 4302228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "meminfo", 4303228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4304228561Snp sysctl_meminfo, "A", "memory regions"); 4305228561Snp 4306251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "mps_tcam", 4307251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4308251213Snp sysctl_mps_tcam, "A", "MPS TCAM entries"); 4309251213Snp 4310228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "path_mtus", 4311228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4312228561Snp sysctl_path_mtus, "A", "path MTUs"); 4313228561Snp 4314228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pm_stats", 4315228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4316228561Snp sysctl_pm_stats, "A", "PM statistics"); 4317228561Snp 4318228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_stats", 4319228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4320228561Snp sysctl_rdma_stats, "A", "RDMA statistics"); 4321228561Snp 4322228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tcp_stats", 4323228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4324228561Snp sysctl_tcp_stats, "A", "TCP statistics"); 4325228561Snp 4326228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tids", 4327228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4328228561Snp sysctl_tids, "A", "TID information"); 4329228561Snp 4330228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_err_stats", 4331228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4332228561Snp sysctl_tp_err_stats, "A", "TP error statistics"); 4333228561Snp 4334251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_la", 4335251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4336251213Snp sysctl_tp_la, "A", "TP logic analyzer"); 4337251213Snp 4338228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_rate", 4339228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4340228561Snp sysctl_tx_rate, "A", "Tx rate"); 4341248925Snp 4342251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ulprx_la", 4343251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4344251213Snp sysctl_ulprx_la, "A", "ULPRX logic analyzer"); 4345251213Snp 4346248925Snp if (is_t5(sc)) { 4347249392Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "wcwr_stats", 4348248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4349249392Snp sysctl_wcwr_stats, "A", "write combined work requests"); 4350248925Snp } 4351231115Snp#endif 4352228561Snp 4353237263Snp#ifdef TCP_OFFLOAD 4354228561Snp if (is_offload(sc)) { 4355228561Snp /* 4356228561Snp * dev.t4nex.X.toe. 4357228561Snp */ 4358228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "toe", CTLFLAG_RD, 4359228561Snp NULL, "TOE parameters"); 4360228561Snp children = SYSCTL_CHILDREN(oid); 4361228561Snp 4362228561Snp sc->tt.sndbuf = 256 * 1024; 4363228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "sndbuf", CTLFLAG_RW, 4364228561Snp &sc->tt.sndbuf, 0, "max hardware send buffer size"); 4365228561Snp 4366228561Snp sc->tt.ddp = 0; 4367228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp", CTLFLAG_RW, 4368228561Snp &sc->tt.ddp, 0, "DDP allowed"); 4369239341Snp 4370239341Snp sc->tt.indsz = G_INDICATESIZE(t4_read_reg(sc, A_TP_PARA_REG5)); 4371228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "indsz", CTLFLAG_RW, 4372228561Snp &sc->tt.indsz, 0, "DDP max indicate size allowed"); 4373239341Snp 4374239341Snp sc->tt.ddp_thres = 4375239341Snp G_RXCOALESCESIZE(t4_read_reg(sc, A_TP_PARA_REG2)); 4376228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp_thres", CTLFLAG_RW, 4377228561Snp &sc->tt.ddp_thres, 0, "DDP threshold"); 4378228561Snp } 4379228561Snp#endif 4380228561Snp 4381228561Snp 4382218792Snp return (0); 4383218792Snp} 4384218792Snp 4385218792Snpstatic int 4386218792Snpcxgbe_sysctls(struct port_info *pi) 4387218792Snp{ 4388218792Snp struct sysctl_ctx_list *ctx; 4389218792Snp struct sysctl_oid *oid; 4390218792Snp struct sysctl_oid_list *children; 4391218792Snp 4392218792Snp ctx = device_get_sysctl_ctx(pi->dev); 4393218792Snp 4394218792Snp /* 4395218792Snp * dev.cxgbe.X. 4396218792Snp */ 4397218792Snp oid = device_get_sysctl_tree(pi->dev); 4398218792Snp children = SYSCTL_CHILDREN(oid); 4399218792Snp 4400218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD, 4401218792Snp &pi->nrxq, 0, "# of rx queues"); 4402218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD, 4403218792Snp &pi->ntxq, 0, "# of tx queues"); 4404218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD, 4405218792Snp &pi->first_rxq, 0, "index of first rx queue"); 4406218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD, 4407218792Snp &pi->first_txq, 0, "index of first tx queue"); 4408218792Snp 4409237263Snp#ifdef TCP_OFFLOAD 4410228561Snp if (is_offload(pi->adapter)) { 4411228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldrxq", CTLFLAG_RD, 4412228561Snp &pi->nofldrxq, 0, 4413228561Snp "# of rx queues for offloaded TCP connections"); 4414228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldtxq", CTLFLAG_RD, 4415228561Snp &pi->nofldtxq, 0, 4416228561Snp "# of tx queues for offloaded TCP connections"); 4417228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_rxq", 4418228561Snp CTLFLAG_RD, &pi->first_ofld_rxq, 0, 4419228561Snp "index of first TOE rx queue"); 4420228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_txq", 4421228561Snp CTLFLAG_RD, &pi->first_ofld_txq, 0, 4422228561Snp "index of first TOE tx queue"); 4423228561Snp } 4424228561Snp#endif 4425228561Snp 4426218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx", 4427218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I", 4428218792Snp "holdoff timer index"); 4429218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx", 4430218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I", 4431218792Snp "holdoff packet counter index"); 4432218792Snp 4433218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq", 4434218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I", 4435218792Snp "rx queue size"); 4436218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq", 4437218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I", 4438218792Snp "tx queue size"); 4439218792Snp 4440218792Snp /* 4441218792Snp * dev.cxgbe.X.stats. 4442218792Snp */ 4443218792Snp oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, 4444218792Snp NULL, "port statistics"); 4445218792Snp children = SYSCTL_CHILDREN(oid); 4446218792Snp 4447218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \ 4448218792Snp SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \ 4449218792Snp CTLTYPE_U64 | CTLFLAG_RD, pi->adapter, reg, \ 4450218792Snp sysctl_handle_t4_reg64, "QU", desc) 4451218792Snp 4452218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames", 4453218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L)); 4454218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames", 4455218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L)); 4456218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames", 4457218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L)); 4458218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames", 4459218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L)); 4460218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames", 4461218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L)); 4462218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames", 4463218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L)); 4464218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_64", 4465218792Snp "# of tx frames in this range", 4466218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L)); 4467218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127", 4468218792Snp "# of tx frames in this range", 4469218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L)); 4470218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255", 4471218792Snp "# of tx frames in this range", 4472218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L)); 4473218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511", 4474218792Snp "# of tx frames in this range", 4475218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L)); 4476218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023", 4477218792Snp "# of tx frames in this range", 4478218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L)); 4479218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518", 4480218792Snp "# of tx frames in this range", 4481218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L)); 4482218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max", 4483218792Snp "# of tx frames in this range", 4484218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L)); 4485218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames", 4486218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L)); 4487218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted", 4488218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L)); 4489218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted", 4490218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L)); 4491218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted", 4492218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L)); 4493218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted", 4494218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L)); 4495218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted", 4496218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L)); 4497218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted", 4498218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L)); 4499218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted", 4500218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L)); 4501218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted", 4502218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L)); 4503218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted", 4504218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L)); 4505218792Snp 4506218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames", 4507218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L)); 4508218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames", 4509218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L)); 4510218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames", 4511218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L)); 4512218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames", 4513218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L)); 4514218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames", 4515218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L)); 4516218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU", 4517218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L)); 4518218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames", 4519218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L)); 4520218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err", 4521218792Snp "# of frames received with bad FCS", 4522218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L)); 4523218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_len_err", 4524218792Snp "# of frames received with length error", 4525218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L)); 4526218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors", 4527218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L)); 4528218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received", 4529218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L)); 4530218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_64", 4531218792Snp "# of rx frames in this range", 4532218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L)); 4533218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127", 4534218792Snp "# of rx frames in this range", 4535218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L)); 4536218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255", 4537218792Snp "# of rx frames in this range", 4538218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L)); 4539218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511", 4540218792Snp "# of rx frames in this range", 4541218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L)); 4542218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023", 4543218792Snp "# of rx frames in this range", 4544218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L)); 4545218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518", 4546218792Snp "# of rx frames in this range", 4547218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L)); 4548218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max", 4549218792Snp "# of rx frames in this range", 4550218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L)); 4551218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received", 4552218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L)); 4553218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received", 4554218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L)); 4555218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received", 4556218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L)); 4557218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received", 4558218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L)); 4559218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received", 4560218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L)); 4561218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received", 4562218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L)); 4563218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received", 4564218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L)); 4565218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received", 4566218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L)); 4567218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received", 4568218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L)); 4569218792Snp 4570218792Snp#undef SYSCTL_ADD_T4_REG64 4571218792Snp 4572218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \ 4573218792Snp SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \ 4574218792Snp &pi->stats.name, desc) 4575218792Snp 4576218792Snp /* We get these from port_stats and they may be stale by upto 1s */ 4577218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0, 4578218792Snp "# drops due to buffer-group 0 overflows"); 4579218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1, 4580218792Snp "# drops due to buffer-group 1 overflows"); 4581218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2, 4582218792Snp "# drops due to buffer-group 2 overflows"); 4583218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3, 4584218792Snp "# drops due to buffer-group 3 overflows"); 4585218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc0, 4586218792Snp "# of buffer-group 0 truncated packets"); 4587218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc1, 4588218792Snp "# of buffer-group 1 truncated packets"); 4589218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc2, 4590218792Snp "# of buffer-group 2 truncated packets"); 4591218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc3, 4592218792Snp "# of buffer-group 3 truncated packets"); 4593218792Snp 4594218792Snp#undef SYSCTL_ADD_T4_PORTSTAT 4595218792Snp 4596218792Snp return (0); 4597218792Snp} 4598218792Snp 4599218792Snpstatic int 4600219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS) 4601219436Snp{ 4602219436Snp int rc, *i; 4603219436Snp struct sbuf sb; 4604219436Snp 4605219436Snp sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); 4606219436Snp for (i = arg1; arg2; arg2 -= sizeof(int), i++) 4607219436Snp sbuf_printf(&sb, "%d ", *i); 4608219436Snp sbuf_trim(&sb); 4609219436Snp sbuf_finish(&sb); 4610219436Snp rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 4611219436Snp sbuf_delete(&sb); 4612219436Snp return (rc); 4613219436Snp} 4614219436Snp 4615219436Snpstatic int 4616228561Snpsysctl_bitfield(SYSCTL_HANDLER_ARGS) 4617228561Snp{ 4618228561Snp int rc; 4619228561Snp struct sbuf *sb; 4620228561Snp 4621228561Snp rc = sysctl_wire_old_buffer(req, 0); 4622228561Snp if (rc != 0) 4623228561Snp return(rc); 4624228561Snp 4625228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 4626228561Snp if (sb == NULL) 4627228561Snp return (ENOMEM); 4628228561Snp 4629228561Snp sbuf_printf(sb, "%b", (int)arg2, (char *)arg1); 4630228561Snp rc = sbuf_finish(sb); 4631228561Snp sbuf_delete(sb); 4632228561Snp 4633228561Snp return (rc); 4634228561Snp} 4635228561Snp 4636228561Snpstatic int 4637218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS) 4638218792Snp{ 4639218792Snp struct port_info *pi = arg1; 4640218792Snp struct adapter *sc = pi->adapter; 4641218792Snp int idx, rc, i; 4642245274Snp struct sge_rxq *rxq; 4643245274Snp uint8_t v; 4644218792Snp 4645218792Snp idx = pi->tmr_idx; 4646218792Snp 4647218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 4648218792Snp if (rc != 0 || req->newptr == NULL) 4649218792Snp return (rc); 4650218792Snp 4651218792Snp if (idx < 0 || idx >= SGE_NTIMERS) 4652218792Snp return (EINVAL); 4653218792Snp 4654245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4655245274Snp "t4tmr"); 4656245274Snp if (rc) 4657245274Snp return (rc); 4658228561Snp 4659245274Snp v = V_QINTR_TIMER_IDX(idx) | V_QINTR_CNT_EN(pi->pktc_idx != -1); 4660245274Snp for_each_rxq(pi, i, rxq) { 4661228561Snp#ifdef atomic_store_rel_8 4662245274Snp atomic_store_rel_8(&rxq->iq.intr_params, v); 4663228561Snp#else 4664245274Snp rxq->iq.intr_params = v; 4665228561Snp#endif 4666218792Snp } 4667245274Snp pi->tmr_idx = idx; 4668218792Snp 4669245274Snp end_synchronized_op(sc, LOCK_HELD); 4670245274Snp return (0); 4671218792Snp} 4672218792Snp 4673218792Snpstatic int 4674218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS) 4675218792Snp{ 4676218792Snp struct port_info *pi = arg1; 4677218792Snp struct adapter *sc = pi->adapter; 4678218792Snp int idx, rc; 4679218792Snp 4680218792Snp idx = pi->pktc_idx; 4681218792Snp 4682218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 4683218792Snp if (rc != 0 || req->newptr == NULL) 4684218792Snp return (rc); 4685218792Snp 4686218792Snp if (idx < -1 || idx >= SGE_NCOUNTERS) 4687218792Snp return (EINVAL); 4688218792Snp 4689245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4690245274Snp "t4pktc"); 4691245274Snp if (rc) 4692245274Snp return (rc); 4693245274Snp 4694245274Snp if (pi->flags & PORT_INIT_DONE) 4695228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 4696245274Snp else 4697218792Snp pi->pktc_idx = idx; 4698218792Snp 4699245274Snp end_synchronized_op(sc, LOCK_HELD); 4700218792Snp return (rc); 4701218792Snp} 4702218792Snp 4703218792Snpstatic int 4704218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS) 4705218792Snp{ 4706218792Snp struct port_info *pi = arg1; 4707218792Snp struct adapter *sc = pi->adapter; 4708218792Snp int qsize, rc; 4709218792Snp 4710218792Snp qsize = pi->qsize_rxq; 4711218792Snp 4712218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 4713218792Snp if (rc != 0 || req->newptr == NULL) 4714218792Snp return (rc); 4715218792Snp 4716218792Snp if (qsize < 128 || (qsize & 7)) 4717218792Snp return (EINVAL); 4718218792Snp 4719245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4720245274Snp "t4rxqs"); 4721245274Snp if (rc) 4722245274Snp return (rc); 4723245274Snp 4724245274Snp if (pi->flags & PORT_INIT_DONE) 4725228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 4726245274Snp else 4727218792Snp pi->qsize_rxq = qsize; 4728218792Snp 4729245274Snp end_synchronized_op(sc, LOCK_HELD); 4730218792Snp return (rc); 4731218792Snp} 4732218792Snp 4733218792Snpstatic int 4734218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS) 4735218792Snp{ 4736218792Snp struct port_info *pi = arg1; 4737218792Snp struct adapter *sc = pi->adapter; 4738218792Snp int qsize, rc; 4739218792Snp 4740218792Snp qsize = pi->qsize_txq; 4741218792Snp 4742218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 4743218792Snp if (rc != 0 || req->newptr == NULL) 4744218792Snp return (rc); 4745218792Snp 4746245274Snp /* bufring size must be powerof2 */ 4747245274Snp if (qsize < 128 || !powerof2(qsize)) 4748218792Snp return (EINVAL); 4749218792Snp 4750245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4751245274Snp "t4txqs"); 4752245274Snp if (rc) 4753245274Snp return (rc); 4754245274Snp 4755245274Snp if (pi->flags & PORT_INIT_DONE) 4756228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 4757245274Snp else 4758218792Snp pi->qsize_txq = qsize; 4759218792Snp 4760245274Snp end_synchronized_op(sc, LOCK_HELD); 4761218792Snp return (rc); 4762218792Snp} 4763218792Snp 4764218792Snpstatic int 4765218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS) 4766218792Snp{ 4767218792Snp struct adapter *sc = arg1; 4768218792Snp int reg = arg2; 4769218792Snp uint64_t val; 4770218792Snp 4771218792Snp val = t4_read_reg64(sc, reg); 4772218792Snp 4773218792Snp return (sysctl_handle_64(oidp, &val, 0, req)); 4774218792Snp} 4775218792Snp 4776231115Snp#ifdef SBUF_DRAIN 4777228561Snpstatic int 4778228561Snpsysctl_cctrl(SYSCTL_HANDLER_ARGS) 4779228561Snp{ 4780228561Snp struct adapter *sc = arg1; 4781228561Snp struct sbuf *sb; 4782228561Snp int rc, i; 4783228561Snp uint16_t incr[NMTUS][NCCTRL_WIN]; 4784228561Snp static const char *dec_fac[] = { 4785228561Snp "0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875", 4786228561Snp "0.9375" 4787228561Snp }; 4788228561Snp 4789228561Snp rc = sysctl_wire_old_buffer(req, 0); 4790228561Snp if (rc != 0) 4791228561Snp return (rc); 4792228561Snp 4793228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 4794228561Snp if (sb == NULL) 4795228561Snp return (ENOMEM); 4796228561Snp 4797228561Snp t4_read_cong_tbl(sc, incr); 4798228561Snp 4799228561Snp for (i = 0; i < NCCTRL_WIN; ++i) { 4800228561Snp sbuf_printf(sb, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i, 4801228561Snp incr[0][i], incr[1][i], incr[2][i], incr[3][i], incr[4][i], 4802228561Snp incr[5][i], incr[6][i], incr[7][i]); 4803228561Snp sbuf_printf(sb, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n", 4804228561Snp incr[8][i], incr[9][i], incr[10][i], incr[11][i], 4805228561Snp incr[12][i], incr[13][i], incr[14][i], incr[15][i], 4806228561Snp sc->params.a_wnd[i], dec_fac[sc->params.b_wnd[i]]); 4807228561Snp } 4808228561Snp 4809228561Snp rc = sbuf_finish(sb); 4810228561Snp sbuf_delete(sb); 4811228561Snp 4812228561Snp return (rc); 4813228561Snp} 4814228561Snp 4815248925Snpstatic const char *qname[CIM_NUM_IBQ + CIM_NUM_OBQ_T5] = { 4816247122Snp "TP0", "TP1", "ULP", "SGE0", "SGE1", "NC-SI", /* ibq's */ 4817248925Snp "ULP0", "ULP1", "ULP2", "ULP3", "SGE", "NC-SI", /* obq's */ 4818248925Snp "SGE0-RX", "SGE1-RX" /* additional obq's (T5 onwards) */ 4819247122Snp}; 4820247122Snp 4821228561Snpstatic int 4822247122Snpsysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS) 4823247122Snp{ 4824247122Snp struct adapter *sc = arg1; 4825247122Snp struct sbuf *sb; 4826247122Snp int rc, i, n, qid = arg2; 4827247122Snp uint32_t *buf, *p; 4828247122Snp char *qtype; 4829248925Snp u_int cim_num_obq = is_t4(sc) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5; 4830247122Snp 4831248925Snp KASSERT(qid >= 0 && qid < CIM_NUM_IBQ + cim_num_obq, 4832247122Snp ("%s: bad qid %d\n", __func__, qid)); 4833247122Snp 4834247122Snp if (qid < CIM_NUM_IBQ) { 4835247122Snp /* inbound queue */ 4836247122Snp qtype = "IBQ"; 4837247122Snp n = 4 * CIM_IBQ_SIZE; 4838247122Snp buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); 4839247122Snp rc = t4_read_cim_ibq(sc, qid, buf, n); 4840247122Snp } else { 4841247122Snp /* outbound queue */ 4842247122Snp qtype = "OBQ"; 4843247122Snp qid -= CIM_NUM_IBQ; 4844248925Snp n = 4 * cim_num_obq * CIM_OBQ_SIZE; 4845247122Snp buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); 4846247122Snp rc = t4_read_cim_obq(sc, qid, buf, n); 4847247122Snp } 4848247122Snp 4849247122Snp if (rc < 0) { 4850247122Snp rc = -rc; 4851247122Snp goto done; 4852247122Snp } 4853247122Snp n = rc * sizeof(uint32_t); /* rc has # of words actually read */ 4854247122Snp 4855247122Snp rc = sysctl_wire_old_buffer(req, 0); 4856247122Snp if (rc != 0) 4857247122Snp goto done; 4858247122Snp 4859248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req); 4860247122Snp if (sb == NULL) { 4861247122Snp rc = ENOMEM; 4862247122Snp goto done; 4863247122Snp } 4864247122Snp 4865247122Snp sbuf_printf(sb, "%s%d %s", qtype , qid, qname[arg2]); 4866247122Snp for (i = 0, p = buf; i < n; i += 16, p += 4) 4867247122Snp sbuf_printf(sb, "\n%#06x: %08x %08x %08x %08x", i, p[0], p[1], 4868247122Snp p[2], p[3]); 4869247122Snp 4870247122Snp rc = sbuf_finish(sb); 4871247122Snp sbuf_delete(sb); 4872247122Snpdone: 4873247122Snp free(buf, M_CXGBE); 4874247122Snp return (rc); 4875247122Snp} 4876247122Snp 4877247122Snpstatic int 4878247122Snpsysctl_cim_la(SYSCTL_HANDLER_ARGS) 4879247122Snp{ 4880247122Snp struct adapter *sc = arg1; 4881247122Snp u_int cfg; 4882247122Snp struct sbuf *sb; 4883247122Snp uint32_t *buf, *p; 4884247122Snp int rc; 4885247122Snp 4886247122Snp rc = -t4_cim_read(sc, A_UP_UP_DBG_LA_CFG, 1, &cfg); 4887247122Snp if (rc != 0) 4888247122Snp return (rc); 4889247122Snp 4890247122Snp rc = sysctl_wire_old_buffer(req, 0); 4891247122Snp if (rc != 0) 4892247122Snp return (rc); 4893247122Snp 4894247122Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 4895247122Snp if (sb == NULL) 4896247122Snp return (ENOMEM); 4897247122Snp 4898247122Snp buf = malloc(sc->params.cim_la_size * sizeof(uint32_t), M_CXGBE, 4899247122Snp M_ZERO | M_WAITOK); 4900247122Snp 4901247122Snp rc = -t4_cim_read_la(sc, buf, NULL); 4902247122Snp if (rc != 0) 4903247122Snp goto done; 4904247122Snp 4905247122Snp sbuf_printf(sb, "Status Data PC%s", 4906247122Snp cfg & F_UPDBGLACAPTPCONLY ? "" : 4907247122Snp " LS0Stat LS0Addr LS0Data"); 4908247122Snp 4909247122Snp KASSERT((sc->params.cim_la_size & 7) == 0, 4910247122Snp ("%s: p will walk off the end of buf", __func__)); 4911247122Snp 4912247122Snp for (p = buf; p < &buf[sc->params.cim_la_size]; p += 8) { 4913247122Snp if (cfg & F_UPDBGLACAPTPCONLY) { 4914247122Snp sbuf_printf(sb, "\n %02x %08x %08x", p[5] & 0xff, 4915247122Snp p[6], p[7]); 4916247122Snp sbuf_printf(sb, "\n %02x %02x%06x %02x%06x", 4917247122Snp (p[3] >> 8) & 0xff, p[3] & 0xff, p[4] >> 8, 4918247122Snp p[4] & 0xff, p[5] >> 8); 4919247122Snp sbuf_printf(sb, "\n %02x %x%07x %x%07x", 4920247122Snp (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, 4921247122Snp p[1] & 0xf, p[2] >> 4); 4922247122Snp } else { 4923247122Snp sbuf_printf(sb, 4924247122Snp "\n %02x %x%07x %x%07x %08x %08x " 4925247122Snp "%08x%08x%08x%08x", 4926247122Snp (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, 4927247122Snp p[1] & 0xf, p[2] >> 4, p[2] & 0xf, p[3], p[4], p[5], 4928247122Snp p[6], p[7]); 4929247122Snp } 4930247122Snp } 4931247122Snp 4932247122Snp rc = sbuf_finish(sb); 4933247122Snp sbuf_delete(sb); 4934247122Snpdone: 4935247122Snp free(buf, M_CXGBE); 4936247122Snp return (rc); 4937247122Snp} 4938247122Snp 4939247122Snpstatic int 4940251213Snpsysctl_cim_ma_la(SYSCTL_HANDLER_ARGS) 4941251213Snp{ 4942251213Snp struct adapter *sc = arg1; 4943251213Snp u_int i; 4944251213Snp struct sbuf *sb; 4945251213Snp uint32_t *buf, *p; 4946251213Snp int rc; 4947251213Snp 4948251213Snp rc = sysctl_wire_old_buffer(req, 0); 4949251213Snp if (rc != 0) 4950251213Snp return (rc); 4951251213Snp 4952251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 4953251213Snp if (sb == NULL) 4954251213Snp return (ENOMEM); 4955251213Snp 4956251213Snp buf = malloc(2 * CIM_MALA_SIZE * 5 * sizeof(uint32_t), M_CXGBE, 4957251213Snp M_ZERO | M_WAITOK); 4958251213Snp 4959251213Snp t4_cim_read_ma_la(sc, buf, buf + 5 * CIM_MALA_SIZE); 4960251213Snp p = buf; 4961251213Snp 4962251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) { 4963251213Snp sbuf_printf(sb, "\n%02x%08x%08x%08x%08x", p[4], p[3], p[2], 4964251213Snp p[1], p[0]); 4965251213Snp } 4966251213Snp 4967251213Snp sbuf_printf(sb, "\n\nCnt ID Tag UE Data RDY VLD"); 4968251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) { 4969251213Snp sbuf_printf(sb, "\n%3u %2u %x %u %08x%08x %u %u", 4970251213Snp (p[2] >> 10) & 0xff, (p[2] >> 7) & 7, 4971251213Snp (p[2] >> 3) & 0xf, (p[2] >> 2) & 1, 4972251213Snp (p[1] >> 2) | ((p[2] & 3) << 30), 4973251213Snp (p[0] >> 2) | ((p[1] & 3) << 30), (p[0] >> 1) & 1, 4974251213Snp p[0] & 1); 4975251213Snp } 4976251213Snp 4977251213Snp rc = sbuf_finish(sb); 4978251213Snp sbuf_delete(sb); 4979251213Snp free(buf, M_CXGBE); 4980251213Snp return (rc); 4981251213Snp} 4982251213Snp 4983251213Snpstatic int 4984251213Snpsysctl_cim_pif_la(SYSCTL_HANDLER_ARGS) 4985251213Snp{ 4986251213Snp struct adapter *sc = arg1; 4987251213Snp u_int i; 4988251213Snp struct sbuf *sb; 4989251213Snp uint32_t *buf, *p; 4990251213Snp int rc; 4991251213Snp 4992251213Snp rc = sysctl_wire_old_buffer(req, 0); 4993251213Snp if (rc != 0) 4994251213Snp return (rc); 4995251213Snp 4996251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 4997251213Snp if (sb == NULL) 4998251213Snp return (ENOMEM); 4999251213Snp 5000251213Snp buf = malloc(2 * CIM_PIFLA_SIZE * 6 * sizeof(uint32_t), M_CXGBE, 5001251213Snp M_ZERO | M_WAITOK); 5002251213Snp 5003251213Snp t4_cim_read_pif_la(sc, buf, buf + 6 * CIM_PIFLA_SIZE, NULL, NULL); 5004251213Snp p = buf; 5005251213Snp 5006251213Snp sbuf_printf(sb, "Cntl ID DataBE Addr Data"); 5007251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 6) { 5008251213Snp sbuf_printf(sb, "\n %02x %02x %04x %08x %08x%08x%08x%08x", 5009251213Snp (p[5] >> 22) & 0xff, (p[5] >> 16) & 0x3f, p[5] & 0xffff, 5010251213Snp p[4], p[3], p[2], p[1], p[0]); 5011251213Snp } 5012251213Snp 5013251213Snp sbuf_printf(sb, "\n\nCntl ID Data"); 5014251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 6) { 5015251213Snp sbuf_printf(sb, "\n %02x %02x %08x%08x%08x%08x", 5016251213Snp (p[4] >> 6) & 0xff, p[4] & 0x3f, p[3], p[2], p[1], p[0]); 5017251213Snp } 5018251213Snp 5019251213Snp rc = sbuf_finish(sb); 5020251213Snp sbuf_delete(sb); 5021251213Snp free(buf, M_CXGBE); 5022251213Snp return (rc); 5023251213Snp} 5024251213Snp 5025251213Snpstatic int 5026247122Snpsysctl_cim_qcfg(SYSCTL_HANDLER_ARGS) 5027247122Snp{ 5028247122Snp struct adapter *sc = arg1; 5029247122Snp struct sbuf *sb; 5030247122Snp int rc, i; 5031248925Snp uint16_t base[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; 5032248925Snp uint16_t size[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; 5033247122Snp uint16_t thres[CIM_NUM_IBQ]; 5034248925Snp uint32_t obq_wr[2 * CIM_NUM_OBQ_T5], *wr = obq_wr; 5035248925Snp uint32_t stat[4 * (CIM_NUM_IBQ + CIM_NUM_OBQ_T5)], *p = stat; 5036248925Snp u_int cim_num_obq, ibq_rdaddr, obq_rdaddr, nq; 5037247122Snp 5038248925Snp if (is_t4(sc)) { 5039248925Snp cim_num_obq = CIM_NUM_OBQ; 5040248925Snp ibq_rdaddr = A_UP_IBQ_0_RDADDR; 5041248925Snp obq_rdaddr = A_UP_OBQ_0_REALADDR; 5042248925Snp } else { 5043248925Snp cim_num_obq = CIM_NUM_OBQ_T5; 5044248925Snp ibq_rdaddr = A_UP_IBQ_0_SHADOW_RDADDR; 5045248925Snp obq_rdaddr = A_UP_OBQ_0_SHADOW_REALADDR; 5046248925Snp } 5047248925Snp nq = CIM_NUM_IBQ + cim_num_obq; 5048248925Snp 5049248925Snp rc = -t4_cim_read(sc, ibq_rdaddr, 4 * nq, stat); 5050247122Snp if (rc == 0) 5051248925Snp rc = -t4_cim_read(sc, obq_rdaddr, 2 * cim_num_obq, obq_wr); 5052247122Snp if (rc != 0) 5053247122Snp return (rc); 5054247122Snp 5055247122Snp t4_read_cimq_cfg(sc, base, size, thres); 5056247122Snp 5057247122Snp rc = sysctl_wire_old_buffer(req, 0); 5058247122Snp if (rc != 0) 5059247122Snp return (rc); 5060247122Snp 5061248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req); 5062247122Snp if (sb == NULL) 5063247122Snp return (ENOMEM); 5064247122Snp 5065247122Snp sbuf_printf(sb, "Queue Base Size Thres RdPtr WrPtr SOP EOP Avail"); 5066247122Snp 5067247122Snp for (i = 0; i < CIM_NUM_IBQ; i++, p += 4) 5068248925Snp sbuf_printf(sb, "\n%7s %5x %5u %5u %6x %4x %4u %4u %5u", 5069247122Snp qname[i], base[i], size[i], thres[i], G_IBQRDADDR(p[0]), 5070247122Snp G_IBQWRADDR(p[1]), G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), 5071247122Snp G_QUEREMFLITS(p[2]) * 16); 5072248925Snp for ( ; i < nq; i++, p += 4, wr += 2) 5073248925Snp sbuf_printf(sb, "\n%7s %5x %5u %12x %4x %4u %4u %5u", qname[i], 5074247122Snp base[i], size[i], G_QUERDADDR(p[0]) & 0x3fff, 5075247122Snp wr[0] - base[i], G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), 5076247122Snp G_QUEREMFLITS(p[2]) * 16); 5077247122Snp 5078247122Snp rc = sbuf_finish(sb); 5079247122Snp sbuf_delete(sb); 5080247122Snp 5081247122Snp return (rc); 5082247122Snp} 5083247122Snp 5084247122Snpstatic int 5085228561Snpsysctl_cpl_stats(SYSCTL_HANDLER_ARGS) 5086228561Snp{ 5087228561Snp struct adapter *sc = arg1; 5088228561Snp struct sbuf *sb; 5089228561Snp int rc; 5090228561Snp struct tp_cpl_stats stats; 5091228561Snp 5092228561Snp rc = sysctl_wire_old_buffer(req, 0); 5093228561Snp if (rc != 0) 5094228561Snp return (rc); 5095228561Snp 5096228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5097228561Snp if (sb == NULL) 5098228561Snp return (ENOMEM); 5099228561Snp 5100228561Snp t4_tp_get_cpl_stats(sc, &stats); 5101228561Snp 5102228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 5103228561Snp "channel 3\n"); 5104228561Snp sbuf_printf(sb, "CPL requests: %10u %10u %10u %10u\n", 5105228561Snp stats.req[0], stats.req[1], stats.req[2], stats.req[3]); 5106228561Snp sbuf_printf(sb, "CPL responses: %10u %10u %10u %10u", 5107228561Snp stats.rsp[0], stats.rsp[1], stats.rsp[2], stats.rsp[3]); 5108228561Snp 5109228561Snp rc = sbuf_finish(sb); 5110228561Snp sbuf_delete(sb); 5111228561Snp 5112228561Snp return (rc); 5113228561Snp} 5114228561Snp 5115228561Snpstatic int 5116228561Snpsysctl_ddp_stats(SYSCTL_HANDLER_ARGS) 5117228561Snp{ 5118228561Snp struct adapter *sc = arg1; 5119228561Snp struct sbuf *sb; 5120228561Snp int rc; 5121228561Snp struct tp_usm_stats stats; 5122228561Snp 5123228561Snp rc = sysctl_wire_old_buffer(req, 0); 5124228561Snp if (rc != 0) 5125228561Snp return(rc); 5126228561Snp 5127228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5128228561Snp if (sb == NULL) 5129228561Snp return (ENOMEM); 5130228561Snp 5131228561Snp t4_get_usm_stats(sc, &stats); 5132228561Snp 5133228561Snp sbuf_printf(sb, "Frames: %u\n", stats.frames); 5134228561Snp sbuf_printf(sb, "Octets: %ju\n", stats.octets); 5135228561Snp sbuf_printf(sb, "Drops: %u", stats.drops); 5136228561Snp 5137228561Snp rc = sbuf_finish(sb); 5138228561Snp sbuf_delete(sb); 5139228561Snp 5140228561Snp return (rc); 5141228561Snp} 5142228561Snp 5143222551Snpconst char *devlog_level_strings[] = { 5144222551Snp [FW_DEVLOG_LEVEL_EMERG] = "EMERG", 5145222551Snp [FW_DEVLOG_LEVEL_CRIT] = "CRIT", 5146222551Snp [FW_DEVLOG_LEVEL_ERR] = "ERR", 5147222551Snp [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", 5148222551Snp [FW_DEVLOG_LEVEL_INFO] = "INFO", 5149222551Snp [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" 5150222551Snp}; 5151222551Snp 5152222551Snpconst char *devlog_facility_strings[] = { 5153222551Snp [FW_DEVLOG_FACILITY_CORE] = "CORE", 5154222551Snp [FW_DEVLOG_FACILITY_SCHED] = "SCHED", 5155222551Snp [FW_DEVLOG_FACILITY_TIMER] = "TIMER", 5156222551Snp [FW_DEVLOG_FACILITY_RES] = "RES", 5157222551Snp [FW_DEVLOG_FACILITY_HW] = "HW", 5158222551Snp [FW_DEVLOG_FACILITY_FLR] = "FLR", 5159222551Snp [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", 5160222551Snp [FW_DEVLOG_FACILITY_PHY] = "PHY", 5161222551Snp [FW_DEVLOG_FACILITY_MAC] = "MAC", 5162222551Snp [FW_DEVLOG_FACILITY_PORT] = "PORT", 5163222551Snp [FW_DEVLOG_FACILITY_VI] = "VI", 5164222551Snp [FW_DEVLOG_FACILITY_FILTER] = "FILTER", 5165222551Snp [FW_DEVLOG_FACILITY_ACL] = "ACL", 5166222551Snp [FW_DEVLOG_FACILITY_TM] = "TM", 5167222551Snp [FW_DEVLOG_FACILITY_QFC] = "QFC", 5168222551Snp [FW_DEVLOG_FACILITY_DCB] = "DCB", 5169222551Snp [FW_DEVLOG_FACILITY_ETH] = "ETH", 5170222551Snp [FW_DEVLOG_FACILITY_OFLD] = "OFLD", 5171222551Snp [FW_DEVLOG_FACILITY_RI] = "RI", 5172222551Snp [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", 5173222551Snp [FW_DEVLOG_FACILITY_FCOE] = "FCOE", 5174222551Snp [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", 5175222551Snp [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE" 5176222551Snp}; 5177222551Snp 5178222551Snpstatic int 5179222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS) 5180222551Snp{ 5181222551Snp struct adapter *sc = arg1; 5182222551Snp struct devlog_params *dparams = &sc->params.devlog; 5183222551Snp struct fw_devlog_e *buf, *e; 5184222551Snp int i, j, rc, nentries, first = 0; 5185222551Snp struct sbuf *sb; 5186222551Snp uint64_t ftstamp = UINT64_MAX; 5187222551Snp 5188248925Snp if (dparams->start == 0) { 5189248925Snp dparams->memtype = 0; 5190248925Snp dparams->start = 0x84000; 5191248925Snp dparams->size = 32768; 5192248925Snp } 5193222551Snp 5194222551Snp nentries = dparams->size / sizeof(struct fw_devlog_e); 5195222551Snp 5196222551Snp buf = malloc(dparams->size, M_CXGBE, M_NOWAIT); 5197222551Snp if (buf == NULL) 5198222551Snp return (ENOMEM); 5199222551Snp 5200222551Snp rc = -t4_mem_read(sc, dparams->memtype, dparams->start, dparams->size, 5201222551Snp (void *)buf); 5202222551Snp if (rc != 0) 5203222551Snp goto done; 5204222551Snp 5205222551Snp for (i = 0; i < nentries; i++) { 5206222551Snp e = &buf[i]; 5207222551Snp 5208222551Snp if (e->timestamp == 0) 5209222551Snp break; /* end */ 5210222551Snp 5211222551Snp e->timestamp = be64toh(e->timestamp); 5212222551Snp e->seqno = be32toh(e->seqno); 5213222551Snp for (j = 0; j < 8; j++) 5214222551Snp e->params[j] = be32toh(e->params[j]); 5215222551Snp 5216222551Snp if (e->timestamp < ftstamp) { 5217222551Snp ftstamp = e->timestamp; 5218222551Snp first = i; 5219222551Snp } 5220222551Snp } 5221222551Snp 5222222551Snp if (buf[first].timestamp == 0) 5223222551Snp goto done; /* nothing in the log */ 5224222551Snp 5225222551Snp rc = sysctl_wire_old_buffer(req, 0); 5226222551Snp if (rc != 0) 5227222551Snp goto done; 5228222551Snp 5229222551Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5230228561Snp if (sb == NULL) { 5231228561Snp rc = ENOMEM; 5232228561Snp goto done; 5233228561Snp } 5234228561Snp sbuf_printf(sb, "%10s %15s %8s %8s %s\n", 5235222551Snp "Seq#", "Tstamp", "Level", "Facility", "Message"); 5236222551Snp 5237222551Snp i = first; 5238222551Snp do { 5239222551Snp e = &buf[i]; 5240222551Snp if (e->timestamp == 0) 5241222551Snp break; /* end */ 5242222551Snp 5243222551Snp sbuf_printf(sb, "%10d %15ju %8s %8s ", 5244222551Snp e->seqno, e->timestamp, 5245240452Snp (e->level < nitems(devlog_level_strings) ? 5246222551Snp devlog_level_strings[e->level] : "UNKNOWN"), 5247240452Snp (e->facility < nitems(devlog_facility_strings) ? 5248222551Snp devlog_facility_strings[e->facility] : "UNKNOWN")); 5249222551Snp sbuf_printf(sb, e->fmt, e->params[0], e->params[1], 5250222551Snp e->params[2], e->params[3], e->params[4], 5251222551Snp e->params[5], e->params[6], e->params[7]); 5252222551Snp 5253222551Snp if (++i == nentries) 5254222551Snp i = 0; 5255222551Snp } while (i != first); 5256222551Snp 5257222551Snp rc = sbuf_finish(sb); 5258222551Snp sbuf_delete(sb); 5259222551Snpdone: 5260222551Snp free(buf, M_CXGBE); 5261222551Snp return (rc); 5262222551Snp} 5263222551Snp 5264228561Snpstatic int 5265228561Snpsysctl_fcoe_stats(SYSCTL_HANDLER_ARGS) 5266228561Snp{ 5267228561Snp struct adapter *sc = arg1; 5268228561Snp struct sbuf *sb; 5269228561Snp int rc; 5270228561Snp struct tp_fcoe_stats stats[4]; 5271228561Snp 5272228561Snp rc = sysctl_wire_old_buffer(req, 0); 5273228561Snp if (rc != 0) 5274228561Snp return (rc); 5275228561Snp 5276228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5277228561Snp if (sb == NULL) 5278228561Snp return (ENOMEM); 5279228561Snp 5280228561Snp t4_get_fcoe_stats(sc, 0, &stats[0]); 5281228561Snp t4_get_fcoe_stats(sc, 1, &stats[1]); 5282228561Snp t4_get_fcoe_stats(sc, 2, &stats[2]); 5283228561Snp t4_get_fcoe_stats(sc, 3, &stats[3]); 5284228561Snp 5285228561Snp sbuf_printf(sb, " channel 0 channel 1 " 5286228561Snp "channel 2 channel 3\n"); 5287228561Snp sbuf_printf(sb, "octetsDDP: %16ju %16ju %16ju %16ju\n", 5288228561Snp stats[0].octetsDDP, stats[1].octetsDDP, stats[2].octetsDDP, 5289228561Snp stats[3].octetsDDP); 5290228561Snp sbuf_printf(sb, "framesDDP: %16u %16u %16u %16u\n", stats[0].framesDDP, 5291228561Snp stats[1].framesDDP, stats[2].framesDDP, stats[3].framesDDP); 5292228561Snp sbuf_printf(sb, "framesDrop: %16u %16u %16u %16u", 5293228561Snp stats[0].framesDrop, stats[1].framesDrop, stats[2].framesDrop, 5294228561Snp stats[3].framesDrop); 5295228561Snp 5296228561Snp rc = sbuf_finish(sb); 5297228561Snp sbuf_delete(sb); 5298228561Snp 5299228561Snp return (rc); 5300228561Snp} 5301228561Snp 5302228561Snpstatic int 5303228561Snpsysctl_hw_sched(SYSCTL_HANDLER_ARGS) 5304228561Snp{ 5305228561Snp struct adapter *sc = arg1; 5306228561Snp struct sbuf *sb; 5307228561Snp int rc, i; 5308228561Snp unsigned int map, kbps, ipg, mode; 5309228561Snp unsigned int pace_tab[NTX_SCHED]; 5310228561Snp 5311228561Snp rc = sysctl_wire_old_buffer(req, 0); 5312228561Snp if (rc != 0) 5313228561Snp return (rc); 5314228561Snp 5315228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5316228561Snp if (sb == NULL) 5317228561Snp return (ENOMEM); 5318228561Snp 5319228561Snp map = t4_read_reg(sc, A_TP_TX_MOD_QUEUE_REQ_MAP); 5320228561Snp mode = G_TIMERMODE(t4_read_reg(sc, A_TP_MOD_CONFIG)); 5321228561Snp t4_read_pace_tbl(sc, pace_tab); 5322228561Snp 5323228561Snp sbuf_printf(sb, "Scheduler Mode Channel Rate (Kbps) " 5324228561Snp "Class IPG (0.1 ns) Flow IPG (us)"); 5325228561Snp 5326228561Snp for (i = 0; i < NTX_SCHED; ++i, map >>= 2) { 5327228561Snp t4_get_tx_sched(sc, i, &kbps, &ipg); 5328228561Snp sbuf_printf(sb, "\n %u %-5s %u ", i, 5329228561Snp (mode & (1 << i)) ? "flow" : "class", map & 3); 5330228561Snp if (kbps) 5331228561Snp sbuf_printf(sb, "%9u ", kbps); 5332228561Snp else 5333228561Snp sbuf_printf(sb, " disabled "); 5334228561Snp 5335228561Snp if (ipg) 5336228561Snp sbuf_printf(sb, "%13u ", ipg); 5337228561Snp else 5338228561Snp sbuf_printf(sb, " disabled "); 5339228561Snp 5340228561Snp if (pace_tab[i]) 5341228561Snp sbuf_printf(sb, "%10u", pace_tab[i]); 5342228561Snp else 5343228561Snp sbuf_printf(sb, " disabled"); 5344228561Snp } 5345228561Snp 5346228561Snp rc = sbuf_finish(sb); 5347228561Snp sbuf_delete(sb); 5348228561Snp 5349228561Snp return (rc); 5350228561Snp} 5351228561Snp 5352228561Snpstatic int 5353228561Snpsysctl_lb_stats(SYSCTL_HANDLER_ARGS) 5354228561Snp{ 5355228561Snp struct adapter *sc = arg1; 5356228561Snp struct sbuf *sb; 5357228561Snp int rc, i, j; 5358228561Snp uint64_t *p0, *p1; 5359228561Snp struct lb_port_stats s[2]; 5360228561Snp static const char *stat_name[] = { 5361228561Snp "OctetsOK:", "FramesOK:", "BcastFrames:", "McastFrames:", 5362228561Snp "UcastFrames:", "ErrorFrames:", "Frames64:", "Frames65To127:", 5363228561Snp "Frames128To255:", "Frames256To511:", "Frames512To1023:", 5364228561Snp "Frames1024To1518:", "Frames1519ToMax:", "FramesDropped:", 5365228561Snp "BG0FramesDropped:", "BG1FramesDropped:", "BG2FramesDropped:", 5366228561Snp "BG3FramesDropped:", "BG0FramesTrunc:", "BG1FramesTrunc:", 5367228561Snp "BG2FramesTrunc:", "BG3FramesTrunc:" 5368228561Snp }; 5369228561Snp 5370228561Snp rc = sysctl_wire_old_buffer(req, 0); 5371228561Snp if (rc != 0) 5372228561Snp return (rc); 5373228561Snp 5374228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5375228561Snp if (sb == NULL) 5376228561Snp return (ENOMEM); 5377228561Snp 5378228561Snp memset(s, 0, sizeof(s)); 5379228561Snp 5380228561Snp for (i = 0; i < 4; i += 2) { 5381228561Snp t4_get_lb_stats(sc, i, &s[0]); 5382228561Snp t4_get_lb_stats(sc, i + 1, &s[1]); 5383228561Snp 5384228561Snp p0 = &s[0].octets; 5385228561Snp p1 = &s[1].octets; 5386228561Snp sbuf_printf(sb, "%s Loopback %u" 5387228561Snp " Loopback %u", i == 0 ? "" : "\n", i, i + 1); 5388228561Snp 5389240452Snp for (j = 0; j < nitems(stat_name); j++) 5390228561Snp sbuf_printf(sb, "\n%-17s %20ju %20ju", stat_name[j], 5391228561Snp *p0++, *p1++); 5392228561Snp } 5393228561Snp 5394228561Snp rc = sbuf_finish(sb); 5395228561Snp sbuf_delete(sb); 5396228561Snp 5397228561Snp return (rc); 5398228561Snp} 5399228561Snp 5400228561Snpstruct mem_desc { 5401228561Snp unsigned int base; 5402228561Snp unsigned int limit; 5403228561Snp unsigned int idx; 5404228561Snp}; 5405228561Snp 5406228561Snpstatic int 5407228561Snpmem_desc_cmp(const void *a, const void *b) 5408228561Snp{ 5409228561Snp return ((const struct mem_desc *)a)->base - 5410228561Snp ((const struct mem_desc *)b)->base; 5411228561Snp} 5412228561Snp 5413228561Snpstatic void 5414228561Snpmem_region_show(struct sbuf *sb, const char *name, unsigned int from, 5415228561Snp unsigned int to) 5416228561Snp{ 5417228561Snp unsigned int size; 5418228561Snp 5419228561Snp size = to - from + 1; 5420228561Snp if (size == 0) 5421228561Snp return; 5422228561Snp 5423228561Snp /* XXX: need humanize_number(3) in libkern for a more readable 'size' */ 5424228561Snp sbuf_printf(sb, "%-15s %#x-%#x [%u]\n", name, from, to, size); 5425228561Snp} 5426228561Snp 5427228561Snpstatic int 5428228561Snpsysctl_meminfo(SYSCTL_HANDLER_ARGS) 5429228561Snp{ 5430228561Snp struct adapter *sc = arg1; 5431228561Snp struct sbuf *sb; 5432228561Snp int rc, i, n; 5433248925Snp uint32_t lo, hi, used, alloc; 5434248925Snp static const char *memory[] = {"EDC0:", "EDC1:", "MC:", "MC0:", "MC1:"}; 5435228561Snp static const char *region[] = { 5436228561Snp "DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:", 5437228561Snp "Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:", 5438228561Snp "Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:", 5439228561Snp "TDDP region:", "TPT region:", "STAG region:", "RQ region:", 5440248925Snp "RQUDP region:", "PBL region:", "TXPBL region:", 5441248925Snp "DBVFIFO region:", "ULPRX state:", "ULPTX state:", 5442248925Snp "On-chip queues:" 5443228561Snp }; 5444248925Snp struct mem_desc avail[4]; 5445240452Snp struct mem_desc mem[nitems(region) + 3]; /* up to 3 holes */ 5446228561Snp struct mem_desc *md = mem; 5447228561Snp 5448228561Snp rc = sysctl_wire_old_buffer(req, 0); 5449228561Snp if (rc != 0) 5450228561Snp return (rc); 5451228561Snp 5452228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5453228561Snp if (sb == NULL) 5454228561Snp return (ENOMEM); 5455228561Snp 5456240452Snp for (i = 0; i < nitems(mem); i++) { 5457228561Snp mem[i].limit = 0; 5458228561Snp mem[i].idx = i; 5459228561Snp } 5460228561Snp 5461228561Snp /* Find and sort the populated memory ranges */ 5462228561Snp i = 0; 5463228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 5464228561Snp if (lo & F_EDRAM0_ENABLE) { 5465228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 5466228561Snp avail[i].base = G_EDRAM0_BASE(hi) << 20; 5467228561Snp avail[i].limit = avail[i].base + (G_EDRAM0_SIZE(hi) << 20); 5468228561Snp avail[i].idx = 0; 5469228561Snp i++; 5470228561Snp } 5471228561Snp if (lo & F_EDRAM1_ENABLE) { 5472228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 5473228561Snp avail[i].base = G_EDRAM1_BASE(hi) << 20; 5474228561Snp avail[i].limit = avail[i].base + (G_EDRAM1_SIZE(hi) << 20); 5475228561Snp avail[i].idx = 1; 5476228561Snp i++; 5477228561Snp } 5478228561Snp if (lo & F_EXT_MEM_ENABLE) { 5479228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 5480228561Snp avail[i].base = G_EXT_MEM_BASE(hi) << 20; 5481248925Snp avail[i].limit = avail[i].base + 5482248925Snp (G_EXT_MEM_SIZE(hi) << 20); 5483248925Snp avail[i].idx = is_t4(sc) ? 2 : 3; /* Call it MC for T4 */ 5484228561Snp i++; 5485228561Snp } 5486248925Snp if (!is_t4(sc) && lo & F_EXT_MEM1_ENABLE) { 5487248925Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 5488248925Snp avail[i].base = G_EXT_MEM1_BASE(hi) << 20; 5489248925Snp avail[i].limit = avail[i].base + 5490248925Snp (G_EXT_MEM1_SIZE(hi) << 20); 5491248925Snp avail[i].idx = 4; 5492248925Snp i++; 5493248925Snp } 5494228561Snp if (!i) /* no memory available */ 5495228561Snp return 0; 5496228561Snp qsort(avail, i, sizeof(struct mem_desc), mem_desc_cmp); 5497228561Snp 5498228561Snp (md++)->base = t4_read_reg(sc, A_SGE_DBQ_CTXT_BADDR); 5499228561Snp (md++)->base = t4_read_reg(sc, A_SGE_IMSG_CTXT_BADDR); 5500228561Snp (md++)->base = t4_read_reg(sc, A_SGE_FLM_CACHE_BADDR); 5501228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 5502228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_BASE); 5503228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TIMER_BASE); 5504228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_RX_FLST_BASE); 5505228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_TX_FLST_BASE); 5506228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_PS_FLST_BASE); 5507228561Snp 5508228561Snp /* the next few have explicit upper bounds */ 5509228561Snp md->base = t4_read_reg(sc, A_TP_PMM_TX_BASE); 5510228561Snp md->limit = md->base - 1 + 5511228561Snp t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE) * 5512228561Snp G_PMTXMAXPAGE(t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE)); 5513228561Snp md++; 5514228561Snp 5515228561Snp md->base = t4_read_reg(sc, A_TP_PMM_RX_BASE); 5516228561Snp md->limit = md->base - 1 + 5517228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) * 5518228561Snp G_PMRXMAXPAGE(t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE)); 5519228561Snp md++; 5520228561Snp 5521228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 5522228561Snp hi = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4; 5523228561Snp md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE); 5524228561Snp md->limit = (sc->tids.ntids - hi) * 16 + md->base - 1; 5525228561Snp } else { 5526228561Snp md->base = 0; 5527240452Snp md->idx = nitems(region); /* hide it */ 5528228561Snp } 5529228561Snp md++; 5530228561Snp 5531228561Snp#define ulp_region(reg) \ 5532228561Snp md->base = t4_read_reg(sc, A_ULP_ ## reg ## _LLIMIT);\ 5533228561Snp (md++)->limit = t4_read_reg(sc, A_ULP_ ## reg ## _ULIMIT) 5534228561Snp 5535228561Snp ulp_region(RX_ISCSI); 5536228561Snp ulp_region(RX_TDDP); 5537228561Snp ulp_region(TX_TPT); 5538228561Snp ulp_region(RX_STAG); 5539228561Snp ulp_region(RX_RQ); 5540228561Snp ulp_region(RX_RQUDP); 5541228561Snp ulp_region(RX_PBL); 5542228561Snp ulp_region(TX_PBL); 5543228561Snp#undef ulp_region 5544228561Snp 5545248925Snp md->base = 0; 5546248925Snp md->idx = nitems(region); 5547248925Snp if (!is_t4(sc) && t4_read_reg(sc, A_SGE_CONTROL2) & F_VFIFO_ENABLE) { 5548248925Snp md->base = G_BASEADDR(t4_read_reg(sc, A_SGE_DBVFIFO_BADDR)); 5549248925Snp md->limit = md->base + (G_DBVFIFO_SIZE((t4_read_reg(sc, 5550248925Snp A_SGE_DBVFIFO_SIZE))) << 2) - 1; 5551248925Snp } 5552248925Snp md++; 5553248925Snp 5554228561Snp md->base = t4_read_reg(sc, A_ULP_RX_CTX_BASE); 5555228561Snp md->limit = md->base + sc->tids.ntids - 1; 5556228561Snp md++; 5557228561Snp md->base = t4_read_reg(sc, A_ULP_TX_ERR_TABLE_BASE); 5558228561Snp md->limit = md->base + sc->tids.ntids - 1; 5559228561Snp md++; 5560228561Snp 5561228561Snp md->base = sc->vres.ocq.start; 5562228561Snp if (sc->vres.ocq.size) 5563228561Snp md->limit = md->base + sc->vres.ocq.size - 1; 5564228561Snp else 5565240452Snp md->idx = nitems(region); /* hide it */ 5566228561Snp md++; 5567228561Snp 5568228561Snp /* add any address-space holes, there can be up to 3 */ 5569228561Snp for (n = 0; n < i - 1; n++) 5570228561Snp if (avail[n].limit < avail[n + 1].base) 5571228561Snp (md++)->base = avail[n].limit; 5572228561Snp if (avail[n].limit) 5573228561Snp (md++)->base = avail[n].limit; 5574228561Snp 5575228561Snp n = md - mem; 5576228561Snp qsort(mem, n, sizeof(struct mem_desc), mem_desc_cmp); 5577228561Snp 5578228561Snp for (lo = 0; lo < i; lo++) 5579228561Snp mem_region_show(sb, memory[avail[lo].idx], avail[lo].base, 5580228561Snp avail[lo].limit - 1); 5581228561Snp 5582228561Snp sbuf_printf(sb, "\n"); 5583228561Snp for (i = 0; i < n; i++) { 5584240452Snp if (mem[i].idx >= nitems(region)) 5585228561Snp continue; /* skip holes */ 5586228561Snp if (!mem[i].limit) 5587228561Snp mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0; 5588228561Snp mem_region_show(sb, region[mem[i].idx], mem[i].base, 5589228561Snp mem[i].limit); 5590228561Snp } 5591228561Snp 5592228561Snp sbuf_printf(sb, "\n"); 5593228561Snp lo = t4_read_reg(sc, A_CIM_SDRAM_BASE_ADDR); 5594228561Snp hi = t4_read_reg(sc, A_CIM_SDRAM_ADDR_SIZE) + lo - 1; 5595228561Snp mem_region_show(sb, "uP RAM:", lo, hi); 5596228561Snp 5597228561Snp lo = t4_read_reg(sc, A_CIM_EXTMEM2_BASE_ADDR); 5598228561Snp hi = t4_read_reg(sc, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1; 5599228561Snp mem_region_show(sb, "uP Extmem2:", lo, hi); 5600228561Snp 5601228561Snp lo = t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE); 5602228561Snp sbuf_printf(sb, "\n%u Rx pages of size %uKiB for %u channels\n", 5603228561Snp G_PMRXMAXPAGE(lo), 5604228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) >> 10, 5605228561Snp (lo & F_PMRXNUMCHN) ? 2 : 1); 5606228561Snp 5607228561Snp lo = t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE); 5608228561Snp hi = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE); 5609228561Snp sbuf_printf(sb, "%u Tx pages of size %u%ciB for %u channels\n", 5610228561Snp G_PMTXMAXPAGE(lo), 5611228561Snp hi >= (1 << 20) ? (hi >> 20) : (hi >> 10), 5612228561Snp hi >= (1 << 20) ? 'M' : 'K', 1 << G_PMTXNUMCHN(lo)); 5613228561Snp sbuf_printf(sb, "%u p-structs\n", 5614228561Snp t4_read_reg(sc, A_TP_CMM_MM_MAX_PSTRUCT)); 5615228561Snp 5616228561Snp for (i = 0; i < 4; i++) { 5617228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV0 + i * 4); 5618248925Snp if (is_t4(sc)) { 5619248925Snp used = G_USED(lo); 5620248925Snp alloc = G_ALLOC(lo); 5621248925Snp } else { 5622248925Snp used = G_T5_USED(lo); 5623248925Snp alloc = G_T5_ALLOC(lo); 5624248925Snp } 5625228561Snp sbuf_printf(sb, "\nPort %d using %u pages out of %u allocated", 5626248925Snp i, used, alloc); 5627228561Snp } 5628228561Snp for (i = 0; i < 4; i++) { 5629228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV4 + i * 4); 5630248925Snp if (is_t4(sc)) { 5631248925Snp used = G_USED(lo); 5632248925Snp alloc = G_ALLOC(lo); 5633248925Snp } else { 5634248925Snp used = G_T5_USED(lo); 5635248925Snp alloc = G_T5_ALLOC(lo); 5636248925Snp } 5637228561Snp sbuf_printf(sb, 5638228561Snp "\nLoopback %d using %u pages out of %u allocated", 5639248925Snp i, used, alloc); 5640228561Snp } 5641228561Snp 5642228561Snp rc = sbuf_finish(sb); 5643228561Snp sbuf_delete(sb); 5644228561Snp 5645228561Snp return (rc); 5646228561Snp} 5647228561Snp 5648251213Snpstatic inline void 5649251213Snptcamxy2valmask(uint64_t x, uint64_t y, uint8_t *addr, uint64_t *mask) 5650251213Snp{ 5651251213Snp *mask = x | y; 5652251213Snp y = htobe64(y); 5653251213Snp memcpy(addr, (char *)&y + 2, ETHER_ADDR_LEN); 5654251213Snp} 5655251213Snp 5656228561Snpstatic int 5657251213Snpsysctl_mps_tcam(SYSCTL_HANDLER_ARGS) 5658251213Snp{ 5659251213Snp struct adapter *sc = arg1; 5660251213Snp struct sbuf *sb; 5661251213Snp int rc, i, n; 5662251213Snp 5663251213Snp rc = sysctl_wire_old_buffer(req, 0); 5664251213Snp if (rc != 0) 5665251213Snp return (rc); 5666251213Snp 5667251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5668251213Snp if (sb == NULL) 5669251213Snp return (ENOMEM); 5670251213Snp 5671251213Snp sbuf_printf(sb, 5672251213Snp "Idx Ethernet address Mask Vld Ports PF" 5673251213Snp " VF Replication P0 P1 P2 P3 ML"); 5674251213Snp n = is_t4(sc) ? NUM_MPS_CLS_SRAM_L_INSTANCES : 5675251213Snp NUM_MPS_T5_CLS_SRAM_L_INSTANCES; 5676251213Snp for (i = 0; i < n; i++) { 5677251213Snp uint64_t tcamx, tcamy, mask; 5678251213Snp uint32_t cls_lo, cls_hi; 5679251213Snp uint8_t addr[ETHER_ADDR_LEN]; 5680251213Snp 5681251213Snp tcamy = t4_read_reg64(sc, MPS_CLS_TCAM_Y_L(i)); 5682251213Snp tcamx = t4_read_reg64(sc, MPS_CLS_TCAM_X_L(i)); 5683251213Snp cls_lo = t4_read_reg(sc, MPS_CLS_SRAM_L(i)); 5684251213Snp cls_hi = t4_read_reg(sc, MPS_CLS_SRAM_H(i)); 5685251213Snp 5686251213Snp if (tcamx & tcamy) 5687251213Snp continue; 5688251213Snp 5689251213Snp tcamxy2valmask(tcamx, tcamy, addr, &mask); 5690251213Snp sbuf_printf(sb, "\n%3u %02x:%02x:%02x:%02x:%02x:%02x %012jx" 5691251213Snp " %c %#x%4u%4d", i, addr[0], addr[1], addr[2], 5692251213Snp addr[3], addr[4], addr[5], (uintmax_t)mask, 5693251213Snp (cls_lo & F_SRAM_VLD) ? 'Y' : 'N', 5694251213Snp G_PORTMAP(cls_hi), G_PF(cls_lo), 5695251213Snp (cls_lo & F_VF_VALID) ? G_VF(cls_lo) : -1); 5696251213Snp 5697251213Snp if (cls_lo & F_REPLICATE) { 5698251213Snp struct fw_ldst_cmd ldst_cmd; 5699251213Snp 5700251213Snp memset(&ldst_cmd, 0, sizeof(ldst_cmd)); 5701251213Snp ldst_cmd.op_to_addrspace = 5702251213Snp htobe32(V_FW_CMD_OP(FW_LDST_CMD) | 5703251213Snp F_FW_CMD_REQUEST | F_FW_CMD_READ | 5704251213Snp V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MPS)); 5705251213Snp ldst_cmd.cycles_to_len16 = htobe32(FW_LEN16(ldst_cmd)); 5706251213Snp ldst_cmd.u.mps.fid_ctl = 5707251213Snp htobe16(V_FW_LDST_CMD_FID(FW_LDST_MPS_RPLC) | 5708251213Snp V_FW_LDST_CMD_CTL(i)); 5709251213Snp 5710251213Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, 5711251213Snp "t4mps"); 5712251213Snp if (rc) 5713251213Snp break; 5714251213Snp rc = -t4_wr_mbox(sc, sc->mbox, &ldst_cmd, 5715251213Snp sizeof(ldst_cmd), &ldst_cmd); 5716251213Snp end_synchronized_op(sc, 0); 5717251213Snp 5718251213Snp if (rc != 0) { 5719251213Snp sbuf_printf(sb, 5720251213Snp " ------------ error %3u ------------", rc); 5721251213Snp rc = 0; 5722251213Snp } else { 5723251213Snp sbuf_printf(sb, " %08x %08x %08x %08x", 5724251213Snp be32toh(ldst_cmd.u.mps.rplc127_96), 5725251213Snp be32toh(ldst_cmd.u.mps.rplc95_64), 5726251213Snp be32toh(ldst_cmd.u.mps.rplc63_32), 5727251213Snp be32toh(ldst_cmd.u.mps.rplc31_0)); 5728251213Snp } 5729251213Snp } else 5730251213Snp sbuf_printf(sb, "%36s", ""); 5731251213Snp 5732251213Snp sbuf_printf(sb, "%4u%3u%3u%3u %#3x", G_SRAM_PRIO0(cls_lo), 5733251213Snp G_SRAM_PRIO1(cls_lo), G_SRAM_PRIO2(cls_lo), 5734251213Snp G_SRAM_PRIO3(cls_lo), (cls_lo >> S_MULTILISTEN0) & 0xf); 5735251213Snp } 5736251213Snp 5737251213Snp if (rc) 5738251213Snp (void) sbuf_finish(sb); 5739251213Snp else 5740251213Snp rc = sbuf_finish(sb); 5741251213Snp sbuf_delete(sb); 5742251213Snp 5743251213Snp return (rc); 5744251213Snp} 5745251213Snp 5746251213Snpstatic int 5747228561Snpsysctl_path_mtus(SYSCTL_HANDLER_ARGS) 5748228561Snp{ 5749228561Snp struct adapter *sc = arg1; 5750228561Snp struct sbuf *sb; 5751228561Snp int rc; 5752228561Snp uint16_t mtus[NMTUS]; 5753228561Snp 5754228561Snp rc = sysctl_wire_old_buffer(req, 0); 5755228561Snp if (rc != 0) 5756228561Snp return (rc); 5757228561Snp 5758228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5759228561Snp if (sb == NULL) 5760228561Snp return (ENOMEM); 5761228561Snp 5762228561Snp t4_read_mtu_tbl(sc, mtus, NULL); 5763228561Snp 5764228561Snp sbuf_printf(sb, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", 5765228561Snp mtus[0], mtus[1], mtus[2], mtus[3], mtus[4], mtus[5], mtus[6], 5766228561Snp mtus[7], mtus[8], mtus[9], mtus[10], mtus[11], mtus[12], mtus[13], 5767228561Snp mtus[14], mtus[15]); 5768228561Snp 5769228561Snp rc = sbuf_finish(sb); 5770228561Snp sbuf_delete(sb); 5771228561Snp 5772228561Snp return (rc); 5773228561Snp} 5774228561Snp 5775228561Snpstatic int 5776228561Snpsysctl_pm_stats(SYSCTL_HANDLER_ARGS) 5777228561Snp{ 5778228561Snp struct adapter *sc = arg1; 5779228561Snp struct sbuf *sb; 5780228561Snp int rc, i; 5781228561Snp uint32_t tx_cnt[PM_NSTATS], rx_cnt[PM_NSTATS]; 5782228561Snp uint64_t tx_cyc[PM_NSTATS], rx_cyc[PM_NSTATS]; 5783228561Snp static const char *pm_stats[] = { 5784228561Snp "Read:", "Write bypass:", "Write mem:", "Flush:", "FIFO wait:" 5785228561Snp }; 5786228561Snp 5787228561Snp rc = sysctl_wire_old_buffer(req, 0); 5788228561Snp if (rc != 0) 5789228561Snp return (rc); 5790228561Snp 5791228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5792228561Snp if (sb == NULL) 5793228561Snp return (ENOMEM); 5794228561Snp 5795228561Snp t4_pmtx_get_stats(sc, tx_cnt, tx_cyc); 5796228561Snp t4_pmrx_get_stats(sc, rx_cnt, rx_cyc); 5797228561Snp 5798228561Snp sbuf_printf(sb, " Tx count Tx cycles " 5799228561Snp "Rx count Rx cycles"); 5800228561Snp for (i = 0; i < PM_NSTATS; i++) 5801228561Snp sbuf_printf(sb, "\n%-13s %10u %20ju %10u %20ju", 5802228561Snp pm_stats[i], tx_cnt[i], tx_cyc[i], rx_cnt[i], rx_cyc[i]); 5803228561Snp 5804228561Snp rc = sbuf_finish(sb); 5805228561Snp sbuf_delete(sb); 5806228561Snp 5807228561Snp return (rc); 5808228561Snp} 5809228561Snp 5810228561Snpstatic int 5811228561Snpsysctl_rdma_stats(SYSCTL_HANDLER_ARGS) 5812228561Snp{ 5813228561Snp struct adapter *sc = arg1; 5814228561Snp struct sbuf *sb; 5815228561Snp int rc; 5816228561Snp struct tp_rdma_stats stats; 5817228561Snp 5818228561Snp rc = sysctl_wire_old_buffer(req, 0); 5819228561Snp if (rc != 0) 5820228561Snp return (rc); 5821228561Snp 5822228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5823228561Snp if (sb == NULL) 5824228561Snp return (ENOMEM); 5825228561Snp 5826228561Snp t4_tp_get_rdma_stats(sc, &stats); 5827228561Snp sbuf_printf(sb, "NoRQEModDefferals: %u\n", stats.rqe_dfr_mod); 5828228561Snp sbuf_printf(sb, "NoRQEPktDefferals: %u", stats.rqe_dfr_pkt); 5829228561Snp 5830228561Snp rc = sbuf_finish(sb); 5831228561Snp sbuf_delete(sb); 5832228561Snp 5833228561Snp return (rc); 5834228561Snp} 5835228561Snp 5836228561Snpstatic int 5837228561Snpsysctl_tcp_stats(SYSCTL_HANDLER_ARGS) 5838228561Snp{ 5839228561Snp struct adapter *sc = arg1; 5840228561Snp struct sbuf *sb; 5841228561Snp int rc; 5842228561Snp struct tp_tcp_stats v4, v6; 5843228561Snp 5844228561Snp rc = sysctl_wire_old_buffer(req, 0); 5845228561Snp if (rc != 0) 5846228561Snp return (rc); 5847228561Snp 5848228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5849228561Snp if (sb == NULL) 5850228561Snp return (ENOMEM); 5851228561Snp 5852228561Snp t4_tp_get_tcp_stats(sc, &v4, &v6); 5853228561Snp sbuf_printf(sb, 5854228561Snp " IP IPv6\n"); 5855228561Snp sbuf_printf(sb, "OutRsts: %20u %20u\n", 5856228561Snp v4.tcpOutRsts, v6.tcpOutRsts); 5857228561Snp sbuf_printf(sb, "InSegs: %20ju %20ju\n", 5858228561Snp v4.tcpInSegs, v6.tcpInSegs); 5859228561Snp sbuf_printf(sb, "OutSegs: %20ju %20ju\n", 5860228561Snp v4.tcpOutSegs, v6.tcpOutSegs); 5861228561Snp sbuf_printf(sb, "RetransSegs: %20ju %20ju", 5862228561Snp v4.tcpRetransSegs, v6.tcpRetransSegs); 5863228561Snp 5864228561Snp rc = sbuf_finish(sb); 5865228561Snp sbuf_delete(sb); 5866228561Snp 5867228561Snp return (rc); 5868228561Snp} 5869228561Snp 5870228561Snpstatic int 5871228561Snpsysctl_tids(SYSCTL_HANDLER_ARGS) 5872228561Snp{ 5873228561Snp struct adapter *sc = arg1; 5874228561Snp struct sbuf *sb; 5875228561Snp int rc; 5876228561Snp struct tid_info *t = &sc->tids; 5877228561Snp 5878228561Snp rc = sysctl_wire_old_buffer(req, 0); 5879228561Snp if (rc != 0) 5880228561Snp return (rc); 5881228561Snp 5882228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5883228561Snp if (sb == NULL) 5884228561Snp return (ENOMEM); 5885228561Snp 5886228561Snp if (t->natids) { 5887228561Snp sbuf_printf(sb, "ATID range: 0-%u, in use: %u\n", t->natids - 1, 5888228561Snp t->atids_in_use); 5889228561Snp } 5890228561Snp 5891228561Snp if (t->ntids) { 5892228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 5893228561Snp uint32_t b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4; 5894228561Snp 5895228561Snp if (b) { 5896228561Snp sbuf_printf(sb, "TID range: 0-%u, %u-%u", b - 1, 5897228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 5898228561Snp t->ntids - 1); 5899228561Snp } else { 5900228561Snp sbuf_printf(sb, "TID range: %u-%u", 5901228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 5902228561Snp t->ntids - 1); 5903228561Snp } 5904228561Snp } else 5905228561Snp sbuf_printf(sb, "TID range: 0-%u", t->ntids - 1); 5906228561Snp sbuf_printf(sb, ", in use: %u\n", 5907228561Snp atomic_load_acq_int(&t->tids_in_use)); 5908228561Snp } 5909228561Snp 5910228561Snp if (t->nstids) { 5911228561Snp sbuf_printf(sb, "STID range: %u-%u, in use: %u\n", t->stid_base, 5912228561Snp t->stid_base + t->nstids - 1, t->stids_in_use); 5913228561Snp } 5914228561Snp 5915228561Snp if (t->nftids) { 5916228561Snp sbuf_printf(sb, "FTID range: %u-%u\n", t->ftid_base, 5917228561Snp t->ftid_base + t->nftids - 1); 5918228561Snp } 5919228561Snp 5920228561Snp sbuf_printf(sb, "HW TID usage: %u IP users, %u IPv6 users", 5921228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV4), 5922228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV6)); 5923228561Snp 5924228561Snp rc = sbuf_finish(sb); 5925228561Snp sbuf_delete(sb); 5926228561Snp 5927228561Snp return (rc); 5928228561Snp} 5929228561Snp 5930228561Snpstatic int 5931228561Snpsysctl_tp_err_stats(SYSCTL_HANDLER_ARGS) 5932228561Snp{ 5933228561Snp struct adapter *sc = arg1; 5934228561Snp struct sbuf *sb; 5935228561Snp int rc; 5936228561Snp struct tp_err_stats stats; 5937228561Snp 5938228561Snp rc = sysctl_wire_old_buffer(req, 0); 5939228561Snp if (rc != 0) 5940228561Snp return (rc); 5941228561Snp 5942228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5943228561Snp if (sb == NULL) 5944228561Snp return (ENOMEM); 5945228561Snp 5946228561Snp t4_tp_get_err_stats(sc, &stats); 5947228561Snp 5948228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 5949228561Snp "channel 3\n"); 5950228561Snp sbuf_printf(sb, "macInErrs: %10u %10u %10u %10u\n", 5951228561Snp stats.macInErrs[0], stats.macInErrs[1], stats.macInErrs[2], 5952228561Snp stats.macInErrs[3]); 5953228561Snp sbuf_printf(sb, "hdrInErrs: %10u %10u %10u %10u\n", 5954228561Snp stats.hdrInErrs[0], stats.hdrInErrs[1], stats.hdrInErrs[2], 5955228561Snp stats.hdrInErrs[3]); 5956228561Snp sbuf_printf(sb, "tcpInErrs: %10u %10u %10u %10u\n", 5957228561Snp stats.tcpInErrs[0], stats.tcpInErrs[1], stats.tcpInErrs[2], 5958228561Snp stats.tcpInErrs[3]); 5959228561Snp sbuf_printf(sb, "tcp6InErrs: %10u %10u %10u %10u\n", 5960228561Snp stats.tcp6InErrs[0], stats.tcp6InErrs[1], stats.tcp6InErrs[2], 5961228561Snp stats.tcp6InErrs[3]); 5962228561Snp sbuf_printf(sb, "tnlCongDrops: %10u %10u %10u %10u\n", 5963228561Snp stats.tnlCongDrops[0], stats.tnlCongDrops[1], stats.tnlCongDrops[2], 5964228561Snp stats.tnlCongDrops[3]); 5965228561Snp sbuf_printf(sb, "tnlTxDrops: %10u %10u %10u %10u\n", 5966228561Snp stats.tnlTxDrops[0], stats.tnlTxDrops[1], stats.tnlTxDrops[2], 5967228561Snp stats.tnlTxDrops[3]); 5968228561Snp sbuf_printf(sb, "ofldVlanDrops: %10u %10u %10u %10u\n", 5969228561Snp stats.ofldVlanDrops[0], stats.ofldVlanDrops[1], 5970228561Snp stats.ofldVlanDrops[2], stats.ofldVlanDrops[3]); 5971228561Snp sbuf_printf(sb, "ofldChanDrops: %10u %10u %10u %10u\n\n", 5972228561Snp stats.ofldChanDrops[0], stats.ofldChanDrops[1], 5973228561Snp stats.ofldChanDrops[2], stats.ofldChanDrops[3]); 5974228561Snp sbuf_printf(sb, "ofldNoNeigh: %u\nofldCongDefer: %u", 5975228561Snp stats.ofldNoNeigh, stats.ofldCongDefer); 5976228561Snp 5977228561Snp rc = sbuf_finish(sb); 5978228561Snp sbuf_delete(sb); 5979228561Snp 5980228561Snp return (rc); 5981228561Snp} 5982228561Snp 5983251213Snpstruct field_desc { 5984251213Snp const char *name; 5985251213Snp u_int start; 5986251213Snp u_int width; 5987251213Snp}; 5988251213Snp 5989251213Snpstatic void 5990251213Snpfield_desc_show(struct sbuf *sb, uint64_t v, const struct field_desc *f) 5991251213Snp{ 5992251213Snp char buf[32]; 5993251213Snp int line_size = 0; 5994251213Snp 5995251213Snp while (f->name) { 5996251213Snp uint64_t mask = (1ULL << f->width) - 1; 5997251213Snp int len = snprintf(buf, sizeof(buf), "%s: %ju", f->name, 5998251213Snp ((uintmax_t)v >> f->start) & mask); 5999251213Snp 6000251213Snp if (line_size + len >= 79) { 6001251213Snp line_size = 8; 6002251213Snp sbuf_printf(sb, "\n "); 6003251213Snp } 6004251213Snp sbuf_printf(sb, "%s ", buf); 6005251213Snp line_size += len + 1; 6006251213Snp f++; 6007251213Snp } 6008251213Snp sbuf_printf(sb, "\n"); 6009251213Snp} 6010251213Snp 6011251213Snpstatic struct field_desc tp_la0[] = { 6012251213Snp { "RcfOpCodeOut", 60, 4 }, 6013251213Snp { "State", 56, 4 }, 6014251213Snp { "WcfState", 52, 4 }, 6015251213Snp { "RcfOpcSrcOut", 50, 2 }, 6016251213Snp { "CRxError", 49, 1 }, 6017251213Snp { "ERxError", 48, 1 }, 6018251213Snp { "SanityFailed", 47, 1 }, 6019251213Snp { "SpuriousMsg", 46, 1 }, 6020251213Snp { "FlushInputMsg", 45, 1 }, 6021251213Snp { "FlushInputCpl", 44, 1 }, 6022251213Snp { "RssUpBit", 43, 1 }, 6023251213Snp { "RssFilterHit", 42, 1 }, 6024251213Snp { "Tid", 32, 10 }, 6025251213Snp { "InitTcb", 31, 1 }, 6026251213Snp { "LineNumber", 24, 7 }, 6027251213Snp { "Emsg", 23, 1 }, 6028251213Snp { "EdataOut", 22, 1 }, 6029251213Snp { "Cmsg", 21, 1 }, 6030251213Snp { "CdataOut", 20, 1 }, 6031251213Snp { "EreadPdu", 19, 1 }, 6032251213Snp { "CreadPdu", 18, 1 }, 6033251213Snp { "TunnelPkt", 17, 1 }, 6034251213Snp { "RcfPeerFin", 16, 1 }, 6035251213Snp { "RcfReasonOut", 12, 4 }, 6036251213Snp { "TxCchannel", 10, 2 }, 6037251213Snp { "RcfTxChannel", 8, 2 }, 6038251213Snp { "RxEchannel", 6, 2 }, 6039251213Snp { "RcfRxChannel", 5, 1 }, 6040251213Snp { "RcfDataOutSrdy", 4, 1 }, 6041251213Snp { "RxDvld", 3, 1 }, 6042251213Snp { "RxOoDvld", 2, 1 }, 6043251213Snp { "RxCongestion", 1, 1 }, 6044251213Snp { "TxCongestion", 0, 1 }, 6045251213Snp { NULL } 6046251213Snp}; 6047251213Snp 6048251213Snpstatic struct field_desc tp_la1[] = { 6049251213Snp { "CplCmdIn", 56, 8 }, 6050251213Snp { "CplCmdOut", 48, 8 }, 6051251213Snp { "ESynOut", 47, 1 }, 6052251213Snp { "EAckOut", 46, 1 }, 6053251213Snp { "EFinOut", 45, 1 }, 6054251213Snp { "ERstOut", 44, 1 }, 6055251213Snp { "SynIn", 43, 1 }, 6056251213Snp { "AckIn", 42, 1 }, 6057251213Snp { "FinIn", 41, 1 }, 6058251213Snp { "RstIn", 40, 1 }, 6059251213Snp { "DataIn", 39, 1 }, 6060251213Snp { "DataInVld", 38, 1 }, 6061251213Snp { "PadIn", 37, 1 }, 6062251213Snp { "RxBufEmpty", 36, 1 }, 6063251213Snp { "RxDdp", 35, 1 }, 6064251213Snp { "RxFbCongestion", 34, 1 }, 6065251213Snp { "TxFbCongestion", 33, 1 }, 6066251213Snp { "TxPktSumSrdy", 32, 1 }, 6067251213Snp { "RcfUlpType", 28, 4 }, 6068251213Snp { "Eread", 27, 1 }, 6069251213Snp { "Ebypass", 26, 1 }, 6070251213Snp { "Esave", 25, 1 }, 6071251213Snp { "Static0", 24, 1 }, 6072251213Snp { "Cread", 23, 1 }, 6073251213Snp { "Cbypass", 22, 1 }, 6074251213Snp { "Csave", 21, 1 }, 6075251213Snp { "CPktOut", 20, 1 }, 6076251213Snp { "RxPagePoolFull", 18, 2 }, 6077251213Snp { "RxLpbkPkt", 17, 1 }, 6078251213Snp { "TxLpbkPkt", 16, 1 }, 6079251213Snp { "RxVfValid", 15, 1 }, 6080251213Snp { "SynLearned", 14, 1 }, 6081251213Snp { "SetDelEntry", 13, 1 }, 6082251213Snp { "SetInvEntry", 12, 1 }, 6083251213Snp { "CpcmdDvld", 11, 1 }, 6084251213Snp { "CpcmdSave", 10, 1 }, 6085251213Snp { "RxPstructsFull", 8, 2 }, 6086251213Snp { "EpcmdDvld", 7, 1 }, 6087251213Snp { "EpcmdFlush", 6, 1 }, 6088251213Snp { "EpcmdTrimPrefix", 5, 1 }, 6089251213Snp { "EpcmdTrimPostfix", 4, 1 }, 6090251213Snp { "ERssIp4Pkt", 3, 1 }, 6091251213Snp { "ERssIp6Pkt", 2, 1 }, 6092251213Snp { "ERssTcpUdpPkt", 1, 1 }, 6093251213Snp { "ERssFceFipPkt", 0, 1 }, 6094251213Snp { NULL } 6095251213Snp}; 6096251213Snp 6097251213Snpstatic struct field_desc tp_la2[] = { 6098251213Snp { "CplCmdIn", 56, 8 }, 6099251213Snp { "MpsVfVld", 55, 1 }, 6100251213Snp { "MpsPf", 52, 3 }, 6101251213Snp { "MpsVf", 44, 8 }, 6102251213Snp { "SynIn", 43, 1 }, 6103251213Snp { "AckIn", 42, 1 }, 6104251213Snp { "FinIn", 41, 1 }, 6105251213Snp { "RstIn", 40, 1 }, 6106251213Snp { "DataIn", 39, 1 }, 6107251213Snp { "DataInVld", 38, 1 }, 6108251213Snp { "PadIn", 37, 1 }, 6109251213Snp { "RxBufEmpty", 36, 1 }, 6110251213Snp { "RxDdp", 35, 1 }, 6111251213Snp { "RxFbCongestion", 34, 1 }, 6112251213Snp { "TxFbCongestion", 33, 1 }, 6113251213Snp { "TxPktSumSrdy", 32, 1 }, 6114251213Snp { "RcfUlpType", 28, 4 }, 6115251213Snp { "Eread", 27, 1 }, 6116251213Snp { "Ebypass", 26, 1 }, 6117251213Snp { "Esave", 25, 1 }, 6118251213Snp { "Static0", 24, 1 }, 6119251213Snp { "Cread", 23, 1 }, 6120251213Snp { "Cbypass", 22, 1 }, 6121251213Snp { "Csave", 21, 1 }, 6122251213Snp { "CPktOut", 20, 1 }, 6123251213Snp { "RxPagePoolFull", 18, 2 }, 6124251213Snp { "RxLpbkPkt", 17, 1 }, 6125251213Snp { "TxLpbkPkt", 16, 1 }, 6126251213Snp { "RxVfValid", 15, 1 }, 6127251213Snp { "SynLearned", 14, 1 }, 6128251213Snp { "SetDelEntry", 13, 1 }, 6129251213Snp { "SetInvEntry", 12, 1 }, 6130251213Snp { "CpcmdDvld", 11, 1 }, 6131251213Snp { "CpcmdSave", 10, 1 }, 6132251213Snp { "RxPstructsFull", 8, 2 }, 6133251213Snp { "EpcmdDvld", 7, 1 }, 6134251213Snp { "EpcmdFlush", 6, 1 }, 6135251213Snp { "EpcmdTrimPrefix", 5, 1 }, 6136251213Snp { "EpcmdTrimPostfix", 4, 1 }, 6137251213Snp { "ERssIp4Pkt", 3, 1 }, 6138251213Snp { "ERssIp6Pkt", 2, 1 }, 6139251213Snp { "ERssTcpUdpPkt", 1, 1 }, 6140251213Snp { "ERssFceFipPkt", 0, 1 }, 6141251213Snp { NULL } 6142251213Snp}; 6143251213Snp 6144251213Snpstatic void 6145251213Snptp_la_show(struct sbuf *sb, uint64_t *p, int idx) 6146251213Snp{ 6147251213Snp 6148251213Snp field_desc_show(sb, *p, tp_la0); 6149251213Snp} 6150251213Snp 6151251213Snpstatic void 6152251213Snptp_la_show2(struct sbuf *sb, uint64_t *p, int idx) 6153251213Snp{ 6154251213Snp 6155251213Snp if (idx) 6156251213Snp sbuf_printf(sb, "\n"); 6157251213Snp field_desc_show(sb, p[0], tp_la0); 6158251213Snp if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) 6159251213Snp field_desc_show(sb, p[1], tp_la0); 6160251213Snp} 6161251213Snp 6162251213Snpstatic void 6163251213Snptp_la_show3(struct sbuf *sb, uint64_t *p, int idx) 6164251213Snp{ 6165251213Snp 6166251213Snp if (idx) 6167251213Snp sbuf_printf(sb, "\n"); 6168251213Snp field_desc_show(sb, p[0], tp_la0); 6169251213Snp if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) 6170251213Snp field_desc_show(sb, p[1], (p[0] & (1 << 17)) ? tp_la2 : tp_la1); 6171251213Snp} 6172251213Snp 6173228561Snpstatic int 6174251213Snpsysctl_tp_la(SYSCTL_HANDLER_ARGS) 6175251213Snp{ 6176251213Snp struct adapter *sc = arg1; 6177251213Snp struct sbuf *sb; 6178251213Snp uint64_t *buf, *p; 6179251213Snp int rc; 6180251213Snp u_int i, inc; 6181251213Snp void (*show_func)(struct sbuf *, uint64_t *, int); 6182251213Snp 6183251213Snp rc = sysctl_wire_old_buffer(req, 0); 6184251213Snp if (rc != 0) 6185251213Snp return (rc); 6186251213Snp 6187251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6188251213Snp if (sb == NULL) 6189251213Snp return (ENOMEM); 6190251213Snp 6191251213Snp buf = malloc(TPLA_SIZE * sizeof(uint64_t), M_CXGBE, M_ZERO | M_WAITOK); 6192251213Snp 6193251213Snp t4_tp_read_la(sc, buf, NULL); 6194251213Snp p = buf; 6195251213Snp 6196251213Snp switch (G_DBGLAMODE(t4_read_reg(sc, A_TP_DBG_LA_CONFIG))) { 6197251213Snp case 2: 6198251213Snp inc = 2; 6199251213Snp show_func = tp_la_show2; 6200251213Snp break; 6201251213Snp case 3: 6202251213Snp inc = 2; 6203251213Snp show_func = tp_la_show3; 6204251213Snp break; 6205251213Snp default: 6206251213Snp inc = 1; 6207251213Snp show_func = tp_la_show; 6208251213Snp } 6209251213Snp 6210251213Snp for (i = 0; i < TPLA_SIZE / inc; i++, p += inc) 6211251213Snp (*show_func)(sb, p, i); 6212251213Snp 6213251213Snp rc = sbuf_finish(sb); 6214251213Snp sbuf_delete(sb); 6215251213Snp free(buf, M_CXGBE); 6216251213Snp return (rc); 6217251213Snp} 6218251213Snp 6219251213Snpstatic int 6220228561Snpsysctl_tx_rate(SYSCTL_HANDLER_ARGS) 6221228561Snp{ 6222228561Snp struct adapter *sc = arg1; 6223228561Snp struct sbuf *sb; 6224228561Snp int rc; 6225228561Snp u64 nrate[NCHAN], orate[NCHAN]; 6226228561Snp 6227228561Snp rc = sysctl_wire_old_buffer(req, 0); 6228228561Snp if (rc != 0) 6229228561Snp return (rc); 6230228561Snp 6231228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6232228561Snp if (sb == NULL) 6233228561Snp return (ENOMEM); 6234228561Snp 6235228561Snp t4_get_chan_txrate(sc, nrate, orate); 6236228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 6237228561Snp "channel 3\n"); 6238228561Snp sbuf_printf(sb, "NIC B/s: %10ju %10ju %10ju %10ju\n", 6239228561Snp nrate[0], nrate[1], nrate[2], nrate[3]); 6240228561Snp sbuf_printf(sb, "Offload B/s: %10ju %10ju %10ju %10ju", 6241228561Snp orate[0], orate[1], orate[2], orate[3]); 6242228561Snp 6243228561Snp rc = sbuf_finish(sb); 6244228561Snp sbuf_delete(sb); 6245228561Snp 6246228561Snp return (rc); 6247228561Snp} 6248248925Snp 6249248925Snpstatic int 6250251213Snpsysctl_ulprx_la(SYSCTL_HANDLER_ARGS) 6251251213Snp{ 6252251213Snp struct adapter *sc = arg1; 6253251213Snp struct sbuf *sb; 6254251213Snp uint32_t *buf, *p; 6255251213Snp int rc, i; 6256251213Snp 6257251213Snp rc = sysctl_wire_old_buffer(req, 0); 6258251213Snp if (rc != 0) 6259251213Snp return (rc); 6260251213Snp 6261251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6262251213Snp if (sb == NULL) 6263251213Snp return (ENOMEM); 6264251213Snp 6265251213Snp buf = malloc(ULPRX_LA_SIZE * 8 * sizeof(uint32_t), M_CXGBE, 6266251213Snp M_ZERO | M_WAITOK); 6267251213Snp 6268251213Snp t4_ulprx_read_la(sc, buf); 6269251213Snp p = buf; 6270251213Snp 6271251213Snp sbuf_printf(sb, " Pcmd Type Message" 6272251213Snp " Data"); 6273251213Snp for (i = 0; i < ULPRX_LA_SIZE; i++, p += 8) { 6274251213Snp sbuf_printf(sb, "\n%08x%08x %4x %08x %08x%08x%08x%08x", 6275251213Snp p[1], p[0], p[2], p[3], p[7], p[6], p[5], p[4]); 6276251213Snp } 6277251213Snp 6278251213Snp rc = sbuf_finish(sb); 6279251213Snp sbuf_delete(sb); 6280251213Snp free(buf, M_CXGBE); 6281251213Snp return (rc); 6282251213Snp} 6283251213Snp 6284251213Snpstatic int 6285249392Snpsysctl_wcwr_stats(SYSCTL_HANDLER_ARGS) 6286248925Snp{ 6287248925Snp struct adapter *sc = arg1; 6288248925Snp struct sbuf *sb; 6289248925Snp int rc, v; 6290248925Snp 6291248925Snp rc = sysctl_wire_old_buffer(req, 0); 6292248925Snp if (rc != 0) 6293248925Snp return (rc); 6294248925Snp 6295248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6296248925Snp if (sb == NULL) 6297248925Snp return (ENOMEM); 6298248925Snp 6299248925Snp v = t4_read_reg(sc, A_SGE_STAT_CFG); 6300248925Snp if (G_STATSOURCE_T5(v) == 7) { 6301248925Snp if (G_STATMODE(v) == 0) { 6302249383Snp sbuf_printf(sb, "total %d, incomplete %d", 6303248925Snp t4_read_reg(sc, A_SGE_STAT_TOTAL), 6304248925Snp t4_read_reg(sc, A_SGE_STAT_MATCH)); 6305248925Snp } else if (G_STATMODE(v) == 1) { 6306249383Snp sbuf_printf(sb, "total %d, data overflow %d", 6307248925Snp t4_read_reg(sc, A_SGE_STAT_TOTAL), 6308248925Snp t4_read_reg(sc, A_SGE_STAT_MATCH)); 6309248925Snp } 6310248925Snp } 6311248925Snp rc = sbuf_finish(sb); 6312248925Snp sbuf_delete(sb); 6313248925Snp 6314248925Snp return (rc); 6315248925Snp} 6316231115Snp#endif 6317228561Snp 6318219286Snpstatic inline void 6319219286Snptxq_start(struct ifnet *ifp, struct sge_txq *txq) 6320219286Snp{ 6321219286Snp struct buf_ring *br; 6322219286Snp struct mbuf *m; 6323219286Snp 6324219286Snp TXQ_LOCK_ASSERT_OWNED(txq); 6325219286Snp 6326220873Snp br = txq->br; 6327219286Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 6328219286Snp if (m) 6329219286Snp t4_eth_tx(ifp, txq, m); 6330219286Snp} 6331219286Snp 6332219286Snpvoid 6333228561Snpt4_tx_callout(void *arg) 6334219286Snp{ 6335228561Snp struct sge_eq *eq = arg; 6336228561Snp struct adapter *sc; 6337219286Snp 6338228561Snp if (EQ_TRYLOCK(eq) == 0) 6339228561Snp goto reschedule; 6340228561Snp 6341228561Snp if (eq->flags & EQ_STALLED && !can_resume_tx(eq)) { 6342228561Snp EQ_UNLOCK(eq); 6343228561Snpreschedule: 6344228561Snp if (__predict_true(!(eq->flags && EQ_DOOMED))) 6345228561Snp callout_schedule(&eq->tx_callout, 1); 6346228561Snp return; 6347228561Snp } 6348228561Snp 6349228561Snp EQ_LOCK_ASSERT_OWNED(eq); 6350228561Snp 6351228561Snp if (__predict_true((eq->flags & EQ_DOOMED) == 0)) { 6352228561Snp 6353228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 6354228561Snp struct sge_txq *txq = arg; 6355228561Snp struct port_info *pi = txq->ifp->if_softc; 6356228561Snp 6357228561Snp sc = pi->adapter; 6358228561Snp } else { 6359228561Snp struct sge_wrq *wrq = arg; 6360228561Snp 6361228561Snp sc = wrq->adapter; 6362228561Snp } 6363228561Snp 6364228561Snp taskqueue_enqueue(sc->tq[eq->tx_chan], &eq->tx_task); 6365228561Snp } 6366228561Snp 6367228561Snp EQ_UNLOCK(eq); 6368228561Snp} 6369228561Snp 6370228561Snpvoid 6371228561Snpt4_tx_task(void *arg, int count) 6372228561Snp{ 6373228561Snp struct sge_eq *eq = arg; 6374228561Snp 6375228561Snp EQ_LOCK(eq); 6376228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 6377228561Snp struct sge_txq *txq = arg; 6378220649Snp txq_start(txq->ifp, txq); 6379228561Snp } else { 6380228561Snp struct sge_wrq *wrq = arg; 6381228561Snp t4_wrq_tx_locked(wrq->adapter, wrq, NULL); 6382228561Snp } 6383228561Snp EQ_UNLOCK(eq); 6384219286Snp} 6385219286Snp 6386221474Snpstatic uint32_t 6387221474Snpfconf_to_mode(uint32_t fconf) 6388221474Snp{ 6389221474Snp uint32_t mode; 6390221474Snp 6391221474Snp mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR | 6392221474Snp T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT; 6393221474Snp 6394221474Snp if (fconf & F_FRAGMENTATION) 6395221474Snp mode |= T4_FILTER_IP_FRAGMENT; 6396221474Snp 6397221474Snp if (fconf & F_MPSHITTYPE) 6398221474Snp mode |= T4_FILTER_MPS_HIT_TYPE; 6399221474Snp 6400221474Snp if (fconf & F_MACMATCH) 6401221474Snp mode |= T4_FILTER_MAC_IDX; 6402221474Snp 6403221474Snp if (fconf & F_ETHERTYPE) 6404221474Snp mode |= T4_FILTER_ETH_TYPE; 6405221474Snp 6406221474Snp if (fconf & F_PROTOCOL) 6407221474Snp mode |= T4_FILTER_IP_PROTO; 6408221474Snp 6409221474Snp if (fconf & F_TOS) 6410221474Snp mode |= T4_FILTER_IP_TOS; 6411221474Snp 6412221474Snp if (fconf & F_VLAN) 6413228561Snp mode |= T4_FILTER_VLAN; 6414221474Snp 6415221474Snp if (fconf & F_VNIC_ID) 6416228561Snp mode |= T4_FILTER_VNIC; 6417221474Snp 6418221474Snp if (fconf & F_PORT) 6419221474Snp mode |= T4_FILTER_PORT; 6420221474Snp 6421221474Snp if (fconf & F_FCOE) 6422221474Snp mode |= T4_FILTER_FCoE; 6423221474Snp 6424221474Snp return (mode); 6425221474Snp} 6426221474Snp 6427221474Snpstatic uint32_t 6428221474Snpmode_to_fconf(uint32_t mode) 6429221474Snp{ 6430221474Snp uint32_t fconf = 0; 6431221474Snp 6432221474Snp if (mode & T4_FILTER_IP_FRAGMENT) 6433221474Snp fconf |= F_FRAGMENTATION; 6434221474Snp 6435221474Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 6436221474Snp fconf |= F_MPSHITTYPE; 6437221474Snp 6438221474Snp if (mode & T4_FILTER_MAC_IDX) 6439221474Snp fconf |= F_MACMATCH; 6440221474Snp 6441221474Snp if (mode & T4_FILTER_ETH_TYPE) 6442221474Snp fconf |= F_ETHERTYPE; 6443221474Snp 6444221474Snp if (mode & T4_FILTER_IP_PROTO) 6445221474Snp fconf |= F_PROTOCOL; 6446221474Snp 6447221474Snp if (mode & T4_FILTER_IP_TOS) 6448221474Snp fconf |= F_TOS; 6449221474Snp 6450228561Snp if (mode & T4_FILTER_VLAN) 6451221474Snp fconf |= F_VLAN; 6452221474Snp 6453228561Snp if (mode & T4_FILTER_VNIC) 6454221474Snp fconf |= F_VNIC_ID; 6455221474Snp 6456221474Snp if (mode & T4_FILTER_PORT) 6457221474Snp fconf |= F_PORT; 6458221474Snp 6459221474Snp if (mode & T4_FILTER_FCoE) 6460221474Snp fconf |= F_FCOE; 6461221474Snp 6462221474Snp return (fconf); 6463221474Snp} 6464221474Snp 6465221474Snpstatic uint32_t 6466221474Snpfspec_to_fconf(struct t4_filter_specification *fs) 6467221474Snp{ 6468221474Snp uint32_t fconf = 0; 6469221474Snp 6470221474Snp if (fs->val.frag || fs->mask.frag) 6471221474Snp fconf |= F_FRAGMENTATION; 6472221474Snp 6473221474Snp if (fs->val.matchtype || fs->mask.matchtype) 6474221474Snp fconf |= F_MPSHITTYPE; 6475221474Snp 6476221474Snp if (fs->val.macidx || fs->mask.macidx) 6477221474Snp fconf |= F_MACMATCH; 6478221474Snp 6479221474Snp if (fs->val.ethtype || fs->mask.ethtype) 6480221474Snp fconf |= F_ETHERTYPE; 6481221474Snp 6482221474Snp if (fs->val.proto || fs->mask.proto) 6483221474Snp fconf |= F_PROTOCOL; 6484221474Snp 6485221474Snp if (fs->val.tos || fs->mask.tos) 6486221474Snp fconf |= F_TOS; 6487221474Snp 6488228561Snp if (fs->val.vlan_vld || fs->mask.vlan_vld) 6489221474Snp fconf |= F_VLAN; 6490221474Snp 6491228561Snp if (fs->val.vnic_vld || fs->mask.vnic_vld) 6492221474Snp fconf |= F_VNIC_ID; 6493221474Snp 6494221474Snp if (fs->val.iport || fs->mask.iport) 6495221474Snp fconf |= F_PORT; 6496221474Snp 6497221474Snp if (fs->val.fcoe || fs->mask.fcoe) 6498221474Snp fconf |= F_FCOE; 6499221474Snp 6500221474Snp return (fconf); 6501221474Snp} 6502221474Snp 6503221474Snpstatic int 6504221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode) 6505221474Snp{ 6506245274Snp int rc; 6507221474Snp uint32_t fconf; 6508221474Snp 6509245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 6510245274Snp "t4getfm"); 6511245274Snp if (rc) 6512245274Snp return (rc); 6513245274Snp 6514221474Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1, 6515221474Snp A_TP_VLAN_PRI_MAP); 6516221474Snp 6517228561Snp if (sc->filter_mode != fconf) { 6518228561Snp log(LOG_WARNING, "%s: cached filter mode out of sync %x %x.\n", 6519228561Snp device_get_nameunit(sc->dev), sc->filter_mode, fconf); 6520228561Snp sc->filter_mode = fconf; 6521228561Snp } 6522221474Snp 6523228561Snp *mode = fconf_to_mode(sc->filter_mode); 6524228561Snp 6525245274Snp end_synchronized_op(sc, LOCK_HELD); 6526221474Snp return (0); 6527221474Snp} 6528221474Snp 6529221474Snpstatic int 6530221474Snpset_filter_mode(struct adapter *sc, uint32_t mode) 6531221474Snp{ 6532221474Snp uint32_t fconf; 6533221474Snp int rc; 6534221474Snp 6535221474Snp fconf = mode_to_fconf(mode); 6536221474Snp 6537245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 6538245274Snp "t4setfm"); 6539245274Snp if (rc) 6540245274Snp return (rc); 6541221474Snp 6542221474Snp if (sc->tids.ftids_in_use > 0) { 6543221474Snp rc = EBUSY; 6544221474Snp goto done; 6545221474Snp } 6546221474Snp 6547237263Snp#ifdef TCP_OFFLOAD 6548228561Snp if (sc->offload_map) { 6549228561Snp rc = EBUSY; 6550228561Snp goto done; 6551228561Snp } 6552228561Snp#endif 6553228561Snp 6554228561Snp#ifdef notyet 6555221474Snp rc = -t4_set_filter_mode(sc, fconf); 6556228561Snp if (rc == 0) 6557228561Snp sc->filter_mode = fconf; 6558228561Snp#else 6559228561Snp rc = ENOTSUP; 6560228561Snp#endif 6561228561Snp 6562221474Snpdone: 6563245274Snp end_synchronized_op(sc, LOCK_HELD); 6564221474Snp return (rc); 6565221474Snp} 6566221474Snp 6567222552Snpstatic inline uint64_t 6568222552Snpget_filter_hits(struct adapter *sc, uint32_t fid) 6569222552Snp{ 6570248925Snp uint32_t mw_base, off, tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 6571222552Snp uint64_t hits; 6572222552Snp 6573248925Snp memwin_info(sc, 0, &mw_base, NULL); 6574248925Snp off = position_memwin(sc, 0, 6575222552Snp tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE); 6576248925Snp hits = t4_read_reg64(sc, mw_base + off + 16); 6577222552Snp 6578222552Snp return (be64toh(hits)); 6579222552Snp} 6580222552Snp 6581221474Snpstatic int 6582221474Snpget_filter(struct adapter *sc, struct t4_filter *t) 6583221474Snp{ 6584245274Snp int i, rc, nfilters = sc->tids.nftids; 6585221474Snp struct filter_entry *f; 6586221474Snp 6587245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 6588245274Snp "t4getf"); 6589245274Snp if (rc) 6590245274Snp return (rc); 6591221474Snp 6592221474Snp if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL || 6593221474Snp t->idx >= nfilters) { 6594221474Snp t->idx = 0xffffffff; 6595245274Snp goto done; 6596221474Snp } 6597221474Snp 6598221474Snp f = &sc->tids.ftid_tab[t->idx]; 6599221474Snp for (i = t->idx; i < nfilters; i++, f++) { 6600221474Snp if (f->valid) { 6601221474Snp t->idx = i; 6602222509Snp t->l2tidx = f->l2t ? f->l2t->idx : 0; 6603222509Snp t->smtidx = f->smtidx; 6604222552Snp if (f->fs.hitcnts) 6605222552Snp t->hits = get_filter_hits(sc, t->idx); 6606222552Snp else 6607222552Snp t->hits = UINT64_MAX; 6608221474Snp t->fs = f->fs; 6609221474Snp 6610245274Snp goto done; 6611221474Snp } 6612221474Snp } 6613221474Snp 6614221474Snp t->idx = 0xffffffff; 6615245274Snpdone: 6616245274Snp end_synchronized_op(sc, LOCK_HELD); 6617221474Snp return (0); 6618221474Snp} 6619221474Snp 6620221474Snpstatic int 6621221474Snpset_filter(struct adapter *sc, struct t4_filter *t) 6622221474Snp{ 6623221474Snp unsigned int nfilters, nports; 6624221474Snp struct filter_entry *f; 6625245274Snp int i, rc; 6626221474Snp 6627245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setf"); 6628245274Snp if (rc) 6629245274Snp return (rc); 6630221474Snp 6631221474Snp nfilters = sc->tids.nftids; 6632221474Snp nports = sc->params.nports; 6633221474Snp 6634245274Snp if (nfilters == 0) { 6635245274Snp rc = ENOTSUP; 6636245274Snp goto done; 6637245274Snp } 6638221474Snp 6639245274Snp if (!(sc->flags & FULL_INIT_DONE)) { 6640245274Snp rc = EAGAIN; 6641245274Snp goto done; 6642245274Snp } 6643221474Snp 6644245274Snp if (t->idx >= nfilters) { 6645245274Snp rc = EINVAL; 6646245274Snp goto done; 6647245274Snp } 6648221474Snp 6649221474Snp /* Validate against the global filter mode */ 6650245274Snp if ((sc->filter_mode | fspec_to_fconf(&t->fs)) != sc->filter_mode) { 6651245274Snp rc = E2BIG; 6652245274Snp goto done; 6653245274Snp } 6654221474Snp 6655245274Snp if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) { 6656245274Snp rc = EINVAL; 6657245274Snp goto done; 6658245274Snp } 6659221474Snp 6660245274Snp if (t->fs.val.iport >= nports) { 6661245274Snp rc = EINVAL; 6662245274Snp goto done; 6663245274Snp } 6664221474Snp 6665221474Snp /* Can't specify an iq if not steering to it */ 6666245274Snp if (!t->fs.dirsteer && t->fs.iq) { 6667245274Snp rc = EINVAL; 6668245274Snp goto done; 6669245274Snp } 6670221474Snp 6671221474Snp /* IPv6 filter idx must be 4 aligned */ 6672221474Snp if (t->fs.type == 1 && 6673245274Snp ((t->idx & 0x3) || t->idx + 4 >= nfilters)) { 6674245274Snp rc = EINVAL; 6675245274Snp goto done; 6676245274Snp } 6677221474Snp 6678221474Snp if (sc->tids.ftid_tab == NULL) { 6679221474Snp KASSERT(sc->tids.ftids_in_use == 0, 6680221474Snp ("%s: no memory allocated but filters_in_use > 0", 6681221474Snp __func__)); 6682221474Snp 6683221474Snp sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) * 6684221474Snp nfilters, M_CXGBE, M_NOWAIT | M_ZERO); 6685245274Snp if (sc->tids.ftid_tab == NULL) { 6686245274Snp rc = ENOMEM; 6687245274Snp goto done; 6688245274Snp } 6689245274Snp mtx_init(&sc->tids.ftid_lock, "T4 filters", 0, MTX_DEF); 6690221474Snp } 6691221474Snp 6692221474Snp for (i = 0; i < 4; i++) { 6693221474Snp f = &sc->tids.ftid_tab[t->idx + i]; 6694221474Snp 6695245274Snp if (f->pending || f->valid) { 6696245274Snp rc = EBUSY; 6697245274Snp goto done; 6698245274Snp } 6699245274Snp if (f->locked) { 6700245274Snp rc = EPERM; 6701245274Snp goto done; 6702245274Snp } 6703221474Snp 6704221474Snp if (t->fs.type == 0) 6705221474Snp break; 6706221474Snp } 6707221474Snp 6708221474Snp f = &sc->tids.ftid_tab[t->idx]; 6709221474Snp f->fs = t->fs; 6710221474Snp 6711245274Snp rc = set_filter_wr(sc, t->idx); 6712245274Snpdone: 6713245274Snp end_synchronized_op(sc, 0); 6714245274Snp 6715245274Snp if (rc == 0) { 6716245274Snp mtx_lock(&sc->tids.ftid_lock); 6717245274Snp for (;;) { 6718245274Snp if (f->pending == 0) { 6719245274Snp rc = f->valid ? 0 : EIO; 6720245274Snp break; 6721245274Snp } 6722245274Snp 6723245274Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 6724245274Snp PCATCH, "t4setfw", 0)) { 6725245274Snp rc = EINPROGRESS; 6726245274Snp break; 6727245274Snp } 6728245274Snp } 6729245274Snp mtx_unlock(&sc->tids.ftid_lock); 6730245274Snp } 6731245274Snp return (rc); 6732221474Snp} 6733221474Snp 6734221474Snpstatic int 6735221474Snpdel_filter(struct adapter *sc, struct t4_filter *t) 6736221474Snp{ 6737221474Snp unsigned int nfilters; 6738221474Snp struct filter_entry *f; 6739245274Snp int rc; 6740221474Snp 6741245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4delf"); 6742245274Snp if (rc) 6743245274Snp return (rc); 6744221474Snp 6745221474Snp nfilters = sc->tids.nftids; 6746221474Snp 6747245274Snp if (nfilters == 0) { 6748245274Snp rc = ENOTSUP; 6749245274Snp goto done; 6750245274Snp } 6751221474Snp 6752221474Snp if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 || 6753245274Snp t->idx >= nfilters) { 6754245274Snp rc = EINVAL; 6755245274Snp goto done; 6756245274Snp } 6757221474Snp 6758245274Snp if (!(sc->flags & FULL_INIT_DONE)) { 6759245274Snp rc = EAGAIN; 6760245274Snp goto done; 6761245274Snp } 6762221474Snp 6763221474Snp f = &sc->tids.ftid_tab[t->idx]; 6764221474Snp 6765245274Snp if (f->pending) { 6766245274Snp rc = EBUSY; 6767245274Snp goto done; 6768245274Snp } 6769245274Snp if (f->locked) { 6770245274Snp rc = EPERM; 6771245274Snp goto done; 6772245274Snp } 6773221474Snp 6774221474Snp if (f->valid) { 6775221474Snp t->fs = f->fs; /* extra info for the caller */ 6776245274Snp rc = del_filter_wr(sc, t->idx); 6777221474Snp } 6778221474Snp 6779245274Snpdone: 6780245274Snp end_synchronized_op(sc, 0); 6781245274Snp 6782245274Snp if (rc == 0) { 6783245274Snp mtx_lock(&sc->tids.ftid_lock); 6784245274Snp for (;;) { 6785245274Snp if (f->pending == 0) { 6786245274Snp rc = f->valid ? EIO : 0; 6787245274Snp break; 6788245274Snp } 6789245274Snp 6790245274Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 6791245274Snp PCATCH, "t4delfw", 0)) { 6792245274Snp rc = EINPROGRESS; 6793245274Snp break; 6794245274Snp } 6795245274Snp } 6796245274Snp mtx_unlock(&sc->tids.ftid_lock); 6797245274Snp } 6798245274Snp 6799245274Snp return (rc); 6800221474Snp} 6801221474Snp 6802221474Snpstatic void 6803222509Snpclear_filter(struct filter_entry *f) 6804221474Snp{ 6805222509Snp if (f->l2t) 6806222509Snp t4_l2t_release(f->l2t); 6807222509Snp 6808221474Snp bzero(f, sizeof (*f)); 6809221474Snp} 6810221474Snp 6811221474Snpstatic int 6812221474Snpset_filter_wr(struct adapter *sc, int fidx) 6813221474Snp{ 6814221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 6815237263Snp struct wrqe *wr; 6816221474Snp struct fw_filter_wr *fwr; 6817221474Snp unsigned int ftid; 6818221474Snp 6819245274Snp ASSERT_SYNCHRONIZED_OP(sc); 6820221474Snp 6821222509Snp if (f->fs.newdmac || f->fs.newvlan) { 6822222509Snp /* This filter needs an L2T entry; allocate one. */ 6823222509Snp f->l2t = t4_l2t_alloc_switching(sc->l2t); 6824222509Snp if (f->l2t == NULL) 6825222509Snp return (EAGAIN); 6826222509Snp if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport, 6827222509Snp f->fs.dmac)) { 6828222509Snp t4_l2t_release(f->l2t); 6829222509Snp f->l2t = NULL; 6830222509Snp return (ENOMEM); 6831222509Snp } 6832222509Snp } 6833221474Snp 6834221474Snp ftid = sc->tids.ftid_base + fidx; 6835221474Snp 6836237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 6837237263Snp if (wr == NULL) 6838221474Snp return (ENOMEM); 6839221474Snp 6840237263Snp fwr = wrtod(wr); 6841221474Snp bzero(fwr, sizeof (*fwr)); 6842221474Snp 6843221474Snp fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR)); 6844221474Snp fwr->len16_pkd = htobe32(FW_LEN16(*fwr)); 6845221474Snp fwr->tid_to_iq = 6846221474Snp htobe32(V_FW_FILTER_WR_TID(ftid) | 6847221474Snp V_FW_FILTER_WR_RQTYPE(f->fs.type) | 6848221474Snp V_FW_FILTER_WR_NOREPLY(0) | 6849221474Snp V_FW_FILTER_WR_IQ(f->fs.iq)); 6850221474Snp fwr->del_filter_to_l2tix = 6851221474Snp htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) | 6852221474Snp V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) | 6853221474Snp V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) | 6854221474Snp V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) | 6855221474Snp V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) | 6856221474Snp V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) | 6857221474Snp V_FW_FILTER_WR_DMAC(f->fs.newdmac) | 6858221474Snp V_FW_FILTER_WR_SMAC(f->fs.newsmac) | 6859221474Snp V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT || 6860221474Snp f->fs.newvlan == VLAN_REWRITE) | 6861221474Snp V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE || 6862221474Snp f->fs.newvlan == VLAN_REWRITE) | 6863221474Snp V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) | 6864221474Snp V_FW_FILTER_WR_TXCHAN(f->fs.eport) | 6865221474Snp V_FW_FILTER_WR_PRIO(f->fs.prio) | 6866222509Snp V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0)); 6867221474Snp fwr->ethtype = htobe16(f->fs.val.ethtype); 6868221474Snp fwr->ethtypem = htobe16(f->fs.mask.ethtype); 6869221474Snp fwr->frag_to_ovlan_vldm = 6870221474Snp (V_FW_FILTER_WR_FRAG(f->fs.val.frag) | 6871221474Snp V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) | 6872228561Snp V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) | 6873228561Snp V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.vnic_vld) | 6874228561Snp V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) | 6875228561Snp V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.vnic_vld)); 6876221474Snp fwr->smac_sel = 0; 6877221474Snp fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) | 6878228561Snp V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id)); 6879221474Snp fwr->maci_to_matchtypem = 6880221474Snp htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) | 6881221474Snp V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) | 6882221474Snp V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) | 6883221474Snp V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) | 6884221474Snp V_FW_FILTER_WR_PORT(f->fs.val.iport) | 6885221474Snp V_FW_FILTER_WR_PORTM(f->fs.mask.iport) | 6886221474Snp V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) | 6887221474Snp V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype)); 6888221474Snp fwr->ptcl = f->fs.val.proto; 6889221474Snp fwr->ptclm = f->fs.mask.proto; 6890221474Snp fwr->ttyp = f->fs.val.tos; 6891221474Snp fwr->ttypm = f->fs.mask.tos; 6892228561Snp fwr->ivlan = htobe16(f->fs.val.vlan); 6893228561Snp fwr->ivlanm = htobe16(f->fs.mask.vlan); 6894228561Snp fwr->ovlan = htobe16(f->fs.val.vnic); 6895228561Snp fwr->ovlanm = htobe16(f->fs.mask.vnic); 6896221474Snp bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip)); 6897221474Snp bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm)); 6898221474Snp bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip)); 6899221474Snp bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm)); 6900221474Snp fwr->lp = htobe16(f->fs.val.dport); 6901221474Snp fwr->lpm = htobe16(f->fs.mask.dport); 6902221474Snp fwr->fp = htobe16(f->fs.val.sport); 6903221474Snp fwr->fpm = htobe16(f->fs.mask.sport); 6904221474Snp if (f->fs.newsmac) 6905221474Snp bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma)); 6906221474Snp 6907221474Snp f->pending = 1; 6908221474Snp sc->tids.ftids_in_use++; 6909228561Snp 6910237263Snp t4_wrq_tx(sc, wr); 6911228561Snp return (0); 6912221474Snp} 6913221474Snp 6914221474Snpstatic int 6915221474Snpdel_filter_wr(struct adapter *sc, int fidx) 6916221474Snp{ 6917221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 6918237263Snp struct wrqe *wr; 6919221474Snp struct fw_filter_wr *fwr; 6920228561Snp unsigned int ftid; 6921221474Snp 6922221474Snp ftid = sc->tids.ftid_base + fidx; 6923221474Snp 6924237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 6925237263Snp if (wr == NULL) 6926221474Snp return (ENOMEM); 6927237263Snp fwr = wrtod(wr); 6928221474Snp bzero(fwr, sizeof (*fwr)); 6929221474Snp 6930228561Snp t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id); 6931221474Snp 6932221474Snp f->pending = 1; 6933237263Snp t4_wrq_tx(sc, wr); 6934228561Snp return (0); 6935221474Snp} 6936221474Snp 6937239338Snpint 6938239338Snpt4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 6939221474Snp{ 6940228561Snp struct adapter *sc = iq->adapter; 6941228561Snp const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1); 6942221474Snp unsigned int idx = GET_TID(rpl); 6943221474Snp 6944228561Snp KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__, 6945228561Snp rss->opcode)); 6946228561Snp 6947221474Snp if (idx >= sc->tids.ftid_base && 6948221474Snp (idx -= sc->tids.ftid_base) < sc->tids.nftids) { 6949221474Snp unsigned int rc = G_COOKIE(rpl->cookie); 6950221474Snp struct filter_entry *f = &sc->tids.ftid_tab[idx]; 6951221474Snp 6952245274Snp mtx_lock(&sc->tids.ftid_lock); 6953228561Snp if (rc == FW_FILTER_WR_FLT_ADDED) { 6954245274Snp KASSERT(f->pending, ("%s: filter[%u] isn't pending.", 6955245274Snp __func__, idx)); 6956221474Snp f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff; 6957221474Snp f->pending = 0; /* asynchronous setup completed */ 6958221474Snp f->valid = 1; 6959231120Snp } else { 6960231120Snp if (rc != FW_FILTER_WR_FLT_DELETED) { 6961231120Snp /* Add or delete failed, display an error */ 6962231120Snp log(LOG_ERR, 6963231120Snp "filter %u setup failed with error %u\n", 6964231120Snp idx, rc); 6965231120Snp } 6966228561Snp 6967231120Snp clear_filter(f); 6968231120Snp sc->tids.ftids_in_use--; 6969221474Snp } 6970245274Snp wakeup(&sc->tids.ftid_tab); 6971245274Snp mtx_unlock(&sc->tids.ftid_lock); 6972221474Snp } 6973228561Snp 6974228561Snp return (0); 6975221474Snp} 6976221474Snp 6977222973Snpstatic int 6978222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt) 6979222973Snp{ 6980245274Snp int rc; 6981222973Snp 6982222973Snp if (cntxt->cid > M_CTXTQID) 6983245274Snp return (EINVAL); 6984222973Snp 6985222973Snp if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS && 6986222973Snp cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM) 6987245274Snp return (EINVAL); 6988222973Snp 6989246575Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ctxt"); 6990246575Snp if (rc) 6991246575Snp return (rc); 6992246575Snp 6993222973Snp if (sc->flags & FW_OK) { 6994246575Snp rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id, 6995246575Snp &cntxt->data[0]); 6996246575Snp if (rc == 0) 6997246575Snp goto done; 6998222973Snp } 6999222973Snp 7000245274Snp /* 7001245274Snp * Read via firmware failed or wasn't even attempted. Read directly via 7002245274Snp * the backdoor. 7003245274Snp */ 7004246575Snp rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id, &cntxt->data[0]); 7005246575Snpdone: 7006246575Snp end_synchronized_op(sc, 0); 7007245274Snp return (rc); 7008245274Snp} 7009222973Snp 7010245274Snpstatic int 7011245274Snpload_fw(struct adapter *sc, struct t4_data *fw) 7012245274Snp{ 7013245274Snp int rc; 7014245274Snp uint8_t *fw_data; 7015245274Snp 7016245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ldfw"); 7017245274Snp if (rc) 7018245274Snp return (rc); 7019245274Snp 7020245274Snp if (sc->flags & FULL_INIT_DONE) { 7021245274Snp rc = EBUSY; 7022245274Snp goto done; 7023222973Snp } 7024222973Snp 7025245274Snp fw_data = malloc(fw->len, M_CXGBE, M_WAITOK); 7026245274Snp if (fw_data == NULL) { 7027245274Snp rc = ENOMEM; 7028245274Snp goto done; 7029245274Snp } 7030245274Snp 7031245274Snp rc = copyin(fw->data, fw_data, fw->len); 7032245274Snp if (rc == 0) 7033245274Snp rc = -t4_load_fw(sc, fw_data, fw->len); 7034245274Snp 7035245274Snp free(fw_data, M_CXGBE); 7036245274Snpdone: 7037245274Snp end_synchronized_op(sc, 0); 7038222973Snp return (rc); 7039222973Snp} 7040222973Snp 7041228561Snpstatic int 7042248925Snpread_card_mem(struct adapter *sc, int win, struct t4_mem_range *mr) 7043228561Snp{ 7044248925Snp uint32_t addr, off, remaining, i, n; 7045228561Snp uint32_t *buf, *b; 7046248925Snp uint32_t mw_base, mw_aperture; 7047228561Snp int rc; 7048248925Snp uint8_t *dst; 7049228561Snp 7050248925Snp rc = validate_mem_range(sc, mr->addr, mr->len); 7051248925Snp if (rc != 0) 7052248925Snp return (rc); 7053228561Snp 7054248925Snp memwin_info(sc, win, &mw_base, &mw_aperture); 7055248925Snp buf = b = malloc(min(mr->len, mw_aperture), M_CXGBE, M_WAITOK); 7056248925Snp addr = mr->addr; 7057228561Snp remaining = mr->len; 7058248925Snp dst = (void *)mr->data; 7059228561Snp 7060228561Snp while (remaining) { 7061248925Snp off = position_memwin(sc, win, addr); 7062228561Snp 7063228561Snp /* number of bytes that we'll copy in the inner loop */ 7064248925Snp n = min(remaining, mw_aperture - off); 7065248925Snp for (i = 0; i < n; i += 4) 7066248925Snp *b++ = t4_read_reg(sc, mw_base + off + i); 7067228561Snp 7068248925Snp rc = copyout(buf, dst, n); 7069248925Snp if (rc != 0) 7070248925Snp break; 7071228561Snp 7072248925Snp b = buf; 7073248925Snp dst += n; 7074248925Snp remaining -= n; 7075248925Snp addr += n; 7076228561Snp } 7077228561Snp 7078228561Snp free(buf, M_CXGBE); 7079228561Snp return (rc); 7080228561Snp} 7081228561Snp 7082241399Snpstatic int 7083241399Snpread_i2c(struct adapter *sc, struct t4_i2c_data *i2cd) 7084241399Snp{ 7085241399Snp int rc; 7086241399Snp 7087241399Snp if (i2cd->len == 0 || i2cd->port_id >= sc->params.nports) 7088241399Snp return (EINVAL); 7089241399Snp 7090241399Snp if (i2cd->len > 1) { 7091241399Snp /* XXX: need fw support for longer reads in one go */ 7092241399Snp return (ENOTSUP); 7093241399Snp } 7094241399Snp 7095245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4i2crd"); 7096245274Snp if (rc) 7097245274Snp return (rc); 7098241399Snp rc = -t4_i2c_rd(sc, sc->mbox, i2cd->port_id, i2cd->dev_addr, 7099241399Snp i2cd->offset, &i2cd->data[0]); 7100245274Snp end_synchronized_op(sc, 0); 7101241399Snp 7102241399Snp return (rc); 7103241399Snp} 7104241399Snp 7105218792Snpint 7106218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap) 7107218792Snp{ 7108222102Snp int i; 7109218792Snp 7110222102Snp return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0); 7111218792Snp} 7112218792Snp 7113218792Snpint 7114218792Snpt4_os_pci_save_state(struct adapter *sc) 7115218792Snp{ 7116218792Snp device_t dev; 7117218792Snp struct pci_devinfo *dinfo; 7118218792Snp 7119218792Snp dev = sc->dev; 7120218792Snp dinfo = device_get_ivars(dev); 7121218792Snp 7122218792Snp pci_cfg_save(dev, dinfo, 0); 7123218792Snp return (0); 7124218792Snp} 7125218792Snp 7126218792Snpint 7127218792Snpt4_os_pci_restore_state(struct adapter *sc) 7128218792Snp{ 7129218792Snp device_t dev; 7130218792Snp struct pci_devinfo *dinfo; 7131218792Snp 7132218792Snp dev = sc->dev; 7133218792Snp dinfo = device_get_ivars(dev); 7134218792Snp 7135218792Snp pci_cfg_restore(dev, dinfo); 7136218792Snp return (0); 7137218792Snp} 7138219299Snp 7139218792Snpvoid 7140218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx) 7141218792Snp{ 7142218792Snp struct port_info *pi = sc->port[idx]; 7143218792Snp static const char *mod_str[] = { 7144220232Snp NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM" 7145218792Snp }; 7146218792Snp 7147218792Snp if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 7148218792Snp if_printf(pi->ifp, "transceiver unplugged.\n"); 7149220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) 7150220232Snp if_printf(pi->ifp, "unknown transceiver inserted.\n"); 7151220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) 7152220232Snp if_printf(pi->ifp, "unsupported transceiver inserted.\n"); 7153240452Snp else if (pi->mod_type > 0 && pi->mod_type < nitems(mod_str)) { 7154218792Snp if_printf(pi->ifp, "%s transceiver inserted.\n", 7155218792Snp mod_str[pi->mod_type]); 7156219299Snp } else { 7157219299Snp if_printf(pi->ifp, "transceiver (type %d) inserted.\n", 7158219299Snp pi->mod_type); 7159219299Snp } 7160218792Snp} 7161218792Snp 7162218792Snpvoid 7163218792Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat) 7164218792Snp{ 7165218792Snp struct port_info *pi = sc->port[idx]; 7166218792Snp struct ifnet *ifp = pi->ifp; 7167218792Snp 7168218792Snp if (link_stat) { 7169218792Snp ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed); 7170218792Snp if_link_state_change(ifp, LINK_STATE_UP); 7171218792Snp } else 7172218792Snp if_link_state_change(ifp, LINK_STATE_DOWN); 7173218792Snp} 7174218792Snp 7175228561Snpvoid 7176228561Snpt4_iterate(void (*func)(struct adapter *, void *), void *arg) 7177228561Snp{ 7178228561Snp struct adapter *sc; 7179228561Snp 7180228561Snp mtx_lock(&t4_list_lock); 7181228561Snp SLIST_FOREACH(sc, &t4_list, link) { 7182228561Snp /* 7183228561Snp * func should not make any assumptions about what state sc is 7184228561Snp * in - the only guarantee is that sc->sc_lock is a valid lock. 7185228561Snp */ 7186228561Snp func(sc, arg); 7187228561Snp } 7188228561Snp mtx_unlock(&t4_list_lock); 7189228561Snp} 7190228561Snp 7191218792Snpstatic int 7192218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td) 7193218792Snp{ 7194218792Snp return (0); 7195218792Snp} 7196218792Snp 7197218792Snpstatic int 7198218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td) 7199218792Snp{ 7200218792Snp return (0); 7201218792Snp} 7202218792Snp 7203218792Snpstatic int 7204218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag, 7205218792Snp struct thread *td) 7206218792Snp{ 7207218792Snp int rc; 7208218792Snp struct adapter *sc = dev->si_drv1; 7209218792Snp 7210218792Snp rc = priv_check(td, PRIV_DRIVER); 7211218792Snp if (rc != 0) 7212218792Snp return (rc); 7213218792Snp 7214218792Snp switch (cmd) { 7215220410Snp case CHELSIO_T4_GETREG: { 7216220410Snp struct t4_reg *edata = (struct t4_reg *)data; 7217220410Snp 7218218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 7219218792Snp return (EFAULT); 7220220410Snp 7221220410Snp if (edata->size == 4) 7222220410Snp edata->val = t4_read_reg(sc, edata->addr); 7223220410Snp else if (edata->size == 8) 7224220410Snp edata->val = t4_read_reg64(sc, edata->addr); 7225220410Snp else 7226220410Snp return (EINVAL); 7227220410Snp 7228218792Snp break; 7229218792Snp } 7230220410Snp case CHELSIO_T4_SETREG: { 7231220410Snp struct t4_reg *edata = (struct t4_reg *)data; 7232220410Snp 7233218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 7234218792Snp return (EFAULT); 7235220410Snp 7236220410Snp if (edata->size == 4) { 7237220410Snp if (edata->val & 0xffffffff00000000) 7238220410Snp return (EINVAL); 7239220410Snp t4_write_reg(sc, edata->addr, (uint32_t) edata->val); 7240220410Snp } else if (edata->size == 8) 7241220410Snp t4_write_reg64(sc, edata->addr, edata->val); 7242220410Snp else 7243220410Snp return (EINVAL); 7244218792Snp break; 7245218792Snp } 7246218792Snp case CHELSIO_T4_REGDUMP: { 7247218792Snp struct t4_regdump *regs = (struct t4_regdump *)data; 7248248925Snp int reglen = is_t4(sc) ? T4_REGDUMP_SIZE : T5_REGDUMP_SIZE; 7249218792Snp uint8_t *buf; 7250218792Snp 7251218792Snp if (regs->len < reglen) { 7252218792Snp regs->len = reglen; /* hint to the caller */ 7253218792Snp return (ENOBUFS); 7254218792Snp } 7255218792Snp 7256218792Snp regs->len = reglen; 7257218792Snp buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO); 7258218792Snp t4_get_regs(sc, regs, buf); 7259218792Snp rc = copyout(buf, regs->data, reglen); 7260218792Snp free(buf, M_CXGBE); 7261218792Snp break; 7262218792Snp } 7263221474Snp case CHELSIO_T4_GET_FILTER_MODE: 7264221474Snp rc = get_filter_mode(sc, (uint32_t *)data); 7265221474Snp break; 7266221474Snp case CHELSIO_T4_SET_FILTER_MODE: 7267221474Snp rc = set_filter_mode(sc, *(uint32_t *)data); 7268221474Snp break; 7269221474Snp case CHELSIO_T4_GET_FILTER: 7270221474Snp rc = get_filter(sc, (struct t4_filter *)data); 7271221474Snp break; 7272221474Snp case CHELSIO_T4_SET_FILTER: 7273221474Snp rc = set_filter(sc, (struct t4_filter *)data); 7274221474Snp break; 7275221474Snp case CHELSIO_T4_DEL_FILTER: 7276221474Snp rc = del_filter(sc, (struct t4_filter *)data); 7277221474Snp break; 7278222973Snp case CHELSIO_T4_GET_SGE_CONTEXT: 7279222973Snp rc = get_sge_context(sc, (struct t4_sge_context *)data); 7280222973Snp break; 7281245274Snp case CHELSIO_T4_LOAD_FW: 7282245274Snp rc = load_fw(sc, (struct t4_data *)data); 7283228561Snp break; 7284228561Snp case CHELSIO_T4_GET_MEM: 7285248925Snp rc = read_card_mem(sc, 2, (struct t4_mem_range *)data); 7286228561Snp break; 7287241399Snp case CHELSIO_T4_GET_I2C: 7288241399Snp rc = read_i2c(sc, (struct t4_i2c_data *)data); 7289241399Snp break; 7290241409Snp case CHELSIO_T4_CLEAR_STATS: { 7291245518Snp int i; 7292241409Snp u_int port_id = *(uint32_t *)data; 7293245518Snp struct port_info *pi; 7294241409Snp 7295241409Snp if (port_id >= sc->params.nports) 7296241409Snp return (EINVAL); 7297241409Snp 7298245518Snp /* MAC stats */ 7299241409Snp t4_clr_port_stats(sc, port_id); 7300245518Snp 7301245518Snp pi = sc->port[port_id]; 7302245518Snp if (pi->flags & PORT_INIT_DONE) { 7303245518Snp struct sge_rxq *rxq; 7304245518Snp struct sge_txq *txq; 7305245518Snp struct sge_wrq *wrq; 7306245518Snp 7307245518Snp for_each_rxq(pi, i, rxq) { 7308245518Snp#if defined(INET) || defined(INET6) 7309245518Snp rxq->lro.lro_queued = 0; 7310245518Snp rxq->lro.lro_flushed = 0; 7311245518Snp#endif 7312245518Snp rxq->rxcsum = 0; 7313245518Snp rxq->vlan_extraction = 0; 7314245518Snp } 7315245518Snp 7316245518Snp for_each_txq(pi, i, txq) { 7317245518Snp txq->txcsum = 0; 7318245518Snp txq->tso_wrs = 0; 7319245518Snp txq->vlan_insertion = 0; 7320245518Snp txq->imm_wrs = 0; 7321245518Snp txq->sgl_wrs = 0; 7322245518Snp txq->txpkt_wrs = 0; 7323245518Snp txq->txpkts_wrs = 0; 7324245518Snp txq->txpkts_pkts = 0; 7325246093Snp txq->br->br_drops = 0; 7326245518Snp txq->no_dmamap = 0; 7327245518Snp txq->no_desc = 0; 7328245518Snp } 7329245518Snp 7330245518Snp#ifdef TCP_OFFLOAD 7331245518Snp /* nothing to clear for each ofld_rxq */ 7332245518Snp 7333245518Snp for_each_ofld_txq(pi, i, wrq) { 7334245518Snp wrq->tx_wrs = 0; 7335245518Snp wrq->no_desc = 0; 7336245518Snp } 7337245518Snp#endif 7338245518Snp wrq = &sc->sge.ctrlq[pi->port_id]; 7339245518Snp wrq->tx_wrs = 0; 7340245518Snp wrq->no_desc = 0; 7341245518Snp } 7342241409Snp break; 7343241409Snp } 7344218792Snp default: 7345218792Snp rc = EINVAL; 7346218792Snp } 7347218792Snp 7348218792Snp return (rc); 7349218792Snp} 7350218792Snp 7351237263Snp#ifdef TCP_OFFLOAD 7352219392Snpstatic int 7353228561Snptoe_capability(struct port_info *pi, int enable) 7354228561Snp{ 7355228561Snp int rc; 7356228561Snp struct adapter *sc = pi->adapter; 7357228561Snp 7358245274Snp ASSERT_SYNCHRONIZED_OP(sc); 7359228561Snp 7360228561Snp if (!is_offload(sc)) 7361228561Snp return (ENODEV); 7362228561Snp 7363228561Snp if (enable) { 7364237263Snp if (!(sc->flags & FULL_INIT_DONE)) { 7365245274Snp rc = cxgbe_init_synchronized(pi); 7366245274Snp if (rc) 7367245274Snp return (rc); 7368237263Snp } 7369237263Snp 7370228561Snp if (isset(&sc->offload_map, pi->port_id)) 7371228561Snp return (0); 7372228561Snp 7373237263Snp if (!(sc->flags & TOM_INIT_DONE)) { 7374237263Snp rc = t4_activate_uld(sc, ULD_TOM); 7375237263Snp if (rc == EAGAIN) { 7376237263Snp log(LOG_WARNING, 7377237263Snp "You must kldload t4_tom.ko before trying " 7378237263Snp "to enable TOE on a cxgbe interface.\n"); 7379237263Snp } 7380228561Snp if (rc != 0) 7381228561Snp return (rc); 7382237263Snp KASSERT(sc->tom_softc != NULL, 7383237263Snp ("%s: TOM activated but softc NULL", __func__)); 7384237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 7385237263Snp ("%s: TOM activated but flag not set", __func__)); 7386228561Snp } 7387228561Snp 7388228561Snp setbit(&sc->offload_map, pi->port_id); 7389228561Snp } else { 7390228561Snp if (!isset(&sc->offload_map, pi->port_id)) 7391228561Snp return (0); 7392228561Snp 7393237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 7394237263Snp ("%s: TOM never initialized?", __func__)); 7395228561Snp clrbit(&sc->offload_map, pi->port_id); 7396228561Snp } 7397228561Snp 7398228561Snp return (0); 7399228561Snp} 7400228561Snp 7401228561Snp/* 7402228561Snp * Add an upper layer driver to the global list. 7403228561Snp */ 7404228561Snpint 7405228561Snpt4_register_uld(struct uld_info *ui) 7406228561Snp{ 7407228561Snp int rc = 0; 7408228561Snp struct uld_info *u; 7409228561Snp 7410228561Snp mtx_lock(&t4_uld_list_lock); 7411228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 7412228561Snp if (u->uld_id == ui->uld_id) { 7413228561Snp rc = EEXIST; 7414228561Snp goto done; 7415228561Snp } 7416228561Snp } 7417228561Snp 7418228561Snp SLIST_INSERT_HEAD(&t4_uld_list, ui, link); 7419228561Snp ui->refcount = 0; 7420228561Snpdone: 7421228561Snp mtx_unlock(&t4_uld_list_lock); 7422228561Snp return (rc); 7423228561Snp} 7424228561Snp 7425228561Snpint 7426228561Snpt4_unregister_uld(struct uld_info *ui) 7427228561Snp{ 7428228561Snp int rc = EINVAL; 7429228561Snp struct uld_info *u; 7430228561Snp 7431228561Snp mtx_lock(&t4_uld_list_lock); 7432228561Snp 7433228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 7434228561Snp if (u == ui) { 7435228561Snp if (ui->refcount > 0) { 7436228561Snp rc = EBUSY; 7437228561Snp goto done; 7438228561Snp } 7439228561Snp 7440228561Snp SLIST_REMOVE(&t4_uld_list, ui, uld_info, link); 7441228561Snp rc = 0; 7442228561Snp goto done; 7443228561Snp } 7444228561Snp } 7445228561Snpdone: 7446228561Snp mtx_unlock(&t4_uld_list_lock); 7447228561Snp return (rc); 7448228561Snp} 7449228561Snp 7450237263Snpint 7451237263Snpt4_activate_uld(struct adapter *sc, int id) 7452228561Snp{ 7453228561Snp int rc = EAGAIN; 7454228561Snp struct uld_info *ui; 7455228561Snp 7456245274Snp ASSERT_SYNCHRONIZED_OP(sc); 7457245274Snp 7458228561Snp mtx_lock(&t4_uld_list_lock); 7459228561Snp 7460228561Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 7461228561Snp if (ui->uld_id == id) { 7462237263Snp rc = ui->activate(sc); 7463237263Snp if (rc == 0) 7464228561Snp ui->refcount++; 7465228561Snp goto done; 7466228561Snp } 7467228561Snp } 7468228561Snpdone: 7469228561Snp mtx_unlock(&t4_uld_list_lock); 7470228561Snp 7471228561Snp return (rc); 7472228561Snp} 7473228561Snp 7474237263Snpint 7475237263Snpt4_deactivate_uld(struct adapter *sc, int id) 7476228561Snp{ 7477237263Snp int rc = EINVAL; 7478237263Snp struct uld_info *ui; 7479228561Snp 7480245274Snp ASSERT_SYNCHRONIZED_OP(sc); 7481245274Snp 7482228561Snp mtx_lock(&t4_uld_list_lock); 7483228561Snp 7484237263Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 7485237263Snp if (ui->uld_id == id) { 7486237263Snp rc = ui->deactivate(sc); 7487237263Snp if (rc == 0) 7488237263Snp ui->refcount--; 7489237263Snp goto done; 7490237263Snp } 7491228561Snp } 7492228561Snpdone: 7493228561Snp mtx_unlock(&t4_uld_list_lock); 7494228561Snp 7495228561Snp return (rc); 7496228561Snp} 7497228561Snp#endif 7498228561Snp 7499228561Snp/* 7500228561Snp * Come up with reasonable defaults for some of the tunables, provided they're 7501228561Snp * not set by the user (in which case we'll use the values as is). 7502228561Snp */ 7503228561Snpstatic void 7504228561Snptweak_tunables(void) 7505228561Snp{ 7506228561Snp int nc = mp_ncpus; /* our snapshot of the number of CPUs */ 7507228561Snp 7508228561Snp if (t4_ntxq10g < 1) 7509228561Snp t4_ntxq10g = min(nc, NTXQ_10G); 7510228561Snp 7511228561Snp if (t4_ntxq1g < 1) 7512228561Snp t4_ntxq1g = min(nc, NTXQ_1G); 7513228561Snp 7514228561Snp if (t4_nrxq10g < 1) 7515228561Snp t4_nrxq10g = min(nc, NRXQ_10G); 7516228561Snp 7517228561Snp if (t4_nrxq1g < 1) 7518228561Snp t4_nrxq1g = min(nc, NRXQ_1G); 7519228561Snp 7520237263Snp#ifdef TCP_OFFLOAD 7521228561Snp if (t4_nofldtxq10g < 1) 7522228561Snp t4_nofldtxq10g = min(nc, NOFLDTXQ_10G); 7523228561Snp 7524228561Snp if (t4_nofldtxq1g < 1) 7525228561Snp t4_nofldtxq1g = min(nc, NOFLDTXQ_1G); 7526228561Snp 7527228561Snp if (t4_nofldrxq10g < 1) 7528228561Snp t4_nofldrxq10g = min(nc, NOFLDRXQ_10G); 7529228561Snp 7530228561Snp if (t4_nofldrxq1g < 1) 7531228561Snp t4_nofldrxq1g = min(nc, NOFLDRXQ_1G); 7532238028Snp 7533238028Snp if (t4_toecaps_allowed == -1) 7534238028Snp t4_toecaps_allowed = FW_CAPS_CONFIG_TOE; 7535238028Snp#else 7536238028Snp if (t4_toecaps_allowed == -1) 7537238028Snp t4_toecaps_allowed = 0; 7538228561Snp#endif 7539228561Snp 7540228561Snp if (t4_tmr_idx_10g < 0 || t4_tmr_idx_10g >= SGE_NTIMERS) 7541228561Snp t4_tmr_idx_10g = TMR_IDX_10G; 7542228561Snp 7543228561Snp if (t4_pktc_idx_10g < -1 || t4_pktc_idx_10g >= SGE_NCOUNTERS) 7544228561Snp t4_pktc_idx_10g = PKTC_IDX_10G; 7545228561Snp 7546228561Snp if (t4_tmr_idx_1g < 0 || t4_tmr_idx_1g >= SGE_NTIMERS) 7547228561Snp t4_tmr_idx_1g = TMR_IDX_1G; 7548228561Snp 7549228561Snp if (t4_pktc_idx_1g < -1 || t4_pktc_idx_1g >= SGE_NCOUNTERS) 7550228561Snp t4_pktc_idx_1g = PKTC_IDX_1G; 7551228561Snp 7552228561Snp if (t4_qsize_txq < 128) 7553228561Snp t4_qsize_txq = 128; 7554228561Snp 7555228561Snp if (t4_qsize_rxq < 128) 7556228561Snp t4_qsize_rxq = 128; 7557228561Snp while (t4_qsize_rxq & 7) 7558228561Snp t4_qsize_rxq++; 7559228561Snp 7560228561Snp t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX; 7561228561Snp} 7562228561Snp 7563228561Snpstatic int 7564249370Snpmod_event(module_t mod, int cmd, void *arg) 7565219392Snp{ 7566228561Snp int rc = 0; 7567249370Snp static int loaded = 0; 7568219392Snp 7569228561Snp switch (cmd) { 7570228561Snp case MOD_LOAD: 7571249370Snp if (atomic_fetchadd_int(&loaded, 1)) 7572249370Snp break; 7573219392Snp t4_sge_modload(); 7574228561Snp mtx_init(&t4_list_lock, "T4 adapters", 0, MTX_DEF); 7575228561Snp SLIST_INIT(&t4_list); 7576237263Snp#ifdef TCP_OFFLOAD 7577228561Snp mtx_init(&t4_uld_list_lock, "T4 ULDs", 0, MTX_DEF); 7578228561Snp SLIST_INIT(&t4_uld_list); 7579228561Snp#endif 7580228561Snp tweak_tunables(); 7581228561Snp break; 7582219392Snp 7583228561Snp case MOD_UNLOAD: 7584249370Snp if (atomic_fetchadd_int(&loaded, -1) > 1) 7585249370Snp break; 7586237263Snp#ifdef TCP_OFFLOAD 7587228561Snp mtx_lock(&t4_uld_list_lock); 7588228561Snp if (!SLIST_EMPTY(&t4_uld_list)) { 7589228561Snp rc = EBUSY; 7590228561Snp mtx_unlock(&t4_uld_list_lock); 7591228561Snp break; 7592228561Snp } 7593228561Snp mtx_unlock(&t4_uld_list_lock); 7594228561Snp mtx_destroy(&t4_uld_list_lock); 7595228561Snp#endif 7596228561Snp mtx_lock(&t4_list_lock); 7597228561Snp if (!SLIST_EMPTY(&t4_list)) { 7598228561Snp rc = EBUSY; 7599228561Snp mtx_unlock(&t4_list_lock); 7600228561Snp break; 7601228561Snp } 7602228561Snp mtx_unlock(&t4_list_lock); 7603228561Snp mtx_destroy(&t4_list_lock); 7604228561Snp break; 7605228561Snp } 7606228561Snp 7607228561Snp return (rc); 7608219392Snp} 7609219392Snp 7610248925Snpstatic devclass_t t4_devclass, t5_devclass; 7611248925Snpstatic devclass_t cxgbe_devclass, cxl_devclass; 7612218792Snp 7613249370SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, mod_event, 0); 7614218792SnpMODULE_VERSION(t4nex, 1); 7615250697SkibMODULE_DEPEND(t4nex, firmware, 1, 1, 1); 7616218792Snp 7617249370SnpDRIVER_MODULE(t5nex, pci, t5_driver, t5_devclass, mod_event, 0); 7618248925SnpMODULE_VERSION(t5nex, 1); 7619250697SkibMODULE_DEPEND(t5nex, firmware, 1, 1, 1); 7620248925Snp 7621218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0); 7622218792SnpMODULE_VERSION(cxgbe, 1); 7623248925Snp 7624248925SnpDRIVER_MODULE(cxl, t5nex, cxl_driver, cxl_devclass, 0, 0); 7625248925SnpMODULE_VERSION(cxl, 1); 7626