t4_main.c revision 252747
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 252747 2013-07-05 01:53:51Z 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); 376252747Snpstatic int sysctl_btphy(SYSCTL_HANDLER_ARGS); 377218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS); 378218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS); 379218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS); 380218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS); 381218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS); 382231115Snp#ifdef SBUF_DRAIN 383228561Snpstatic int sysctl_cctrl(SYSCTL_HANDLER_ARGS); 384247122Snpstatic int sysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS); 385247122Snpstatic int sysctl_cim_la(SYSCTL_HANDLER_ARGS); 386251213Snpstatic int sysctl_cim_ma_la(SYSCTL_HANDLER_ARGS); 387251213Snpstatic int sysctl_cim_pif_la(SYSCTL_HANDLER_ARGS); 388247122Snpstatic int sysctl_cim_qcfg(SYSCTL_HANDLER_ARGS); 389228561Snpstatic int sysctl_cpl_stats(SYSCTL_HANDLER_ARGS); 390228561Snpstatic int sysctl_ddp_stats(SYSCTL_HANDLER_ARGS); 391222551Snpstatic int sysctl_devlog(SYSCTL_HANDLER_ARGS); 392228561Snpstatic int sysctl_fcoe_stats(SYSCTL_HANDLER_ARGS); 393228561Snpstatic int sysctl_hw_sched(SYSCTL_HANDLER_ARGS); 394228561Snpstatic int sysctl_lb_stats(SYSCTL_HANDLER_ARGS); 395228561Snpstatic int sysctl_meminfo(SYSCTL_HANDLER_ARGS); 396251213Snpstatic int sysctl_mps_tcam(SYSCTL_HANDLER_ARGS); 397228561Snpstatic int sysctl_path_mtus(SYSCTL_HANDLER_ARGS); 398228561Snpstatic int sysctl_pm_stats(SYSCTL_HANDLER_ARGS); 399228561Snpstatic int sysctl_rdma_stats(SYSCTL_HANDLER_ARGS); 400228561Snpstatic int sysctl_tcp_stats(SYSCTL_HANDLER_ARGS); 401228561Snpstatic int sysctl_tids(SYSCTL_HANDLER_ARGS); 402228561Snpstatic int sysctl_tp_err_stats(SYSCTL_HANDLER_ARGS); 403251213Snpstatic int sysctl_tp_la(SYSCTL_HANDLER_ARGS); 404228561Snpstatic int sysctl_tx_rate(SYSCTL_HANDLER_ARGS); 405251213Snpstatic int sysctl_ulprx_la(SYSCTL_HANDLER_ARGS); 406249392Snpstatic int sysctl_wcwr_stats(SYSCTL_HANDLER_ARGS); 407231115Snp#endif 408219286Snpstatic inline void txq_start(struct ifnet *, struct sge_txq *); 409221474Snpstatic uint32_t fconf_to_mode(uint32_t); 410221474Snpstatic uint32_t mode_to_fconf(uint32_t); 411221474Snpstatic uint32_t fspec_to_fconf(struct t4_filter_specification *); 412221474Snpstatic int get_filter_mode(struct adapter *, uint32_t *); 413221474Snpstatic int set_filter_mode(struct adapter *, uint32_t); 414222552Snpstatic inline uint64_t get_filter_hits(struct adapter *, uint32_t); 415221474Snpstatic int get_filter(struct adapter *, struct t4_filter *); 416221474Snpstatic int set_filter(struct adapter *, struct t4_filter *); 417221474Snpstatic int del_filter(struct adapter *, struct t4_filter *); 418222509Snpstatic void clear_filter(struct filter_entry *); 419221474Snpstatic int set_filter_wr(struct adapter *, int); 420221474Snpstatic int del_filter_wr(struct adapter *, int); 421222973Snpstatic int get_sge_context(struct adapter *, struct t4_sge_context *); 422245274Snpstatic int load_fw(struct adapter *, struct t4_data *); 423248925Snpstatic int read_card_mem(struct adapter *, int, struct t4_mem_range *); 424241399Snpstatic int read_i2c(struct adapter *, struct t4_i2c_data *); 425237263Snp#ifdef TCP_OFFLOAD 426228561Snpstatic int toe_capability(struct port_info *, int); 427228561Snp#endif 428249370Snpstatic int mod_event(module_t, int, void *); 429218792Snp 430248925Snpstruct { 431218792Snp uint16_t device; 432218792Snp char *desc; 433218792Snp} t4_pciids[] = { 434237587Snp {0xa000, "Chelsio Terminator 4 FPGA"}, 435237587Snp {0x4400, "Chelsio T440-dbg"}, 436237587Snp {0x4401, "Chelsio T420-CR"}, 437237587Snp {0x4402, "Chelsio T422-CR"}, 438237587Snp {0x4403, "Chelsio T440-CR"}, 439237587Snp {0x4404, "Chelsio T420-BCH"}, 440237587Snp {0x4405, "Chelsio T440-BCH"}, 441237587Snp {0x4406, "Chelsio T440-CH"}, 442237587Snp {0x4407, "Chelsio T420-SO"}, 443237587Snp {0x4408, "Chelsio T420-CX"}, 444237587Snp {0x4409, "Chelsio T420-BT"}, 445237587Snp {0x440a, "Chelsio T404-BT"}, 446244580Snp {0x440e, "Chelsio T440-LP-CR"}, 447248925Snp}, t5_pciids[] = { 448248925Snp {0xb000, "Chelsio Terminator 5 FPGA"}, 449248925Snp {0x5400, "Chelsio T580-dbg"}, 450249393Snp {0x5401, "Chelsio T520-CR"}, 451249393Snp {0x5407, "Chelsio T520-SO"}, 452249393Snp {0x5408, "Chelsio T520-CX"}, 453250093Snp {0x5410, "Chelsio T580-LP-CR"}, /* 2 x 40G */ 454249393Snp {0x5411, "Chelsio T520-LL-CR"}, 455249393Snp#ifdef notyet 456249393Snp {0x5402, "Chelsio T522-CR"}, 457249393Snp {0x5403, "Chelsio T540-CR"}, 458249393Snp {0x5404, "Chelsio T520-BCH"}, 459249393Snp {0x5405, "Chelsio T540-BCH"}, 460249393Snp {0x5406, "Chelsio T540-CH"}, 461249393Snp {0x5409, "Chelsio T520-BT"}, 462249393Snp {0x540a, "Chelsio T504-BT"}, 463249393Snp {0x540b, "Chelsio B520-SR"}, 464249393Snp {0x540c, "Chelsio B504-BT"}, 465249393Snp {0x540d, "Chelsio T580-CR"}, 466249393Snp {0x540e, "Chelsio T540-LP-CR"}, 467249393Snp {0x540f, "Chelsio Amsterdam"}, 468249393Snp {0x5412, "Chelsio T560-CR"}, 469249393Snp {0x5413, "Chelsio T580-CR"}, 470249393Snp#endif 471218792Snp}; 472218792Snp 473237263Snp#ifdef TCP_OFFLOAD 474237263Snp/* 475237263Snp * service_iq() has an iq and needs the fl. Offset of fl from the iq should be 476237263Snp * exactly the same for both rxq and ofld_rxq. 477237263Snp */ 478237263SnpCTASSERT(offsetof(struct sge_ofld_rxq, iq) == offsetof(struct sge_rxq, iq)); 479228561SnpCTASSERT(offsetof(struct sge_ofld_rxq, fl) == offsetof(struct sge_rxq, fl)); 480228561Snp#endif 481228561Snp 482239336Snp/* No easy way to include t4_msg.h before adapter.h so we check this way */ 483240452SnpCTASSERT(nitems(((struct adapter *)0)->cpl_handler) == NUM_CPL_CMDS); 484240452SnpCTASSERT(nitems(((struct adapter *)0)->fw_msg_handler) == NUM_FW6_TYPES); 485239336Snp 486218792Snpstatic int 487218792Snpt4_probe(device_t dev) 488218792Snp{ 489218792Snp int i; 490218792Snp uint16_t v = pci_get_vendor(dev); 491218792Snp uint16_t d = pci_get_device(dev); 492237587Snp uint8_t f = pci_get_function(dev); 493218792Snp 494218792Snp if (v != PCI_VENDOR_ID_CHELSIO) 495218792Snp return (ENXIO); 496218792Snp 497237587Snp /* Attach only to PF0 of the FPGA */ 498237587Snp if (d == 0xa000 && f != 0) 499237587Snp return (ENXIO); 500237587Snp 501240452Snp for (i = 0; i < nitems(t4_pciids); i++) { 502237587Snp if (d == t4_pciids[i].device) { 503218792Snp device_set_desc(dev, t4_pciids[i].desc); 504218792Snp return (BUS_PROBE_DEFAULT); 505218792Snp } 506218792Snp } 507218792Snp 508218792Snp return (ENXIO); 509218792Snp} 510218792Snp 511218792Snpstatic int 512248925Snpt5_probe(device_t dev) 513248925Snp{ 514248925Snp int i; 515248925Snp uint16_t v = pci_get_vendor(dev); 516248925Snp uint16_t d = pci_get_device(dev); 517248925Snp uint8_t f = pci_get_function(dev); 518248925Snp 519248925Snp if (v != PCI_VENDOR_ID_CHELSIO) 520248925Snp return (ENXIO); 521248925Snp 522248925Snp /* Attach only to PF0 of the FPGA */ 523248925Snp if (d == 0xb000 && f != 0) 524248925Snp return (ENXIO); 525248925Snp 526248925Snp for (i = 0; i < nitems(t5_pciids); i++) { 527248925Snp if (d == t5_pciids[i].device) { 528248925Snp device_set_desc(dev, t5_pciids[i].desc); 529248925Snp return (BUS_PROBE_DEFAULT); 530248925Snp } 531248925Snp } 532248925Snp 533248925Snp return (ENXIO); 534248925Snp} 535248925Snp 536248925Snpstatic int 537218792Snpt4_attach(device_t dev) 538218792Snp{ 539218792Snp struct adapter *sc; 540218792Snp int rc = 0, i, n10g, n1g, rqidx, tqidx; 541218792Snp struct intrs_and_queues iaq; 542218792Snp struct sge *s; 543237263Snp#ifdef TCP_OFFLOAD 544228561Snp int ofld_rqidx, ofld_tqidx; 545228561Snp#endif 546218792Snp 547218792Snp sc = device_get_softc(dev); 548218792Snp sc->dev = dev; 549218792Snp 550218792Snp pci_enable_busmaster(dev); 551222085Snp if (pci_find_cap(dev, PCIY_EXPRESS, &i) == 0) { 552228561Snp uint32_t v; 553228561Snp 554222085Snp pci_set_max_read_req(dev, 4096); 555240680Sgavin v = pci_read_config(dev, i + PCIER_DEVICE_CTL, 2); 556240680Sgavin v |= PCIEM_CTL_RELAXED_ORD_ENABLE; 557240680Sgavin pci_write_config(dev, i + PCIER_DEVICE_CTL, v, 2); 558222085Snp } 559222085Snp 560218792Snp snprintf(sc->lockname, sizeof(sc->lockname), "%s", 561218792Snp device_get_nameunit(dev)); 562218792Snp mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF); 563228561Snp mtx_lock(&t4_list_lock); 564228561Snp SLIST_INSERT_HEAD(&t4_list, sc, link); 565228561Snp mtx_unlock(&t4_list_lock); 566218792Snp 567228561Snp mtx_init(&sc->sfl_lock, "starving freelists", 0, MTX_DEF); 568228561Snp TAILQ_INIT(&sc->sfl); 569228561Snp callout_init(&sc->sfl_callout, CALLOUT_MPSAFE); 570228561Snp 571248925Snp rc = map_bars_0_and_4(sc); 572218792Snp if (rc != 0) 573218792Snp goto done; /* error message displayed already */ 574218792Snp 575237587Snp /* 576237587Snp * This is the real PF# to which we're attaching. Works from within PCI 577237587Snp * passthrough environments too, where pci_get_function() could return a 578237587Snp * different PF# depending on the passthrough configuration. We need to 579237587Snp * use the real PF# in all our communication with the firmware. 580237587Snp */ 581237587Snp sc->pf = G_SOURCEPF(t4_read_reg(sc, A_PL_WHOAMI)); 582237587Snp sc->mbox = sc->pf; 583237587Snp 584218792Snp memset(sc->chan_map, 0xff, sizeof(sc->chan_map)); 585237263Snp sc->an_handler = an_not_handled; 586240452Snp for (i = 0; i < nitems(sc->cpl_handler); i++) 587228561Snp sc->cpl_handler[i] = cpl_not_handled; 588240452Snp for (i = 0; i < nitems(sc->fw_msg_handler); i++) 589239336Snp sc->fw_msg_handler[i] = fw_msg_not_handled; 590239338Snp t4_register_cpl_handler(sc, CPL_SET_TCB_RPL, t4_filter_rpl); 591248925Snp t4_init_sge_cpl_handlers(sc); 592218792Snp 593218792Snp /* Prepare the adapter for operation */ 594218792Snp rc = -t4_prep_adapter(sc); 595218792Snp if (rc != 0) { 596218792Snp device_printf(dev, "failed to prepare adapter: %d.\n", rc); 597218792Snp goto done; 598218792Snp } 599218792Snp 600228561Snp /* 601228561Snp * Do this really early, with the memory windows set up even before the 602228561Snp * character device. The userland tool's register i/o and mem read 603228561Snp * will work even in "recovery mode". 604228561Snp */ 605228561Snp setup_memwin(sc); 606248925Snp sc->cdev = make_dev(is_t4(sc) ? &t4_cdevsw : &t5_cdevsw, 607248925Snp device_get_unit(dev), UID_ROOT, GID_WHEEL, 0600, "%s", 608248925Snp device_get_nameunit(dev)); 609248925Snp if (sc->cdev == NULL) 610248925Snp device_printf(dev, "failed to create nexus char device.\n"); 611248925Snp else 612248925Snp sc->cdev->si_drv1 = sc; 613218792Snp 614228561Snp /* Go no further if recovery mode has been requested. */ 615228561Snp if (TUNABLE_INT_FETCH("hw.cxgbe.sos", &i) && i != 0) { 616228561Snp device_printf(dev, "recovery mode.\n"); 617228561Snp goto done; 618228561Snp } 619228561Snp 620218792Snp /* Prepare the firmware for operation */ 621218792Snp rc = prep_firmware(sc); 622218792Snp if (rc != 0) 623218792Snp goto done; /* error message displayed already */ 624218792Snp 625248925Snp rc = get_params__post_init(sc); 626228561Snp if (rc != 0) 627228561Snp goto done; /* error message displayed already */ 628222551Snp 629248925Snp rc = set_params__post_init(sc); 630228561Snp if (rc != 0) 631228561Snp goto done; /* error message displayed already */ 632218792Snp 633248925Snp rc = map_bar_2(sc); 634228561Snp if (rc != 0) 635228561Snp goto done; /* error message displayed already */ 636218792Snp 637218792Snp rc = t4_create_dma_tag(sc); 638218792Snp if (rc != 0) 639218792Snp goto done; /* error message displayed already */ 640218792Snp 641218792Snp /* 642218792Snp * First pass over all the ports - allocate VIs and initialize some 643218792Snp * basic parameters like mac address, port type, etc. We also figure 644218792Snp * out whether a port is 10G or 1G and use that information when 645218792Snp * calculating how many interrupts to attempt to allocate. 646218792Snp */ 647218792Snp n10g = n1g = 0; 648218792Snp for_each_port(sc, i) { 649218792Snp struct port_info *pi; 650218792Snp 651218792Snp pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK); 652218792Snp sc->port[i] = pi; 653218792Snp 654218792Snp /* These must be set before t4_port_init */ 655218792Snp pi->adapter = sc; 656218792Snp pi->port_id = i; 657218792Snp 658218792Snp /* Allocate the vi and initialize parameters like mac addr */ 659218792Snp rc = -t4_port_init(pi, sc->mbox, sc->pf, 0); 660218792Snp if (rc != 0) { 661218792Snp device_printf(dev, "unable to initialize port %d: %d\n", 662218792Snp i, rc); 663218792Snp free(pi, M_CXGBE); 664222510Snp sc->port[i] = NULL; 665222510Snp goto done; 666218792Snp } 667218792Snp 668218792Snp snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d", 669218792Snp device_get_nameunit(dev), i); 670218792Snp mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF); 671218792Snp 672250092Snp if (is_10G_port(pi) || is_40G_port(pi)) { 673218792Snp n10g++; 674228561Snp pi->tmr_idx = t4_tmr_idx_10g; 675228561Snp pi->pktc_idx = t4_pktc_idx_10g; 676218792Snp } else { 677218792Snp n1g++; 678228561Snp pi->tmr_idx = t4_tmr_idx_1g; 679228561Snp pi->pktc_idx = t4_pktc_idx_1g; 680218792Snp } 681218792Snp 682218792Snp pi->xact_addr_filt = -1; 683252747Snp pi->linkdnrc = -1; 684218792Snp 685228561Snp pi->qsize_rxq = t4_qsize_rxq; 686228561Snp pi->qsize_txq = t4_qsize_txq; 687218792Snp 688248925Snp pi->dev = device_add_child(dev, is_t4(sc) ? "cxgbe" : "cxl", -1); 689218792Snp if (pi->dev == NULL) { 690218792Snp device_printf(dev, 691218792Snp "failed to add device for port %d.\n", i); 692218792Snp rc = ENXIO; 693218792Snp goto done; 694218792Snp } 695218792Snp device_set_softc(pi->dev, pi); 696218792Snp } 697218792Snp 698218792Snp /* 699218792Snp * Interrupt type, # of interrupts, # of rx/tx queues, etc. 700218792Snp */ 701218792Snp rc = cfg_itype_and_nqueues(sc, n10g, n1g, &iaq); 702218792Snp if (rc != 0) 703218792Snp goto done; /* error message displayed already */ 704218792Snp 705218792Snp sc->intr_type = iaq.intr_type; 706218792Snp sc->intr_count = iaq.nirq; 707228561Snp sc->flags |= iaq.intr_flags; 708218792Snp 709218792Snp s = &sc->sge; 710218792Snp s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g; 711218792Snp s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g; 712220873Snp s->neq = s->ntxq + s->nrxq; /* the free list in an rxq is an eq */ 713228561Snp s->neq += sc->params.nports + 1;/* ctrl queues: 1 per port + 1 mgmt */ 714218792Snp s->niq = s->nrxq + 1; /* 1 extra for firmware event queue */ 715222510Snp 716237263Snp#ifdef TCP_OFFLOAD 717228561Snp if (is_offload(sc)) { 718228561Snp 719228561Snp s->nofldrxq = n10g * iaq.nofldrxq10g + n1g * iaq.nofldrxq1g; 720228561Snp s->nofldtxq = n10g * iaq.nofldtxq10g + n1g * iaq.nofldtxq1g; 721228561Snp s->neq += s->nofldtxq + s->nofldrxq; 722228561Snp s->niq += s->nofldrxq; 723228561Snp 724228561Snp s->ofld_rxq = malloc(s->nofldrxq * sizeof(struct sge_ofld_rxq), 725228561Snp M_CXGBE, M_ZERO | M_WAITOK); 726228561Snp s->ofld_txq = malloc(s->nofldtxq * sizeof(struct sge_wrq), 727228561Snp M_CXGBE, M_ZERO | M_WAITOK); 728228561Snp } 729228561Snp#endif 730228561Snp 731228561Snp s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_wrq), M_CXGBE, 732220873Snp M_ZERO | M_WAITOK); 733218792Snp s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE, 734218792Snp M_ZERO | M_WAITOK); 735218792Snp s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE, 736218792Snp M_ZERO | M_WAITOK); 737218792Snp s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE, 738218792Snp M_ZERO | M_WAITOK); 739218792Snp s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE, 740218792Snp M_ZERO | M_WAITOK); 741218792Snp 742218792Snp sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE, 743218792Snp M_ZERO | M_WAITOK); 744218792Snp 745228561Snp t4_init_l2t(sc, M_WAITOK); 746222509Snp 747218792Snp /* 748218792Snp * Second pass over the ports. This time we know the number of rx and 749218792Snp * tx queues that each port should get. 750218792Snp */ 751218792Snp rqidx = tqidx = 0; 752237263Snp#ifdef TCP_OFFLOAD 753228561Snp ofld_rqidx = ofld_tqidx = 0; 754228561Snp#endif 755218792Snp for_each_port(sc, i) { 756218792Snp struct port_info *pi = sc->port[i]; 757218792Snp 758218792Snp if (pi == NULL) 759218792Snp continue; 760218792Snp 761218792Snp pi->first_rxq = rqidx; 762218792Snp pi->first_txq = tqidx; 763250092Snp if (is_10G_port(pi) || is_40G_port(pi)) { 764228561Snp pi->nrxq = iaq.nrxq10g; 765228561Snp pi->ntxq = iaq.ntxq10g; 766228561Snp } else { 767228561Snp pi->nrxq = iaq.nrxq1g; 768228561Snp pi->ntxq = iaq.ntxq1g; 769228561Snp } 770218792Snp 771218792Snp rqidx += pi->nrxq; 772218792Snp tqidx += pi->ntxq; 773228561Snp 774237263Snp#ifdef TCP_OFFLOAD 775228561Snp if (is_offload(sc)) { 776228561Snp pi->first_ofld_rxq = ofld_rqidx; 777228561Snp pi->first_ofld_txq = ofld_tqidx; 778250092Snp if (is_10G_port(pi) || is_40G_port(pi)) { 779228561Snp pi->nofldrxq = iaq.nofldrxq10g; 780228561Snp pi->nofldtxq = iaq.nofldtxq10g; 781228561Snp } else { 782228561Snp pi->nofldrxq = iaq.nofldrxq1g; 783228561Snp pi->nofldtxq = iaq.nofldtxq1g; 784228561Snp } 785228561Snp ofld_rqidx += pi->nofldrxq; 786228561Snp ofld_tqidx += pi->nofldtxq; 787228561Snp } 788228561Snp#endif 789218792Snp } 790218792Snp 791240453Snp rc = setup_intr_handlers(sc); 792240453Snp if (rc != 0) { 793240453Snp device_printf(dev, 794240453Snp "failed to setup interrupt handlers: %d\n", rc); 795240453Snp goto done; 796240453Snp } 797240453Snp 798218792Snp rc = bus_generic_attach(dev); 799218792Snp if (rc != 0) { 800218792Snp device_printf(dev, 801218792Snp "failed to attach all child ports: %d\n", rc); 802218792Snp goto done; 803218792Snp } 804218792Snp 805218792Snp device_printf(dev, 806228561Snp "PCIe x%d, %d ports, %d %s interrupt%s, %d eq, %d iq\n", 807228561Snp sc->params.pci.width, sc->params.nports, sc->intr_count, 808228561Snp sc->intr_type == INTR_MSIX ? "MSI-X" : 809228561Snp (sc->intr_type == INTR_MSI ? "MSI" : "INTx"), 810228561Snp sc->intr_count > 1 ? "s" : "", sc->sge.neq, sc->sge.niq); 811228561Snp 812218792Snp t4_set_desc(sc); 813218792Snp 814218792Snpdone: 815228561Snp if (rc != 0 && sc->cdev) { 816228561Snp /* cdev was created and so cxgbetool works; recover that way. */ 817228561Snp device_printf(dev, 818228561Snp "error during attach, adapter is now in recovery mode.\n"); 819228561Snp rc = 0; 820228561Snp } 821228561Snp 822218792Snp if (rc != 0) 823218792Snp t4_detach(dev); 824228561Snp else 825228561Snp t4_sysctls(sc); 826218792Snp 827218792Snp return (rc); 828218792Snp} 829218792Snp 830218792Snp/* 831218792Snp * Idempotent 832218792Snp */ 833218792Snpstatic int 834218792Snpt4_detach(device_t dev) 835218792Snp{ 836218792Snp struct adapter *sc; 837218792Snp struct port_info *pi; 838228561Snp int i, rc; 839218792Snp 840218792Snp sc = device_get_softc(dev); 841218792Snp 842228561Snp if (sc->flags & FULL_INIT_DONE) 843228561Snp t4_intr_disable(sc); 844228561Snp 845228561Snp if (sc->cdev) { 846218792Snp destroy_dev(sc->cdev); 847228561Snp sc->cdev = NULL; 848228561Snp } 849218792Snp 850228561Snp rc = bus_generic_detach(dev); 851228561Snp if (rc) { 852228561Snp device_printf(dev, 853228561Snp "failed to detach child devices: %d\n", rc); 854228561Snp return (rc); 855228561Snp } 856228561Snp 857240453Snp for (i = 0; i < sc->intr_count; i++) 858240453Snp t4_free_irq(sc, &sc->irq[i]); 859240453Snp 860218792Snp for (i = 0; i < MAX_NPORTS; i++) { 861218792Snp pi = sc->port[i]; 862218792Snp if (pi) { 863218792Snp t4_free_vi(pi->adapter, sc->mbox, sc->pf, 0, pi->viid); 864218792Snp if (pi->dev) 865218792Snp device_delete_child(dev, pi->dev); 866218792Snp 867218792Snp mtx_destroy(&pi->pi_lock); 868218792Snp free(pi, M_CXGBE); 869218792Snp } 870218792Snp } 871218792Snp 872228561Snp if (sc->flags & FULL_INIT_DONE) 873228561Snp adapter_full_uninit(sc); 874228561Snp 875218792Snp if (sc->flags & FW_OK) 876218792Snp t4_fw_bye(sc, sc->mbox); 877218792Snp 878219944Snp if (sc->intr_type == INTR_MSI || sc->intr_type == INTR_MSIX) 879218792Snp pci_release_msi(dev); 880218792Snp 881218792Snp if (sc->regs_res) 882218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid, 883218792Snp sc->regs_res); 884218792Snp 885248925Snp if (sc->udbs_res) 886248925Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->udbs_rid, 887248925Snp sc->udbs_res); 888248925Snp 889218792Snp if (sc->msix_res) 890218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid, 891218792Snp sc->msix_res); 892218792Snp 893222509Snp if (sc->l2t) 894222509Snp t4_free_l2t(sc->l2t); 895222509Snp 896237263Snp#ifdef TCP_OFFLOAD 897228561Snp free(sc->sge.ofld_rxq, M_CXGBE); 898228561Snp free(sc->sge.ofld_txq, M_CXGBE); 899228561Snp#endif 900218792Snp free(sc->irq, M_CXGBE); 901218792Snp free(sc->sge.rxq, M_CXGBE); 902218792Snp free(sc->sge.txq, M_CXGBE); 903220873Snp free(sc->sge.ctrlq, M_CXGBE); 904218792Snp free(sc->sge.iqmap, M_CXGBE); 905218792Snp free(sc->sge.eqmap, M_CXGBE); 906221474Snp free(sc->tids.ftid_tab, M_CXGBE); 907218792Snp t4_destroy_dma_tag(sc); 908228561Snp if (mtx_initialized(&sc->sc_lock)) { 909228561Snp mtx_lock(&t4_list_lock); 910228561Snp SLIST_REMOVE(&t4_list, sc, adapter, link); 911228561Snp mtx_unlock(&t4_list_lock); 912228561Snp mtx_destroy(&sc->sc_lock); 913228561Snp } 914218792Snp 915245274Snp if (mtx_initialized(&sc->tids.ftid_lock)) 916245274Snp mtx_destroy(&sc->tids.ftid_lock); 917228561Snp if (mtx_initialized(&sc->sfl_lock)) 918228561Snp mtx_destroy(&sc->sfl_lock); 919228561Snp 920218792Snp bzero(sc, sizeof(*sc)); 921218792Snp 922218792Snp return (0); 923218792Snp} 924218792Snp 925218792Snp 926218792Snpstatic int 927218792Snpcxgbe_probe(device_t dev) 928218792Snp{ 929218792Snp char buf[128]; 930218792Snp struct port_info *pi = device_get_softc(dev); 931218792Snp 932228561Snp snprintf(buf, sizeof(buf), "port %d", pi->port_id); 933218792Snp device_set_desc_copy(dev, buf); 934218792Snp 935218792Snp return (BUS_PROBE_DEFAULT); 936218792Snp} 937218792Snp 938218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \ 939218792Snp IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \ 940237831Snp IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6) 941237819Snp#define T4_CAP_ENABLE (T4_CAP) 942218792Snp 943218792Snpstatic int 944218792Snpcxgbe_attach(device_t dev) 945218792Snp{ 946218792Snp struct port_info *pi = device_get_softc(dev); 947218792Snp struct ifnet *ifp; 948218792Snp 949218792Snp /* Allocate an ifnet and set it up */ 950218792Snp ifp = if_alloc(IFT_ETHER); 951218792Snp if (ifp == NULL) { 952218792Snp device_printf(dev, "Cannot allocate ifnet\n"); 953218792Snp return (ENOMEM); 954218792Snp } 955218792Snp pi->ifp = ifp; 956218792Snp ifp->if_softc = pi; 957218792Snp 958218792Snp callout_init(&pi->tick, CALLOUT_MPSAFE); 959218792Snp 960218792Snp if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 961218792Snp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 962218792Snp 963218792Snp ifp->if_init = cxgbe_init; 964218792Snp ifp->if_ioctl = cxgbe_ioctl; 965218792Snp ifp->if_transmit = cxgbe_transmit; 966218792Snp ifp->if_qflush = cxgbe_qflush; 967218792Snp 968218792Snp ifp->if_capabilities = T4_CAP; 969237263Snp#ifdef TCP_OFFLOAD 970228561Snp if (is_offload(pi->adapter)) 971245933Snp ifp->if_capabilities |= IFCAP_TOE; 972228561Snp#endif 973218792Snp ifp->if_capenable = T4_CAP_ENABLE; 974237799Snp ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO | 975237799Snp CSUM_UDP_IPV6 | CSUM_TCP_IPV6; 976218792Snp 977218792Snp /* Initialize ifmedia for this port */ 978218792Snp ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change, 979218792Snp cxgbe_media_status); 980218792Snp build_medialist(pi); 981218792Snp 982237263Snp pi->vlan_c = EVENTHANDLER_REGISTER(vlan_config, cxgbe_vlan_config, ifp, 983237263Snp EVENTHANDLER_PRI_ANY); 984237263Snp 985218792Snp ether_ifattach(ifp, pi->hw_addr); 986218792Snp 987237263Snp#ifdef TCP_OFFLOAD 988228561Snp if (is_offload(pi->adapter)) { 989228561Snp device_printf(dev, 990228561Snp "%d txq, %d rxq (NIC); %d txq, %d rxq (TOE)\n", 991228561Snp pi->ntxq, pi->nrxq, pi->nofldtxq, pi->nofldrxq); 992228561Snp } else 993218792Snp#endif 994228561Snp device_printf(dev, "%d txq, %d rxq\n", pi->ntxq, pi->nrxq); 995218792Snp 996218792Snp cxgbe_sysctls(pi); 997218792Snp 998218792Snp return (0); 999218792Snp} 1000218792Snp 1001218792Snpstatic int 1002218792Snpcxgbe_detach(device_t dev) 1003218792Snp{ 1004218792Snp struct port_info *pi = device_get_softc(dev); 1005218792Snp struct adapter *sc = pi->adapter; 1006228561Snp struct ifnet *ifp = pi->ifp; 1007218792Snp 1008218792Snp /* Tell if_ioctl and if_init that the port is going away */ 1009218792Snp ADAPTER_LOCK(sc); 1010218792Snp SET_DOOMED(pi); 1011218792Snp wakeup(&sc->flags); 1012218792Snp while (IS_BUSY(sc)) 1013218792Snp mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0); 1014218792Snp SET_BUSY(sc); 1015245274Snp#ifdef INVARIANTS 1016245274Snp sc->last_op = "t4detach"; 1017245274Snp sc->last_op_thr = curthread; 1018245274Snp#endif 1019218792Snp ADAPTER_UNLOCK(sc); 1020218792Snp 1021237263Snp if (pi->vlan_c) 1022237263Snp EVENTHANDLER_DEREGISTER(vlan_config, pi->vlan_c); 1023237263Snp 1024228561Snp PORT_LOCK(pi); 1025228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1026228561Snp callout_stop(&pi->tick); 1027228561Snp PORT_UNLOCK(pi); 1028228561Snp callout_drain(&pi->tick); 1029218792Snp 1030228561Snp /* Let detach proceed even if these fail. */ 1031228561Snp cxgbe_uninit_synchronized(pi); 1032228561Snp port_full_uninit(pi); 1033219286Snp 1034218792Snp ifmedia_removeall(&pi->media); 1035218792Snp ether_ifdetach(pi->ifp); 1036218792Snp if_free(pi->ifp); 1037218792Snp 1038218792Snp ADAPTER_LOCK(sc); 1039218792Snp CLR_BUSY(sc); 1040245274Snp wakeup(&sc->flags); 1041218792Snp ADAPTER_UNLOCK(sc); 1042218792Snp 1043218792Snp return (0); 1044218792Snp} 1045218792Snp 1046218792Snpstatic void 1047218792Snpcxgbe_init(void *arg) 1048218792Snp{ 1049218792Snp struct port_info *pi = arg; 1050218792Snp struct adapter *sc = pi->adapter; 1051218792Snp 1052245274Snp if (begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4init") != 0) 1053245274Snp return; 1054245274Snp cxgbe_init_synchronized(pi); 1055245274Snp end_synchronized_op(sc, 0); 1056218792Snp} 1057218792Snp 1058218792Snpstatic int 1059218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) 1060218792Snp{ 1061218792Snp int rc = 0, mtu, flags; 1062218792Snp struct port_info *pi = ifp->if_softc; 1063218792Snp struct adapter *sc = pi->adapter; 1064218792Snp struct ifreq *ifr = (struct ifreq *)data; 1065218792Snp uint32_t mask; 1066218792Snp 1067218792Snp switch (cmd) { 1068218792Snp case SIOCSIFMTU: 1069245274Snp mtu = ifr->ifr_mtu; 1070245274Snp if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) 1071245274Snp return (EINVAL); 1072245274Snp 1073245274Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4mtu"); 1074245274Snp if (rc) 1075218792Snp return (rc); 1076245274Snp ifp->if_mtu = mtu; 1077252728Snp if (pi->flags & PORT_INIT_DONE) { 1078245274Snp t4_update_fl_bufsize(ifp); 1079252728Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1080252728Snp 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) ( \ 1829252661Snp V_FW_HDR_FW_VER_MAJOR(chip##FW_VERSION_MAJOR) | \ 1830252661Snp V_FW_HDR_FW_VER_MINOR(chip##FW_VERSION_MINOR) | \ 1831252661Snp V_FW_HDR_FW_VER_MICRO(chip##FW_VERSION_MICRO) | \ 1832252661Snp V_FW_HDR_FW_VER_BUILD(chip##FW_VERSION_BUILD)) 1833252661Snp#define FW_INTFVER(chip, intf) (chip##FW_HDR_INTFVER_##intf) 1834248925Snp 1835248925Snpstruct fw_info { 1836248925Snp uint8_t chip; 1837248925Snp char *kld_name; 1838248925Snp char *fw_mod_name; 1839248925Snp struct fw_hdr fw_hdr; /* XXX: waste of space, need a sparse struct */ 1840248925Snp} fw_info[] = { 1841248925Snp { 1842248925Snp .chip = CHELSIO_T4, 1843248925Snp .kld_name = "t4fw_cfg", 1844248925Snp .fw_mod_name = "t4fw", 1845248925Snp .fw_hdr = { 1846248925Snp .chip = FW_HDR_CHIP_T4, 1847248925Snp .fw_ver = htobe32_const(FW_VERSION(T4)), 1848248925Snp .intfver_nic = FW_INTFVER(T4, NIC), 1849248925Snp .intfver_vnic = FW_INTFVER(T4, VNIC), 1850248925Snp .intfver_ofld = FW_INTFVER(T4, OFLD), 1851248925Snp .intfver_ri = FW_INTFVER(T4, RI), 1852248925Snp .intfver_iscsipdu = FW_INTFVER(T4, ISCSIPDU), 1853248925Snp .intfver_iscsi = FW_INTFVER(T4, ISCSI), 1854248925Snp .intfver_fcoepdu = FW_INTFVER(T4, FCOEPDU), 1855248925Snp .intfver_fcoe = FW_INTFVER(T4, FCOE), 1856248925Snp }, 1857248925Snp }, { 1858248925Snp .chip = CHELSIO_T5, 1859248925Snp .kld_name = "t5fw_cfg", 1860248925Snp .fw_mod_name = "t5fw", 1861248925Snp .fw_hdr = { 1862248925Snp .chip = FW_HDR_CHIP_T5, 1863248925Snp .fw_ver = htobe32_const(FW_VERSION(T5)), 1864248925Snp .intfver_nic = FW_INTFVER(T5, NIC), 1865248925Snp .intfver_vnic = FW_INTFVER(T5, VNIC), 1866248925Snp .intfver_ofld = FW_INTFVER(T5, OFLD), 1867248925Snp .intfver_ri = FW_INTFVER(T5, RI), 1868248925Snp .intfver_iscsipdu = FW_INTFVER(T5, ISCSIPDU), 1869248925Snp .intfver_iscsi = FW_INTFVER(T5, ISCSI), 1870248925Snp .intfver_fcoepdu = FW_INTFVER(T5, FCOEPDU), 1871248925Snp .intfver_fcoe = FW_INTFVER(T5, FCOE), 1872248925Snp }, 1873248925Snp } 1874248925Snp}; 1875248925Snp 1876248925Snpstatic struct fw_info * 1877248925Snpfind_fw_info(int chip) 1878248925Snp{ 1879248925Snp int i; 1880248925Snp 1881248925Snp for (i = 0; i < nitems(fw_info); i++) { 1882248925Snp if (fw_info[i].chip == chip) 1883248925Snp return (&fw_info[i]); 1884248925Snp } 1885248925Snp return (NULL); 1886248925Snp} 1887248925Snp 1888218792Snp/* 1889248925Snp * Is the given firmware API compatible with the one the driver was compiled 1890248925Snp * with? 1891247347Snp */ 1892247347Snpstatic int 1893248925Snpfw_compatible(const struct fw_hdr *hdr1, const struct fw_hdr *hdr2) 1894247347Snp{ 1895247347Snp 1896248925Snp /* short circuit if it's the exact same firmware version */ 1897248925Snp if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver) 1898247347Snp return (1); 1899247347Snp 1900247347Snp /* 1901247347Snp * XXX: Is this too conservative? Perhaps I should limit this to the 1902247347Snp * features that are supported in the driver. 1903247347Snp */ 1904248925Snp#define SAME_INTF(x) (hdr1->intfver_##x == hdr2->intfver_##x) 1905248925Snp if (hdr1->chip == hdr2->chip && SAME_INTF(nic) && SAME_INTF(vnic) && 1906248925Snp SAME_INTF(ofld) && SAME_INTF(ri) && SAME_INTF(iscsipdu) && 1907248925Snp SAME_INTF(iscsi) && SAME_INTF(fcoepdu) && SAME_INTF(fcoe)) 1908247347Snp return (1); 1909248925Snp#undef SAME_INTF 1910247347Snp 1911247347Snp return (0); 1912247347Snp} 1913247347Snp 1914247347Snp/* 1915251434Snp * The firmware in the KLD is usable, but should it be installed? This routine 1916251434Snp * explains itself in detail if it indicates the KLD firmware should be 1917251434Snp * installed. 1918249376Snp */ 1919249376Snpstatic int 1920249376Snpshould_install_kld_fw(struct adapter *sc, int card_fw_usable, int k, int c) 1921249376Snp{ 1922249376Snp const char *reason; 1923249376Snp 1924249376Snp if (!card_fw_usable) { 1925249376Snp reason = "incompatible or unusable"; 1926249376Snp goto install; 1927249376Snp } 1928249376Snp 1929249376Snp if (k > c) { 1930249376Snp reason = "older than the version bundled with this driver"; 1931249376Snp goto install; 1932249376Snp } 1933249376Snp 1934249376Snp if (t4_fw_install == 2 && k != c) { 1935249376Snp reason = "different than the version bundled with this driver"; 1936249376Snp goto install; 1937249376Snp } 1938249376Snp 1939249376Snp return (0); 1940249376Snp 1941249376Snpinstall: 1942251434Snp if (t4_fw_install == 0) { 1943251434Snp device_printf(sc->dev, "firmware on card (%u.%u.%u.%u) is %s, " 1944251434Snp "but the driver is prohibited from installing a different " 1945251434Snp "firmware on the card.\n", 1946251434Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 1947251434Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), reason); 1948251434Snp 1949251434Snp return (0); 1950251434Snp } 1951251434Snp 1952249376Snp device_printf(sc->dev, "firmware on card (%u.%u.%u.%u) is %s, " 1953249376Snp "installing firmware %u.%u.%u.%u on card.\n", 1954249376Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 1955249376Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), reason, 1956249376Snp G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k), 1957249376Snp G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k)); 1958249376Snp 1959249376Snp return (1); 1960249376Snp} 1961249376Snp/* 1962248925Snp * Establish contact with the firmware and determine if we are the master driver 1963248925Snp * or not, and whether we are responsible for chip initialization. 1964218792Snp */ 1965218792Snpstatic int 1966218792Snpprep_firmware(struct adapter *sc) 1967218792Snp{ 1968248925Snp const struct firmware *fw = NULL, *default_cfg; 1969248925Snp int rc, pf, card_fw_usable, kld_fw_usable, need_fw_reset = 1; 1970218792Snp enum dev_state state; 1971248925Snp struct fw_info *fw_info; 1972248925Snp struct fw_hdr *card_fw; /* fw on the card */ 1973248925Snp const struct fw_hdr *kld_fw; /* fw in the KLD */ 1974248925Snp const struct fw_hdr *drv_fw; /* fw header the driver was compiled 1975248925Snp against */ 1976218792Snp 1977248925Snp /* Contact firmware. */ 1978248925Snp rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state); 1979248925Snp if (rc < 0 || state == DEV_STATE_ERR) { 1980248925Snp rc = -rc; 1981248925Snp device_printf(sc->dev, 1982248925Snp "failed to connect to the firmware: %d, %d.\n", rc, state); 1983248925Snp return (rc); 1984248925Snp } 1985248925Snp pf = rc; 1986248925Snp if (pf == sc->mbox) 1987248925Snp sc->flags |= MASTER_PF; 1988248925Snp else if (state == DEV_STATE_UNINIT) { 1989248925Snp /* 1990248925Snp * We didn't get to be the master so we definitely won't be 1991248925Snp * configuring the chip. It's a bug if someone else hasn't 1992248925Snp * configured it already. 1993248925Snp */ 1994248925Snp device_printf(sc->dev, "couldn't be master(%d), " 1995248925Snp "device not already initialized either(%d).\n", rc, state); 1996248925Snp return (EDOOFUS); 1997248925Snp } 1998228561Snp 1999248925Snp /* This is the firmware whose headers the driver was compiled against */ 2000248925Snp fw_info = find_fw_info(chip_id(sc)); 2001248925Snp if (fw_info == NULL) { 2002248925Snp device_printf(sc->dev, 2003248925Snp "unable to look up firmware information for chip %d.\n", 2004248925Snp chip_id(sc)); 2005248925Snp return (EINVAL); 2006248925Snp } 2007248925Snp drv_fw = &fw_info->fw_hdr; 2008248925Snp 2009248925Snp /* 2010248925Snp * The firmware KLD contains many modules. The KLD name is also the 2011248925Snp * name of the module that contains the default config file. 2012248925Snp */ 2013248925Snp default_cfg = firmware_get(fw_info->kld_name); 2014248925Snp 2015247347Snp /* Read the header of the firmware on the card */ 2016247347Snp card_fw = malloc(sizeof(*card_fw), M_CXGBE, M_ZERO | M_WAITOK); 2017247347Snp rc = -t4_read_flash(sc, FLASH_FW_START, 2018247347Snp sizeof (*card_fw) / sizeof (uint32_t), (uint32_t *)card_fw, 1); 2019247347Snp if (rc == 0) 2020248925Snp card_fw_usable = fw_compatible(drv_fw, (const void*)card_fw); 2021247347Snp else { 2022247347Snp device_printf(sc->dev, 2023247347Snp "Unable to read card's firmware header: %d\n", rc); 2024247347Snp card_fw_usable = 0; 2025247347Snp } 2026218792Snp 2027247347Snp /* This is the firmware in the KLD */ 2028248925Snp fw = firmware_get(fw_info->fw_mod_name); 2029247347Snp if (fw != NULL) { 2030247347Snp kld_fw = (const void *)fw->data; 2031248925Snp kld_fw_usable = fw_compatible(drv_fw, kld_fw); 2032247347Snp } else { 2033247347Snp kld_fw = NULL; 2034247347Snp kld_fw_usable = 0; 2035247347Snp } 2036219287Snp 2037248925Snp if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver && 2038251434Snp (!kld_fw_usable || kld_fw->fw_ver == drv_fw->fw_ver)) { 2039248925Snp /* 2040248925Snp * Common case: the firmware on the card is an exact match and 2041248925Snp * the KLD is an exact match too, or the KLD is 2042251434Snp * absent/incompatible. Note that t4_fw_install = 2 is ignored 2043251434Snp * here -- use cxgbetool loadfw if you want to reinstall the 2044251434Snp * same firmware as the one on the card. 2045248925Snp */ 2046248925Snp } else if (kld_fw_usable && state == DEV_STATE_UNINIT && 2047249376Snp should_install_kld_fw(sc, card_fw_usable, be32toh(kld_fw->fw_ver), 2048249376Snp be32toh(card_fw->fw_ver))) { 2049219287Snp 2050250221Snp rc = -t4_fw_upgrade(sc, sc->mbox, fw->data, fw->datasize, 0); 2051247347Snp if (rc != 0) { 2052247347Snp device_printf(sc->dev, 2053247347Snp "failed to install firmware: %d\n", rc); 2054228561Snp goto done; 2055219287Snp } 2056219287Snp 2057247347Snp /* Installed successfully, update the cached header too. */ 2058247347Snp memcpy(card_fw, kld_fw, sizeof(*card_fw)); 2059247347Snp card_fw_usable = 1; 2060248925Snp need_fw_reset = 0; /* already reset as part of load_fw */ 2061247347Snp } 2062219287Snp 2063247347Snp if (!card_fw_usable) { 2064248925Snp uint32_t d, c, k; 2065247347Snp 2066248925Snp d = ntohl(drv_fw->fw_ver); 2067247347Snp c = ntohl(card_fw->fw_ver); 2068247347Snp k = kld_fw ? ntohl(kld_fw->fw_ver) : 0; 2069247347Snp 2070247347Snp device_printf(sc->dev, "Cannot find a usable firmware: " 2071248925Snp "fw_install %d, chip state %d, " 2072248925Snp "driver compiled with %d.%d.%d.%d, " 2073247347Snp "card has %d.%d.%d.%d, KLD has %d.%d.%d.%d\n", 2074248925Snp t4_fw_install, state, 2075248925Snp G_FW_HDR_FW_VER_MAJOR(d), G_FW_HDR_FW_VER_MINOR(d), 2076248925Snp G_FW_HDR_FW_VER_MICRO(d), G_FW_HDR_FW_VER_BUILD(d), 2077247347Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 2078247347Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), 2079247347Snp G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k), 2080247347Snp G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k)); 2081248925Snp rc = EINVAL; 2082247347Snp goto done; 2083218792Snp } 2084218792Snp 2085247347Snp /* We're using whatever's on the card and it's known to be good. */ 2086247347Snp sc->params.fw_vers = ntohl(card_fw->fw_ver); 2087247347Snp snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u", 2088247347Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 2089247347Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 2090247347Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 2091247347Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 2092252705Snp t4_get_tp_version(sc, &sc->params.tp_vers); 2093247347Snp 2094218792Snp /* Reset device */ 2095248925Snp if (need_fw_reset && 2096248925Snp (rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST)) != 0) { 2097218792Snp device_printf(sc->dev, "firmware reset failed: %d.\n", rc); 2098218792Snp if (rc != ETIMEDOUT && rc != EIO) 2099218792Snp t4_fw_bye(sc, sc->mbox); 2100228561Snp goto done; 2101218792Snp } 2102248925Snp sc->flags |= FW_OK; 2103218792Snp 2104248925Snp rc = get_params__pre_init(sc); 2105248925Snp if (rc != 0) 2106248925Snp goto done; /* error message displayed already */ 2107248925Snp 2108228561Snp /* Partition adapter resources as specified in the config file. */ 2109248925Snp if (state == DEV_STATE_UNINIT) { 2110228561Snp 2111248925Snp KASSERT(sc->flags & MASTER_PF, 2112248925Snp ("%s: trying to change chip settings when not master.", 2113248925Snp __func__)); 2114228561Snp 2115248925Snp rc = partition_resources(sc, default_cfg, fw_info->kld_name); 2116228561Snp if (rc != 0) 2117228561Snp goto done; /* error message displayed already */ 2118248925Snp 2119248925Snp t4_tweak_chip_settings(sc); 2120248925Snp 2121248925Snp /* get basic stuff going */ 2122248925Snp rc = -t4_fw_initialize(sc, sc->mbox); 2123248925Snp if (rc != 0) { 2124248925Snp device_printf(sc->dev, "fw init failed: %d.\n", rc); 2125248925Snp goto done; 2126248925Snp } 2127245936Snp } else { 2128248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "pf%d", pf); 2129248925Snp sc->cfcsum = 0; 2130228561Snp } 2131228561Snp 2132228561Snpdone: 2133247347Snp free(card_fw, M_CXGBE); 2134228561Snp if (fw != NULL) 2135228561Snp firmware_put(fw, FIRMWARE_UNLOAD); 2136228561Snp if (default_cfg != NULL) 2137228561Snp firmware_put(default_cfg, FIRMWARE_UNLOAD); 2138228561Snp 2139228561Snp return (rc); 2140218792Snp} 2141218792Snp 2142228561Snp#define FW_PARAM_DEV(param) \ 2143228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ 2144228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) 2145228561Snp#define FW_PARAM_PFVF(param) \ 2146228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ 2147228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)) 2148228561Snp 2149228561Snp/* 2150248925Snp * Partition chip resources for use between various PFs, VFs, etc. 2151228561Snp */ 2152218792Snpstatic int 2153248925Snppartition_resources(struct adapter *sc, const struct firmware *default_cfg, 2154248925Snp const char *name_prefix) 2155222551Snp{ 2156248925Snp const struct firmware *cfg = NULL; 2157248925Snp int rc = 0; 2158248925Snp struct fw_caps_config_cmd caps; 2159248925Snp uint32_t mtype, moff, finicsum, cfcsum; 2160222551Snp 2161248925Snp /* 2162248925Snp * Figure out what configuration file to use. Pick the default config 2163248925Snp * file for the card if the user hasn't specified one explicitly. 2164248925Snp */ 2165248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", t4_cfg_file); 2166248925Snp if (strncmp(t4_cfg_file, DEFAULT_CF, sizeof(t4_cfg_file)) == 0) { 2167248925Snp /* Card specific overrides go here. */ 2168248925Snp if (pci_get_device(sc->dev) == 0x440a) 2169248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), UWIRE_CF); 2170249376Snp if (is_fpga(sc)) 2171249376Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), FPGA_CF); 2172222551Snp } 2173222551Snp 2174248925Snp /* 2175248925Snp * We need to load another module if the profile is anything except 2176248925Snp * "default" or "flash". 2177248925Snp */ 2178248925Snp if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) != 0 && 2179248925Snp strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) { 2180248925Snp char s[32]; 2181248925Snp 2182248925Snp snprintf(s, sizeof(s), "%s_%s", name_prefix, sc->cfg_file); 2183248925Snp cfg = firmware_get(s); 2184248925Snp if (cfg == NULL) { 2185248925Snp if (default_cfg != NULL) { 2186249376Snp device_printf(sc->dev, 2187249376Snp "unable to load module \"%s\" for " 2188249376Snp "configuration profile \"%s\", will use " 2189249376Snp "the default config file instead.\n", 2190249376Snp s, sc->cfg_file); 2191248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), 2192248925Snp "%s", DEFAULT_CF); 2193248925Snp } else { 2194249376Snp device_printf(sc->dev, 2195249376Snp "unable to load module \"%s\" for " 2196249376Snp "configuration profile \"%s\", will use " 2197249376Snp "the config file on the card's flash " 2198249376Snp "instead.\n", s, sc->cfg_file); 2199248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), 2200248925Snp "%s", FLASH_CF); 2201248925Snp } 2202248925Snp } 2203228561Snp } 2204222551Snp 2205248925Snp if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) == 0 && 2206248925Snp default_cfg == NULL) { 2207228561Snp device_printf(sc->dev, 2208248925Snp "default config file not available, will use the config " 2209248925Snp "file on the card's flash instead.\n"); 2210248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", FLASH_CF); 2211228561Snp } 2212228561Snp 2213248925Snp if (strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) { 2214248925Snp u_int cflen, i, n; 2215248925Snp const uint32_t *cfdata; 2216248925Snp uint32_t param, val, addr, off, mw_base, mw_aperture; 2217228561Snp 2218248925Snp KASSERT(cfg != NULL || default_cfg != NULL, 2219248925Snp ("%s: no config to upload", __func__)); 2220228561Snp 2221248925Snp /* 2222248925Snp * Ask the firmware where it wants us to upload the config file. 2223248925Snp */ 2224248925Snp param = FW_PARAM_DEV(CF); 2225248925Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 2226248925Snp if (rc != 0) { 2227248925Snp /* No support for config file? Shouldn't happen. */ 2228248925Snp device_printf(sc->dev, 2229248925Snp "failed to query config file location: %d.\n", rc); 2230248925Snp goto done; 2231248925Snp } 2232248925Snp mtype = G_FW_PARAMS_PARAM_Y(val); 2233248925Snp moff = G_FW_PARAMS_PARAM_Z(val) << 16; 2234228561Snp 2235248925Snp /* 2236248925Snp * XXX: sheer laziness. We deliberately added 4 bytes of 2237248925Snp * useless stuffing/comments at the end of the config file so 2238248925Snp * it's ok to simply throw away the last remaining bytes when 2239248925Snp * the config file is not an exact multiple of 4. This also 2240248925Snp * helps with the validate_mt_off_len check. 2241248925Snp */ 2242248925Snp if (cfg != NULL) { 2243248925Snp cflen = cfg->datasize & ~3; 2244248925Snp cfdata = cfg->data; 2245248925Snp } else { 2246248925Snp cflen = default_cfg->datasize & ~3; 2247248925Snp cfdata = default_cfg->data; 2248248925Snp } 2249222551Snp 2250248925Snp if (cflen > FLASH_CFG_MAX_SIZE) { 2251248925Snp device_printf(sc->dev, 2252248925Snp "config file too long (%d, max allowed is %d). " 2253248925Snp "Will try to use the config on the card, if any.\n", 2254248925Snp cflen, FLASH_CFG_MAX_SIZE); 2255248925Snp goto use_config_on_flash; 2256248925Snp } 2257218792Snp 2258248925Snp rc = validate_mt_off_len(sc, mtype, moff, cflen, &addr); 2259248925Snp if (rc != 0) { 2260248925Snp device_printf(sc->dev, 2261248925Snp "%s: addr (%d/0x%x) or len %d is not valid: %d. " 2262248925Snp "Will try to use the config on the card, if any.\n", 2263248925Snp __func__, mtype, moff, cflen, rc); 2264248925Snp goto use_config_on_flash; 2265248925Snp } 2266248925Snp 2267248925Snp memwin_info(sc, 2, &mw_base, &mw_aperture); 2268248925Snp while (cflen) { 2269248925Snp off = position_memwin(sc, 2, addr); 2270248925Snp n = min(cflen, mw_aperture - off); 2271248925Snp for (i = 0; i < n; i += 4) 2272248925Snp t4_write_reg(sc, mw_base + off + i, *cfdata++); 2273248925Snp cflen -= n; 2274248925Snp addr += n; 2275248925Snp } 2276248925Snp } else { 2277248925Snpuse_config_on_flash: 2278228561Snp mtype = FW_MEMTYPE_CF_FLASH; 2279248925Snp moff = t4_flash_cfg_addr(sc); 2280228561Snp } 2281228561Snp 2282228561Snp bzero(&caps, sizeof(caps)); 2283228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2284218792Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2285228561Snp caps.cfvalid_to_len16 = htobe32(F_FW_CAPS_CONFIG_CMD_CFVALID | 2286228561Snp V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) | 2287248925Snp V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(moff >> 16) | FW_LEN16(caps)); 2288228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 2289228561Snp if (rc != 0) { 2290228561Snp device_printf(sc->dev, 2291249376Snp "failed to pre-process config file: %d " 2292249376Snp "(mtype %d, moff 0x%x).\n", rc, mtype, moff); 2293248925Snp goto done; 2294228561Snp } 2295218792Snp 2296228561Snp finicsum = be32toh(caps.finicsum); 2297228561Snp cfcsum = be32toh(caps.cfcsum); 2298228561Snp if (finicsum != cfcsum) { 2299228561Snp device_printf(sc->dev, 2300228561Snp "WARNING: config file checksum mismatch: %08x %08x\n", 2301228561Snp finicsum, cfcsum); 2302228561Snp } 2303228561Snp sc->cfcsum = cfcsum; 2304218792Snp 2305228561Snp#define LIMIT_CAPS(x) do { \ 2306228561Snp caps.x &= htobe16(t4_##x##_allowed); \ 2307228561Snp sc->x = htobe16(caps.x); \ 2308228561Snp} while (0) 2309228561Snp 2310228561Snp /* 2311228561Snp * Let the firmware know what features will (not) be used so it can tune 2312228561Snp * things accordingly. 2313228561Snp */ 2314228561Snp LIMIT_CAPS(linkcaps); 2315228561Snp LIMIT_CAPS(niccaps); 2316228561Snp LIMIT_CAPS(toecaps); 2317228561Snp LIMIT_CAPS(rdmacaps); 2318228561Snp LIMIT_CAPS(iscsicaps); 2319228561Snp LIMIT_CAPS(fcoecaps); 2320228561Snp#undef LIMIT_CAPS 2321228561Snp 2322228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2323218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE); 2324228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 2325228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), NULL); 2326228561Snp if (rc != 0) { 2327228561Snp device_printf(sc->dev, 2328228561Snp "failed to process config file: %d.\n", rc); 2329228561Snp } 2330248925Snpdone: 2331248925Snp if (cfg != NULL) 2332248925Snp firmware_put(cfg, FIRMWARE_UNLOAD); 2333248925Snp return (rc); 2334218792Snp} 2335218792Snp 2336228561Snp/* 2337248925Snp * Retrieve parameters that are needed (or nice to have) very early. 2338228561Snp */ 2339218792Snpstatic int 2340228561Snpget_params__pre_init(struct adapter *sc) 2341218792Snp{ 2342218792Snp int rc; 2343228561Snp uint32_t param[2], val[2]; 2344228561Snp struct fw_devlog_cmd cmd; 2345228561Snp struct devlog_params *dlog = &sc->params.devlog; 2346218792Snp 2347228561Snp param[0] = FW_PARAM_DEV(PORTVEC); 2348228561Snp param[1] = FW_PARAM_DEV(CCLK); 2349228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 2350218792Snp if (rc != 0) { 2351218792Snp device_printf(sc->dev, 2352228561Snp "failed to query parameters (pre_init): %d.\n", rc); 2353228561Snp return (rc); 2354218792Snp } 2355218792Snp 2356218792Snp sc->params.portvec = val[0]; 2357240452Snp sc->params.nports = bitcount32(val[0]); 2358228561Snp sc->params.vpd.cclk = val[1]; 2359218792Snp 2360228561Snp /* Read device log parameters. */ 2361228561Snp bzero(&cmd, sizeof(cmd)); 2362228561Snp cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) | 2363228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2364228561Snp cmd.retval_len16 = htobe32(FW_LEN16(cmd)); 2365228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &cmd, sizeof(cmd), &cmd); 2366228561Snp if (rc != 0) { 2367228561Snp device_printf(sc->dev, 2368228561Snp "failed to get devlog parameters: %d.\n", rc); 2369228561Snp bzero(dlog, sizeof (*dlog)); 2370228561Snp rc = 0; /* devlog isn't critical for device operation */ 2371228561Snp } else { 2372228561Snp val[0] = be32toh(cmd.memtype_devlog_memaddr16_devlog); 2373228561Snp dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(val[0]); 2374228561Snp dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(val[0]) << 4; 2375228561Snp dlog->size = be32toh(cmd.memsize_devlog); 2376228561Snp } 2377228561Snp 2378228561Snp return (rc); 2379228561Snp} 2380228561Snp 2381228561Snp/* 2382228561Snp * Retrieve various parameters that are of interest to the driver. The device 2383228561Snp * has been initialized by the firmware at this point. 2384228561Snp */ 2385228561Snpstatic int 2386228561Snpget_params__post_init(struct adapter *sc) 2387228561Snp{ 2388228561Snp int rc; 2389228561Snp uint32_t param[7], val[7]; 2390228561Snp struct fw_caps_config_cmd caps; 2391228561Snp 2392228561Snp param[0] = FW_PARAM_PFVF(IQFLINT_START); 2393228561Snp param[1] = FW_PARAM_PFVF(EQ_START); 2394228561Snp param[2] = FW_PARAM_PFVF(FILTER_START); 2395228561Snp param[3] = FW_PARAM_PFVF(FILTER_END); 2396245434Snp param[4] = FW_PARAM_PFVF(L2T_START); 2397245434Snp param[5] = FW_PARAM_PFVF(L2T_END); 2398245434Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2399228561Snp if (rc != 0) { 2400228561Snp device_printf(sc->dev, 2401228561Snp "failed to query parameters (post_init): %d.\n", rc); 2402228561Snp return (rc); 2403228561Snp } 2404228561Snp 2405228561Snp sc->sge.iq_start = val[0]; 2406228561Snp sc->sge.eq_start = val[1]; 2407228561Snp sc->tids.ftid_base = val[2]; 2408228561Snp sc->tids.nftids = val[3] - val[2] + 1; 2409245434Snp sc->vres.l2t.start = val[4]; 2410245434Snp sc->vres.l2t.size = val[5] - val[4] + 1; 2411245434Snp KASSERT(sc->vres.l2t.size <= L2T_SIZE, 2412245434Snp ("%s: L2 table size (%u) larger than expected (%u)", 2413245434Snp __func__, sc->vres.l2t.size, L2T_SIZE)); 2414228561Snp 2415228561Snp /* get capabilites */ 2416228561Snp bzero(&caps, sizeof(caps)); 2417228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2418228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2419228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 2420228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 2421228561Snp if (rc != 0) { 2422228561Snp device_printf(sc->dev, 2423228561Snp "failed to get card capabilities: %d.\n", rc); 2424228561Snp return (rc); 2425228561Snp } 2426228561Snp 2427228561Snp if (caps.toecaps) { 2428218792Snp /* query offload-related parameters */ 2429228561Snp param[0] = FW_PARAM_DEV(NTID); 2430228561Snp param[1] = FW_PARAM_PFVF(SERVER_START); 2431228561Snp param[2] = FW_PARAM_PFVF(SERVER_END); 2432228561Snp param[3] = FW_PARAM_PFVF(TDDP_START); 2433228561Snp param[4] = FW_PARAM_PFVF(TDDP_END); 2434228561Snp param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 2435228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2436218792Snp if (rc != 0) { 2437218792Snp device_printf(sc->dev, 2438218792Snp "failed to query TOE parameters: %d.\n", rc); 2439228561Snp return (rc); 2440218792Snp } 2441218792Snp sc->tids.ntids = val[0]; 2442218792Snp sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS); 2443218792Snp sc->tids.stid_base = val[1]; 2444218792Snp sc->tids.nstids = val[2] - val[1] + 1; 2445218792Snp sc->vres.ddp.start = val[3]; 2446218792Snp sc->vres.ddp.size = val[4] - val[3] + 1; 2447218792Snp sc->params.ofldq_wr_cred = val[5]; 2448218792Snp sc->params.offload = 1; 2449218792Snp } 2450228561Snp if (caps.rdmacaps) { 2451228561Snp param[0] = FW_PARAM_PFVF(STAG_START); 2452228561Snp param[1] = FW_PARAM_PFVF(STAG_END); 2453228561Snp param[2] = FW_PARAM_PFVF(RQ_START); 2454228561Snp param[3] = FW_PARAM_PFVF(RQ_END); 2455228561Snp param[4] = FW_PARAM_PFVF(PBL_START); 2456228561Snp param[5] = FW_PARAM_PFVF(PBL_END); 2457228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2458218792Snp if (rc != 0) { 2459218792Snp device_printf(sc->dev, 2460228561Snp "failed to query RDMA parameters(1): %d.\n", rc); 2461228561Snp return (rc); 2462218792Snp } 2463218792Snp sc->vres.stag.start = val[0]; 2464218792Snp sc->vres.stag.size = val[1] - val[0] + 1; 2465218792Snp sc->vres.rq.start = val[2]; 2466218792Snp sc->vres.rq.size = val[3] - val[2] + 1; 2467218792Snp sc->vres.pbl.start = val[4]; 2468218792Snp sc->vres.pbl.size = val[5] - val[4] + 1; 2469228561Snp 2470228561Snp param[0] = FW_PARAM_PFVF(SQRQ_START); 2471228561Snp param[1] = FW_PARAM_PFVF(SQRQ_END); 2472228561Snp param[2] = FW_PARAM_PFVF(CQ_START); 2473228561Snp param[3] = FW_PARAM_PFVF(CQ_END); 2474228561Snp param[4] = FW_PARAM_PFVF(OCQ_START); 2475228561Snp param[5] = FW_PARAM_PFVF(OCQ_END); 2476228561Snp rc = -t4_query_params(sc, 0, 0, 0, 6, param, val); 2477228561Snp if (rc != 0) { 2478228561Snp device_printf(sc->dev, 2479228561Snp "failed to query RDMA parameters(2): %d.\n", rc); 2480228561Snp return (rc); 2481228561Snp } 2482228561Snp sc->vres.qp.start = val[0]; 2483228561Snp sc->vres.qp.size = val[1] - val[0] + 1; 2484228561Snp sc->vres.cq.start = val[2]; 2485228561Snp sc->vres.cq.size = val[3] - val[2] + 1; 2486228561Snp sc->vres.ocq.start = val[4]; 2487228561Snp sc->vres.ocq.size = val[5] - val[4] + 1; 2488218792Snp } 2489228561Snp if (caps.iscsicaps) { 2490228561Snp param[0] = FW_PARAM_PFVF(ISCSI_START); 2491228561Snp param[1] = FW_PARAM_PFVF(ISCSI_END); 2492228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 2493218792Snp if (rc != 0) { 2494218792Snp device_printf(sc->dev, 2495218792Snp "failed to query iSCSI parameters: %d.\n", rc); 2496228561Snp return (rc); 2497218792Snp } 2498218792Snp sc->vres.iscsi.start = val[0]; 2499218792Snp sc->vres.iscsi.size = val[1] - val[0] + 1; 2500218792Snp } 2501218792Snp 2502248925Snp /* 2503248925Snp * We've got the params we wanted to query via the firmware. Now grab 2504248925Snp * some others directly from the chip. 2505248925Snp */ 2506248925Snp rc = t4_read_chip_settings(sc); 2507228561Snp 2508218792Snp return (rc); 2509218792Snp} 2510218792Snp 2511247291Snpstatic int 2512247291Snpset_params__post_init(struct adapter *sc) 2513247291Snp{ 2514247291Snp uint32_t param, val; 2515247291Snp 2516249382Snp /* ask for encapsulated CPLs */ 2517247291Snp param = FW_PARAM_PFVF(CPLFW4MSG_ENCAP); 2518249382Snp val = 1; 2519249382Snp (void)t4_set_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 2520247291Snp 2521249382Snp return (0); 2522247291Snp} 2523247291Snp 2524228561Snp#undef FW_PARAM_PFVF 2525228561Snp#undef FW_PARAM_DEV 2526228561Snp 2527218792Snpstatic void 2528218792Snpt4_set_desc(struct adapter *sc) 2529218792Snp{ 2530218792Snp char buf[128]; 2531218792Snp struct adapter_params *p = &sc->params; 2532218792Snp 2533228561Snp snprintf(buf, sizeof(buf), "Chelsio %s %sNIC (rev %d), S/N:%s, E/C:%s", 2534248925Snp p->vpd.id, is_offload(sc) ? "R" : "", chip_rev(sc), p->vpd.sn, 2535248925Snp p->vpd.ec); 2536218792Snp 2537218792Snp device_set_desc_copy(sc->dev, buf); 2538218792Snp} 2539218792Snp 2540218792Snpstatic void 2541218792Snpbuild_medialist(struct port_info *pi) 2542218792Snp{ 2543218792Snp struct ifmedia *media = &pi->media; 2544218792Snp int data, m; 2545218792Snp 2546218792Snp PORT_LOCK(pi); 2547218792Snp 2548218792Snp ifmedia_removeall(media); 2549218792Snp 2550218792Snp m = IFM_ETHER | IFM_FDX; 2551218792Snp data = (pi->port_type << 8) | pi->mod_type; 2552218792Snp 2553218792Snp switch(pi->port_type) { 2554218792Snp case FW_PORT_TYPE_BT_XFI: 2555218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2556218792Snp break; 2557218792Snp 2558218792Snp case FW_PORT_TYPE_BT_XAUI: 2559218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2560218792Snp /* fall through */ 2561218792Snp 2562218792Snp case FW_PORT_TYPE_BT_SGMII: 2563218792Snp ifmedia_add(media, m | IFM_1000_T, data, NULL); 2564218792Snp ifmedia_add(media, m | IFM_100_TX, data, NULL); 2565218792Snp ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL); 2566218792Snp ifmedia_set(media, IFM_ETHER | IFM_AUTO); 2567218792Snp break; 2568218792Snp 2569218792Snp case FW_PORT_TYPE_CX4: 2570218792Snp ifmedia_add(media, m | IFM_10G_CX4, data, NULL); 2571218792Snp ifmedia_set(media, m | IFM_10G_CX4); 2572218792Snp break; 2573218792Snp 2574218792Snp case FW_PORT_TYPE_SFP: 2575218792Snp case FW_PORT_TYPE_FIBER_XFI: 2576218792Snp case FW_PORT_TYPE_FIBER_XAUI: 2577218792Snp switch (pi->mod_type) { 2578218792Snp 2579218792Snp case FW_PORT_MOD_TYPE_LR: 2580218792Snp ifmedia_add(media, m | IFM_10G_LR, data, NULL); 2581218792Snp ifmedia_set(media, m | IFM_10G_LR); 2582218792Snp break; 2583218792Snp 2584218792Snp case FW_PORT_MOD_TYPE_SR: 2585218792Snp ifmedia_add(media, m | IFM_10G_SR, data, NULL); 2586218792Snp ifmedia_set(media, m | IFM_10G_SR); 2587218792Snp break; 2588218792Snp 2589218792Snp case FW_PORT_MOD_TYPE_LRM: 2590218792Snp ifmedia_add(media, m | IFM_10G_LRM, data, NULL); 2591218792Snp ifmedia_set(media, m | IFM_10G_LRM); 2592218792Snp break; 2593218792Snp 2594218792Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2595218792Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2596218792Snp ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL); 2597218792Snp ifmedia_set(media, m | IFM_10G_TWINAX); 2598218792Snp break; 2599218792Snp 2600218792Snp case FW_PORT_MOD_TYPE_NONE: 2601218792Snp m &= ~IFM_FDX; 2602218792Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2603218792Snp ifmedia_set(media, m | IFM_NONE); 2604218792Snp break; 2605218792Snp 2606218792Snp case FW_PORT_MOD_TYPE_NA: 2607218792Snp case FW_PORT_MOD_TYPE_ER: 2608218792Snp default: 2609250092Snp device_printf(pi->dev, 2610250092Snp "unknown port_type (%d), mod_type (%d)\n", 2611250092Snp pi->port_type, pi->mod_type); 2612218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2613218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2614218792Snp break; 2615218792Snp } 2616218792Snp break; 2617218792Snp 2618250092Snp case FW_PORT_TYPE_QSFP: 2619250092Snp switch (pi->mod_type) { 2620250092Snp 2621250092Snp case FW_PORT_MOD_TYPE_LR: 2622250092Snp ifmedia_add(media, m | IFM_40G_LR4, data, NULL); 2623250092Snp ifmedia_set(media, m | IFM_40G_LR4); 2624250092Snp break; 2625250092Snp 2626250092Snp case FW_PORT_MOD_TYPE_SR: 2627250092Snp ifmedia_add(media, m | IFM_40G_SR4, data, NULL); 2628250092Snp ifmedia_set(media, m | IFM_40G_SR4); 2629250092Snp break; 2630250614Snp 2631250092Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2632250092Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2633250092Snp ifmedia_add(media, m | IFM_40G_CR4, data, NULL); 2634250092Snp ifmedia_set(media, m | IFM_40G_CR4); 2635250092Snp break; 2636250092Snp 2637250614Snp case FW_PORT_MOD_TYPE_NONE: 2638250614Snp m &= ~IFM_FDX; 2639250614Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2640250614Snp ifmedia_set(media, m | IFM_NONE); 2641250614Snp break; 2642250614Snp 2643250092Snp default: 2644250092Snp device_printf(pi->dev, 2645250092Snp "unknown port_type (%d), mod_type (%d)\n", 2646250092Snp pi->port_type, pi->mod_type); 2647250092Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2648250092Snp ifmedia_set(media, m | IFM_UNKNOWN); 2649250092Snp break; 2650250092Snp } 2651250092Snp break; 2652250092Snp 2653218792Snp default: 2654250092Snp device_printf(pi->dev, 2655250092Snp "unknown port_type (%d), mod_type (%d)\n", pi->port_type, 2656250092Snp pi->mod_type); 2657218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2658218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2659218792Snp break; 2660218792Snp } 2661218792Snp 2662218792Snp PORT_UNLOCK(pi); 2663218792Snp} 2664218792Snp 2665231172Snp#define FW_MAC_EXACT_CHUNK 7 2666231172Snp 2667218792Snp/* 2668218792Snp * Program the port's XGMAC based on parameters in ifnet. The caller also 2669218792Snp * indicates which parameters should be programmed (the rest are left alone). 2670218792Snp */ 2671218792Snpstatic int 2672218792Snpupdate_mac_settings(struct port_info *pi, int flags) 2673218792Snp{ 2674218792Snp int rc; 2675218792Snp struct ifnet *ifp = pi->ifp; 2676218792Snp struct adapter *sc = pi->adapter; 2677218792Snp int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1; 2678218792Snp 2679245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2680218792Snp KASSERT(flags, ("%s: not told what to update.", __func__)); 2681218792Snp 2682218792Snp if (flags & XGMAC_MTU) 2683218792Snp mtu = ifp->if_mtu; 2684218792Snp 2685218792Snp if (flags & XGMAC_PROMISC) 2686218792Snp promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0; 2687218792Snp 2688218792Snp if (flags & XGMAC_ALLMULTI) 2689218792Snp allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0; 2690218792Snp 2691218792Snp if (flags & XGMAC_VLANEX) 2692218792Snp vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0; 2693218792Snp 2694218792Snp rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, mtu, promisc, allmulti, 1, 2695218792Snp vlanex, false); 2696218792Snp if (rc) { 2697218792Snp if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, rc); 2698218792Snp return (rc); 2699218792Snp } 2700218792Snp 2701218792Snp if (flags & XGMAC_UCADDR) { 2702218792Snp uint8_t ucaddr[ETHER_ADDR_LEN]; 2703218792Snp 2704218792Snp bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr)); 2705218792Snp rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, 2706218792Snp ucaddr, true, true); 2707218792Snp if (rc < 0) { 2708218792Snp rc = -rc; 2709218792Snp if_printf(ifp, "change_mac failed: %d\n", rc); 2710218792Snp return (rc); 2711218792Snp } else { 2712218792Snp pi->xact_addr_filt = rc; 2713218792Snp rc = 0; 2714218792Snp } 2715218792Snp } 2716218792Snp 2717218792Snp if (flags & XGMAC_MCADDRS) { 2718231172Snp const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK]; 2719218792Snp int del = 1; 2720218792Snp uint64_t hash = 0; 2721218792Snp struct ifmultiaddr *ifma; 2722231172Snp int i = 0, j; 2723218792Snp 2724218792Snp if_maddr_rlock(ifp); 2725218792Snp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2726238054Snp if (ifma->ifma_addr->sa_family != AF_LINK) 2727218792Snp continue; 2728231172Snp mcaddr[i++] = 2729231172Snp LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 2730218792Snp 2731231172Snp if (i == FW_MAC_EXACT_CHUNK) { 2732231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2733231172Snp del, i, mcaddr, NULL, &hash, 0); 2734231172Snp if (rc < 0) { 2735231172Snp rc = -rc; 2736231172Snp for (j = 0; j < i; j++) { 2737231172Snp if_printf(ifp, 2738231172Snp "failed to add mc address" 2739231172Snp " %02x:%02x:%02x:" 2740231172Snp "%02x:%02x:%02x rc=%d\n", 2741231172Snp mcaddr[j][0], mcaddr[j][1], 2742231172Snp mcaddr[j][2], mcaddr[j][3], 2743231172Snp mcaddr[j][4], mcaddr[j][5], 2744231172Snp rc); 2745231172Snp } 2746231172Snp goto mcfail; 2747231172Snp } 2748231172Snp del = 0; 2749231172Snp i = 0; 2750231172Snp } 2751231172Snp } 2752231172Snp if (i > 0) { 2753231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2754231172Snp del, i, mcaddr, NULL, &hash, 0); 2755218792Snp if (rc < 0) { 2756218792Snp rc = -rc; 2757231172Snp for (j = 0; j < i; j++) { 2758231172Snp if_printf(ifp, 2759231172Snp "failed to add mc address" 2760231172Snp " %02x:%02x:%02x:" 2761231172Snp "%02x:%02x:%02x rc=%d\n", 2762231172Snp mcaddr[j][0], mcaddr[j][1], 2763231172Snp mcaddr[j][2], mcaddr[j][3], 2764231172Snp mcaddr[j][4], mcaddr[j][5], 2765231172Snp rc); 2766231172Snp } 2767218792Snp goto mcfail; 2768218792Snp } 2769218792Snp } 2770218792Snp 2771218792Snp rc = -t4_set_addr_hash(sc, sc->mbox, pi->viid, 0, hash, 0); 2772218792Snp if (rc != 0) 2773218792Snp if_printf(ifp, "failed to set mc address hash: %d", rc); 2774218792Snpmcfail: 2775218792Snp if_maddr_runlock(ifp); 2776218792Snp } 2777218792Snp 2778218792Snp return (rc); 2779218792Snp} 2780218792Snp 2781245274Snpint 2782245274Snpbegin_synchronized_op(struct adapter *sc, struct port_info *pi, int flags, 2783245274Snp char *wmesg) 2784218792Snp{ 2785245274Snp int rc, pri; 2786218792Snp 2787245274Snp#ifdef WITNESS 2788245274Snp /* the caller thinks it's ok to sleep, but is it really? */ 2789245274Snp if (flags & SLEEP_OK) 2790245274Snp pause("t4slptst", 1); 2791245274Snp#endif 2792218792Snp 2793245274Snp if (INTR_OK) 2794245274Snp pri = PCATCH; 2795245274Snp else 2796245274Snp pri = 0; 2797245274Snp 2798245274Snp ADAPTER_LOCK(sc); 2799245274Snp for (;;) { 2800245274Snp 2801245274Snp if (pi && IS_DOOMED(pi)) { 2802245274Snp rc = ENXIO; 2803245274Snp goto done; 2804245274Snp } 2805245274Snp 2806245274Snp if (!IS_BUSY(sc)) { 2807245274Snp rc = 0; 2808245274Snp break; 2809245274Snp } 2810245274Snp 2811245274Snp if (!(flags & SLEEP_OK)) { 2812245274Snp rc = EBUSY; 2813245274Snp goto done; 2814245274Snp } 2815245274Snp 2816245274Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, pri, wmesg, 0)) { 2817218792Snp rc = EINTR; 2818218792Snp goto done; 2819218792Snp } 2820218792Snp } 2821245274Snp 2822218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 2823218792Snp SET_BUSY(sc); 2824245274Snp#ifdef INVARIANTS 2825245274Snp sc->last_op = wmesg; 2826245274Snp sc->last_op_thr = curthread; 2827245274Snp#endif 2828218792Snp 2829245274Snpdone: 2830245274Snp if (!(flags & HOLD_LOCK) || rc) 2831245274Snp ADAPTER_UNLOCK(sc); 2832218792Snp 2833245274Snp return (rc); 2834245274Snp} 2835245274Snp 2836245274Snpvoid 2837245274Snpend_synchronized_op(struct adapter *sc, int flags) 2838245274Snp{ 2839245274Snp 2840245274Snp if (flags & LOCK_HELD) 2841245274Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 2842245274Snp else 2843245274Snp ADAPTER_LOCK(sc); 2844245274Snp 2845218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 2846218792Snp CLR_BUSY(sc); 2847245274Snp wakeup(&sc->flags); 2848218792Snp ADAPTER_UNLOCK(sc); 2849218792Snp} 2850218792Snp 2851218792Snpstatic int 2852218792Snpcxgbe_init_synchronized(struct port_info *pi) 2853218792Snp{ 2854218792Snp struct adapter *sc = pi->adapter; 2855218792Snp struct ifnet *ifp = pi->ifp; 2856228561Snp int rc = 0; 2857218792Snp 2858245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2859218792Snp 2860218792Snp if (isset(&sc->open_device_map, pi->port_id)) { 2861218792Snp KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, 2862218792Snp ("mismatch between open_device_map and if_drv_flags")); 2863218792Snp return (0); /* already running */ 2864218792Snp } 2865218792Snp 2866228561Snp if (!(sc->flags & FULL_INIT_DONE) && 2867228561Snp ((rc = adapter_full_init(sc)) != 0)) 2868218792Snp return (rc); /* error message displayed already */ 2869218792Snp 2870228561Snp if (!(pi->flags & PORT_INIT_DONE) && 2871228561Snp ((rc = port_full_init(pi)) != 0)) 2872228561Snp return (rc); /* error message displayed already */ 2873218792Snp 2874218792Snp rc = update_mac_settings(pi, XGMAC_ALL); 2875218792Snp if (rc) 2876218792Snp goto done; /* error message displayed already */ 2877218792Snp 2878218792Snp rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg); 2879218792Snp if (rc != 0) { 2880218792Snp if_printf(ifp, "start_link failed: %d\n", rc); 2881218792Snp goto done; 2882218792Snp } 2883218792Snp 2884218792Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true); 2885218792Snp if (rc != 0) { 2886218792Snp if_printf(ifp, "enable_vi failed: %d\n", rc); 2887218792Snp goto done; 2888218792Snp } 2889218792Snp 2890218792Snp /* all ok */ 2891218792Snp setbit(&sc->open_device_map, pi->port_id); 2892245274Snp PORT_LOCK(pi); 2893218792Snp ifp->if_drv_flags |= IFF_DRV_RUNNING; 2894245274Snp PORT_UNLOCK(pi); 2895218792Snp 2896218792Snp callout_reset(&pi->tick, hz, cxgbe_tick, pi); 2897218792Snpdone: 2898218792Snp if (rc != 0) 2899218792Snp cxgbe_uninit_synchronized(pi); 2900218792Snp 2901218792Snp return (rc); 2902218792Snp} 2903218792Snp 2904218792Snp/* 2905218792Snp * Idempotent. 2906218792Snp */ 2907218792Snpstatic int 2908218792Snpcxgbe_uninit_synchronized(struct port_info *pi) 2909218792Snp{ 2910218792Snp struct adapter *sc = pi->adapter; 2911218792Snp struct ifnet *ifp = pi->ifp; 2912218792Snp int rc; 2913218792Snp 2914245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2915218792Snp 2916218792Snp /* 2917228561Snp * Disable the VI so that all its data in either direction is discarded 2918228561Snp * by the MPS. Leave everything else (the queues, interrupts, and 1Hz 2919228561Snp * tick) intact as the TP can deliver negative advice or data that it's 2920228561Snp * holding in its RAM (for an offloaded connection) even after the VI is 2921228561Snp * disabled. 2922218792Snp */ 2923228561Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false); 2924228561Snp if (rc) { 2925228561Snp if_printf(ifp, "disable_vi failed: %d\n", rc); 2926228561Snp return (rc); 2927228561Snp } 2928228561Snp 2929218792Snp clrbit(&sc->open_device_map, pi->port_id); 2930245274Snp PORT_LOCK(pi); 2931228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2932245274Snp PORT_UNLOCK(pi); 2933218792Snp 2934218792Snp pi->link_cfg.link_ok = 0; 2935218792Snp pi->link_cfg.speed = 0; 2936252747Snp pi->linkdnrc = -1; 2937252747Snp t4_os_link_changed(sc, pi->port_id, 0, -1); 2938218792Snp 2939218792Snp return (0); 2940218792Snp} 2941218792Snp 2942240453Snp/* 2943240453Snp * It is ok for this function to fail midway and return right away. t4_detach 2944240453Snp * will walk the entire sc->irq list and clean up whatever is valid. 2945240453Snp */ 2946218792Snpstatic int 2947240453Snpsetup_intr_handlers(struct adapter *sc) 2948218792Snp{ 2949240453Snp int rc, rid, p, q; 2950222510Snp char s[8]; 2951222510Snp struct irq *irq; 2952228561Snp struct port_info *pi; 2953228561Snp struct sge_rxq *rxq; 2954237263Snp#ifdef TCP_OFFLOAD 2955228561Snp struct sge_ofld_rxq *ofld_rxq; 2956228561Snp#endif 2957218792Snp 2958218792Snp /* 2959218792Snp * Setup interrupts. 2960218792Snp */ 2961222510Snp irq = &sc->irq[0]; 2962222510Snp rid = sc->intr_type == INTR_INTX ? 0 : 1; 2963218792Snp if (sc->intr_count == 1) { 2964228561Snp KASSERT(!(sc->flags & INTR_DIRECT), 2965228561Snp ("%s: single interrupt && INTR_DIRECT?", __func__)); 2966222510Snp 2967240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_all, sc, "all"); 2968240453Snp if (rc != 0) 2969240453Snp return (rc); 2970218792Snp } else { 2971228561Snp /* Multiple interrupts. */ 2972228561Snp KASSERT(sc->intr_count >= T4_EXTRA_INTR + sc->params.nports, 2973228561Snp ("%s: too few intr.", __func__)); 2974228561Snp 2975228561Snp /* The first one is always error intr */ 2976240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_err, sc, "err"); 2977240453Snp if (rc != 0) 2978240453Snp return (rc); 2979222510Snp irq++; 2980222510Snp rid++; 2981218792Snp 2982228561Snp /* The second one is always the firmware event queue */ 2983240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_evt, &sc->sge.fwq, 2984240453Snp "evt"); 2985240453Snp if (rc != 0) 2986240453Snp return (rc); 2987228561Snp irq++; 2988228561Snp rid++; 2989222510Snp 2990228561Snp /* 2991228561Snp * Note that if INTR_DIRECT is not set then either the NIC rx 2992228561Snp * queues or (exclusive or) the TOE rx queueus will be taking 2993228561Snp * direct interrupts. 2994228561Snp * 2995228561Snp * There is no need to check for is_offload(sc) as nofldrxq 2996228561Snp * will be 0 if offload is disabled. 2997228561Snp */ 2998228561Snp for_each_port(sc, p) { 2999228561Snp pi = sc->port[p]; 3000222510Snp 3001237263Snp#ifdef TCP_OFFLOAD 3002228561Snp /* 3003228561Snp * Skip over the NIC queues if they aren't taking direct 3004228561Snp * interrupts. 3005228561Snp */ 3006228561Snp if (!(sc->flags & INTR_DIRECT) && 3007228561Snp pi->nofldrxq > pi->nrxq) 3008228561Snp goto ofld_queues; 3009228561Snp#endif 3010228561Snp rxq = &sc->sge.rxq[pi->first_rxq]; 3011228561Snp for (q = 0; q < pi->nrxq; q++, rxq++) { 3012228561Snp snprintf(s, sizeof(s), "%d.%d", p, q); 3013240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, rxq, 3014240453Snp s); 3015240453Snp if (rc != 0) 3016240453Snp return (rc); 3017222510Snp irq++; 3018222510Snp rid++; 3019218792Snp } 3020218792Snp 3021237263Snp#ifdef TCP_OFFLOAD 3022228561Snp /* 3023228561Snp * Skip over the offload queues if they aren't taking 3024228561Snp * direct interrupts. 3025228561Snp */ 3026228561Snp if (!(sc->flags & INTR_DIRECT)) 3027228561Snp continue; 3028228561Snpofld_queues: 3029228561Snp ofld_rxq = &sc->sge.ofld_rxq[pi->first_ofld_rxq]; 3030228561Snp for (q = 0; q < pi->nofldrxq; q++, ofld_rxq++) { 3031228561Snp snprintf(s, sizeof(s), "%d,%d", p, q); 3032240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, 3033240453Snp ofld_rxq, s); 3034240453Snp if (rc != 0) 3035240453Snp return (rc); 3036228561Snp irq++; 3037228561Snp rid++; 3038218792Snp } 3039228561Snp#endif 3040218792Snp } 3041218792Snp } 3042218792Snp 3043240453Snp return (0); 3044240453Snp} 3045240453Snp 3046240453Snpstatic int 3047240453Snpadapter_full_init(struct adapter *sc) 3048240453Snp{ 3049240453Snp int rc, i; 3050240453Snp 3051240453Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 3052240453Snp KASSERT((sc->flags & FULL_INIT_DONE) == 0, 3053240453Snp ("%s: FULL_INIT_DONE already", __func__)); 3054240453Snp 3055240453Snp /* 3056240453Snp * queues that belong to the adapter (not any particular port). 3057240453Snp */ 3058240453Snp rc = t4_setup_adapter_queues(sc); 3059240453Snp if (rc != 0) 3060240453Snp goto done; 3061240453Snp 3062240453Snp for (i = 0; i < nitems(sc->tq); i++) { 3063240453Snp sc->tq[i] = taskqueue_create("t4 taskq", M_NOWAIT, 3064240453Snp taskqueue_thread_enqueue, &sc->tq[i]); 3065240453Snp if (sc->tq[i] == NULL) { 3066240453Snp device_printf(sc->dev, 3067240453Snp "failed to allocate task queue %d\n", i); 3068240453Snp rc = ENOMEM; 3069240453Snp goto done; 3070240453Snp } 3071240453Snp taskqueue_start_threads(&sc->tq[i], 1, PI_NET, "%s tq%d", 3072240453Snp device_get_nameunit(sc->dev), i); 3073240453Snp } 3074240453Snp 3075218792Snp t4_intr_enable(sc); 3076218792Snp sc->flags |= FULL_INIT_DONE; 3077218792Snpdone: 3078218792Snp if (rc != 0) 3079228561Snp adapter_full_uninit(sc); 3080218792Snp 3081218792Snp return (rc); 3082218792Snp} 3083218792Snp 3084218792Snpstatic int 3085228561Snpadapter_full_uninit(struct adapter *sc) 3086218792Snp{ 3087218792Snp int i; 3088218792Snp 3089218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 3090218792Snp 3091220873Snp t4_teardown_adapter_queues(sc); 3092218792Snp 3093240452Snp for (i = 0; i < nitems(sc->tq) && sc->tq[i]; i++) { 3094228561Snp taskqueue_free(sc->tq[i]); 3095228561Snp sc->tq[i] = NULL; 3096228561Snp } 3097228561Snp 3098218792Snp sc->flags &= ~FULL_INIT_DONE; 3099218792Snp 3100218792Snp return (0); 3101218792Snp} 3102218792Snp 3103218792Snpstatic int 3104228561Snpport_full_init(struct port_info *pi) 3105228561Snp{ 3106228561Snp struct adapter *sc = pi->adapter; 3107228561Snp struct ifnet *ifp = pi->ifp; 3108228561Snp uint16_t *rss; 3109228561Snp struct sge_rxq *rxq; 3110228561Snp int rc, i; 3111228561Snp 3112245274Snp ASSERT_SYNCHRONIZED_OP(sc); 3113228561Snp KASSERT((pi->flags & PORT_INIT_DONE) == 0, 3114228561Snp ("%s: PORT_INIT_DONE already", __func__)); 3115228561Snp 3116228561Snp sysctl_ctx_init(&pi->ctx); 3117228561Snp pi->flags |= PORT_SYSCTL_CTX; 3118228561Snp 3119228561Snp /* 3120228561Snp * Allocate tx/rx/fl queues for this port. 3121228561Snp */ 3122228561Snp rc = t4_setup_port_queues(pi); 3123228561Snp if (rc != 0) 3124228561Snp goto done; /* error message displayed already */ 3125228561Snp 3126228561Snp /* 3127228561Snp * Setup RSS for this port. 3128228561Snp */ 3129228561Snp rss = malloc(pi->nrxq * sizeof (*rss), M_CXGBE, 3130228561Snp M_ZERO | M_WAITOK); 3131228561Snp for_each_rxq(pi, i, rxq) { 3132228561Snp rss[i] = rxq->iq.abs_id; 3133228561Snp } 3134228561Snp rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, 3135228561Snp pi->rss_size, rss, pi->nrxq); 3136228561Snp free(rss, M_CXGBE); 3137228561Snp if (rc != 0) { 3138228561Snp if_printf(ifp, "rss_config failed: %d\n", rc); 3139228561Snp goto done; 3140228561Snp } 3141228561Snp 3142228561Snp pi->flags |= PORT_INIT_DONE; 3143228561Snpdone: 3144228561Snp if (rc != 0) 3145228561Snp port_full_uninit(pi); 3146228561Snp 3147228561Snp return (rc); 3148228561Snp} 3149228561Snp 3150228561Snp/* 3151228561Snp * Idempotent. 3152228561Snp */ 3153228561Snpstatic int 3154228561Snpport_full_uninit(struct port_info *pi) 3155228561Snp{ 3156228561Snp struct adapter *sc = pi->adapter; 3157228561Snp int i; 3158228561Snp struct sge_rxq *rxq; 3159228561Snp struct sge_txq *txq; 3160237263Snp#ifdef TCP_OFFLOAD 3161228561Snp struct sge_ofld_rxq *ofld_rxq; 3162228561Snp struct sge_wrq *ofld_txq; 3163228561Snp#endif 3164228561Snp 3165228561Snp if (pi->flags & PORT_INIT_DONE) { 3166228561Snp 3167228561Snp /* Need to quiesce queues. XXX: ctrl queues? */ 3168228561Snp 3169228561Snp for_each_txq(pi, i, txq) { 3170228561Snp quiesce_eq(sc, &txq->eq); 3171228561Snp } 3172228561Snp 3173237263Snp#ifdef TCP_OFFLOAD 3174228561Snp for_each_ofld_txq(pi, i, ofld_txq) { 3175228561Snp quiesce_eq(sc, &ofld_txq->eq); 3176228561Snp } 3177228561Snp#endif 3178228561Snp 3179228561Snp for_each_rxq(pi, i, rxq) { 3180228561Snp quiesce_iq(sc, &rxq->iq); 3181228561Snp quiesce_fl(sc, &rxq->fl); 3182228561Snp } 3183228561Snp 3184237263Snp#ifdef TCP_OFFLOAD 3185228561Snp for_each_ofld_rxq(pi, i, ofld_rxq) { 3186228561Snp quiesce_iq(sc, &ofld_rxq->iq); 3187228561Snp quiesce_fl(sc, &ofld_rxq->fl); 3188228561Snp } 3189228561Snp#endif 3190228561Snp } 3191228561Snp 3192228561Snp t4_teardown_port_queues(pi); 3193228561Snp pi->flags &= ~PORT_INIT_DONE; 3194228561Snp 3195228561Snp return (0); 3196228561Snp} 3197228561Snp 3198228561Snpstatic void 3199228561Snpquiesce_eq(struct adapter *sc, struct sge_eq *eq) 3200228561Snp{ 3201228561Snp EQ_LOCK(eq); 3202228561Snp eq->flags |= EQ_DOOMED; 3203228561Snp 3204228561Snp /* 3205228561Snp * Wait for the response to a credit flush if one's 3206228561Snp * pending. 3207228561Snp */ 3208228561Snp while (eq->flags & EQ_CRFLUSHED) 3209228561Snp mtx_sleep(eq, &eq->eq_lock, 0, "crflush", 0); 3210228561Snp EQ_UNLOCK(eq); 3211228561Snp 3212228561Snp callout_drain(&eq->tx_callout); /* XXX: iffy */ 3213228561Snp pause("callout", 10); /* Still iffy */ 3214228561Snp 3215228561Snp taskqueue_drain(sc->tq[eq->tx_chan], &eq->tx_task); 3216228561Snp} 3217228561Snp 3218228561Snpstatic void 3219228561Snpquiesce_iq(struct adapter *sc, struct sge_iq *iq) 3220228561Snp{ 3221228561Snp (void) sc; /* unused */ 3222228561Snp 3223228561Snp /* Synchronize with the interrupt handler */ 3224228561Snp while (!atomic_cmpset_int(&iq->state, IQS_IDLE, IQS_DISABLED)) 3225228561Snp pause("iqfree", 1); 3226228561Snp} 3227228561Snp 3228228561Snpstatic void 3229228561Snpquiesce_fl(struct adapter *sc, struct sge_fl *fl) 3230228561Snp{ 3231228561Snp mtx_lock(&sc->sfl_lock); 3232228561Snp FL_LOCK(fl); 3233228561Snp fl->flags |= FL_DOOMED; 3234228561Snp FL_UNLOCK(fl); 3235228561Snp mtx_unlock(&sc->sfl_lock); 3236228561Snp 3237228561Snp callout_drain(&sc->sfl_callout); 3238228561Snp KASSERT((fl->flags & FL_STARVING) == 0, 3239228561Snp ("%s: still starving", __func__)); 3240228561Snp} 3241228561Snp 3242228561Snpstatic int 3243218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid, 3244228561Snp driver_intr_t *handler, void *arg, char *name) 3245218792Snp{ 3246218792Snp int rc; 3247218792Snp 3248218792Snp irq->rid = rid; 3249218792Snp irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid, 3250218792Snp RF_SHAREABLE | RF_ACTIVE); 3251218792Snp if (irq->res == NULL) { 3252218792Snp device_printf(sc->dev, 3253218792Snp "failed to allocate IRQ for rid %d, name %s.\n", rid, name); 3254218792Snp return (ENOMEM); 3255218792Snp } 3256218792Snp 3257218792Snp rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET, 3258218792Snp NULL, handler, arg, &irq->tag); 3259218792Snp if (rc != 0) { 3260218792Snp device_printf(sc->dev, 3261218792Snp "failed to setup interrupt for rid %d, name %s: %d\n", 3262218792Snp rid, name, rc); 3263218792Snp } else if (name) 3264218792Snp bus_describe_intr(sc->dev, irq->res, irq->tag, name); 3265218792Snp 3266218792Snp return (rc); 3267218792Snp} 3268218792Snp 3269218792Snpstatic int 3270218792Snpt4_free_irq(struct adapter *sc, struct irq *irq) 3271218792Snp{ 3272218792Snp if (irq->tag) 3273218792Snp bus_teardown_intr(sc->dev, irq->res, irq->tag); 3274218792Snp if (irq->res) 3275218792Snp bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res); 3276218792Snp 3277218792Snp bzero(irq, sizeof(*irq)); 3278218792Snp 3279218792Snp return (0); 3280218792Snp} 3281218792Snp 3282218792Snpstatic void 3283218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start, 3284218792Snp unsigned int end) 3285218792Snp{ 3286218792Snp uint32_t *p = (uint32_t *)(buf + start); 3287218792Snp 3288218792Snp for ( ; start <= end; start += sizeof(uint32_t)) 3289218792Snp *p++ = t4_read_reg(sc, start); 3290218792Snp} 3291218792Snp 3292218792Snpstatic void 3293218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf) 3294218792Snp{ 3295248925Snp int i, n; 3296248925Snp const unsigned int *reg_ranges; 3297248925Snp static const unsigned int t4_reg_ranges[] = { 3298218792Snp 0x1008, 0x1108, 3299218792Snp 0x1180, 0x11b4, 3300218792Snp 0x11fc, 0x123c, 3301218792Snp 0x1300, 0x173c, 3302218792Snp 0x1800, 0x18fc, 3303218792Snp 0x3000, 0x30d8, 3304218792Snp 0x30e0, 0x5924, 3305218792Snp 0x5960, 0x59d4, 3306218792Snp 0x5a00, 0x5af8, 3307218792Snp 0x6000, 0x6098, 3308218792Snp 0x6100, 0x6150, 3309218792Snp 0x6200, 0x6208, 3310218792Snp 0x6240, 0x6248, 3311218792Snp 0x6280, 0x6338, 3312218792Snp 0x6370, 0x638c, 3313218792Snp 0x6400, 0x643c, 3314218792Snp 0x6500, 0x6524, 3315218792Snp 0x6a00, 0x6a38, 3316218792Snp 0x6a60, 0x6a78, 3317218792Snp 0x6b00, 0x6b84, 3318218792Snp 0x6bf0, 0x6c84, 3319218792Snp 0x6cf0, 0x6d84, 3320218792Snp 0x6df0, 0x6e84, 3321218792Snp 0x6ef0, 0x6f84, 3322218792Snp 0x6ff0, 0x7084, 3323218792Snp 0x70f0, 0x7184, 3324218792Snp 0x71f0, 0x7284, 3325218792Snp 0x72f0, 0x7384, 3326218792Snp 0x73f0, 0x7450, 3327218792Snp 0x7500, 0x7530, 3328218792Snp 0x7600, 0x761c, 3329218792Snp 0x7680, 0x76cc, 3330218792Snp 0x7700, 0x7798, 3331218792Snp 0x77c0, 0x77fc, 3332218792Snp 0x7900, 0x79fc, 3333218792Snp 0x7b00, 0x7c38, 3334218792Snp 0x7d00, 0x7efc, 3335218792Snp 0x8dc0, 0x8e1c, 3336218792Snp 0x8e30, 0x8e78, 3337218792Snp 0x8ea0, 0x8f6c, 3338218792Snp 0x8fc0, 0x9074, 3339218792Snp 0x90fc, 0x90fc, 3340218792Snp 0x9400, 0x9458, 3341218792Snp 0x9600, 0x96bc, 3342218792Snp 0x9800, 0x9808, 3343218792Snp 0x9820, 0x983c, 3344218792Snp 0x9850, 0x9864, 3345218792Snp 0x9c00, 0x9c6c, 3346218792Snp 0x9c80, 0x9cec, 3347218792Snp 0x9d00, 0x9d6c, 3348218792Snp 0x9d80, 0x9dec, 3349218792Snp 0x9e00, 0x9e6c, 3350218792Snp 0x9e80, 0x9eec, 3351218792Snp 0x9f00, 0x9f6c, 3352218792Snp 0x9f80, 0x9fec, 3353218792Snp 0xd004, 0xd03c, 3354218792Snp 0xdfc0, 0xdfe0, 3355218792Snp 0xe000, 0xea7c, 3356218792Snp 0xf000, 0x11190, 3357237439Snp 0x19040, 0x1906c, 3358237439Snp 0x19078, 0x19080, 3359237439Snp 0x1908c, 0x19124, 3360218792Snp 0x19150, 0x191b0, 3361218792Snp 0x191d0, 0x191e8, 3362218792Snp 0x19238, 0x1924c, 3363218792Snp 0x193f8, 0x19474, 3364218792Snp 0x19490, 0x194f8, 3365218792Snp 0x19800, 0x19f30, 3366218792Snp 0x1a000, 0x1a06c, 3367218792Snp 0x1a0b0, 0x1a120, 3368218792Snp 0x1a128, 0x1a138, 3369218792Snp 0x1a190, 0x1a1c4, 3370218792Snp 0x1a1fc, 0x1a1fc, 3371218792Snp 0x1e040, 0x1e04c, 3372237439Snp 0x1e284, 0x1e28c, 3373218792Snp 0x1e2c0, 0x1e2c0, 3374218792Snp 0x1e2e0, 0x1e2e0, 3375218792Snp 0x1e300, 0x1e384, 3376218792Snp 0x1e3c0, 0x1e3c8, 3377218792Snp 0x1e440, 0x1e44c, 3378237439Snp 0x1e684, 0x1e68c, 3379218792Snp 0x1e6c0, 0x1e6c0, 3380218792Snp 0x1e6e0, 0x1e6e0, 3381218792Snp 0x1e700, 0x1e784, 3382218792Snp 0x1e7c0, 0x1e7c8, 3383218792Snp 0x1e840, 0x1e84c, 3384237439Snp 0x1ea84, 0x1ea8c, 3385218792Snp 0x1eac0, 0x1eac0, 3386218792Snp 0x1eae0, 0x1eae0, 3387218792Snp 0x1eb00, 0x1eb84, 3388218792Snp 0x1ebc0, 0x1ebc8, 3389218792Snp 0x1ec40, 0x1ec4c, 3390237439Snp 0x1ee84, 0x1ee8c, 3391218792Snp 0x1eec0, 0x1eec0, 3392218792Snp 0x1eee0, 0x1eee0, 3393218792Snp 0x1ef00, 0x1ef84, 3394218792Snp 0x1efc0, 0x1efc8, 3395218792Snp 0x1f040, 0x1f04c, 3396237439Snp 0x1f284, 0x1f28c, 3397218792Snp 0x1f2c0, 0x1f2c0, 3398218792Snp 0x1f2e0, 0x1f2e0, 3399218792Snp 0x1f300, 0x1f384, 3400218792Snp 0x1f3c0, 0x1f3c8, 3401218792Snp 0x1f440, 0x1f44c, 3402237439Snp 0x1f684, 0x1f68c, 3403218792Snp 0x1f6c0, 0x1f6c0, 3404218792Snp 0x1f6e0, 0x1f6e0, 3405218792Snp 0x1f700, 0x1f784, 3406218792Snp 0x1f7c0, 0x1f7c8, 3407218792Snp 0x1f840, 0x1f84c, 3408237439Snp 0x1fa84, 0x1fa8c, 3409218792Snp 0x1fac0, 0x1fac0, 3410218792Snp 0x1fae0, 0x1fae0, 3411218792Snp 0x1fb00, 0x1fb84, 3412218792Snp 0x1fbc0, 0x1fbc8, 3413218792Snp 0x1fc40, 0x1fc4c, 3414237439Snp 0x1fe84, 0x1fe8c, 3415218792Snp 0x1fec0, 0x1fec0, 3416218792Snp 0x1fee0, 0x1fee0, 3417218792Snp 0x1ff00, 0x1ff84, 3418218792Snp 0x1ffc0, 0x1ffc8, 3419218792Snp 0x20000, 0x2002c, 3420218792Snp 0x20100, 0x2013c, 3421218792Snp 0x20190, 0x201c8, 3422218792Snp 0x20200, 0x20318, 3423218792Snp 0x20400, 0x20528, 3424218792Snp 0x20540, 0x20614, 3425218792Snp 0x21000, 0x21040, 3426218792Snp 0x2104c, 0x21060, 3427218792Snp 0x210c0, 0x210ec, 3428218792Snp 0x21200, 0x21268, 3429218792Snp 0x21270, 0x21284, 3430218792Snp 0x212fc, 0x21388, 3431218792Snp 0x21400, 0x21404, 3432218792Snp 0x21500, 0x21518, 3433218792Snp 0x2152c, 0x2153c, 3434218792Snp 0x21550, 0x21554, 3435218792Snp 0x21600, 0x21600, 3436218792Snp 0x21608, 0x21628, 3437218792Snp 0x21630, 0x2163c, 3438218792Snp 0x21700, 0x2171c, 3439218792Snp 0x21780, 0x2178c, 3440218792Snp 0x21800, 0x21c38, 3441218792Snp 0x21c80, 0x21d7c, 3442218792Snp 0x21e00, 0x21e04, 3443218792Snp 0x22000, 0x2202c, 3444218792Snp 0x22100, 0x2213c, 3445218792Snp 0x22190, 0x221c8, 3446218792Snp 0x22200, 0x22318, 3447218792Snp 0x22400, 0x22528, 3448218792Snp 0x22540, 0x22614, 3449218792Snp 0x23000, 0x23040, 3450218792Snp 0x2304c, 0x23060, 3451218792Snp 0x230c0, 0x230ec, 3452218792Snp 0x23200, 0x23268, 3453218792Snp 0x23270, 0x23284, 3454218792Snp 0x232fc, 0x23388, 3455218792Snp 0x23400, 0x23404, 3456218792Snp 0x23500, 0x23518, 3457218792Snp 0x2352c, 0x2353c, 3458218792Snp 0x23550, 0x23554, 3459218792Snp 0x23600, 0x23600, 3460218792Snp 0x23608, 0x23628, 3461218792Snp 0x23630, 0x2363c, 3462218792Snp 0x23700, 0x2371c, 3463218792Snp 0x23780, 0x2378c, 3464218792Snp 0x23800, 0x23c38, 3465218792Snp 0x23c80, 0x23d7c, 3466218792Snp 0x23e00, 0x23e04, 3467218792Snp 0x24000, 0x2402c, 3468218792Snp 0x24100, 0x2413c, 3469218792Snp 0x24190, 0x241c8, 3470218792Snp 0x24200, 0x24318, 3471218792Snp 0x24400, 0x24528, 3472218792Snp 0x24540, 0x24614, 3473218792Snp 0x25000, 0x25040, 3474218792Snp 0x2504c, 0x25060, 3475218792Snp 0x250c0, 0x250ec, 3476218792Snp 0x25200, 0x25268, 3477218792Snp 0x25270, 0x25284, 3478218792Snp 0x252fc, 0x25388, 3479218792Snp 0x25400, 0x25404, 3480218792Snp 0x25500, 0x25518, 3481218792Snp 0x2552c, 0x2553c, 3482218792Snp 0x25550, 0x25554, 3483218792Snp 0x25600, 0x25600, 3484218792Snp 0x25608, 0x25628, 3485218792Snp 0x25630, 0x2563c, 3486218792Snp 0x25700, 0x2571c, 3487218792Snp 0x25780, 0x2578c, 3488218792Snp 0x25800, 0x25c38, 3489218792Snp 0x25c80, 0x25d7c, 3490218792Snp 0x25e00, 0x25e04, 3491218792Snp 0x26000, 0x2602c, 3492218792Snp 0x26100, 0x2613c, 3493218792Snp 0x26190, 0x261c8, 3494218792Snp 0x26200, 0x26318, 3495218792Snp 0x26400, 0x26528, 3496218792Snp 0x26540, 0x26614, 3497218792Snp 0x27000, 0x27040, 3498218792Snp 0x2704c, 0x27060, 3499218792Snp 0x270c0, 0x270ec, 3500218792Snp 0x27200, 0x27268, 3501218792Snp 0x27270, 0x27284, 3502218792Snp 0x272fc, 0x27388, 3503218792Snp 0x27400, 0x27404, 3504218792Snp 0x27500, 0x27518, 3505218792Snp 0x2752c, 0x2753c, 3506218792Snp 0x27550, 0x27554, 3507218792Snp 0x27600, 0x27600, 3508218792Snp 0x27608, 0x27628, 3509218792Snp 0x27630, 0x2763c, 3510218792Snp 0x27700, 0x2771c, 3511218792Snp 0x27780, 0x2778c, 3512218792Snp 0x27800, 0x27c38, 3513218792Snp 0x27c80, 0x27d7c, 3514218792Snp 0x27e00, 0x27e04 3515218792Snp }; 3516248925Snp static const unsigned int t5_reg_ranges[] = { 3517248925Snp 0x1008, 0x1148, 3518248925Snp 0x1180, 0x11b4, 3519248925Snp 0x11fc, 0x123c, 3520248925Snp 0x1280, 0x173c, 3521248925Snp 0x1800, 0x18fc, 3522248925Snp 0x3000, 0x3028, 3523248925Snp 0x3060, 0x30d8, 3524248925Snp 0x30e0, 0x30fc, 3525248925Snp 0x3140, 0x357c, 3526248925Snp 0x35a8, 0x35cc, 3527248925Snp 0x35ec, 0x35ec, 3528248925Snp 0x3600, 0x5624, 3529248925Snp 0x56cc, 0x575c, 3530248925Snp 0x580c, 0x5814, 3531248925Snp 0x5890, 0x58bc, 3532248925Snp 0x5940, 0x59dc, 3533248925Snp 0x59fc, 0x5a18, 3534248925Snp 0x5a60, 0x5a9c, 3535248925Snp 0x5b94, 0x5bfc, 3536248925Snp 0x6000, 0x6040, 3537248925Snp 0x6058, 0x614c, 3538248925Snp 0x7700, 0x7798, 3539248925Snp 0x77c0, 0x78fc, 3540248925Snp 0x7b00, 0x7c54, 3541248925Snp 0x7d00, 0x7efc, 3542248925Snp 0x8dc0, 0x8de0, 3543248925Snp 0x8df8, 0x8e84, 3544248925Snp 0x8ea0, 0x8f84, 3545248925Snp 0x8fc0, 0x90f8, 3546248925Snp 0x9400, 0x9470, 3547248925Snp 0x9600, 0x96f4, 3548248925Snp 0x9800, 0x9808, 3549248925Snp 0x9820, 0x983c, 3550248925Snp 0x9850, 0x9864, 3551248925Snp 0x9c00, 0x9c6c, 3552248925Snp 0x9c80, 0x9cec, 3553248925Snp 0x9d00, 0x9d6c, 3554248925Snp 0x9d80, 0x9dec, 3555248925Snp 0x9e00, 0x9e6c, 3556248925Snp 0x9e80, 0x9eec, 3557248925Snp 0x9f00, 0x9f6c, 3558248925Snp 0x9f80, 0xa020, 3559248925Snp 0xd004, 0xd03c, 3560248925Snp 0xdfc0, 0xdfe0, 3561248925Snp 0xe000, 0x11088, 3562248925Snp 0x1109c, 0x1117c, 3563248925Snp 0x11190, 0x11204, 3564248925Snp 0x19040, 0x1906c, 3565248925Snp 0x19078, 0x19080, 3566248925Snp 0x1908c, 0x19124, 3567248925Snp 0x19150, 0x191b0, 3568248925Snp 0x191d0, 0x191e8, 3569248925Snp 0x19238, 0x19290, 3570248925Snp 0x193f8, 0x19474, 3571248925Snp 0x19490, 0x194cc, 3572248925Snp 0x194f0, 0x194f8, 3573248925Snp 0x19c00, 0x19c60, 3574248925Snp 0x19c94, 0x19e10, 3575248925Snp 0x19e50, 0x19f34, 3576248925Snp 0x19f40, 0x19f50, 3577248925Snp 0x19f90, 0x19fe4, 3578248925Snp 0x1a000, 0x1a06c, 3579248925Snp 0x1a0b0, 0x1a120, 3580248925Snp 0x1a128, 0x1a138, 3581248925Snp 0x1a190, 0x1a1c4, 3582248925Snp 0x1a1fc, 0x1a1fc, 3583248925Snp 0x1e008, 0x1e00c, 3584248925Snp 0x1e040, 0x1e04c, 3585248925Snp 0x1e284, 0x1e290, 3586248925Snp 0x1e2c0, 0x1e2c0, 3587248925Snp 0x1e2e0, 0x1e2e0, 3588248925Snp 0x1e300, 0x1e384, 3589248925Snp 0x1e3c0, 0x1e3c8, 3590248925Snp 0x1e408, 0x1e40c, 3591248925Snp 0x1e440, 0x1e44c, 3592248925Snp 0x1e684, 0x1e690, 3593248925Snp 0x1e6c0, 0x1e6c0, 3594248925Snp 0x1e6e0, 0x1e6e0, 3595248925Snp 0x1e700, 0x1e784, 3596248925Snp 0x1e7c0, 0x1e7c8, 3597248925Snp 0x1e808, 0x1e80c, 3598248925Snp 0x1e840, 0x1e84c, 3599248925Snp 0x1ea84, 0x1ea90, 3600248925Snp 0x1eac0, 0x1eac0, 3601248925Snp 0x1eae0, 0x1eae0, 3602248925Snp 0x1eb00, 0x1eb84, 3603248925Snp 0x1ebc0, 0x1ebc8, 3604248925Snp 0x1ec08, 0x1ec0c, 3605248925Snp 0x1ec40, 0x1ec4c, 3606248925Snp 0x1ee84, 0x1ee90, 3607248925Snp 0x1eec0, 0x1eec0, 3608248925Snp 0x1eee0, 0x1eee0, 3609248925Snp 0x1ef00, 0x1ef84, 3610248925Snp 0x1efc0, 0x1efc8, 3611248925Snp 0x1f008, 0x1f00c, 3612248925Snp 0x1f040, 0x1f04c, 3613248925Snp 0x1f284, 0x1f290, 3614248925Snp 0x1f2c0, 0x1f2c0, 3615248925Snp 0x1f2e0, 0x1f2e0, 3616248925Snp 0x1f300, 0x1f384, 3617248925Snp 0x1f3c0, 0x1f3c8, 3618248925Snp 0x1f408, 0x1f40c, 3619248925Snp 0x1f440, 0x1f44c, 3620248925Snp 0x1f684, 0x1f690, 3621248925Snp 0x1f6c0, 0x1f6c0, 3622248925Snp 0x1f6e0, 0x1f6e0, 3623248925Snp 0x1f700, 0x1f784, 3624248925Snp 0x1f7c0, 0x1f7c8, 3625248925Snp 0x1f808, 0x1f80c, 3626248925Snp 0x1f840, 0x1f84c, 3627248925Snp 0x1fa84, 0x1fa90, 3628248925Snp 0x1fac0, 0x1fac0, 3629248925Snp 0x1fae0, 0x1fae0, 3630248925Snp 0x1fb00, 0x1fb84, 3631248925Snp 0x1fbc0, 0x1fbc8, 3632248925Snp 0x1fc08, 0x1fc0c, 3633248925Snp 0x1fc40, 0x1fc4c, 3634248925Snp 0x1fe84, 0x1fe90, 3635248925Snp 0x1fec0, 0x1fec0, 3636248925Snp 0x1fee0, 0x1fee0, 3637248925Snp 0x1ff00, 0x1ff84, 3638248925Snp 0x1ffc0, 0x1ffc8, 3639252312Snp 0x30000, 0x30030, 3640248925Snp 0x30100, 0x30144, 3641248925Snp 0x30190, 0x301d0, 3642248925Snp 0x30200, 0x30318, 3643248925Snp 0x30400, 0x3052c, 3644248925Snp 0x30540, 0x3061c, 3645248925Snp 0x30800, 0x30834, 3646248925Snp 0x308c0, 0x30908, 3647248925Snp 0x30910, 0x309ac, 3648252312Snp 0x30a00, 0x30a2c, 3649248925Snp 0x30a44, 0x30a50, 3650248925Snp 0x30a74, 0x30c24, 3651252312Snp 0x30d00, 0x30d00, 3652248925Snp 0x30d08, 0x30d14, 3653248925Snp 0x30d1c, 0x30d20, 3654248925Snp 0x30d3c, 0x30d50, 3655248925Snp 0x31200, 0x3120c, 3656248925Snp 0x31220, 0x31220, 3657248925Snp 0x31240, 0x31240, 3658252312Snp 0x31600, 0x3160c, 3659248925Snp 0x31a00, 0x31a1c, 3660252312Snp 0x31e00, 0x31e20, 3661248925Snp 0x31e38, 0x31e3c, 3662248925Snp 0x31e80, 0x31e80, 3663248925Snp 0x31e88, 0x31ea8, 3664248925Snp 0x31eb0, 0x31eb4, 3665248925Snp 0x31ec8, 0x31ed4, 3666248925Snp 0x31fb8, 0x32004, 3667252312Snp 0x32200, 0x32200, 3668252312Snp 0x32208, 0x32240, 3669252312Snp 0x32248, 0x32280, 3670252312Snp 0x32288, 0x322c0, 3671248925Snp 0x322c8, 0x322fc, 3672248925Snp 0x32600, 0x32630, 3673248925Snp 0x32a00, 0x32abc, 3674248925Snp 0x32b00, 0x32b70, 3675248925Snp 0x33000, 0x33048, 3676248925Snp 0x33060, 0x3309c, 3677248925Snp 0x330f0, 0x33148, 3678248925Snp 0x33160, 0x3319c, 3679248925Snp 0x331f0, 0x332e4, 3680248925Snp 0x332f8, 0x333e4, 3681248925Snp 0x333f8, 0x33448, 3682248925Snp 0x33460, 0x3349c, 3683248925Snp 0x334f0, 0x33548, 3684248925Snp 0x33560, 0x3359c, 3685248925Snp 0x335f0, 0x336e4, 3686248925Snp 0x336f8, 0x337e4, 3687248925Snp 0x337f8, 0x337fc, 3688248925Snp 0x33814, 0x33814, 3689248925Snp 0x3382c, 0x3382c, 3690248925Snp 0x33880, 0x3388c, 3691248925Snp 0x338e8, 0x338ec, 3692248925Snp 0x33900, 0x33948, 3693248925Snp 0x33960, 0x3399c, 3694248925Snp 0x339f0, 0x33ae4, 3695248925Snp 0x33af8, 0x33b10, 3696248925Snp 0x33b28, 0x33b28, 3697248925Snp 0x33b3c, 0x33b50, 3698248925Snp 0x33bf0, 0x33c10, 3699248925Snp 0x33c28, 0x33c28, 3700248925Snp 0x33c3c, 0x33c50, 3701248925Snp 0x33cf0, 0x33cfc, 3702252312Snp 0x34000, 0x34030, 3703248925Snp 0x34100, 0x34144, 3704248925Snp 0x34190, 0x341d0, 3705248925Snp 0x34200, 0x34318, 3706248925Snp 0x34400, 0x3452c, 3707248925Snp 0x34540, 0x3461c, 3708248925Snp 0x34800, 0x34834, 3709248925Snp 0x348c0, 0x34908, 3710248925Snp 0x34910, 0x349ac, 3711252312Snp 0x34a00, 0x34a2c, 3712248925Snp 0x34a44, 0x34a50, 3713248925Snp 0x34a74, 0x34c24, 3714252312Snp 0x34d00, 0x34d00, 3715248925Snp 0x34d08, 0x34d14, 3716248925Snp 0x34d1c, 0x34d20, 3717248925Snp 0x34d3c, 0x34d50, 3718248925Snp 0x35200, 0x3520c, 3719248925Snp 0x35220, 0x35220, 3720248925Snp 0x35240, 0x35240, 3721252312Snp 0x35600, 0x3560c, 3722248925Snp 0x35a00, 0x35a1c, 3723252312Snp 0x35e00, 0x35e20, 3724248925Snp 0x35e38, 0x35e3c, 3725248925Snp 0x35e80, 0x35e80, 3726248925Snp 0x35e88, 0x35ea8, 3727248925Snp 0x35eb0, 0x35eb4, 3728248925Snp 0x35ec8, 0x35ed4, 3729248925Snp 0x35fb8, 0x36004, 3730252312Snp 0x36200, 0x36200, 3731252312Snp 0x36208, 0x36240, 3732252312Snp 0x36248, 0x36280, 3733252312Snp 0x36288, 0x362c0, 3734248925Snp 0x362c8, 0x362fc, 3735248925Snp 0x36600, 0x36630, 3736248925Snp 0x36a00, 0x36abc, 3737248925Snp 0x36b00, 0x36b70, 3738248925Snp 0x37000, 0x37048, 3739248925Snp 0x37060, 0x3709c, 3740248925Snp 0x370f0, 0x37148, 3741248925Snp 0x37160, 0x3719c, 3742248925Snp 0x371f0, 0x372e4, 3743248925Snp 0x372f8, 0x373e4, 3744248925Snp 0x373f8, 0x37448, 3745248925Snp 0x37460, 0x3749c, 3746248925Snp 0x374f0, 0x37548, 3747248925Snp 0x37560, 0x3759c, 3748248925Snp 0x375f0, 0x376e4, 3749248925Snp 0x376f8, 0x377e4, 3750248925Snp 0x377f8, 0x377fc, 3751248925Snp 0x37814, 0x37814, 3752248925Snp 0x3782c, 0x3782c, 3753248925Snp 0x37880, 0x3788c, 3754248925Snp 0x378e8, 0x378ec, 3755248925Snp 0x37900, 0x37948, 3756248925Snp 0x37960, 0x3799c, 3757248925Snp 0x379f0, 0x37ae4, 3758248925Snp 0x37af8, 0x37b10, 3759248925Snp 0x37b28, 0x37b28, 3760248925Snp 0x37b3c, 0x37b50, 3761248925Snp 0x37bf0, 0x37c10, 3762248925Snp 0x37c28, 0x37c28, 3763248925Snp 0x37c3c, 0x37c50, 3764248925Snp 0x37cf0, 0x37cfc, 3765252312Snp 0x38000, 0x38030, 3766248925Snp 0x38100, 0x38144, 3767248925Snp 0x38190, 0x381d0, 3768248925Snp 0x38200, 0x38318, 3769248925Snp 0x38400, 0x3852c, 3770248925Snp 0x38540, 0x3861c, 3771248925Snp 0x38800, 0x38834, 3772248925Snp 0x388c0, 0x38908, 3773248925Snp 0x38910, 0x389ac, 3774252312Snp 0x38a00, 0x38a2c, 3775248925Snp 0x38a44, 0x38a50, 3776248925Snp 0x38a74, 0x38c24, 3777252312Snp 0x38d00, 0x38d00, 3778248925Snp 0x38d08, 0x38d14, 3779248925Snp 0x38d1c, 0x38d20, 3780248925Snp 0x38d3c, 0x38d50, 3781248925Snp 0x39200, 0x3920c, 3782248925Snp 0x39220, 0x39220, 3783248925Snp 0x39240, 0x39240, 3784252312Snp 0x39600, 0x3960c, 3785248925Snp 0x39a00, 0x39a1c, 3786252312Snp 0x39e00, 0x39e20, 3787248925Snp 0x39e38, 0x39e3c, 3788248925Snp 0x39e80, 0x39e80, 3789248925Snp 0x39e88, 0x39ea8, 3790248925Snp 0x39eb0, 0x39eb4, 3791248925Snp 0x39ec8, 0x39ed4, 3792248925Snp 0x39fb8, 0x3a004, 3793252312Snp 0x3a200, 0x3a200, 3794252312Snp 0x3a208, 0x3a240, 3795252312Snp 0x3a248, 0x3a280, 3796252312Snp 0x3a288, 0x3a2c0, 3797248925Snp 0x3a2c8, 0x3a2fc, 3798248925Snp 0x3a600, 0x3a630, 3799248925Snp 0x3aa00, 0x3aabc, 3800248925Snp 0x3ab00, 0x3ab70, 3801248925Snp 0x3b000, 0x3b048, 3802248925Snp 0x3b060, 0x3b09c, 3803248925Snp 0x3b0f0, 0x3b148, 3804248925Snp 0x3b160, 0x3b19c, 3805248925Snp 0x3b1f0, 0x3b2e4, 3806248925Snp 0x3b2f8, 0x3b3e4, 3807248925Snp 0x3b3f8, 0x3b448, 3808248925Snp 0x3b460, 0x3b49c, 3809248925Snp 0x3b4f0, 0x3b548, 3810248925Snp 0x3b560, 0x3b59c, 3811248925Snp 0x3b5f0, 0x3b6e4, 3812248925Snp 0x3b6f8, 0x3b7e4, 3813248925Snp 0x3b7f8, 0x3b7fc, 3814248925Snp 0x3b814, 0x3b814, 3815248925Snp 0x3b82c, 0x3b82c, 3816248925Snp 0x3b880, 0x3b88c, 3817248925Snp 0x3b8e8, 0x3b8ec, 3818248925Snp 0x3b900, 0x3b948, 3819248925Snp 0x3b960, 0x3b99c, 3820248925Snp 0x3b9f0, 0x3bae4, 3821248925Snp 0x3baf8, 0x3bb10, 3822248925Snp 0x3bb28, 0x3bb28, 3823248925Snp 0x3bb3c, 0x3bb50, 3824248925Snp 0x3bbf0, 0x3bc10, 3825248925Snp 0x3bc28, 0x3bc28, 3826248925Snp 0x3bc3c, 0x3bc50, 3827248925Snp 0x3bcf0, 0x3bcfc, 3828252312Snp 0x3c000, 0x3c030, 3829248925Snp 0x3c100, 0x3c144, 3830248925Snp 0x3c190, 0x3c1d0, 3831248925Snp 0x3c200, 0x3c318, 3832248925Snp 0x3c400, 0x3c52c, 3833248925Snp 0x3c540, 0x3c61c, 3834248925Snp 0x3c800, 0x3c834, 3835248925Snp 0x3c8c0, 0x3c908, 3836248925Snp 0x3c910, 0x3c9ac, 3837252312Snp 0x3ca00, 0x3ca2c, 3838248925Snp 0x3ca44, 0x3ca50, 3839248925Snp 0x3ca74, 0x3cc24, 3840252312Snp 0x3cd00, 0x3cd00, 3841248925Snp 0x3cd08, 0x3cd14, 3842248925Snp 0x3cd1c, 0x3cd20, 3843248925Snp 0x3cd3c, 0x3cd50, 3844248925Snp 0x3d200, 0x3d20c, 3845248925Snp 0x3d220, 0x3d220, 3846248925Snp 0x3d240, 0x3d240, 3847252312Snp 0x3d600, 0x3d60c, 3848248925Snp 0x3da00, 0x3da1c, 3849252312Snp 0x3de00, 0x3de20, 3850248925Snp 0x3de38, 0x3de3c, 3851248925Snp 0x3de80, 0x3de80, 3852248925Snp 0x3de88, 0x3dea8, 3853248925Snp 0x3deb0, 0x3deb4, 3854248925Snp 0x3dec8, 0x3ded4, 3855248925Snp 0x3dfb8, 0x3e004, 3856252312Snp 0x3e200, 0x3e200, 3857252312Snp 0x3e208, 0x3e240, 3858252312Snp 0x3e248, 0x3e280, 3859252312Snp 0x3e288, 0x3e2c0, 3860248925Snp 0x3e2c8, 0x3e2fc, 3861248925Snp 0x3e600, 0x3e630, 3862248925Snp 0x3ea00, 0x3eabc, 3863248925Snp 0x3eb00, 0x3eb70, 3864248925Snp 0x3f000, 0x3f048, 3865248925Snp 0x3f060, 0x3f09c, 3866248925Snp 0x3f0f0, 0x3f148, 3867248925Snp 0x3f160, 0x3f19c, 3868248925Snp 0x3f1f0, 0x3f2e4, 3869248925Snp 0x3f2f8, 0x3f3e4, 3870248925Snp 0x3f3f8, 0x3f448, 3871248925Snp 0x3f460, 0x3f49c, 3872248925Snp 0x3f4f0, 0x3f548, 3873248925Snp 0x3f560, 0x3f59c, 3874248925Snp 0x3f5f0, 0x3f6e4, 3875248925Snp 0x3f6f8, 0x3f7e4, 3876248925Snp 0x3f7f8, 0x3f7fc, 3877248925Snp 0x3f814, 0x3f814, 3878248925Snp 0x3f82c, 0x3f82c, 3879248925Snp 0x3f880, 0x3f88c, 3880248925Snp 0x3f8e8, 0x3f8ec, 3881248925Snp 0x3f900, 0x3f948, 3882248925Snp 0x3f960, 0x3f99c, 3883248925Snp 0x3f9f0, 0x3fae4, 3884248925Snp 0x3faf8, 0x3fb10, 3885248925Snp 0x3fb28, 0x3fb28, 3886248925Snp 0x3fb3c, 0x3fb50, 3887248925Snp 0x3fbf0, 0x3fc10, 3888248925Snp 0x3fc28, 0x3fc28, 3889248925Snp 0x3fc3c, 0x3fc50, 3890248925Snp 0x3fcf0, 0x3fcfc, 3891248925Snp 0x40000, 0x4000c, 3892248925Snp 0x40040, 0x40068, 3893248925Snp 0x4007c, 0x40144, 3894248925Snp 0x40180, 0x4018c, 3895248925Snp 0x40200, 0x40298, 3896248925Snp 0x402ac, 0x4033c, 3897248925Snp 0x403f8, 0x403fc, 3898252312Snp 0x41304, 0x413c4, 3899248925Snp 0x41400, 0x4141c, 3900248925Snp 0x41480, 0x414d0, 3901248925Snp 0x44000, 0x44078, 3902248925Snp 0x440c0, 0x44278, 3903248925Snp 0x442c0, 0x44478, 3904248925Snp 0x444c0, 0x44678, 3905248925Snp 0x446c0, 0x44878, 3906248925Snp 0x448c0, 0x449fc, 3907248925Snp 0x45000, 0x45068, 3908248925Snp 0x45080, 0x45084, 3909248925Snp 0x450a0, 0x450b0, 3910248925Snp 0x45200, 0x45268, 3911248925Snp 0x45280, 0x45284, 3912248925Snp 0x452a0, 0x452b0, 3913248925Snp 0x460c0, 0x460e4, 3914248925Snp 0x47000, 0x4708c, 3915248925Snp 0x47200, 0x47250, 3916248925Snp 0x47400, 0x47420, 3917248925Snp 0x47600, 0x47618, 3918248925Snp 0x47800, 0x47814, 3919248925Snp 0x48000, 0x4800c, 3920248925Snp 0x48040, 0x48068, 3921248925Snp 0x4807c, 0x48144, 3922248925Snp 0x48180, 0x4818c, 3923248925Snp 0x48200, 0x48298, 3924248925Snp 0x482ac, 0x4833c, 3925248925Snp 0x483f8, 0x483fc, 3926252312Snp 0x49304, 0x493c4, 3927248925Snp 0x49400, 0x4941c, 3928248925Snp 0x49480, 0x494d0, 3929248925Snp 0x4c000, 0x4c078, 3930248925Snp 0x4c0c0, 0x4c278, 3931248925Snp 0x4c2c0, 0x4c478, 3932248925Snp 0x4c4c0, 0x4c678, 3933248925Snp 0x4c6c0, 0x4c878, 3934248925Snp 0x4c8c0, 0x4c9fc, 3935248925Snp 0x4d000, 0x4d068, 3936248925Snp 0x4d080, 0x4d084, 3937248925Snp 0x4d0a0, 0x4d0b0, 3938248925Snp 0x4d200, 0x4d268, 3939248925Snp 0x4d280, 0x4d284, 3940248925Snp 0x4d2a0, 0x4d2b0, 3941248925Snp 0x4e0c0, 0x4e0e4, 3942248925Snp 0x4f000, 0x4f08c, 3943248925Snp 0x4f200, 0x4f250, 3944248925Snp 0x4f400, 0x4f420, 3945248925Snp 0x4f600, 0x4f618, 3946248925Snp 0x4f800, 0x4f814, 3947248925Snp 0x50000, 0x500cc, 3948248925Snp 0x50400, 0x50400, 3949248925Snp 0x50800, 0x508cc, 3950248925Snp 0x50c00, 0x50c00, 3951248925Snp 0x51000, 0x5101c, 3952248925Snp 0x51300, 0x51308, 3953248925Snp }; 3954218792Snp 3955248925Snp if (is_t4(sc)) { 3956248925Snp reg_ranges = &t4_reg_ranges[0]; 3957248925Snp n = nitems(t4_reg_ranges); 3958248925Snp } else { 3959248925Snp reg_ranges = &t5_reg_ranges[0]; 3960248925Snp n = nitems(t5_reg_ranges); 3961248925Snp } 3962248925Snp 3963248925Snp regs->version = chip_id(sc) | chip_rev(sc) << 10; 3964248925Snp for (i = 0; i < n; i += 2) 3965218792Snp reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]); 3966218792Snp} 3967218792Snp 3968218792Snpstatic void 3969218792Snpcxgbe_tick(void *arg) 3970218792Snp{ 3971218792Snp struct port_info *pi = arg; 3972218792Snp struct ifnet *ifp = pi->ifp; 3973218792Snp struct sge_txq *txq; 3974218792Snp int i, drops; 3975218792Snp struct port_stats *s = &pi->stats; 3976218792Snp 3977218792Snp PORT_LOCK(pi); 3978218792Snp if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 3979218792Snp PORT_UNLOCK(pi); 3980218792Snp return; /* without scheduling another callout */ 3981218792Snp } 3982218792Snp 3983218792Snp t4_get_port_stats(pi->adapter, pi->tx_chan, s); 3984218792Snp 3985228561Snp ifp->if_opackets = s->tx_frames - s->tx_pause; 3986228561Snp ifp->if_ipackets = s->rx_frames - s->rx_pause; 3987228561Snp ifp->if_obytes = s->tx_octets - s->tx_pause * 64; 3988228561Snp ifp->if_ibytes = s->rx_octets - s->rx_pause * 64; 3989228561Snp ifp->if_omcasts = s->tx_mcast_frames - s->tx_pause; 3990228561Snp ifp->if_imcasts = s->rx_mcast_frames - s->rx_pause; 3991218792Snp ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 + 3992239259Snp s->rx_ovflow3 + s->rx_trunc0 + s->rx_trunc1 + s->rx_trunc2 + 3993239259Snp s->rx_trunc3; 3994218792Snp 3995218792Snp drops = s->tx_drop; 3996218792Snp for_each_txq(pi, i, txq) 3997220873Snp drops += txq->br->br_drops; 3998218792Snp ifp->if_snd.ifq_drops = drops; 3999218792Snp 4000218792Snp ifp->if_oerrors = s->tx_error_frames; 4001218792Snp ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long + 4002218792Snp s->rx_fcs_err + s->rx_len_err; 4003218792Snp 4004218792Snp callout_schedule(&pi->tick, hz); 4005218792Snp PORT_UNLOCK(pi); 4006218792Snp} 4007218792Snp 4008237263Snpstatic void 4009237263Snpcxgbe_vlan_config(void *arg, struct ifnet *ifp, uint16_t vid) 4010237263Snp{ 4011237263Snp struct ifnet *vlan; 4012237263Snp 4013241494Snp if (arg != ifp || ifp->if_type != IFT_ETHER) 4014237263Snp return; 4015237263Snp 4016237263Snp vlan = VLAN_DEVAT(ifp, vid); 4017237263Snp VLAN_SETCOOKIE(vlan, ifp); 4018237263Snp} 4019237263Snp 4020218792Snpstatic int 4021228561Snpcpl_not_handled(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 4022228561Snp{ 4023237263Snp 4024228561Snp#ifdef INVARIANTS 4025237263Snp panic("%s: opcode 0x%02x on iq %p with payload %p", 4026228561Snp __func__, rss->opcode, iq, m); 4027228561Snp#else 4028239336Snp log(LOG_ERR, "%s: opcode 0x%02x on iq %p with payload %p\n", 4029228561Snp __func__, rss->opcode, iq, m); 4030228561Snp m_freem(m); 4031228561Snp#endif 4032228561Snp return (EDOOFUS); 4033228561Snp} 4034228561Snp 4035228561Snpint 4036228561Snpt4_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h) 4037228561Snp{ 4038228561Snp uintptr_t *loc, new; 4039228561Snp 4040240452Snp if (opcode >= nitems(sc->cpl_handler)) 4041228561Snp return (EINVAL); 4042228561Snp 4043228561Snp new = h ? (uintptr_t)h : (uintptr_t)cpl_not_handled; 4044228561Snp loc = (uintptr_t *) &sc->cpl_handler[opcode]; 4045228561Snp atomic_store_rel_ptr(loc, new); 4046228561Snp 4047228561Snp return (0); 4048228561Snp} 4049228561Snp 4050228561Snpstatic int 4051237263Snpan_not_handled(struct sge_iq *iq, const struct rsp_ctrl *ctrl) 4052237263Snp{ 4053237263Snp 4054237263Snp#ifdef INVARIANTS 4055237263Snp panic("%s: async notification on iq %p (ctrl %p)", __func__, iq, ctrl); 4056237263Snp#else 4057239336Snp log(LOG_ERR, "%s: async notification on iq %p (ctrl %p)\n", 4058237263Snp __func__, iq, ctrl); 4059237263Snp#endif 4060237263Snp return (EDOOFUS); 4061237263Snp} 4062237263Snp 4063237263Snpint 4064237263Snpt4_register_an_handler(struct adapter *sc, an_handler_t h) 4065237263Snp{ 4066237263Snp uintptr_t *loc, new; 4067237263Snp 4068237263Snp new = h ? (uintptr_t)h : (uintptr_t)an_not_handled; 4069237263Snp loc = (uintptr_t *) &sc->an_handler; 4070237263Snp atomic_store_rel_ptr(loc, new); 4071237263Snp 4072237263Snp return (0); 4073237263Snp} 4074237263Snp 4075237263Snpstatic int 4076239336Snpfw_msg_not_handled(struct adapter *sc, const __be64 *rpl) 4077239336Snp{ 4078241733Sed const struct cpl_fw6_msg *cpl = 4079241733Sed __containerof(rpl, struct cpl_fw6_msg, data[0]); 4080239336Snp 4081239336Snp#ifdef INVARIANTS 4082239336Snp panic("%s: fw_msg type %d", __func__, cpl->type); 4083239336Snp#else 4084239336Snp log(LOG_ERR, "%s: fw_msg type %d\n", __func__, cpl->type); 4085239336Snp#endif 4086239336Snp return (EDOOFUS); 4087239336Snp} 4088239336Snp 4089239336Snpint 4090239336Snpt4_register_fw_msg_handler(struct adapter *sc, int type, fw_msg_handler_t h) 4091239336Snp{ 4092239336Snp uintptr_t *loc, new; 4093239336Snp 4094240452Snp if (type >= nitems(sc->fw_msg_handler)) 4095239336Snp return (EINVAL); 4096239336Snp 4097247291Snp /* 4098247291Snp * These are dispatched by the handler for FW{4|6}_CPL_MSG using the CPL 4099247291Snp * handler dispatch table. Reject any attempt to install a handler for 4100247291Snp * this subtype. 4101247291Snp */ 4102247291Snp if (type == FW_TYPE_RSSCPL || type == FW6_TYPE_RSSCPL) 4103247291Snp return (EINVAL); 4104247291Snp 4105239336Snp new = h ? (uintptr_t)h : (uintptr_t)fw_msg_not_handled; 4106239336Snp loc = (uintptr_t *) &sc->fw_msg_handler[type]; 4107239336Snp atomic_store_rel_ptr(loc, new); 4108239336Snp 4109239336Snp return (0); 4110239336Snp} 4111239336Snp 4112239336Snpstatic int 4113218792Snpt4_sysctls(struct adapter *sc) 4114218792Snp{ 4115218792Snp struct sysctl_ctx_list *ctx; 4116218792Snp struct sysctl_oid *oid; 4117228561Snp struct sysctl_oid_list *children, *c0; 4118228561Snp static char *caps[] = { 4119228561Snp "\20\1PPP\2QFC\3DCBX", /* caps[0] linkcaps */ 4120228561Snp "\20\1NIC\2VM\3IDS\4UM\5UM_ISGL", /* caps[1] niccaps */ 4121228561Snp "\20\1TOE", /* caps[2] toecaps */ 4122228561Snp "\20\1RDDP\2RDMAC", /* caps[3] rdmacaps */ 4123228561Snp "\20\1INITIATOR_PDU\2TARGET_PDU" /* caps[4] iscsicaps */ 4124228561Snp "\3INITIATOR_CNXOFLD\4TARGET_CNXOFLD" 4125228561Snp "\5INITIATOR_SSNOFLD\6TARGET_SSNOFLD", 4126228561Snp "\20\1INITIATOR\2TARGET\3CTRL_OFLD" /* caps[5] fcoecaps */ 4127228561Snp }; 4128249392Snp static char *doorbells = {"\20\1UDB\2WCWR\3UDBWC\4KDB"}; 4129218792Snp 4130218792Snp ctx = device_get_sysctl_ctx(sc->dev); 4131228561Snp 4132228561Snp /* 4133228561Snp * dev.t4nex.X. 4134228561Snp */ 4135218792Snp oid = device_get_sysctl_tree(sc->dev); 4136228561Snp c0 = children = SYSCTL_CHILDREN(oid); 4137218792Snp 4138248925Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, NULL, 4139248925Snp sc->params.nports, "# of ports"); 4140218792Snp 4141218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD, 4142248925Snp NULL, chip_rev(sc), "chip hardware revision"); 4143218792Snp 4144218792Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 4145218792Snp CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 4146218792Snp 4147228561Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "cf", 4148245936Snp CTLFLAG_RD, &sc->cfg_file, 0, "configuration file"); 4149218792Snp 4150248925Snp SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cfcsum", CTLFLAG_RD, NULL, 4151248925Snp sc->cfcsum, "config file checksum"); 4152228561Snp 4153248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "doorbells", 4154248925Snp CTLTYPE_STRING | CTLFLAG_RD, doorbells, sc->doorbells, 4155248925Snp sysctl_bitfield, "A", "available doorbells"); 4156248925Snp 4157228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkcaps", 4158228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[0], sc->linkcaps, 4159228561Snp sysctl_bitfield, "A", "available link capabilities"); 4160228561Snp 4161228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "niccaps", 4162228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[1], sc->niccaps, 4163228561Snp sysctl_bitfield, "A", "available NIC capabilities"); 4164228561Snp 4165228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "toecaps", 4166228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[2], sc->toecaps, 4167228561Snp sysctl_bitfield, "A", "available TCP offload capabilities"); 4168228561Snp 4169228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdmacaps", 4170228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[3], sc->rdmacaps, 4171228561Snp sysctl_bitfield, "A", "available RDMA capabilities"); 4172228561Snp 4173228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "iscsicaps", 4174228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[4], sc->iscsicaps, 4175228561Snp sysctl_bitfield, "A", "available iSCSI capabilities"); 4176228561Snp 4177228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoecaps", 4178228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[5], sc->fcoecaps, 4179228561Snp sysctl_bitfield, "A", "available FCoE capabilities"); 4180228561Snp 4181248925Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, NULL, 4182248925Snp sc->params.vpd.cclk, "core clock frequency (in KHz)"); 4183218792Snp 4184219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers", 4185228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.timer_val, 4186228561Snp sizeof(sc->sge.timer_val), sysctl_int_array, "A", 4187228561Snp "interrupt holdoff timer values (us)"); 4188218792Snp 4189219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts", 4190228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.counter_val, 4191228561Snp sizeof(sc->sge.counter_val), sysctl_int_array, "A", 4192228561Snp "interrupt holdoff packet counter values"); 4193218792Snp 4194252469Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nfilters", CTLFLAG_RD, 4195252469Snp NULL, sc->tids.nftids, "number of filters"); 4196252469Snp 4197231115Snp#ifdef SBUF_DRAIN 4198228561Snp /* 4199228561Snp * dev.t4nex.X.misc. Marked CTLFLAG_SKIP to avoid information overload. 4200228561Snp */ 4201228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "misc", 4202228561Snp CTLFLAG_RD | CTLFLAG_SKIP, NULL, 4203228561Snp "logs and miscellaneous information"); 4204228561Snp children = SYSCTL_CHILDREN(oid); 4205228561Snp 4206228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cctrl", 4207228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4208228561Snp sysctl_cctrl, "A", "congestion control"); 4209228561Snp 4210247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp0", 4211247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4212247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 0 (TP0)"); 4213247122Snp 4214247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp1", 4215247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 1, 4216247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 1 (TP1)"); 4217247122Snp 4218247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ulp", 4219247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 2, 4220247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 2 (ULP)"); 4221247122Snp 4222247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge0", 4223247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 3, 4224247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 3 (SGE0)"); 4225247122Snp 4226247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge1", 4227247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 4, 4228247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 4 (SGE1)"); 4229247122Snp 4230247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ncsi", 4231247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 5, 4232247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 5 (NCSI)"); 4233247122Snp 4234247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_la", 4235247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4236247122Snp sysctl_cim_la, "A", "CIM logic analyzer"); 4237247122Snp 4238251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ma_la", 4239251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4240251213Snp sysctl_cim_ma_la, "A", "CIM MA logic analyzer"); 4241251213Snp 4242247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp0", 4243247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0 + CIM_NUM_IBQ, 4244247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 0 (ULP0)"); 4245247122Snp 4246247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp1", 4247247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 1 + CIM_NUM_IBQ, 4248247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 1 (ULP1)"); 4249247122Snp 4250247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp2", 4251247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 2 + CIM_NUM_IBQ, 4252247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 2 (ULP2)"); 4253247122Snp 4254247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp3", 4255247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 3 + CIM_NUM_IBQ, 4256247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 3 (ULP3)"); 4257247122Snp 4258247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge", 4259247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 4 + CIM_NUM_IBQ, 4260247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 4 (SGE)"); 4261247122Snp 4262247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ncsi", 4263247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 5 + CIM_NUM_IBQ, 4264247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 5 (NCSI)"); 4265247122Snp 4266248925Snp if (is_t5(sc)) { 4267248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge0_rx", 4268248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 6 + CIM_NUM_IBQ, 4269248925Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 6 (SGE0-RX)"); 4270248925Snp 4271248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge1_rx", 4272248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 7 + CIM_NUM_IBQ, 4273248925Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 7 (SGE1-RX)"); 4274248925Snp } 4275248925Snp 4276251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_pif_la", 4277251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4278251213Snp sysctl_cim_pif_la, "A", "CIM PIF logic analyzer"); 4279251213Snp 4280247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_qcfg", 4281247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4282247122Snp sysctl_cim_qcfg, "A", "CIM queue configuration"); 4283247122Snp 4284228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats", 4285228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4286228561Snp sysctl_cpl_stats, "A", "CPL statistics"); 4287228561Snp 4288228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ddp_stats", 4289228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4290228561Snp sysctl_ddp_stats, "A", "DDP statistics"); 4291228561Snp 4292222551Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog", 4293222551Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4294228561Snp sysctl_devlog, "A", "firmware's device log"); 4295222551Snp 4296228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoe_stats", 4297228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4298228561Snp sysctl_fcoe_stats, "A", "FCoE statistics"); 4299228561Snp 4300228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hw_sched", 4301228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4302228561Snp sysctl_hw_sched, "A", "hardware scheduler "); 4303228561Snp 4304228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "l2t", 4305228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4306228561Snp sysctl_l2t, "A", "hardware L2 table"); 4307228561Snp 4308228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats", 4309228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4310228561Snp sysctl_lb_stats, "A", "loopback statistics"); 4311228561Snp 4312228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "meminfo", 4313228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4314228561Snp sysctl_meminfo, "A", "memory regions"); 4315228561Snp 4316251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "mps_tcam", 4317251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4318251213Snp sysctl_mps_tcam, "A", "MPS TCAM entries"); 4319251213Snp 4320228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "path_mtus", 4321228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4322228561Snp sysctl_path_mtus, "A", "path MTUs"); 4323228561Snp 4324228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pm_stats", 4325228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4326228561Snp sysctl_pm_stats, "A", "PM statistics"); 4327228561Snp 4328228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_stats", 4329228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4330228561Snp sysctl_rdma_stats, "A", "RDMA statistics"); 4331228561Snp 4332228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tcp_stats", 4333228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4334228561Snp sysctl_tcp_stats, "A", "TCP statistics"); 4335228561Snp 4336228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tids", 4337228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4338228561Snp sysctl_tids, "A", "TID information"); 4339228561Snp 4340228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_err_stats", 4341228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4342228561Snp sysctl_tp_err_stats, "A", "TP error statistics"); 4343228561Snp 4344251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_la", 4345251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4346251213Snp sysctl_tp_la, "A", "TP logic analyzer"); 4347251213Snp 4348228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_rate", 4349228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4350228561Snp sysctl_tx_rate, "A", "Tx rate"); 4351248925Snp 4352251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ulprx_la", 4353251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4354251213Snp sysctl_ulprx_la, "A", "ULPRX logic analyzer"); 4355251213Snp 4356248925Snp if (is_t5(sc)) { 4357249392Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "wcwr_stats", 4358248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4359249392Snp sysctl_wcwr_stats, "A", "write combined work requests"); 4360248925Snp } 4361231115Snp#endif 4362228561Snp 4363237263Snp#ifdef TCP_OFFLOAD 4364228561Snp if (is_offload(sc)) { 4365228561Snp /* 4366228561Snp * dev.t4nex.X.toe. 4367228561Snp */ 4368228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "toe", CTLFLAG_RD, 4369228561Snp NULL, "TOE parameters"); 4370228561Snp children = SYSCTL_CHILDREN(oid); 4371228561Snp 4372228561Snp sc->tt.sndbuf = 256 * 1024; 4373228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "sndbuf", CTLFLAG_RW, 4374228561Snp &sc->tt.sndbuf, 0, "max hardware send buffer size"); 4375228561Snp 4376228561Snp sc->tt.ddp = 0; 4377228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp", CTLFLAG_RW, 4378228561Snp &sc->tt.ddp, 0, "DDP allowed"); 4379239341Snp 4380239341Snp sc->tt.indsz = G_INDICATESIZE(t4_read_reg(sc, A_TP_PARA_REG5)); 4381228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "indsz", CTLFLAG_RW, 4382228561Snp &sc->tt.indsz, 0, "DDP max indicate size allowed"); 4383239341Snp 4384239341Snp sc->tt.ddp_thres = 4385239341Snp G_RXCOALESCESIZE(t4_read_reg(sc, A_TP_PARA_REG2)); 4386228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp_thres", CTLFLAG_RW, 4387228561Snp &sc->tt.ddp_thres, 0, "DDP threshold"); 4388252728Snp 4389252728Snp sc->tt.rx_coalesce = 1; 4390252728Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_coalesce", 4391252728Snp CTLFLAG_RW, &sc->tt.rx_coalesce, 0, "receive coalescing"); 4392228561Snp } 4393228561Snp#endif 4394228561Snp 4395228561Snp 4396218792Snp return (0); 4397218792Snp} 4398218792Snp 4399218792Snpstatic int 4400218792Snpcxgbe_sysctls(struct port_info *pi) 4401218792Snp{ 4402218792Snp struct sysctl_ctx_list *ctx; 4403218792Snp struct sysctl_oid *oid; 4404218792Snp struct sysctl_oid_list *children; 4405218792Snp 4406218792Snp ctx = device_get_sysctl_ctx(pi->dev); 4407218792Snp 4408218792Snp /* 4409218792Snp * dev.cxgbe.X. 4410218792Snp */ 4411218792Snp oid = device_get_sysctl_tree(pi->dev); 4412218792Snp children = SYSCTL_CHILDREN(oid); 4413218792Snp 4414252747Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "linkdnrc", CTLFLAG_RD, 4415252747Snp &pi->linkdnrc, 0, "reason why link is down"); 4416252747Snp if (pi->port_type == FW_PORT_TYPE_BT_XAUI) { 4417252747Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "temperature", 4418252747Snp CTLTYPE_INT | CTLFLAG_RD, pi, 0, sysctl_btphy, "I", 4419252747Snp "PHY temperature (in Celsius)"); 4420252747Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fw_version", 4421252747Snp CTLTYPE_INT | CTLFLAG_RD, pi, 1, sysctl_btphy, "I", 4422252747Snp "PHY firmware version"); 4423252747Snp } 4424218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD, 4425218792Snp &pi->nrxq, 0, "# of rx queues"); 4426218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD, 4427218792Snp &pi->ntxq, 0, "# of tx queues"); 4428218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD, 4429218792Snp &pi->first_rxq, 0, "index of first rx queue"); 4430218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD, 4431218792Snp &pi->first_txq, 0, "index of first tx queue"); 4432218792Snp 4433237263Snp#ifdef TCP_OFFLOAD 4434228561Snp if (is_offload(pi->adapter)) { 4435228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldrxq", CTLFLAG_RD, 4436228561Snp &pi->nofldrxq, 0, 4437228561Snp "# of rx queues for offloaded TCP connections"); 4438228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldtxq", CTLFLAG_RD, 4439228561Snp &pi->nofldtxq, 0, 4440228561Snp "# of tx queues for offloaded TCP connections"); 4441228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_rxq", 4442228561Snp CTLFLAG_RD, &pi->first_ofld_rxq, 0, 4443228561Snp "index of first TOE rx queue"); 4444228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_txq", 4445228561Snp CTLFLAG_RD, &pi->first_ofld_txq, 0, 4446228561Snp "index of first TOE tx queue"); 4447228561Snp } 4448228561Snp#endif 4449228561Snp 4450218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx", 4451218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I", 4452218792Snp "holdoff timer index"); 4453218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx", 4454218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I", 4455218792Snp "holdoff packet counter index"); 4456218792Snp 4457218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq", 4458218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I", 4459218792Snp "rx queue size"); 4460218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq", 4461218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I", 4462218792Snp "tx queue size"); 4463218792Snp 4464218792Snp /* 4465218792Snp * dev.cxgbe.X.stats. 4466218792Snp */ 4467218792Snp oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, 4468218792Snp NULL, "port statistics"); 4469218792Snp children = SYSCTL_CHILDREN(oid); 4470218792Snp 4471218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \ 4472218792Snp SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \ 4473218792Snp CTLTYPE_U64 | CTLFLAG_RD, pi->adapter, reg, \ 4474218792Snp sysctl_handle_t4_reg64, "QU", desc) 4475218792Snp 4476218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames", 4477218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L)); 4478218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames", 4479218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L)); 4480218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames", 4481218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L)); 4482218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames", 4483218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L)); 4484218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames", 4485218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L)); 4486218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames", 4487218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L)); 4488218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_64", 4489218792Snp "# of tx frames in this range", 4490218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L)); 4491218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127", 4492218792Snp "# of tx frames in this range", 4493218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L)); 4494218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255", 4495218792Snp "# of tx frames in this range", 4496218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L)); 4497218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511", 4498218792Snp "# of tx frames in this range", 4499218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L)); 4500218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023", 4501218792Snp "# of tx frames in this range", 4502218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L)); 4503218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518", 4504218792Snp "# of tx frames in this range", 4505218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L)); 4506218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max", 4507218792Snp "# of tx frames in this range", 4508218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L)); 4509218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames", 4510218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L)); 4511218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted", 4512218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L)); 4513218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted", 4514218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L)); 4515218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted", 4516218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L)); 4517218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted", 4518218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L)); 4519218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted", 4520218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L)); 4521218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted", 4522218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L)); 4523218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted", 4524218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L)); 4525218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted", 4526218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L)); 4527218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted", 4528218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L)); 4529218792Snp 4530218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames", 4531218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L)); 4532218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames", 4533218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L)); 4534218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames", 4535218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L)); 4536218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames", 4537218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L)); 4538218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames", 4539218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L)); 4540218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU", 4541218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L)); 4542218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames", 4543218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L)); 4544218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err", 4545218792Snp "# of frames received with bad FCS", 4546218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L)); 4547218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_len_err", 4548218792Snp "# of frames received with length error", 4549218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L)); 4550218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors", 4551218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L)); 4552218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received", 4553218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L)); 4554218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_64", 4555218792Snp "# of rx frames in this range", 4556218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L)); 4557218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127", 4558218792Snp "# of rx frames in this range", 4559218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L)); 4560218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255", 4561218792Snp "# of rx frames in this range", 4562218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L)); 4563218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511", 4564218792Snp "# of rx frames in this range", 4565218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L)); 4566218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023", 4567218792Snp "# of rx frames in this range", 4568218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L)); 4569218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518", 4570218792Snp "# of rx frames in this range", 4571218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L)); 4572218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max", 4573218792Snp "# of rx frames in this range", 4574218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L)); 4575218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received", 4576218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L)); 4577218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received", 4578218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L)); 4579218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received", 4580218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L)); 4581218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received", 4582218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L)); 4583218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received", 4584218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L)); 4585218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received", 4586218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L)); 4587218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received", 4588218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L)); 4589218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received", 4590218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L)); 4591218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received", 4592218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L)); 4593218792Snp 4594218792Snp#undef SYSCTL_ADD_T4_REG64 4595218792Snp 4596218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \ 4597218792Snp SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \ 4598218792Snp &pi->stats.name, desc) 4599218792Snp 4600218792Snp /* We get these from port_stats and they may be stale by upto 1s */ 4601218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0, 4602218792Snp "# drops due to buffer-group 0 overflows"); 4603218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1, 4604218792Snp "# drops due to buffer-group 1 overflows"); 4605218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2, 4606218792Snp "# drops due to buffer-group 2 overflows"); 4607218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3, 4608218792Snp "# drops due to buffer-group 3 overflows"); 4609218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc0, 4610218792Snp "# of buffer-group 0 truncated packets"); 4611218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc1, 4612218792Snp "# of buffer-group 1 truncated packets"); 4613218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc2, 4614218792Snp "# of buffer-group 2 truncated packets"); 4615218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc3, 4616218792Snp "# of buffer-group 3 truncated packets"); 4617218792Snp 4618218792Snp#undef SYSCTL_ADD_T4_PORTSTAT 4619218792Snp 4620218792Snp return (0); 4621218792Snp} 4622218792Snp 4623218792Snpstatic int 4624219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS) 4625219436Snp{ 4626219436Snp int rc, *i; 4627219436Snp struct sbuf sb; 4628219436Snp 4629219436Snp sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); 4630219436Snp for (i = arg1; arg2; arg2 -= sizeof(int), i++) 4631219436Snp sbuf_printf(&sb, "%d ", *i); 4632219436Snp sbuf_trim(&sb); 4633219436Snp sbuf_finish(&sb); 4634219436Snp rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 4635219436Snp sbuf_delete(&sb); 4636219436Snp return (rc); 4637219436Snp} 4638219436Snp 4639219436Snpstatic int 4640228561Snpsysctl_bitfield(SYSCTL_HANDLER_ARGS) 4641228561Snp{ 4642228561Snp int rc; 4643228561Snp struct sbuf *sb; 4644228561Snp 4645228561Snp rc = sysctl_wire_old_buffer(req, 0); 4646228561Snp if (rc != 0) 4647228561Snp return(rc); 4648228561Snp 4649228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 4650228561Snp if (sb == NULL) 4651228561Snp return (ENOMEM); 4652228561Snp 4653228561Snp sbuf_printf(sb, "%b", (int)arg2, (char *)arg1); 4654228561Snp rc = sbuf_finish(sb); 4655228561Snp sbuf_delete(sb); 4656228561Snp 4657228561Snp return (rc); 4658228561Snp} 4659228561Snp 4660228561Snpstatic int 4661252747Snpsysctl_btphy(SYSCTL_HANDLER_ARGS) 4662252747Snp{ 4663252747Snp struct port_info *pi = arg1; 4664252747Snp int op = arg2; 4665252747Snp struct adapter *sc = pi->adapter; 4666252747Snp u_int v; 4667252747Snp int rc; 4668252747Snp 4669252747Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4btt"); 4670252747Snp if (rc) 4671252747Snp return (rc); 4672252747Snp /* XXX: magic numbers */ 4673252747Snp rc = -t4_mdio_rd(sc, sc->mbox, pi->mdio_addr, 0x1e, op ? 0x20 : 0xc820, 4674252747Snp &v); 4675252747Snp end_synchronized_op(sc, 0); 4676252747Snp if (rc) 4677252747Snp return (rc); 4678252747Snp if (op == 0) 4679252747Snp v /= 256; 4680252747Snp 4681252747Snp rc = sysctl_handle_int(oidp, &v, 0, req); 4682252747Snp return (rc); 4683252747Snp} 4684252747Snp 4685252747Snpstatic int 4686218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS) 4687218792Snp{ 4688218792Snp struct port_info *pi = arg1; 4689218792Snp struct adapter *sc = pi->adapter; 4690218792Snp int idx, rc, i; 4691245274Snp struct sge_rxq *rxq; 4692252724Snp#ifdef TCP_OFFLOAD 4693252724Snp struct sge_ofld_rxq *ofld_rxq; 4694252724Snp#endif 4695245274Snp uint8_t v; 4696218792Snp 4697218792Snp idx = pi->tmr_idx; 4698218792Snp 4699218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 4700218792Snp if (rc != 0 || req->newptr == NULL) 4701218792Snp return (rc); 4702218792Snp 4703218792Snp if (idx < 0 || idx >= SGE_NTIMERS) 4704218792Snp return (EINVAL); 4705218792Snp 4706245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4707245274Snp "t4tmr"); 4708245274Snp if (rc) 4709245274Snp return (rc); 4710228561Snp 4711245274Snp v = V_QINTR_TIMER_IDX(idx) | V_QINTR_CNT_EN(pi->pktc_idx != -1); 4712245274Snp for_each_rxq(pi, i, rxq) { 4713228561Snp#ifdef atomic_store_rel_8 4714245274Snp atomic_store_rel_8(&rxq->iq.intr_params, v); 4715228561Snp#else 4716245274Snp rxq->iq.intr_params = v; 4717228561Snp#endif 4718218792Snp } 4719252724Snp#ifdef TCP_OFFLOAD 4720252724Snp for_each_ofld_rxq(pi, i, ofld_rxq) { 4721252724Snp#ifdef atomic_store_rel_8 4722252724Snp atomic_store_rel_8(&ofld_rxq->iq.intr_params, v); 4723252724Snp#else 4724252724Snp ofld_rxq->iq.intr_params = v; 4725252724Snp#endif 4726252724Snp } 4727252724Snp#endif 4728245274Snp pi->tmr_idx = idx; 4729218792Snp 4730245274Snp end_synchronized_op(sc, LOCK_HELD); 4731245274Snp return (0); 4732218792Snp} 4733218792Snp 4734218792Snpstatic int 4735218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS) 4736218792Snp{ 4737218792Snp struct port_info *pi = arg1; 4738218792Snp struct adapter *sc = pi->adapter; 4739218792Snp int idx, rc; 4740218792Snp 4741218792Snp idx = pi->pktc_idx; 4742218792Snp 4743218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 4744218792Snp if (rc != 0 || req->newptr == NULL) 4745218792Snp return (rc); 4746218792Snp 4747218792Snp if (idx < -1 || idx >= SGE_NCOUNTERS) 4748218792Snp return (EINVAL); 4749218792Snp 4750245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4751245274Snp "t4pktc"); 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->pktc_idx = idx; 4759218792Snp 4760245274Snp end_synchronized_op(sc, LOCK_HELD); 4761218792Snp return (rc); 4762218792Snp} 4763218792Snp 4764218792Snpstatic int 4765218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS) 4766218792Snp{ 4767218792Snp struct port_info *pi = arg1; 4768218792Snp struct adapter *sc = pi->adapter; 4769218792Snp int qsize, rc; 4770218792Snp 4771218792Snp qsize = pi->qsize_rxq; 4772218792Snp 4773218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 4774218792Snp if (rc != 0 || req->newptr == NULL) 4775218792Snp return (rc); 4776218792Snp 4777218792Snp if (qsize < 128 || (qsize & 7)) 4778218792Snp return (EINVAL); 4779218792Snp 4780245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4781245274Snp "t4rxqs"); 4782245274Snp if (rc) 4783245274Snp return (rc); 4784245274Snp 4785245274Snp if (pi->flags & PORT_INIT_DONE) 4786228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 4787245274Snp else 4788218792Snp pi->qsize_rxq = qsize; 4789218792Snp 4790245274Snp end_synchronized_op(sc, LOCK_HELD); 4791218792Snp return (rc); 4792218792Snp} 4793218792Snp 4794218792Snpstatic int 4795218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS) 4796218792Snp{ 4797218792Snp struct port_info *pi = arg1; 4798218792Snp struct adapter *sc = pi->adapter; 4799218792Snp int qsize, rc; 4800218792Snp 4801218792Snp qsize = pi->qsize_txq; 4802218792Snp 4803218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 4804218792Snp if (rc != 0 || req->newptr == NULL) 4805218792Snp return (rc); 4806218792Snp 4807245274Snp /* bufring size must be powerof2 */ 4808245274Snp if (qsize < 128 || !powerof2(qsize)) 4809218792Snp return (EINVAL); 4810218792Snp 4811245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4812245274Snp "t4txqs"); 4813245274Snp if (rc) 4814245274Snp return (rc); 4815245274Snp 4816245274Snp if (pi->flags & PORT_INIT_DONE) 4817228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 4818245274Snp else 4819218792Snp pi->qsize_txq = qsize; 4820218792Snp 4821245274Snp end_synchronized_op(sc, LOCK_HELD); 4822218792Snp return (rc); 4823218792Snp} 4824218792Snp 4825218792Snpstatic int 4826218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS) 4827218792Snp{ 4828218792Snp struct adapter *sc = arg1; 4829218792Snp int reg = arg2; 4830218792Snp uint64_t val; 4831218792Snp 4832218792Snp val = t4_read_reg64(sc, reg); 4833218792Snp 4834218792Snp return (sysctl_handle_64(oidp, &val, 0, req)); 4835218792Snp} 4836218792Snp 4837231115Snp#ifdef SBUF_DRAIN 4838228561Snpstatic int 4839228561Snpsysctl_cctrl(SYSCTL_HANDLER_ARGS) 4840228561Snp{ 4841228561Snp struct adapter *sc = arg1; 4842228561Snp struct sbuf *sb; 4843228561Snp int rc, i; 4844228561Snp uint16_t incr[NMTUS][NCCTRL_WIN]; 4845228561Snp static const char *dec_fac[] = { 4846228561Snp "0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875", 4847228561Snp "0.9375" 4848228561Snp }; 4849228561Snp 4850228561Snp rc = sysctl_wire_old_buffer(req, 0); 4851228561Snp if (rc != 0) 4852228561Snp return (rc); 4853228561Snp 4854228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 4855228561Snp if (sb == NULL) 4856228561Snp return (ENOMEM); 4857228561Snp 4858228561Snp t4_read_cong_tbl(sc, incr); 4859228561Snp 4860228561Snp for (i = 0; i < NCCTRL_WIN; ++i) { 4861228561Snp sbuf_printf(sb, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i, 4862228561Snp incr[0][i], incr[1][i], incr[2][i], incr[3][i], incr[4][i], 4863228561Snp incr[5][i], incr[6][i], incr[7][i]); 4864228561Snp sbuf_printf(sb, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n", 4865228561Snp incr[8][i], incr[9][i], incr[10][i], incr[11][i], 4866228561Snp incr[12][i], incr[13][i], incr[14][i], incr[15][i], 4867228561Snp sc->params.a_wnd[i], dec_fac[sc->params.b_wnd[i]]); 4868228561Snp } 4869228561Snp 4870228561Snp rc = sbuf_finish(sb); 4871228561Snp sbuf_delete(sb); 4872228561Snp 4873228561Snp return (rc); 4874228561Snp} 4875228561Snp 4876248925Snpstatic const char *qname[CIM_NUM_IBQ + CIM_NUM_OBQ_T5] = { 4877247122Snp "TP0", "TP1", "ULP", "SGE0", "SGE1", "NC-SI", /* ibq's */ 4878248925Snp "ULP0", "ULP1", "ULP2", "ULP3", "SGE", "NC-SI", /* obq's */ 4879248925Snp "SGE0-RX", "SGE1-RX" /* additional obq's (T5 onwards) */ 4880247122Snp}; 4881247122Snp 4882228561Snpstatic int 4883247122Snpsysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS) 4884247122Snp{ 4885247122Snp struct adapter *sc = arg1; 4886247122Snp struct sbuf *sb; 4887247122Snp int rc, i, n, qid = arg2; 4888247122Snp uint32_t *buf, *p; 4889247122Snp char *qtype; 4890248925Snp u_int cim_num_obq = is_t4(sc) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5; 4891247122Snp 4892248925Snp KASSERT(qid >= 0 && qid < CIM_NUM_IBQ + cim_num_obq, 4893247122Snp ("%s: bad qid %d\n", __func__, qid)); 4894247122Snp 4895247122Snp if (qid < CIM_NUM_IBQ) { 4896247122Snp /* inbound queue */ 4897247122Snp qtype = "IBQ"; 4898247122Snp n = 4 * CIM_IBQ_SIZE; 4899247122Snp buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); 4900247122Snp rc = t4_read_cim_ibq(sc, qid, buf, n); 4901247122Snp } else { 4902247122Snp /* outbound queue */ 4903247122Snp qtype = "OBQ"; 4904247122Snp qid -= CIM_NUM_IBQ; 4905248925Snp n = 4 * cim_num_obq * CIM_OBQ_SIZE; 4906247122Snp buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); 4907247122Snp rc = t4_read_cim_obq(sc, qid, buf, n); 4908247122Snp } 4909247122Snp 4910247122Snp if (rc < 0) { 4911247122Snp rc = -rc; 4912247122Snp goto done; 4913247122Snp } 4914247122Snp n = rc * sizeof(uint32_t); /* rc has # of words actually read */ 4915247122Snp 4916247122Snp rc = sysctl_wire_old_buffer(req, 0); 4917247122Snp if (rc != 0) 4918247122Snp goto done; 4919247122Snp 4920248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req); 4921247122Snp if (sb == NULL) { 4922247122Snp rc = ENOMEM; 4923247122Snp goto done; 4924247122Snp } 4925247122Snp 4926247122Snp sbuf_printf(sb, "%s%d %s", qtype , qid, qname[arg2]); 4927247122Snp for (i = 0, p = buf; i < n; i += 16, p += 4) 4928247122Snp sbuf_printf(sb, "\n%#06x: %08x %08x %08x %08x", i, p[0], p[1], 4929247122Snp p[2], p[3]); 4930247122Snp 4931247122Snp rc = sbuf_finish(sb); 4932247122Snp sbuf_delete(sb); 4933247122Snpdone: 4934247122Snp free(buf, M_CXGBE); 4935247122Snp return (rc); 4936247122Snp} 4937247122Snp 4938247122Snpstatic int 4939247122Snpsysctl_cim_la(SYSCTL_HANDLER_ARGS) 4940247122Snp{ 4941247122Snp struct adapter *sc = arg1; 4942247122Snp u_int cfg; 4943247122Snp struct sbuf *sb; 4944247122Snp uint32_t *buf, *p; 4945247122Snp int rc; 4946247122Snp 4947247122Snp rc = -t4_cim_read(sc, A_UP_UP_DBG_LA_CFG, 1, &cfg); 4948247122Snp if (rc != 0) 4949247122Snp return (rc); 4950247122Snp 4951247122Snp rc = sysctl_wire_old_buffer(req, 0); 4952247122Snp if (rc != 0) 4953247122Snp return (rc); 4954247122Snp 4955247122Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 4956247122Snp if (sb == NULL) 4957247122Snp return (ENOMEM); 4958247122Snp 4959247122Snp buf = malloc(sc->params.cim_la_size * sizeof(uint32_t), M_CXGBE, 4960247122Snp M_ZERO | M_WAITOK); 4961247122Snp 4962247122Snp rc = -t4_cim_read_la(sc, buf, NULL); 4963247122Snp if (rc != 0) 4964247122Snp goto done; 4965247122Snp 4966247122Snp sbuf_printf(sb, "Status Data PC%s", 4967247122Snp cfg & F_UPDBGLACAPTPCONLY ? "" : 4968247122Snp " LS0Stat LS0Addr LS0Data"); 4969247122Snp 4970247122Snp KASSERT((sc->params.cim_la_size & 7) == 0, 4971247122Snp ("%s: p will walk off the end of buf", __func__)); 4972247122Snp 4973247122Snp for (p = buf; p < &buf[sc->params.cim_la_size]; p += 8) { 4974247122Snp if (cfg & F_UPDBGLACAPTPCONLY) { 4975247122Snp sbuf_printf(sb, "\n %02x %08x %08x", p[5] & 0xff, 4976247122Snp p[6], p[7]); 4977247122Snp sbuf_printf(sb, "\n %02x %02x%06x %02x%06x", 4978247122Snp (p[3] >> 8) & 0xff, p[3] & 0xff, p[4] >> 8, 4979247122Snp p[4] & 0xff, p[5] >> 8); 4980247122Snp sbuf_printf(sb, "\n %02x %x%07x %x%07x", 4981247122Snp (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, 4982247122Snp p[1] & 0xf, p[2] >> 4); 4983247122Snp } else { 4984247122Snp sbuf_printf(sb, 4985247122Snp "\n %02x %x%07x %x%07x %08x %08x " 4986247122Snp "%08x%08x%08x%08x", 4987247122Snp (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, 4988247122Snp p[1] & 0xf, p[2] >> 4, p[2] & 0xf, p[3], p[4], p[5], 4989247122Snp p[6], p[7]); 4990247122Snp } 4991247122Snp } 4992247122Snp 4993247122Snp rc = sbuf_finish(sb); 4994247122Snp sbuf_delete(sb); 4995247122Snpdone: 4996247122Snp free(buf, M_CXGBE); 4997247122Snp return (rc); 4998247122Snp} 4999247122Snp 5000247122Snpstatic int 5001251213Snpsysctl_cim_ma_la(SYSCTL_HANDLER_ARGS) 5002251213Snp{ 5003251213Snp struct adapter *sc = arg1; 5004251213Snp u_int i; 5005251213Snp struct sbuf *sb; 5006251213Snp uint32_t *buf, *p; 5007251213Snp int rc; 5008251213Snp 5009251213Snp rc = sysctl_wire_old_buffer(req, 0); 5010251213Snp if (rc != 0) 5011251213Snp return (rc); 5012251213Snp 5013251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5014251213Snp if (sb == NULL) 5015251213Snp return (ENOMEM); 5016251213Snp 5017251213Snp buf = malloc(2 * CIM_MALA_SIZE * 5 * sizeof(uint32_t), M_CXGBE, 5018251213Snp M_ZERO | M_WAITOK); 5019251213Snp 5020251213Snp t4_cim_read_ma_la(sc, buf, buf + 5 * CIM_MALA_SIZE); 5021251213Snp p = buf; 5022251213Snp 5023251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) { 5024251213Snp sbuf_printf(sb, "\n%02x%08x%08x%08x%08x", p[4], p[3], p[2], 5025251213Snp p[1], p[0]); 5026251213Snp } 5027251213Snp 5028251213Snp sbuf_printf(sb, "\n\nCnt ID Tag UE Data RDY VLD"); 5029251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) { 5030251213Snp sbuf_printf(sb, "\n%3u %2u %x %u %08x%08x %u %u", 5031251213Snp (p[2] >> 10) & 0xff, (p[2] >> 7) & 7, 5032251213Snp (p[2] >> 3) & 0xf, (p[2] >> 2) & 1, 5033251213Snp (p[1] >> 2) | ((p[2] & 3) << 30), 5034251213Snp (p[0] >> 2) | ((p[1] & 3) << 30), (p[0] >> 1) & 1, 5035251213Snp p[0] & 1); 5036251213Snp } 5037251213Snp 5038251213Snp rc = sbuf_finish(sb); 5039251213Snp sbuf_delete(sb); 5040251213Snp free(buf, M_CXGBE); 5041251213Snp return (rc); 5042251213Snp} 5043251213Snp 5044251213Snpstatic int 5045251213Snpsysctl_cim_pif_la(SYSCTL_HANDLER_ARGS) 5046251213Snp{ 5047251213Snp struct adapter *sc = arg1; 5048251213Snp u_int i; 5049251213Snp struct sbuf *sb; 5050251213Snp uint32_t *buf, *p; 5051251213Snp int rc; 5052251213Snp 5053251213Snp rc = sysctl_wire_old_buffer(req, 0); 5054251213Snp if (rc != 0) 5055251213Snp return (rc); 5056251213Snp 5057251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5058251213Snp if (sb == NULL) 5059251213Snp return (ENOMEM); 5060251213Snp 5061251213Snp buf = malloc(2 * CIM_PIFLA_SIZE * 6 * sizeof(uint32_t), M_CXGBE, 5062251213Snp M_ZERO | M_WAITOK); 5063251213Snp 5064251213Snp t4_cim_read_pif_la(sc, buf, buf + 6 * CIM_PIFLA_SIZE, NULL, NULL); 5065251213Snp p = buf; 5066251213Snp 5067251213Snp sbuf_printf(sb, "Cntl ID DataBE Addr Data"); 5068251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 6) { 5069251213Snp sbuf_printf(sb, "\n %02x %02x %04x %08x %08x%08x%08x%08x", 5070251213Snp (p[5] >> 22) & 0xff, (p[5] >> 16) & 0x3f, p[5] & 0xffff, 5071251213Snp p[4], p[3], p[2], p[1], p[0]); 5072251213Snp } 5073251213Snp 5074251213Snp sbuf_printf(sb, "\n\nCntl ID Data"); 5075251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 6) { 5076251213Snp sbuf_printf(sb, "\n %02x %02x %08x%08x%08x%08x", 5077251213Snp (p[4] >> 6) & 0xff, p[4] & 0x3f, p[3], p[2], p[1], p[0]); 5078251213Snp } 5079251213Snp 5080251213Snp rc = sbuf_finish(sb); 5081251213Snp sbuf_delete(sb); 5082251213Snp free(buf, M_CXGBE); 5083251213Snp return (rc); 5084251213Snp} 5085251213Snp 5086251213Snpstatic int 5087247122Snpsysctl_cim_qcfg(SYSCTL_HANDLER_ARGS) 5088247122Snp{ 5089247122Snp struct adapter *sc = arg1; 5090247122Snp struct sbuf *sb; 5091247122Snp int rc, i; 5092248925Snp uint16_t base[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; 5093248925Snp uint16_t size[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; 5094247122Snp uint16_t thres[CIM_NUM_IBQ]; 5095248925Snp uint32_t obq_wr[2 * CIM_NUM_OBQ_T5], *wr = obq_wr; 5096248925Snp uint32_t stat[4 * (CIM_NUM_IBQ + CIM_NUM_OBQ_T5)], *p = stat; 5097248925Snp u_int cim_num_obq, ibq_rdaddr, obq_rdaddr, nq; 5098247122Snp 5099248925Snp if (is_t4(sc)) { 5100248925Snp cim_num_obq = CIM_NUM_OBQ; 5101248925Snp ibq_rdaddr = A_UP_IBQ_0_RDADDR; 5102248925Snp obq_rdaddr = A_UP_OBQ_0_REALADDR; 5103248925Snp } else { 5104248925Snp cim_num_obq = CIM_NUM_OBQ_T5; 5105248925Snp ibq_rdaddr = A_UP_IBQ_0_SHADOW_RDADDR; 5106248925Snp obq_rdaddr = A_UP_OBQ_0_SHADOW_REALADDR; 5107248925Snp } 5108248925Snp nq = CIM_NUM_IBQ + cim_num_obq; 5109248925Snp 5110248925Snp rc = -t4_cim_read(sc, ibq_rdaddr, 4 * nq, stat); 5111247122Snp if (rc == 0) 5112248925Snp rc = -t4_cim_read(sc, obq_rdaddr, 2 * cim_num_obq, obq_wr); 5113247122Snp if (rc != 0) 5114247122Snp return (rc); 5115247122Snp 5116247122Snp t4_read_cimq_cfg(sc, base, size, thres); 5117247122Snp 5118247122Snp rc = sysctl_wire_old_buffer(req, 0); 5119247122Snp if (rc != 0) 5120247122Snp return (rc); 5121247122Snp 5122248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req); 5123247122Snp if (sb == NULL) 5124247122Snp return (ENOMEM); 5125247122Snp 5126247122Snp sbuf_printf(sb, "Queue Base Size Thres RdPtr WrPtr SOP EOP Avail"); 5127247122Snp 5128247122Snp for (i = 0; i < CIM_NUM_IBQ; i++, p += 4) 5129248925Snp sbuf_printf(sb, "\n%7s %5x %5u %5u %6x %4x %4u %4u %5u", 5130247122Snp qname[i], base[i], size[i], thres[i], G_IBQRDADDR(p[0]), 5131247122Snp G_IBQWRADDR(p[1]), G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), 5132247122Snp G_QUEREMFLITS(p[2]) * 16); 5133248925Snp for ( ; i < nq; i++, p += 4, wr += 2) 5134248925Snp sbuf_printf(sb, "\n%7s %5x %5u %12x %4x %4u %4u %5u", qname[i], 5135247122Snp base[i], size[i], G_QUERDADDR(p[0]) & 0x3fff, 5136247122Snp wr[0] - base[i], G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), 5137247122Snp G_QUEREMFLITS(p[2]) * 16); 5138247122Snp 5139247122Snp rc = sbuf_finish(sb); 5140247122Snp sbuf_delete(sb); 5141247122Snp 5142247122Snp return (rc); 5143247122Snp} 5144247122Snp 5145247122Snpstatic int 5146228561Snpsysctl_cpl_stats(SYSCTL_HANDLER_ARGS) 5147228561Snp{ 5148228561Snp struct adapter *sc = arg1; 5149228561Snp struct sbuf *sb; 5150228561Snp int rc; 5151228561Snp struct tp_cpl_stats stats; 5152228561Snp 5153228561Snp rc = sysctl_wire_old_buffer(req, 0); 5154228561Snp if (rc != 0) 5155228561Snp return (rc); 5156228561Snp 5157228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5158228561Snp if (sb == NULL) 5159228561Snp return (ENOMEM); 5160228561Snp 5161228561Snp t4_tp_get_cpl_stats(sc, &stats); 5162228561Snp 5163228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 5164228561Snp "channel 3\n"); 5165228561Snp sbuf_printf(sb, "CPL requests: %10u %10u %10u %10u\n", 5166228561Snp stats.req[0], stats.req[1], stats.req[2], stats.req[3]); 5167228561Snp sbuf_printf(sb, "CPL responses: %10u %10u %10u %10u", 5168228561Snp stats.rsp[0], stats.rsp[1], stats.rsp[2], stats.rsp[3]); 5169228561Snp 5170228561Snp rc = sbuf_finish(sb); 5171228561Snp sbuf_delete(sb); 5172228561Snp 5173228561Snp return (rc); 5174228561Snp} 5175228561Snp 5176228561Snpstatic int 5177228561Snpsysctl_ddp_stats(SYSCTL_HANDLER_ARGS) 5178228561Snp{ 5179228561Snp struct adapter *sc = arg1; 5180228561Snp struct sbuf *sb; 5181228561Snp int rc; 5182228561Snp struct tp_usm_stats stats; 5183228561Snp 5184228561Snp rc = sysctl_wire_old_buffer(req, 0); 5185228561Snp if (rc != 0) 5186228561Snp return(rc); 5187228561Snp 5188228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5189228561Snp if (sb == NULL) 5190228561Snp return (ENOMEM); 5191228561Snp 5192228561Snp t4_get_usm_stats(sc, &stats); 5193228561Snp 5194228561Snp sbuf_printf(sb, "Frames: %u\n", stats.frames); 5195228561Snp sbuf_printf(sb, "Octets: %ju\n", stats.octets); 5196228561Snp sbuf_printf(sb, "Drops: %u", stats.drops); 5197228561Snp 5198228561Snp rc = sbuf_finish(sb); 5199228561Snp sbuf_delete(sb); 5200228561Snp 5201228561Snp return (rc); 5202228561Snp} 5203228561Snp 5204222551Snpconst char *devlog_level_strings[] = { 5205222551Snp [FW_DEVLOG_LEVEL_EMERG] = "EMERG", 5206222551Snp [FW_DEVLOG_LEVEL_CRIT] = "CRIT", 5207222551Snp [FW_DEVLOG_LEVEL_ERR] = "ERR", 5208222551Snp [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", 5209222551Snp [FW_DEVLOG_LEVEL_INFO] = "INFO", 5210222551Snp [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" 5211222551Snp}; 5212222551Snp 5213222551Snpconst char *devlog_facility_strings[] = { 5214222551Snp [FW_DEVLOG_FACILITY_CORE] = "CORE", 5215222551Snp [FW_DEVLOG_FACILITY_SCHED] = "SCHED", 5216222551Snp [FW_DEVLOG_FACILITY_TIMER] = "TIMER", 5217222551Snp [FW_DEVLOG_FACILITY_RES] = "RES", 5218222551Snp [FW_DEVLOG_FACILITY_HW] = "HW", 5219222551Snp [FW_DEVLOG_FACILITY_FLR] = "FLR", 5220222551Snp [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", 5221222551Snp [FW_DEVLOG_FACILITY_PHY] = "PHY", 5222222551Snp [FW_DEVLOG_FACILITY_MAC] = "MAC", 5223222551Snp [FW_DEVLOG_FACILITY_PORT] = "PORT", 5224222551Snp [FW_DEVLOG_FACILITY_VI] = "VI", 5225222551Snp [FW_DEVLOG_FACILITY_FILTER] = "FILTER", 5226222551Snp [FW_DEVLOG_FACILITY_ACL] = "ACL", 5227222551Snp [FW_DEVLOG_FACILITY_TM] = "TM", 5228222551Snp [FW_DEVLOG_FACILITY_QFC] = "QFC", 5229222551Snp [FW_DEVLOG_FACILITY_DCB] = "DCB", 5230222551Snp [FW_DEVLOG_FACILITY_ETH] = "ETH", 5231222551Snp [FW_DEVLOG_FACILITY_OFLD] = "OFLD", 5232222551Snp [FW_DEVLOG_FACILITY_RI] = "RI", 5233222551Snp [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", 5234222551Snp [FW_DEVLOG_FACILITY_FCOE] = "FCOE", 5235222551Snp [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", 5236222551Snp [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE" 5237222551Snp}; 5238222551Snp 5239222551Snpstatic int 5240222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS) 5241222551Snp{ 5242222551Snp struct adapter *sc = arg1; 5243222551Snp struct devlog_params *dparams = &sc->params.devlog; 5244222551Snp struct fw_devlog_e *buf, *e; 5245222551Snp int i, j, rc, nentries, first = 0; 5246222551Snp struct sbuf *sb; 5247222551Snp uint64_t ftstamp = UINT64_MAX; 5248222551Snp 5249248925Snp if (dparams->start == 0) { 5250248925Snp dparams->memtype = 0; 5251248925Snp dparams->start = 0x84000; 5252248925Snp dparams->size = 32768; 5253248925Snp } 5254222551Snp 5255222551Snp nentries = dparams->size / sizeof(struct fw_devlog_e); 5256222551Snp 5257222551Snp buf = malloc(dparams->size, M_CXGBE, M_NOWAIT); 5258222551Snp if (buf == NULL) 5259222551Snp return (ENOMEM); 5260222551Snp 5261222551Snp rc = -t4_mem_read(sc, dparams->memtype, dparams->start, dparams->size, 5262222551Snp (void *)buf); 5263222551Snp if (rc != 0) 5264222551Snp goto done; 5265222551Snp 5266222551Snp for (i = 0; i < nentries; i++) { 5267222551Snp e = &buf[i]; 5268222551Snp 5269222551Snp if (e->timestamp == 0) 5270222551Snp break; /* end */ 5271222551Snp 5272222551Snp e->timestamp = be64toh(e->timestamp); 5273222551Snp e->seqno = be32toh(e->seqno); 5274222551Snp for (j = 0; j < 8; j++) 5275222551Snp e->params[j] = be32toh(e->params[j]); 5276222551Snp 5277222551Snp if (e->timestamp < ftstamp) { 5278222551Snp ftstamp = e->timestamp; 5279222551Snp first = i; 5280222551Snp } 5281222551Snp } 5282222551Snp 5283222551Snp if (buf[first].timestamp == 0) 5284222551Snp goto done; /* nothing in the log */ 5285222551Snp 5286222551Snp rc = sysctl_wire_old_buffer(req, 0); 5287222551Snp if (rc != 0) 5288222551Snp goto done; 5289222551Snp 5290222551Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5291228561Snp if (sb == NULL) { 5292228561Snp rc = ENOMEM; 5293228561Snp goto done; 5294228561Snp } 5295228561Snp sbuf_printf(sb, "%10s %15s %8s %8s %s\n", 5296222551Snp "Seq#", "Tstamp", "Level", "Facility", "Message"); 5297222551Snp 5298222551Snp i = first; 5299222551Snp do { 5300222551Snp e = &buf[i]; 5301222551Snp if (e->timestamp == 0) 5302222551Snp break; /* end */ 5303222551Snp 5304222551Snp sbuf_printf(sb, "%10d %15ju %8s %8s ", 5305222551Snp e->seqno, e->timestamp, 5306240452Snp (e->level < nitems(devlog_level_strings) ? 5307222551Snp devlog_level_strings[e->level] : "UNKNOWN"), 5308240452Snp (e->facility < nitems(devlog_facility_strings) ? 5309222551Snp devlog_facility_strings[e->facility] : "UNKNOWN")); 5310222551Snp sbuf_printf(sb, e->fmt, e->params[0], e->params[1], 5311222551Snp e->params[2], e->params[3], e->params[4], 5312222551Snp e->params[5], e->params[6], e->params[7]); 5313222551Snp 5314222551Snp if (++i == nentries) 5315222551Snp i = 0; 5316222551Snp } while (i != first); 5317222551Snp 5318222551Snp rc = sbuf_finish(sb); 5319222551Snp sbuf_delete(sb); 5320222551Snpdone: 5321222551Snp free(buf, M_CXGBE); 5322222551Snp return (rc); 5323222551Snp} 5324222551Snp 5325228561Snpstatic int 5326228561Snpsysctl_fcoe_stats(SYSCTL_HANDLER_ARGS) 5327228561Snp{ 5328228561Snp struct adapter *sc = arg1; 5329228561Snp struct sbuf *sb; 5330228561Snp int rc; 5331228561Snp struct tp_fcoe_stats stats[4]; 5332228561Snp 5333228561Snp rc = sysctl_wire_old_buffer(req, 0); 5334228561Snp if (rc != 0) 5335228561Snp return (rc); 5336228561Snp 5337228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5338228561Snp if (sb == NULL) 5339228561Snp return (ENOMEM); 5340228561Snp 5341228561Snp t4_get_fcoe_stats(sc, 0, &stats[0]); 5342228561Snp t4_get_fcoe_stats(sc, 1, &stats[1]); 5343228561Snp t4_get_fcoe_stats(sc, 2, &stats[2]); 5344228561Snp t4_get_fcoe_stats(sc, 3, &stats[3]); 5345228561Snp 5346228561Snp sbuf_printf(sb, " channel 0 channel 1 " 5347228561Snp "channel 2 channel 3\n"); 5348228561Snp sbuf_printf(sb, "octetsDDP: %16ju %16ju %16ju %16ju\n", 5349228561Snp stats[0].octetsDDP, stats[1].octetsDDP, stats[2].octetsDDP, 5350228561Snp stats[3].octetsDDP); 5351228561Snp sbuf_printf(sb, "framesDDP: %16u %16u %16u %16u\n", stats[0].framesDDP, 5352228561Snp stats[1].framesDDP, stats[2].framesDDP, stats[3].framesDDP); 5353228561Snp sbuf_printf(sb, "framesDrop: %16u %16u %16u %16u", 5354228561Snp stats[0].framesDrop, stats[1].framesDrop, stats[2].framesDrop, 5355228561Snp stats[3].framesDrop); 5356228561Snp 5357228561Snp rc = sbuf_finish(sb); 5358228561Snp sbuf_delete(sb); 5359228561Snp 5360228561Snp return (rc); 5361228561Snp} 5362228561Snp 5363228561Snpstatic int 5364228561Snpsysctl_hw_sched(SYSCTL_HANDLER_ARGS) 5365228561Snp{ 5366228561Snp struct adapter *sc = arg1; 5367228561Snp struct sbuf *sb; 5368228561Snp int rc, i; 5369228561Snp unsigned int map, kbps, ipg, mode; 5370228561Snp unsigned int pace_tab[NTX_SCHED]; 5371228561Snp 5372228561Snp rc = sysctl_wire_old_buffer(req, 0); 5373228561Snp if (rc != 0) 5374228561Snp return (rc); 5375228561Snp 5376228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5377228561Snp if (sb == NULL) 5378228561Snp return (ENOMEM); 5379228561Snp 5380228561Snp map = t4_read_reg(sc, A_TP_TX_MOD_QUEUE_REQ_MAP); 5381228561Snp mode = G_TIMERMODE(t4_read_reg(sc, A_TP_MOD_CONFIG)); 5382228561Snp t4_read_pace_tbl(sc, pace_tab); 5383228561Snp 5384228561Snp sbuf_printf(sb, "Scheduler Mode Channel Rate (Kbps) " 5385228561Snp "Class IPG (0.1 ns) Flow IPG (us)"); 5386228561Snp 5387228561Snp for (i = 0; i < NTX_SCHED; ++i, map >>= 2) { 5388228561Snp t4_get_tx_sched(sc, i, &kbps, &ipg); 5389228561Snp sbuf_printf(sb, "\n %u %-5s %u ", i, 5390228561Snp (mode & (1 << i)) ? "flow" : "class", map & 3); 5391228561Snp if (kbps) 5392228561Snp sbuf_printf(sb, "%9u ", kbps); 5393228561Snp else 5394228561Snp sbuf_printf(sb, " disabled "); 5395228561Snp 5396228561Snp if (ipg) 5397228561Snp sbuf_printf(sb, "%13u ", ipg); 5398228561Snp else 5399228561Snp sbuf_printf(sb, " disabled "); 5400228561Snp 5401228561Snp if (pace_tab[i]) 5402228561Snp sbuf_printf(sb, "%10u", pace_tab[i]); 5403228561Snp else 5404228561Snp sbuf_printf(sb, " disabled"); 5405228561Snp } 5406228561Snp 5407228561Snp rc = sbuf_finish(sb); 5408228561Snp sbuf_delete(sb); 5409228561Snp 5410228561Snp return (rc); 5411228561Snp} 5412228561Snp 5413228561Snpstatic int 5414228561Snpsysctl_lb_stats(SYSCTL_HANDLER_ARGS) 5415228561Snp{ 5416228561Snp struct adapter *sc = arg1; 5417228561Snp struct sbuf *sb; 5418228561Snp int rc, i, j; 5419228561Snp uint64_t *p0, *p1; 5420228561Snp struct lb_port_stats s[2]; 5421228561Snp static const char *stat_name[] = { 5422228561Snp "OctetsOK:", "FramesOK:", "BcastFrames:", "McastFrames:", 5423228561Snp "UcastFrames:", "ErrorFrames:", "Frames64:", "Frames65To127:", 5424228561Snp "Frames128To255:", "Frames256To511:", "Frames512To1023:", 5425228561Snp "Frames1024To1518:", "Frames1519ToMax:", "FramesDropped:", 5426228561Snp "BG0FramesDropped:", "BG1FramesDropped:", "BG2FramesDropped:", 5427228561Snp "BG3FramesDropped:", "BG0FramesTrunc:", "BG1FramesTrunc:", 5428228561Snp "BG2FramesTrunc:", "BG3FramesTrunc:" 5429228561Snp }; 5430228561Snp 5431228561Snp rc = sysctl_wire_old_buffer(req, 0); 5432228561Snp if (rc != 0) 5433228561Snp return (rc); 5434228561Snp 5435228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5436228561Snp if (sb == NULL) 5437228561Snp return (ENOMEM); 5438228561Snp 5439228561Snp memset(s, 0, sizeof(s)); 5440228561Snp 5441228561Snp for (i = 0; i < 4; i += 2) { 5442228561Snp t4_get_lb_stats(sc, i, &s[0]); 5443228561Snp t4_get_lb_stats(sc, i + 1, &s[1]); 5444228561Snp 5445228561Snp p0 = &s[0].octets; 5446228561Snp p1 = &s[1].octets; 5447228561Snp sbuf_printf(sb, "%s Loopback %u" 5448228561Snp " Loopback %u", i == 0 ? "" : "\n", i, i + 1); 5449228561Snp 5450240452Snp for (j = 0; j < nitems(stat_name); j++) 5451228561Snp sbuf_printf(sb, "\n%-17s %20ju %20ju", stat_name[j], 5452228561Snp *p0++, *p1++); 5453228561Snp } 5454228561Snp 5455228561Snp rc = sbuf_finish(sb); 5456228561Snp sbuf_delete(sb); 5457228561Snp 5458228561Snp return (rc); 5459228561Snp} 5460228561Snp 5461228561Snpstruct mem_desc { 5462228561Snp unsigned int base; 5463228561Snp unsigned int limit; 5464228561Snp unsigned int idx; 5465228561Snp}; 5466228561Snp 5467228561Snpstatic int 5468228561Snpmem_desc_cmp(const void *a, const void *b) 5469228561Snp{ 5470228561Snp return ((const struct mem_desc *)a)->base - 5471228561Snp ((const struct mem_desc *)b)->base; 5472228561Snp} 5473228561Snp 5474228561Snpstatic void 5475228561Snpmem_region_show(struct sbuf *sb, const char *name, unsigned int from, 5476228561Snp unsigned int to) 5477228561Snp{ 5478228561Snp unsigned int size; 5479228561Snp 5480228561Snp size = to - from + 1; 5481228561Snp if (size == 0) 5482228561Snp return; 5483228561Snp 5484228561Snp /* XXX: need humanize_number(3) in libkern for a more readable 'size' */ 5485228561Snp sbuf_printf(sb, "%-15s %#x-%#x [%u]\n", name, from, to, size); 5486228561Snp} 5487228561Snp 5488228561Snpstatic int 5489228561Snpsysctl_meminfo(SYSCTL_HANDLER_ARGS) 5490228561Snp{ 5491228561Snp struct adapter *sc = arg1; 5492228561Snp struct sbuf *sb; 5493228561Snp int rc, i, n; 5494248925Snp uint32_t lo, hi, used, alloc; 5495248925Snp static const char *memory[] = {"EDC0:", "EDC1:", "MC:", "MC0:", "MC1:"}; 5496228561Snp static const char *region[] = { 5497228561Snp "DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:", 5498228561Snp "Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:", 5499228561Snp "Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:", 5500228561Snp "TDDP region:", "TPT region:", "STAG region:", "RQ region:", 5501248925Snp "RQUDP region:", "PBL region:", "TXPBL region:", 5502248925Snp "DBVFIFO region:", "ULPRX state:", "ULPTX state:", 5503248925Snp "On-chip queues:" 5504228561Snp }; 5505248925Snp struct mem_desc avail[4]; 5506240452Snp struct mem_desc mem[nitems(region) + 3]; /* up to 3 holes */ 5507228561Snp struct mem_desc *md = mem; 5508228561Snp 5509228561Snp rc = sysctl_wire_old_buffer(req, 0); 5510228561Snp if (rc != 0) 5511228561Snp return (rc); 5512228561Snp 5513228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5514228561Snp if (sb == NULL) 5515228561Snp return (ENOMEM); 5516228561Snp 5517240452Snp for (i = 0; i < nitems(mem); i++) { 5518228561Snp mem[i].limit = 0; 5519228561Snp mem[i].idx = i; 5520228561Snp } 5521228561Snp 5522228561Snp /* Find and sort the populated memory ranges */ 5523228561Snp i = 0; 5524228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 5525228561Snp if (lo & F_EDRAM0_ENABLE) { 5526228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 5527228561Snp avail[i].base = G_EDRAM0_BASE(hi) << 20; 5528228561Snp avail[i].limit = avail[i].base + (G_EDRAM0_SIZE(hi) << 20); 5529228561Snp avail[i].idx = 0; 5530228561Snp i++; 5531228561Snp } 5532228561Snp if (lo & F_EDRAM1_ENABLE) { 5533228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 5534228561Snp avail[i].base = G_EDRAM1_BASE(hi) << 20; 5535228561Snp avail[i].limit = avail[i].base + (G_EDRAM1_SIZE(hi) << 20); 5536228561Snp avail[i].idx = 1; 5537228561Snp i++; 5538228561Snp } 5539228561Snp if (lo & F_EXT_MEM_ENABLE) { 5540228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 5541228561Snp avail[i].base = G_EXT_MEM_BASE(hi) << 20; 5542248925Snp avail[i].limit = avail[i].base + 5543248925Snp (G_EXT_MEM_SIZE(hi) << 20); 5544248925Snp avail[i].idx = is_t4(sc) ? 2 : 3; /* Call it MC for T4 */ 5545228561Snp i++; 5546228561Snp } 5547248925Snp if (!is_t4(sc) && lo & F_EXT_MEM1_ENABLE) { 5548248925Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 5549248925Snp avail[i].base = G_EXT_MEM1_BASE(hi) << 20; 5550248925Snp avail[i].limit = avail[i].base + 5551248925Snp (G_EXT_MEM1_SIZE(hi) << 20); 5552248925Snp avail[i].idx = 4; 5553248925Snp i++; 5554248925Snp } 5555228561Snp if (!i) /* no memory available */ 5556228561Snp return 0; 5557228561Snp qsort(avail, i, sizeof(struct mem_desc), mem_desc_cmp); 5558228561Snp 5559228561Snp (md++)->base = t4_read_reg(sc, A_SGE_DBQ_CTXT_BADDR); 5560228561Snp (md++)->base = t4_read_reg(sc, A_SGE_IMSG_CTXT_BADDR); 5561228561Snp (md++)->base = t4_read_reg(sc, A_SGE_FLM_CACHE_BADDR); 5562228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 5563228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_BASE); 5564228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TIMER_BASE); 5565228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_RX_FLST_BASE); 5566228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_TX_FLST_BASE); 5567228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_PS_FLST_BASE); 5568228561Snp 5569228561Snp /* the next few have explicit upper bounds */ 5570228561Snp md->base = t4_read_reg(sc, A_TP_PMM_TX_BASE); 5571228561Snp md->limit = md->base - 1 + 5572228561Snp t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE) * 5573228561Snp G_PMTXMAXPAGE(t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE)); 5574228561Snp md++; 5575228561Snp 5576228561Snp md->base = t4_read_reg(sc, A_TP_PMM_RX_BASE); 5577228561Snp md->limit = md->base - 1 + 5578228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) * 5579228561Snp G_PMRXMAXPAGE(t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE)); 5580228561Snp md++; 5581228561Snp 5582228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 5583228561Snp hi = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4; 5584228561Snp md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE); 5585228561Snp md->limit = (sc->tids.ntids - hi) * 16 + md->base - 1; 5586228561Snp } else { 5587228561Snp md->base = 0; 5588240452Snp md->idx = nitems(region); /* hide it */ 5589228561Snp } 5590228561Snp md++; 5591228561Snp 5592228561Snp#define ulp_region(reg) \ 5593228561Snp md->base = t4_read_reg(sc, A_ULP_ ## reg ## _LLIMIT);\ 5594228561Snp (md++)->limit = t4_read_reg(sc, A_ULP_ ## reg ## _ULIMIT) 5595228561Snp 5596228561Snp ulp_region(RX_ISCSI); 5597228561Snp ulp_region(RX_TDDP); 5598228561Snp ulp_region(TX_TPT); 5599228561Snp ulp_region(RX_STAG); 5600228561Snp ulp_region(RX_RQ); 5601228561Snp ulp_region(RX_RQUDP); 5602228561Snp ulp_region(RX_PBL); 5603228561Snp ulp_region(TX_PBL); 5604228561Snp#undef ulp_region 5605228561Snp 5606248925Snp md->base = 0; 5607248925Snp md->idx = nitems(region); 5608248925Snp if (!is_t4(sc) && t4_read_reg(sc, A_SGE_CONTROL2) & F_VFIFO_ENABLE) { 5609248925Snp md->base = G_BASEADDR(t4_read_reg(sc, A_SGE_DBVFIFO_BADDR)); 5610248925Snp md->limit = md->base + (G_DBVFIFO_SIZE((t4_read_reg(sc, 5611248925Snp A_SGE_DBVFIFO_SIZE))) << 2) - 1; 5612248925Snp } 5613248925Snp md++; 5614248925Snp 5615228561Snp md->base = t4_read_reg(sc, A_ULP_RX_CTX_BASE); 5616228561Snp md->limit = md->base + sc->tids.ntids - 1; 5617228561Snp md++; 5618228561Snp md->base = t4_read_reg(sc, A_ULP_TX_ERR_TABLE_BASE); 5619228561Snp md->limit = md->base + sc->tids.ntids - 1; 5620228561Snp md++; 5621228561Snp 5622228561Snp md->base = sc->vres.ocq.start; 5623228561Snp if (sc->vres.ocq.size) 5624228561Snp md->limit = md->base + sc->vres.ocq.size - 1; 5625228561Snp else 5626240452Snp md->idx = nitems(region); /* hide it */ 5627228561Snp md++; 5628228561Snp 5629228561Snp /* add any address-space holes, there can be up to 3 */ 5630228561Snp for (n = 0; n < i - 1; n++) 5631228561Snp if (avail[n].limit < avail[n + 1].base) 5632228561Snp (md++)->base = avail[n].limit; 5633228561Snp if (avail[n].limit) 5634228561Snp (md++)->base = avail[n].limit; 5635228561Snp 5636228561Snp n = md - mem; 5637228561Snp qsort(mem, n, sizeof(struct mem_desc), mem_desc_cmp); 5638228561Snp 5639228561Snp for (lo = 0; lo < i; lo++) 5640228561Snp mem_region_show(sb, memory[avail[lo].idx], avail[lo].base, 5641228561Snp avail[lo].limit - 1); 5642228561Snp 5643228561Snp sbuf_printf(sb, "\n"); 5644228561Snp for (i = 0; i < n; i++) { 5645240452Snp if (mem[i].idx >= nitems(region)) 5646228561Snp continue; /* skip holes */ 5647228561Snp if (!mem[i].limit) 5648228561Snp mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0; 5649228561Snp mem_region_show(sb, region[mem[i].idx], mem[i].base, 5650228561Snp mem[i].limit); 5651228561Snp } 5652228561Snp 5653228561Snp sbuf_printf(sb, "\n"); 5654228561Snp lo = t4_read_reg(sc, A_CIM_SDRAM_BASE_ADDR); 5655228561Snp hi = t4_read_reg(sc, A_CIM_SDRAM_ADDR_SIZE) + lo - 1; 5656228561Snp mem_region_show(sb, "uP RAM:", lo, hi); 5657228561Snp 5658228561Snp lo = t4_read_reg(sc, A_CIM_EXTMEM2_BASE_ADDR); 5659228561Snp hi = t4_read_reg(sc, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1; 5660228561Snp mem_region_show(sb, "uP Extmem2:", lo, hi); 5661228561Snp 5662228561Snp lo = t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE); 5663228561Snp sbuf_printf(sb, "\n%u Rx pages of size %uKiB for %u channels\n", 5664228561Snp G_PMRXMAXPAGE(lo), 5665228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) >> 10, 5666228561Snp (lo & F_PMRXNUMCHN) ? 2 : 1); 5667228561Snp 5668228561Snp lo = t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE); 5669228561Snp hi = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE); 5670228561Snp sbuf_printf(sb, "%u Tx pages of size %u%ciB for %u channels\n", 5671228561Snp G_PMTXMAXPAGE(lo), 5672228561Snp hi >= (1 << 20) ? (hi >> 20) : (hi >> 10), 5673228561Snp hi >= (1 << 20) ? 'M' : 'K', 1 << G_PMTXNUMCHN(lo)); 5674228561Snp sbuf_printf(sb, "%u p-structs\n", 5675228561Snp t4_read_reg(sc, A_TP_CMM_MM_MAX_PSTRUCT)); 5676228561Snp 5677228561Snp for (i = 0; i < 4; i++) { 5678228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV0 + i * 4); 5679248925Snp if (is_t4(sc)) { 5680248925Snp used = G_USED(lo); 5681248925Snp alloc = G_ALLOC(lo); 5682248925Snp } else { 5683248925Snp used = G_T5_USED(lo); 5684248925Snp alloc = G_T5_ALLOC(lo); 5685248925Snp } 5686228561Snp sbuf_printf(sb, "\nPort %d using %u pages out of %u allocated", 5687248925Snp i, used, alloc); 5688228561Snp } 5689228561Snp for (i = 0; i < 4; i++) { 5690228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV4 + i * 4); 5691248925Snp if (is_t4(sc)) { 5692248925Snp used = G_USED(lo); 5693248925Snp alloc = G_ALLOC(lo); 5694248925Snp } else { 5695248925Snp used = G_T5_USED(lo); 5696248925Snp alloc = G_T5_ALLOC(lo); 5697248925Snp } 5698228561Snp sbuf_printf(sb, 5699228561Snp "\nLoopback %d using %u pages out of %u allocated", 5700248925Snp i, used, alloc); 5701228561Snp } 5702228561Snp 5703228561Snp rc = sbuf_finish(sb); 5704228561Snp sbuf_delete(sb); 5705228561Snp 5706228561Snp return (rc); 5707228561Snp} 5708228561Snp 5709251213Snpstatic inline void 5710251213Snptcamxy2valmask(uint64_t x, uint64_t y, uint8_t *addr, uint64_t *mask) 5711251213Snp{ 5712251213Snp *mask = x | y; 5713251213Snp y = htobe64(y); 5714251213Snp memcpy(addr, (char *)&y + 2, ETHER_ADDR_LEN); 5715251213Snp} 5716251213Snp 5717228561Snpstatic int 5718251213Snpsysctl_mps_tcam(SYSCTL_HANDLER_ARGS) 5719251213Snp{ 5720251213Snp struct adapter *sc = arg1; 5721251213Snp struct sbuf *sb; 5722251213Snp int rc, i, n; 5723251213Snp 5724251213Snp rc = sysctl_wire_old_buffer(req, 0); 5725251213Snp if (rc != 0) 5726251213Snp return (rc); 5727251213Snp 5728251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5729251213Snp if (sb == NULL) 5730251213Snp return (ENOMEM); 5731251213Snp 5732251213Snp sbuf_printf(sb, 5733251213Snp "Idx Ethernet address Mask Vld Ports PF" 5734251213Snp " VF Replication P0 P1 P2 P3 ML"); 5735251213Snp n = is_t4(sc) ? NUM_MPS_CLS_SRAM_L_INSTANCES : 5736251213Snp NUM_MPS_T5_CLS_SRAM_L_INSTANCES; 5737251213Snp for (i = 0; i < n; i++) { 5738251213Snp uint64_t tcamx, tcamy, mask; 5739251213Snp uint32_t cls_lo, cls_hi; 5740251213Snp uint8_t addr[ETHER_ADDR_LEN]; 5741251213Snp 5742251213Snp tcamy = t4_read_reg64(sc, MPS_CLS_TCAM_Y_L(i)); 5743251213Snp tcamx = t4_read_reg64(sc, MPS_CLS_TCAM_X_L(i)); 5744251213Snp cls_lo = t4_read_reg(sc, MPS_CLS_SRAM_L(i)); 5745251213Snp cls_hi = t4_read_reg(sc, MPS_CLS_SRAM_H(i)); 5746251213Snp 5747251213Snp if (tcamx & tcamy) 5748251213Snp continue; 5749251213Snp 5750251213Snp tcamxy2valmask(tcamx, tcamy, addr, &mask); 5751251213Snp sbuf_printf(sb, "\n%3u %02x:%02x:%02x:%02x:%02x:%02x %012jx" 5752251213Snp " %c %#x%4u%4d", i, addr[0], addr[1], addr[2], 5753251213Snp addr[3], addr[4], addr[5], (uintmax_t)mask, 5754251213Snp (cls_lo & F_SRAM_VLD) ? 'Y' : 'N', 5755251213Snp G_PORTMAP(cls_hi), G_PF(cls_lo), 5756251213Snp (cls_lo & F_VF_VALID) ? G_VF(cls_lo) : -1); 5757251213Snp 5758251213Snp if (cls_lo & F_REPLICATE) { 5759251213Snp struct fw_ldst_cmd ldst_cmd; 5760251213Snp 5761251213Snp memset(&ldst_cmd, 0, sizeof(ldst_cmd)); 5762251213Snp ldst_cmd.op_to_addrspace = 5763251213Snp htobe32(V_FW_CMD_OP(FW_LDST_CMD) | 5764251213Snp F_FW_CMD_REQUEST | F_FW_CMD_READ | 5765251213Snp V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MPS)); 5766251213Snp ldst_cmd.cycles_to_len16 = htobe32(FW_LEN16(ldst_cmd)); 5767251213Snp ldst_cmd.u.mps.fid_ctl = 5768251213Snp htobe16(V_FW_LDST_CMD_FID(FW_LDST_MPS_RPLC) | 5769251213Snp V_FW_LDST_CMD_CTL(i)); 5770251213Snp 5771251213Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, 5772251213Snp "t4mps"); 5773251213Snp if (rc) 5774251213Snp break; 5775251213Snp rc = -t4_wr_mbox(sc, sc->mbox, &ldst_cmd, 5776251213Snp sizeof(ldst_cmd), &ldst_cmd); 5777251213Snp end_synchronized_op(sc, 0); 5778251213Snp 5779251213Snp if (rc != 0) { 5780251213Snp sbuf_printf(sb, 5781251213Snp " ------------ error %3u ------------", rc); 5782251213Snp rc = 0; 5783251213Snp } else { 5784251213Snp sbuf_printf(sb, " %08x %08x %08x %08x", 5785251213Snp be32toh(ldst_cmd.u.mps.rplc127_96), 5786251213Snp be32toh(ldst_cmd.u.mps.rplc95_64), 5787251213Snp be32toh(ldst_cmd.u.mps.rplc63_32), 5788251213Snp be32toh(ldst_cmd.u.mps.rplc31_0)); 5789251213Snp } 5790251213Snp } else 5791251213Snp sbuf_printf(sb, "%36s", ""); 5792251213Snp 5793251213Snp sbuf_printf(sb, "%4u%3u%3u%3u %#3x", G_SRAM_PRIO0(cls_lo), 5794251213Snp G_SRAM_PRIO1(cls_lo), G_SRAM_PRIO2(cls_lo), 5795251213Snp G_SRAM_PRIO3(cls_lo), (cls_lo >> S_MULTILISTEN0) & 0xf); 5796251213Snp } 5797251213Snp 5798251213Snp if (rc) 5799251213Snp (void) sbuf_finish(sb); 5800251213Snp else 5801251213Snp rc = sbuf_finish(sb); 5802251213Snp sbuf_delete(sb); 5803251213Snp 5804251213Snp return (rc); 5805251213Snp} 5806251213Snp 5807251213Snpstatic int 5808228561Snpsysctl_path_mtus(SYSCTL_HANDLER_ARGS) 5809228561Snp{ 5810228561Snp struct adapter *sc = arg1; 5811228561Snp struct sbuf *sb; 5812228561Snp int rc; 5813228561Snp uint16_t mtus[NMTUS]; 5814228561Snp 5815228561Snp rc = sysctl_wire_old_buffer(req, 0); 5816228561Snp if (rc != 0) 5817228561Snp return (rc); 5818228561Snp 5819228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5820228561Snp if (sb == NULL) 5821228561Snp return (ENOMEM); 5822228561Snp 5823228561Snp t4_read_mtu_tbl(sc, mtus, NULL); 5824228561Snp 5825228561Snp sbuf_printf(sb, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", 5826228561Snp mtus[0], mtus[1], mtus[2], mtus[3], mtus[4], mtus[5], mtus[6], 5827228561Snp mtus[7], mtus[8], mtus[9], mtus[10], mtus[11], mtus[12], mtus[13], 5828228561Snp mtus[14], mtus[15]); 5829228561Snp 5830228561Snp rc = sbuf_finish(sb); 5831228561Snp sbuf_delete(sb); 5832228561Snp 5833228561Snp return (rc); 5834228561Snp} 5835228561Snp 5836228561Snpstatic int 5837228561Snpsysctl_pm_stats(SYSCTL_HANDLER_ARGS) 5838228561Snp{ 5839228561Snp struct adapter *sc = arg1; 5840228561Snp struct sbuf *sb; 5841228561Snp int rc, i; 5842228561Snp uint32_t tx_cnt[PM_NSTATS], rx_cnt[PM_NSTATS]; 5843228561Snp uint64_t tx_cyc[PM_NSTATS], rx_cyc[PM_NSTATS]; 5844228561Snp static const char *pm_stats[] = { 5845228561Snp "Read:", "Write bypass:", "Write mem:", "Flush:", "FIFO wait:" 5846228561Snp }; 5847228561Snp 5848228561Snp rc = sysctl_wire_old_buffer(req, 0); 5849228561Snp if (rc != 0) 5850228561Snp return (rc); 5851228561Snp 5852228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5853228561Snp if (sb == NULL) 5854228561Snp return (ENOMEM); 5855228561Snp 5856228561Snp t4_pmtx_get_stats(sc, tx_cnt, tx_cyc); 5857228561Snp t4_pmrx_get_stats(sc, rx_cnt, rx_cyc); 5858228561Snp 5859228561Snp sbuf_printf(sb, " Tx count Tx cycles " 5860228561Snp "Rx count Rx cycles"); 5861228561Snp for (i = 0; i < PM_NSTATS; i++) 5862228561Snp sbuf_printf(sb, "\n%-13s %10u %20ju %10u %20ju", 5863228561Snp pm_stats[i], tx_cnt[i], tx_cyc[i], rx_cnt[i], rx_cyc[i]); 5864228561Snp 5865228561Snp rc = sbuf_finish(sb); 5866228561Snp sbuf_delete(sb); 5867228561Snp 5868228561Snp return (rc); 5869228561Snp} 5870228561Snp 5871228561Snpstatic int 5872228561Snpsysctl_rdma_stats(SYSCTL_HANDLER_ARGS) 5873228561Snp{ 5874228561Snp struct adapter *sc = arg1; 5875228561Snp struct sbuf *sb; 5876228561Snp int rc; 5877228561Snp struct tp_rdma_stats stats; 5878228561Snp 5879228561Snp rc = sysctl_wire_old_buffer(req, 0); 5880228561Snp if (rc != 0) 5881228561Snp return (rc); 5882228561Snp 5883228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5884228561Snp if (sb == NULL) 5885228561Snp return (ENOMEM); 5886228561Snp 5887228561Snp t4_tp_get_rdma_stats(sc, &stats); 5888228561Snp sbuf_printf(sb, "NoRQEModDefferals: %u\n", stats.rqe_dfr_mod); 5889228561Snp sbuf_printf(sb, "NoRQEPktDefferals: %u", stats.rqe_dfr_pkt); 5890228561Snp 5891228561Snp rc = sbuf_finish(sb); 5892228561Snp sbuf_delete(sb); 5893228561Snp 5894228561Snp return (rc); 5895228561Snp} 5896228561Snp 5897228561Snpstatic int 5898228561Snpsysctl_tcp_stats(SYSCTL_HANDLER_ARGS) 5899228561Snp{ 5900228561Snp struct adapter *sc = arg1; 5901228561Snp struct sbuf *sb; 5902228561Snp int rc; 5903228561Snp struct tp_tcp_stats v4, v6; 5904228561Snp 5905228561Snp rc = sysctl_wire_old_buffer(req, 0); 5906228561Snp if (rc != 0) 5907228561Snp return (rc); 5908228561Snp 5909228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5910228561Snp if (sb == NULL) 5911228561Snp return (ENOMEM); 5912228561Snp 5913228561Snp t4_tp_get_tcp_stats(sc, &v4, &v6); 5914228561Snp sbuf_printf(sb, 5915228561Snp " IP IPv6\n"); 5916228561Snp sbuf_printf(sb, "OutRsts: %20u %20u\n", 5917228561Snp v4.tcpOutRsts, v6.tcpOutRsts); 5918228561Snp sbuf_printf(sb, "InSegs: %20ju %20ju\n", 5919228561Snp v4.tcpInSegs, v6.tcpInSegs); 5920228561Snp sbuf_printf(sb, "OutSegs: %20ju %20ju\n", 5921228561Snp v4.tcpOutSegs, v6.tcpOutSegs); 5922228561Snp sbuf_printf(sb, "RetransSegs: %20ju %20ju", 5923228561Snp v4.tcpRetransSegs, v6.tcpRetransSegs); 5924228561Snp 5925228561Snp rc = sbuf_finish(sb); 5926228561Snp sbuf_delete(sb); 5927228561Snp 5928228561Snp return (rc); 5929228561Snp} 5930228561Snp 5931228561Snpstatic int 5932228561Snpsysctl_tids(SYSCTL_HANDLER_ARGS) 5933228561Snp{ 5934228561Snp struct adapter *sc = arg1; 5935228561Snp struct sbuf *sb; 5936228561Snp int rc; 5937228561Snp struct tid_info *t = &sc->tids; 5938228561Snp 5939228561Snp rc = sysctl_wire_old_buffer(req, 0); 5940228561Snp if (rc != 0) 5941228561Snp return (rc); 5942228561Snp 5943228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5944228561Snp if (sb == NULL) 5945228561Snp return (ENOMEM); 5946228561Snp 5947228561Snp if (t->natids) { 5948228561Snp sbuf_printf(sb, "ATID range: 0-%u, in use: %u\n", t->natids - 1, 5949228561Snp t->atids_in_use); 5950228561Snp } 5951228561Snp 5952228561Snp if (t->ntids) { 5953228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 5954228561Snp uint32_t b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4; 5955228561Snp 5956228561Snp if (b) { 5957228561Snp sbuf_printf(sb, "TID range: 0-%u, %u-%u", b - 1, 5958228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 5959228561Snp t->ntids - 1); 5960228561Snp } else { 5961228561Snp sbuf_printf(sb, "TID range: %u-%u", 5962228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 5963228561Snp t->ntids - 1); 5964228561Snp } 5965228561Snp } else 5966228561Snp sbuf_printf(sb, "TID range: 0-%u", t->ntids - 1); 5967228561Snp sbuf_printf(sb, ", in use: %u\n", 5968228561Snp atomic_load_acq_int(&t->tids_in_use)); 5969228561Snp } 5970228561Snp 5971228561Snp if (t->nstids) { 5972228561Snp sbuf_printf(sb, "STID range: %u-%u, in use: %u\n", t->stid_base, 5973228561Snp t->stid_base + t->nstids - 1, t->stids_in_use); 5974228561Snp } 5975228561Snp 5976228561Snp if (t->nftids) { 5977228561Snp sbuf_printf(sb, "FTID range: %u-%u\n", t->ftid_base, 5978228561Snp t->ftid_base + t->nftids - 1); 5979228561Snp } 5980228561Snp 5981228561Snp sbuf_printf(sb, "HW TID usage: %u IP users, %u IPv6 users", 5982228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV4), 5983228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV6)); 5984228561Snp 5985228561Snp rc = sbuf_finish(sb); 5986228561Snp sbuf_delete(sb); 5987228561Snp 5988228561Snp return (rc); 5989228561Snp} 5990228561Snp 5991228561Snpstatic int 5992228561Snpsysctl_tp_err_stats(SYSCTL_HANDLER_ARGS) 5993228561Snp{ 5994228561Snp struct adapter *sc = arg1; 5995228561Snp struct sbuf *sb; 5996228561Snp int rc; 5997228561Snp struct tp_err_stats stats; 5998228561Snp 5999228561Snp rc = sysctl_wire_old_buffer(req, 0); 6000228561Snp if (rc != 0) 6001228561Snp return (rc); 6002228561Snp 6003228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6004228561Snp if (sb == NULL) 6005228561Snp return (ENOMEM); 6006228561Snp 6007228561Snp t4_tp_get_err_stats(sc, &stats); 6008228561Snp 6009228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 6010228561Snp "channel 3\n"); 6011228561Snp sbuf_printf(sb, "macInErrs: %10u %10u %10u %10u\n", 6012228561Snp stats.macInErrs[0], stats.macInErrs[1], stats.macInErrs[2], 6013228561Snp stats.macInErrs[3]); 6014228561Snp sbuf_printf(sb, "hdrInErrs: %10u %10u %10u %10u\n", 6015228561Snp stats.hdrInErrs[0], stats.hdrInErrs[1], stats.hdrInErrs[2], 6016228561Snp stats.hdrInErrs[3]); 6017228561Snp sbuf_printf(sb, "tcpInErrs: %10u %10u %10u %10u\n", 6018228561Snp stats.tcpInErrs[0], stats.tcpInErrs[1], stats.tcpInErrs[2], 6019228561Snp stats.tcpInErrs[3]); 6020228561Snp sbuf_printf(sb, "tcp6InErrs: %10u %10u %10u %10u\n", 6021228561Snp stats.tcp6InErrs[0], stats.tcp6InErrs[1], stats.tcp6InErrs[2], 6022228561Snp stats.tcp6InErrs[3]); 6023228561Snp sbuf_printf(sb, "tnlCongDrops: %10u %10u %10u %10u\n", 6024228561Snp stats.tnlCongDrops[0], stats.tnlCongDrops[1], stats.tnlCongDrops[2], 6025228561Snp stats.tnlCongDrops[3]); 6026228561Snp sbuf_printf(sb, "tnlTxDrops: %10u %10u %10u %10u\n", 6027228561Snp stats.tnlTxDrops[0], stats.tnlTxDrops[1], stats.tnlTxDrops[2], 6028228561Snp stats.tnlTxDrops[3]); 6029228561Snp sbuf_printf(sb, "ofldVlanDrops: %10u %10u %10u %10u\n", 6030228561Snp stats.ofldVlanDrops[0], stats.ofldVlanDrops[1], 6031228561Snp stats.ofldVlanDrops[2], stats.ofldVlanDrops[3]); 6032228561Snp sbuf_printf(sb, "ofldChanDrops: %10u %10u %10u %10u\n\n", 6033228561Snp stats.ofldChanDrops[0], stats.ofldChanDrops[1], 6034228561Snp stats.ofldChanDrops[2], stats.ofldChanDrops[3]); 6035228561Snp sbuf_printf(sb, "ofldNoNeigh: %u\nofldCongDefer: %u", 6036228561Snp stats.ofldNoNeigh, stats.ofldCongDefer); 6037228561Snp 6038228561Snp rc = sbuf_finish(sb); 6039228561Snp sbuf_delete(sb); 6040228561Snp 6041228561Snp return (rc); 6042228561Snp} 6043228561Snp 6044251213Snpstruct field_desc { 6045251213Snp const char *name; 6046251213Snp u_int start; 6047251213Snp u_int width; 6048251213Snp}; 6049251213Snp 6050251213Snpstatic void 6051251213Snpfield_desc_show(struct sbuf *sb, uint64_t v, const struct field_desc *f) 6052251213Snp{ 6053251213Snp char buf[32]; 6054251213Snp int line_size = 0; 6055251213Snp 6056251213Snp while (f->name) { 6057251213Snp uint64_t mask = (1ULL << f->width) - 1; 6058251213Snp int len = snprintf(buf, sizeof(buf), "%s: %ju", f->name, 6059251213Snp ((uintmax_t)v >> f->start) & mask); 6060251213Snp 6061251213Snp if (line_size + len >= 79) { 6062251213Snp line_size = 8; 6063251213Snp sbuf_printf(sb, "\n "); 6064251213Snp } 6065251213Snp sbuf_printf(sb, "%s ", buf); 6066251213Snp line_size += len + 1; 6067251213Snp f++; 6068251213Snp } 6069251213Snp sbuf_printf(sb, "\n"); 6070251213Snp} 6071251213Snp 6072251213Snpstatic struct field_desc tp_la0[] = { 6073251213Snp { "RcfOpCodeOut", 60, 4 }, 6074251213Snp { "State", 56, 4 }, 6075251213Snp { "WcfState", 52, 4 }, 6076251213Snp { "RcfOpcSrcOut", 50, 2 }, 6077251213Snp { "CRxError", 49, 1 }, 6078251213Snp { "ERxError", 48, 1 }, 6079251213Snp { "SanityFailed", 47, 1 }, 6080251213Snp { "SpuriousMsg", 46, 1 }, 6081251213Snp { "FlushInputMsg", 45, 1 }, 6082251213Snp { "FlushInputCpl", 44, 1 }, 6083251213Snp { "RssUpBit", 43, 1 }, 6084251213Snp { "RssFilterHit", 42, 1 }, 6085251213Snp { "Tid", 32, 10 }, 6086251213Snp { "InitTcb", 31, 1 }, 6087251213Snp { "LineNumber", 24, 7 }, 6088251213Snp { "Emsg", 23, 1 }, 6089251213Snp { "EdataOut", 22, 1 }, 6090251213Snp { "Cmsg", 21, 1 }, 6091251213Snp { "CdataOut", 20, 1 }, 6092251213Snp { "EreadPdu", 19, 1 }, 6093251213Snp { "CreadPdu", 18, 1 }, 6094251213Snp { "TunnelPkt", 17, 1 }, 6095251213Snp { "RcfPeerFin", 16, 1 }, 6096251213Snp { "RcfReasonOut", 12, 4 }, 6097251213Snp { "TxCchannel", 10, 2 }, 6098251213Snp { "RcfTxChannel", 8, 2 }, 6099251213Snp { "RxEchannel", 6, 2 }, 6100251213Snp { "RcfRxChannel", 5, 1 }, 6101251213Snp { "RcfDataOutSrdy", 4, 1 }, 6102251213Snp { "RxDvld", 3, 1 }, 6103251213Snp { "RxOoDvld", 2, 1 }, 6104251213Snp { "RxCongestion", 1, 1 }, 6105251213Snp { "TxCongestion", 0, 1 }, 6106251213Snp { NULL } 6107251213Snp}; 6108251213Snp 6109251213Snpstatic struct field_desc tp_la1[] = { 6110251213Snp { "CplCmdIn", 56, 8 }, 6111251213Snp { "CplCmdOut", 48, 8 }, 6112251213Snp { "ESynOut", 47, 1 }, 6113251213Snp { "EAckOut", 46, 1 }, 6114251213Snp { "EFinOut", 45, 1 }, 6115251213Snp { "ERstOut", 44, 1 }, 6116251213Snp { "SynIn", 43, 1 }, 6117251213Snp { "AckIn", 42, 1 }, 6118251213Snp { "FinIn", 41, 1 }, 6119251213Snp { "RstIn", 40, 1 }, 6120251213Snp { "DataIn", 39, 1 }, 6121251213Snp { "DataInVld", 38, 1 }, 6122251213Snp { "PadIn", 37, 1 }, 6123251213Snp { "RxBufEmpty", 36, 1 }, 6124251213Snp { "RxDdp", 35, 1 }, 6125251213Snp { "RxFbCongestion", 34, 1 }, 6126251213Snp { "TxFbCongestion", 33, 1 }, 6127251213Snp { "TxPktSumSrdy", 32, 1 }, 6128251213Snp { "RcfUlpType", 28, 4 }, 6129251213Snp { "Eread", 27, 1 }, 6130251213Snp { "Ebypass", 26, 1 }, 6131251213Snp { "Esave", 25, 1 }, 6132251213Snp { "Static0", 24, 1 }, 6133251213Snp { "Cread", 23, 1 }, 6134251213Snp { "Cbypass", 22, 1 }, 6135251213Snp { "Csave", 21, 1 }, 6136251213Snp { "CPktOut", 20, 1 }, 6137251213Snp { "RxPagePoolFull", 18, 2 }, 6138251213Snp { "RxLpbkPkt", 17, 1 }, 6139251213Snp { "TxLpbkPkt", 16, 1 }, 6140251213Snp { "RxVfValid", 15, 1 }, 6141251213Snp { "SynLearned", 14, 1 }, 6142251213Snp { "SetDelEntry", 13, 1 }, 6143251213Snp { "SetInvEntry", 12, 1 }, 6144251213Snp { "CpcmdDvld", 11, 1 }, 6145251213Snp { "CpcmdSave", 10, 1 }, 6146251213Snp { "RxPstructsFull", 8, 2 }, 6147251213Snp { "EpcmdDvld", 7, 1 }, 6148251213Snp { "EpcmdFlush", 6, 1 }, 6149251213Snp { "EpcmdTrimPrefix", 5, 1 }, 6150251213Snp { "EpcmdTrimPostfix", 4, 1 }, 6151251213Snp { "ERssIp4Pkt", 3, 1 }, 6152251213Snp { "ERssIp6Pkt", 2, 1 }, 6153251213Snp { "ERssTcpUdpPkt", 1, 1 }, 6154251213Snp { "ERssFceFipPkt", 0, 1 }, 6155251213Snp { NULL } 6156251213Snp}; 6157251213Snp 6158251213Snpstatic struct field_desc tp_la2[] = { 6159251213Snp { "CplCmdIn", 56, 8 }, 6160251213Snp { "MpsVfVld", 55, 1 }, 6161251213Snp { "MpsPf", 52, 3 }, 6162251213Snp { "MpsVf", 44, 8 }, 6163251213Snp { "SynIn", 43, 1 }, 6164251213Snp { "AckIn", 42, 1 }, 6165251213Snp { "FinIn", 41, 1 }, 6166251213Snp { "RstIn", 40, 1 }, 6167251213Snp { "DataIn", 39, 1 }, 6168251213Snp { "DataInVld", 38, 1 }, 6169251213Snp { "PadIn", 37, 1 }, 6170251213Snp { "RxBufEmpty", 36, 1 }, 6171251213Snp { "RxDdp", 35, 1 }, 6172251213Snp { "RxFbCongestion", 34, 1 }, 6173251213Snp { "TxFbCongestion", 33, 1 }, 6174251213Snp { "TxPktSumSrdy", 32, 1 }, 6175251213Snp { "RcfUlpType", 28, 4 }, 6176251213Snp { "Eread", 27, 1 }, 6177251213Snp { "Ebypass", 26, 1 }, 6178251213Snp { "Esave", 25, 1 }, 6179251213Snp { "Static0", 24, 1 }, 6180251213Snp { "Cread", 23, 1 }, 6181251213Snp { "Cbypass", 22, 1 }, 6182251213Snp { "Csave", 21, 1 }, 6183251213Snp { "CPktOut", 20, 1 }, 6184251213Snp { "RxPagePoolFull", 18, 2 }, 6185251213Snp { "RxLpbkPkt", 17, 1 }, 6186251213Snp { "TxLpbkPkt", 16, 1 }, 6187251213Snp { "RxVfValid", 15, 1 }, 6188251213Snp { "SynLearned", 14, 1 }, 6189251213Snp { "SetDelEntry", 13, 1 }, 6190251213Snp { "SetInvEntry", 12, 1 }, 6191251213Snp { "CpcmdDvld", 11, 1 }, 6192251213Snp { "CpcmdSave", 10, 1 }, 6193251213Snp { "RxPstructsFull", 8, 2 }, 6194251213Snp { "EpcmdDvld", 7, 1 }, 6195251213Snp { "EpcmdFlush", 6, 1 }, 6196251213Snp { "EpcmdTrimPrefix", 5, 1 }, 6197251213Snp { "EpcmdTrimPostfix", 4, 1 }, 6198251213Snp { "ERssIp4Pkt", 3, 1 }, 6199251213Snp { "ERssIp6Pkt", 2, 1 }, 6200251213Snp { "ERssTcpUdpPkt", 1, 1 }, 6201251213Snp { "ERssFceFipPkt", 0, 1 }, 6202251213Snp { NULL } 6203251213Snp}; 6204251213Snp 6205251213Snpstatic void 6206251213Snptp_la_show(struct sbuf *sb, uint64_t *p, int idx) 6207251213Snp{ 6208251213Snp 6209251213Snp field_desc_show(sb, *p, tp_la0); 6210251213Snp} 6211251213Snp 6212251213Snpstatic void 6213251213Snptp_la_show2(struct sbuf *sb, uint64_t *p, int idx) 6214251213Snp{ 6215251213Snp 6216251213Snp if (idx) 6217251213Snp sbuf_printf(sb, "\n"); 6218251213Snp field_desc_show(sb, p[0], tp_la0); 6219251213Snp if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) 6220251213Snp field_desc_show(sb, p[1], tp_la0); 6221251213Snp} 6222251213Snp 6223251213Snpstatic void 6224251213Snptp_la_show3(struct sbuf *sb, uint64_t *p, int idx) 6225251213Snp{ 6226251213Snp 6227251213Snp if (idx) 6228251213Snp sbuf_printf(sb, "\n"); 6229251213Snp field_desc_show(sb, p[0], tp_la0); 6230251213Snp if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) 6231251213Snp field_desc_show(sb, p[1], (p[0] & (1 << 17)) ? tp_la2 : tp_la1); 6232251213Snp} 6233251213Snp 6234228561Snpstatic int 6235251213Snpsysctl_tp_la(SYSCTL_HANDLER_ARGS) 6236251213Snp{ 6237251213Snp struct adapter *sc = arg1; 6238251213Snp struct sbuf *sb; 6239251213Snp uint64_t *buf, *p; 6240251213Snp int rc; 6241251213Snp u_int i, inc; 6242251213Snp void (*show_func)(struct sbuf *, uint64_t *, int); 6243251213Snp 6244251213Snp rc = sysctl_wire_old_buffer(req, 0); 6245251213Snp if (rc != 0) 6246251213Snp return (rc); 6247251213Snp 6248251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6249251213Snp if (sb == NULL) 6250251213Snp return (ENOMEM); 6251251213Snp 6252251213Snp buf = malloc(TPLA_SIZE * sizeof(uint64_t), M_CXGBE, M_ZERO | M_WAITOK); 6253251213Snp 6254251213Snp t4_tp_read_la(sc, buf, NULL); 6255251213Snp p = buf; 6256251213Snp 6257251213Snp switch (G_DBGLAMODE(t4_read_reg(sc, A_TP_DBG_LA_CONFIG))) { 6258251213Snp case 2: 6259251213Snp inc = 2; 6260251213Snp show_func = tp_la_show2; 6261251213Snp break; 6262251213Snp case 3: 6263251213Snp inc = 2; 6264251213Snp show_func = tp_la_show3; 6265251213Snp break; 6266251213Snp default: 6267251213Snp inc = 1; 6268251213Snp show_func = tp_la_show; 6269251213Snp } 6270251213Snp 6271251213Snp for (i = 0; i < TPLA_SIZE / inc; i++, p += inc) 6272251213Snp (*show_func)(sb, p, i); 6273251213Snp 6274251213Snp rc = sbuf_finish(sb); 6275251213Snp sbuf_delete(sb); 6276251213Snp free(buf, M_CXGBE); 6277251213Snp return (rc); 6278251213Snp} 6279251213Snp 6280251213Snpstatic int 6281228561Snpsysctl_tx_rate(SYSCTL_HANDLER_ARGS) 6282228561Snp{ 6283228561Snp struct adapter *sc = arg1; 6284228561Snp struct sbuf *sb; 6285228561Snp int rc; 6286228561Snp u64 nrate[NCHAN], orate[NCHAN]; 6287228561Snp 6288228561Snp rc = sysctl_wire_old_buffer(req, 0); 6289228561Snp if (rc != 0) 6290228561Snp return (rc); 6291228561Snp 6292228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6293228561Snp if (sb == NULL) 6294228561Snp return (ENOMEM); 6295228561Snp 6296228561Snp t4_get_chan_txrate(sc, nrate, orate); 6297228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 6298228561Snp "channel 3\n"); 6299228561Snp sbuf_printf(sb, "NIC B/s: %10ju %10ju %10ju %10ju\n", 6300228561Snp nrate[0], nrate[1], nrate[2], nrate[3]); 6301228561Snp sbuf_printf(sb, "Offload B/s: %10ju %10ju %10ju %10ju", 6302228561Snp orate[0], orate[1], orate[2], orate[3]); 6303228561Snp 6304228561Snp rc = sbuf_finish(sb); 6305228561Snp sbuf_delete(sb); 6306228561Snp 6307228561Snp return (rc); 6308228561Snp} 6309248925Snp 6310248925Snpstatic int 6311251213Snpsysctl_ulprx_la(SYSCTL_HANDLER_ARGS) 6312251213Snp{ 6313251213Snp struct adapter *sc = arg1; 6314251213Snp struct sbuf *sb; 6315251213Snp uint32_t *buf, *p; 6316251213Snp int rc, i; 6317251213Snp 6318251213Snp rc = sysctl_wire_old_buffer(req, 0); 6319251213Snp if (rc != 0) 6320251213Snp return (rc); 6321251213Snp 6322251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6323251213Snp if (sb == NULL) 6324251213Snp return (ENOMEM); 6325251213Snp 6326251213Snp buf = malloc(ULPRX_LA_SIZE * 8 * sizeof(uint32_t), M_CXGBE, 6327251213Snp M_ZERO | M_WAITOK); 6328251213Snp 6329251213Snp t4_ulprx_read_la(sc, buf); 6330251213Snp p = buf; 6331251213Snp 6332251213Snp sbuf_printf(sb, " Pcmd Type Message" 6333251213Snp " Data"); 6334251213Snp for (i = 0; i < ULPRX_LA_SIZE; i++, p += 8) { 6335251213Snp sbuf_printf(sb, "\n%08x%08x %4x %08x %08x%08x%08x%08x", 6336251213Snp p[1], p[0], p[2], p[3], p[7], p[6], p[5], p[4]); 6337251213Snp } 6338251213Snp 6339251213Snp rc = sbuf_finish(sb); 6340251213Snp sbuf_delete(sb); 6341251213Snp free(buf, M_CXGBE); 6342251213Snp return (rc); 6343251213Snp} 6344251213Snp 6345251213Snpstatic int 6346249392Snpsysctl_wcwr_stats(SYSCTL_HANDLER_ARGS) 6347248925Snp{ 6348248925Snp struct adapter *sc = arg1; 6349248925Snp struct sbuf *sb; 6350248925Snp int rc, v; 6351248925Snp 6352248925Snp rc = sysctl_wire_old_buffer(req, 0); 6353248925Snp if (rc != 0) 6354248925Snp return (rc); 6355248925Snp 6356248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6357248925Snp if (sb == NULL) 6358248925Snp return (ENOMEM); 6359248925Snp 6360248925Snp v = t4_read_reg(sc, A_SGE_STAT_CFG); 6361248925Snp if (G_STATSOURCE_T5(v) == 7) { 6362248925Snp if (G_STATMODE(v) == 0) { 6363249383Snp sbuf_printf(sb, "total %d, incomplete %d", 6364248925Snp t4_read_reg(sc, A_SGE_STAT_TOTAL), 6365248925Snp t4_read_reg(sc, A_SGE_STAT_MATCH)); 6366248925Snp } else if (G_STATMODE(v) == 1) { 6367249383Snp sbuf_printf(sb, "total %d, data overflow %d", 6368248925Snp t4_read_reg(sc, A_SGE_STAT_TOTAL), 6369248925Snp t4_read_reg(sc, A_SGE_STAT_MATCH)); 6370248925Snp } 6371248925Snp } 6372248925Snp rc = sbuf_finish(sb); 6373248925Snp sbuf_delete(sb); 6374248925Snp 6375248925Snp return (rc); 6376248925Snp} 6377231115Snp#endif 6378228561Snp 6379219286Snpstatic inline void 6380219286Snptxq_start(struct ifnet *ifp, struct sge_txq *txq) 6381219286Snp{ 6382219286Snp struct buf_ring *br; 6383219286Snp struct mbuf *m; 6384219286Snp 6385219286Snp TXQ_LOCK_ASSERT_OWNED(txq); 6386219286Snp 6387220873Snp br = txq->br; 6388219286Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 6389219286Snp if (m) 6390219286Snp t4_eth_tx(ifp, txq, m); 6391219286Snp} 6392219286Snp 6393219286Snpvoid 6394228561Snpt4_tx_callout(void *arg) 6395219286Snp{ 6396228561Snp struct sge_eq *eq = arg; 6397228561Snp struct adapter *sc; 6398219286Snp 6399228561Snp if (EQ_TRYLOCK(eq) == 0) 6400228561Snp goto reschedule; 6401228561Snp 6402228561Snp if (eq->flags & EQ_STALLED && !can_resume_tx(eq)) { 6403228561Snp EQ_UNLOCK(eq); 6404228561Snpreschedule: 6405228561Snp if (__predict_true(!(eq->flags && EQ_DOOMED))) 6406228561Snp callout_schedule(&eq->tx_callout, 1); 6407228561Snp return; 6408228561Snp } 6409228561Snp 6410228561Snp EQ_LOCK_ASSERT_OWNED(eq); 6411228561Snp 6412228561Snp if (__predict_true((eq->flags & EQ_DOOMED) == 0)) { 6413228561Snp 6414228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 6415228561Snp struct sge_txq *txq = arg; 6416228561Snp struct port_info *pi = txq->ifp->if_softc; 6417228561Snp 6418228561Snp sc = pi->adapter; 6419228561Snp } else { 6420228561Snp struct sge_wrq *wrq = arg; 6421228561Snp 6422228561Snp sc = wrq->adapter; 6423228561Snp } 6424228561Snp 6425228561Snp taskqueue_enqueue(sc->tq[eq->tx_chan], &eq->tx_task); 6426228561Snp } 6427228561Snp 6428228561Snp EQ_UNLOCK(eq); 6429228561Snp} 6430228561Snp 6431228561Snpvoid 6432228561Snpt4_tx_task(void *arg, int count) 6433228561Snp{ 6434228561Snp struct sge_eq *eq = arg; 6435228561Snp 6436228561Snp EQ_LOCK(eq); 6437228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 6438228561Snp struct sge_txq *txq = arg; 6439220649Snp txq_start(txq->ifp, txq); 6440228561Snp } else { 6441228561Snp struct sge_wrq *wrq = arg; 6442228561Snp t4_wrq_tx_locked(wrq->adapter, wrq, NULL); 6443228561Snp } 6444228561Snp EQ_UNLOCK(eq); 6445219286Snp} 6446219286Snp 6447221474Snpstatic uint32_t 6448221474Snpfconf_to_mode(uint32_t fconf) 6449221474Snp{ 6450221474Snp uint32_t mode; 6451221474Snp 6452221474Snp mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR | 6453221474Snp T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT; 6454221474Snp 6455221474Snp if (fconf & F_FRAGMENTATION) 6456221474Snp mode |= T4_FILTER_IP_FRAGMENT; 6457221474Snp 6458221474Snp if (fconf & F_MPSHITTYPE) 6459221474Snp mode |= T4_FILTER_MPS_HIT_TYPE; 6460221474Snp 6461221474Snp if (fconf & F_MACMATCH) 6462221474Snp mode |= T4_FILTER_MAC_IDX; 6463221474Snp 6464221474Snp if (fconf & F_ETHERTYPE) 6465221474Snp mode |= T4_FILTER_ETH_TYPE; 6466221474Snp 6467221474Snp if (fconf & F_PROTOCOL) 6468221474Snp mode |= T4_FILTER_IP_PROTO; 6469221474Snp 6470221474Snp if (fconf & F_TOS) 6471221474Snp mode |= T4_FILTER_IP_TOS; 6472221474Snp 6473221474Snp if (fconf & F_VLAN) 6474228561Snp mode |= T4_FILTER_VLAN; 6475221474Snp 6476221474Snp if (fconf & F_VNIC_ID) 6477228561Snp mode |= T4_FILTER_VNIC; 6478221474Snp 6479221474Snp if (fconf & F_PORT) 6480221474Snp mode |= T4_FILTER_PORT; 6481221474Snp 6482221474Snp if (fconf & F_FCOE) 6483221474Snp mode |= T4_FILTER_FCoE; 6484221474Snp 6485221474Snp return (mode); 6486221474Snp} 6487221474Snp 6488221474Snpstatic uint32_t 6489221474Snpmode_to_fconf(uint32_t mode) 6490221474Snp{ 6491221474Snp uint32_t fconf = 0; 6492221474Snp 6493221474Snp if (mode & T4_FILTER_IP_FRAGMENT) 6494221474Snp fconf |= F_FRAGMENTATION; 6495221474Snp 6496221474Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 6497221474Snp fconf |= F_MPSHITTYPE; 6498221474Snp 6499221474Snp if (mode & T4_FILTER_MAC_IDX) 6500221474Snp fconf |= F_MACMATCH; 6501221474Snp 6502221474Snp if (mode & T4_FILTER_ETH_TYPE) 6503221474Snp fconf |= F_ETHERTYPE; 6504221474Snp 6505221474Snp if (mode & T4_FILTER_IP_PROTO) 6506221474Snp fconf |= F_PROTOCOL; 6507221474Snp 6508221474Snp if (mode & T4_FILTER_IP_TOS) 6509221474Snp fconf |= F_TOS; 6510221474Snp 6511228561Snp if (mode & T4_FILTER_VLAN) 6512221474Snp fconf |= F_VLAN; 6513221474Snp 6514228561Snp if (mode & T4_FILTER_VNIC) 6515221474Snp fconf |= F_VNIC_ID; 6516221474Snp 6517221474Snp if (mode & T4_FILTER_PORT) 6518221474Snp fconf |= F_PORT; 6519221474Snp 6520221474Snp if (mode & T4_FILTER_FCoE) 6521221474Snp fconf |= F_FCOE; 6522221474Snp 6523221474Snp return (fconf); 6524221474Snp} 6525221474Snp 6526221474Snpstatic uint32_t 6527221474Snpfspec_to_fconf(struct t4_filter_specification *fs) 6528221474Snp{ 6529221474Snp uint32_t fconf = 0; 6530221474Snp 6531221474Snp if (fs->val.frag || fs->mask.frag) 6532221474Snp fconf |= F_FRAGMENTATION; 6533221474Snp 6534221474Snp if (fs->val.matchtype || fs->mask.matchtype) 6535221474Snp fconf |= F_MPSHITTYPE; 6536221474Snp 6537221474Snp if (fs->val.macidx || fs->mask.macidx) 6538221474Snp fconf |= F_MACMATCH; 6539221474Snp 6540221474Snp if (fs->val.ethtype || fs->mask.ethtype) 6541221474Snp fconf |= F_ETHERTYPE; 6542221474Snp 6543221474Snp if (fs->val.proto || fs->mask.proto) 6544221474Snp fconf |= F_PROTOCOL; 6545221474Snp 6546221474Snp if (fs->val.tos || fs->mask.tos) 6547221474Snp fconf |= F_TOS; 6548221474Snp 6549228561Snp if (fs->val.vlan_vld || fs->mask.vlan_vld) 6550221474Snp fconf |= F_VLAN; 6551221474Snp 6552228561Snp if (fs->val.vnic_vld || fs->mask.vnic_vld) 6553221474Snp fconf |= F_VNIC_ID; 6554221474Snp 6555221474Snp if (fs->val.iport || fs->mask.iport) 6556221474Snp fconf |= F_PORT; 6557221474Snp 6558221474Snp if (fs->val.fcoe || fs->mask.fcoe) 6559221474Snp fconf |= F_FCOE; 6560221474Snp 6561221474Snp return (fconf); 6562221474Snp} 6563221474Snp 6564221474Snpstatic int 6565221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode) 6566221474Snp{ 6567245274Snp int rc; 6568221474Snp uint32_t fconf; 6569221474Snp 6570245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 6571245274Snp "t4getfm"); 6572245274Snp if (rc) 6573245274Snp return (rc); 6574245274Snp 6575221474Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1, 6576221474Snp A_TP_VLAN_PRI_MAP); 6577221474Snp 6578252705Snp if (sc->params.tp.vlan_pri_map != fconf) { 6579228561Snp log(LOG_WARNING, "%s: cached filter mode out of sync %x %x.\n", 6580252705Snp device_get_nameunit(sc->dev), sc->params.tp.vlan_pri_map, 6581252705Snp fconf); 6582252705Snp sc->params.tp.vlan_pri_map = fconf; 6583228561Snp } 6584221474Snp 6585252705Snp *mode = fconf_to_mode(sc->params.tp.vlan_pri_map); 6586228561Snp 6587245274Snp end_synchronized_op(sc, LOCK_HELD); 6588221474Snp return (0); 6589221474Snp} 6590221474Snp 6591221474Snpstatic int 6592221474Snpset_filter_mode(struct adapter *sc, uint32_t mode) 6593221474Snp{ 6594221474Snp uint32_t fconf; 6595221474Snp int rc; 6596221474Snp 6597221474Snp fconf = mode_to_fconf(mode); 6598221474Snp 6599245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 6600245274Snp "t4setfm"); 6601245274Snp if (rc) 6602245274Snp return (rc); 6603221474Snp 6604221474Snp if (sc->tids.ftids_in_use > 0) { 6605221474Snp rc = EBUSY; 6606221474Snp goto done; 6607221474Snp } 6608221474Snp 6609237263Snp#ifdef TCP_OFFLOAD 6610228561Snp if (sc->offload_map) { 6611228561Snp rc = EBUSY; 6612228561Snp goto done; 6613228561Snp } 6614228561Snp#endif 6615228561Snp 6616228561Snp#ifdef notyet 6617221474Snp rc = -t4_set_filter_mode(sc, fconf); 6618228561Snp if (rc == 0) 6619228561Snp sc->filter_mode = fconf; 6620228561Snp#else 6621228561Snp rc = ENOTSUP; 6622228561Snp#endif 6623228561Snp 6624221474Snpdone: 6625245274Snp end_synchronized_op(sc, LOCK_HELD); 6626221474Snp return (rc); 6627221474Snp} 6628221474Snp 6629222552Snpstatic inline uint64_t 6630222552Snpget_filter_hits(struct adapter *sc, uint32_t fid) 6631222552Snp{ 6632248925Snp uint32_t mw_base, off, tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 6633222552Snp uint64_t hits; 6634222552Snp 6635248925Snp memwin_info(sc, 0, &mw_base, NULL); 6636248925Snp off = position_memwin(sc, 0, 6637222552Snp tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE); 6638251358Snp if (is_t4(sc)) { 6639251358Snp hits = t4_read_reg64(sc, mw_base + off + 16); 6640251358Snp hits = be64toh(hits); 6641251358Snp } else { 6642251358Snp hits = t4_read_reg(sc, mw_base + off + 24); 6643251358Snp hits = be32toh(hits); 6644251358Snp } 6645222552Snp 6646251358Snp return (hits); 6647222552Snp} 6648222552Snp 6649221474Snpstatic int 6650221474Snpget_filter(struct adapter *sc, struct t4_filter *t) 6651221474Snp{ 6652245274Snp int i, rc, nfilters = sc->tids.nftids; 6653221474Snp struct filter_entry *f; 6654221474Snp 6655245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 6656245274Snp "t4getf"); 6657245274Snp if (rc) 6658245274Snp return (rc); 6659221474Snp 6660221474Snp if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL || 6661221474Snp t->idx >= nfilters) { 6662221474Snp t->idx = 0xffffffff; 6663245274Snp goto done; 6664221474Snp } 6665221474Snp 6666221474Snp f = &sc->tids.ftid_tab[t->idx]; 6667221474Snp for (i = t->idx; i < nfilters; i++, f++) { 6668221474Snp if (f->valid) { 6669221474Snp t->idx = i; 6670222509Snp t->l2tidx = f->l2t ? f->l2t->idx : 0; 6671222509Snp t->smtidx = f->smtidx; 6672222552Snp if (f->fs.hitcnts) 6673222552Snp t->hits = get_filter_hits(sc, t->idx); 6674222552Snp else 6675222552Snp t->hits = UINT64_MAX; 6676221474Snp t->fs = f->fs; 6677221474Snp 6678245274Snp goto done; 6679221474Snp } 6680221474Snp } 6681221474Snp 6682221474Snp t->idx = 0xffffffff; 6683245274Snpdone: 6684245274Snp end_synchronized_op(sc, LOCK_HELD); 6685221474Snp return (0); 6686221474Snp} 6687221474Snp 6688221474Snpstatic int 6689221474Snpset_filter(struct adapter *sc, struct t4_filter *t) 6690221474Snp{ 6691221474Snp unsigned int nfilters, nports; 6692221474Snp struct filter_entry *f; 6693245274Snp int i, rc; 6694221474Snp 6695245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setf"); 6696245274Snp if (rc) 6697245274Snp return (rc); 6698221474Snp 6699221474Snp nfilters = sc->tids.nftids; 6700221474Snp nports = sc->params.nports; 6701221474Snp 6702245274Snp if (nfilters == 0) { 6703245274Snp rc = ENOTSUP; 6704245274Snp goto done; 6705245274Snp } 6706221474Snp 6707245274Snp if (!(sc->flags & FULL_INIT_DONE)) { 6708245274Snp rc = EAGAIN; 6709245274Snp goto done; 6710245274Snp } 6711221474Snp 6712245274Snp if (t->idx >= nfilters) { 6713245274Snp rc = EINVAL; 6714245274Snp goto done; 6715245274Snp } 6716221474Snp 6717221474Snp /* Validate against the global filter mode */ 6718252705Snp if ((sc->params.tp.vlan_pri_map | fspec_to_fconf(&t->fs)) != 6719252705Snp sc->params.tp.vlan_pri_map) { 6720245274Snp rc = E2BIG; 6721245274Snp goto done; 6722245274Snp } 6723221474Snp 6724245274Snp if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) { 6725245274Snp rc = EINVAL; 6726245274Snp goto done; 6727245274Snp } 6728221474Snp 6729245274Snp if (t->fs.val.iport >= nports) { 6730245274Snp rc = EINVAL; 6731245274Snp goto done; 6732245274Snp } 6733221474Snp 6734221474Snp /* Can't specify an iq if not steering to it */ 6735245274Snp if (!t->fs.dirsteer && t->fs.iq) { 6736245274Snp rc = EINVAL; 6737245274Snp goto done; 6738245274Snp } 6739221474Snp 6740221474Snp /* IPv6 filter idx must be 4 aligned */ 6741221474Snp if (t->fs.type == 1 && 6742245274Snp ((t->idx & 0x3) || t->idx + 4 >= nfilters)) { 6743245274Snp rc = EINVAL; 6744245274Snp goto done; 6745245274Snp } 6746221474Snp 6747221474Snp if (sc->tids.ftid_tab == NULL) { 6748221474Snp KASSERT(sc->tids.ftids_in_use == 0, 6749221474Snp ("%s: no memory allocated but filters_in_use > 0", 6750221474Snp __func__)); 6751221474Snp 6752221474Snp sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) * 6753221474Snp nfilters, M_CXGBE, M_NOWAIT | M_ZERO); 6754245274Snp if (sc->tids.ftid_tab == NULL) { 6755245274Snp rc = ENOMEM; 6756245274Snp goto done; 6757245274Snp } 6758245274Snp mtx_init(&sc->tids.ftid_lock, "T4 filters", 0, MTX_DEF); 6759221474Snp } 6760221474Snp 6761221474Snp for (i = 0; i < 4; i++) { 6762221474Snp f = &sc->tids.ftid_tab[t->idx + i]; 6763221474Snp 6764245274Snp if (f->pending || f->valid) { 6765245274Snp rc = EBUSY; 6766245274Snp goto done; 6767245274Snp } 6768245274Snp if (f->locked) { 6769245274Snp rc = EPERM; 6770245274Snp goto done; 6771245274Snp } 6772221474Snp 6773221474Snp if (t->fs.type == 0) 6774221474Snp break; 6775221474Snp } 6776221474Snp 6777221474Snp f = &sc->tids.ftid_tab[t->idx]; 6778221474Snp f->fs = t->fs; 6779221474Snp 6780245274Snp rc = set_filter_wr(sc, t->idx); 6781245274Snpdone: 6782245274Snp end_synchronized_op(sc, 0); 6783245274Snp 6784245274Snp if (rc == 0) { 6785245274Snp mtx_lock(&sc->tids.ftid_lock); 6786245274Snp for (;;) { 6787245274Snp if (f->pending == 0) { 6788245274Snp rc = f->valid ? 0 : EIO; 6789245274Snp break; 6790245274Snp } 6791245274Snp 6792245274Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 6793245274Snp PCATCH, "t4setfw", 0)) { 6794245274Snp rc = EINPROGRESS; 6795245274Snp break; 6796245274Snp } 6797245274Snp } 6798245274Snp mtx_unlock(&sc->tids.ftid_lock); 6799245274Snp } 6800245274Snp return (rc); 6801221474Snp} 6802221474Snp 6803221474Snpstatic int 6804221474Snpdel_filter(struct adapter *sc, struct t4_filter *t) 6805221474Snp{ 6806221474Snp unsigned int nfilters; 6807221474Snp struct filter_entry *f; 6808245274Snp int rc; 6809221474Snp 6810245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4delf"); 6811245274Snp if (rc) 6812245274Snp return (rc); 6813221474Snp 6814221474Snp nfilters = sc->tids.nftids; 6815221474Snp 6816245274Snp if (nfilters == 0) { 6817245274Snp rc = ENOTSUP; 6818245274Snp goto done; 6819245274Snp } 6820221474Snp 6821221474Snp if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 || 6822245274Snp t->idx >= nfilters) { 6823245274Snp rc = EINVAL; 6824245274Snp goto done; 6825245274Snp } 6826221474Snp 6827245274Snp if (!(sc->flags & FULL_INIT_DONE)) { 6828245274Snp rc = EAGAIN; 6829245274Snp goto done; 6830245274Snp } 6831221474Snp 6832221474Snp f = &sc->tids.ftid_tab[t->idx]; 6833221474Snp 6834245274Snp if (f->pending) { 6835245274Snp rc = EBUSY; 6836245274Snp goto done; 6837245274Snp } 6838245274Snp if (f->locked) { 6839245274Snp rc = EPERM; 6840245274Snp goto done; 6841245274Snp } 6842221474Snp 6843221474Snp if (f->valid) { 6844221474Snp t->fs = f->fs; /* extra info for the caller */ 6845245274Snp rc = del_filter_wr(sc, t->idx); 6846221474Snp } 6847221474Snp 6848245274Snpdone: 6849245274Snp end_synchronized_op(sc, 0); 6850245274Snp 6851245274Snp if (rc == 0) { 6852245274Snp mtx_lock(&sc->tids.ftid_lock); 6853245274Snp for (;;) { 6854245274Snp if (f->pending == 0) { 6855245274Snp rc = f->valid ? EIO : 0; 6856245274Snp break; 6857245274Snp } 6858245274Snp 6859245274Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 6860245274Snp PCATCH, "t4delfw", 0)) { 6861245274Snp rc = EINPROGRESS; 6862245274Snp break; 6863245274Snp } 6864245274Snp } 6865245274Snp mtx_unlock(&sc->tids.ftid_lock); 6866245274Snp } 6867245274Snp 6868245274Snp return (rc); 6869221474Snp} 6870221474Snp 6871221474Snpstatic void 6872222509Snpclear_filter(struct filter_entry *f) 6873221474Snp{ 6874222509Snp if (f->l2t) 6875222509Snp t4_l2t_release(f->l2t); 6876222509Snp 6877221474Snp bzero(f, sizeof (*f)); 6878221474Snp} 6879221474Snp 6880221474Snpstatic int 6881221474Snpset_filter_wr(struct adapter *sc, int fidx) 6882221474Snp{ 6883221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 6884237263Snp struct wrqe *wr; 6885221474Snp struct fw_filter_wr *fwr; 6886221474Snp unsigned int ftid; 6887221474Snp 6888245274Snp ASSERT_SYNCHRONIZED_OP(sc); 6889221474Snp 6890222509Snp if (f->fs.newdmac || f->fs.newvlan) { 6891222509Snp /* This filter needs an L2T entry; allocate one. */ 6892222509Snp f->l2t = t4_l2t_alloc_switching(sc->l2t); 6893222509Snp if (f->l2t == NULL) 6894222509Snp return (EAGAIN); 6895222509Snp if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport, 6896222509Snp f->fs.dmac)) { 6897222509Snp t4_l2t_release(f->l2t); 6898222509Snp f->l2t = NULL; 6899222509Snp return (ENOMEM); 6900222509Snp } 6901222509Snp } 6902221474Snp 6903221474Snp ftid = sc->tids.ftid_base + fidx; 6904221474Snp 6905237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 6906237263Snp if (wr == NULL) 6907221474Snp return (ENOMEM); 6908221474Snp 6909237263Snp fwr = wrtod(wr); 6910221474Snp bzero(fwr, sizeof (*fwr)); 6911221474Snp 6912221474Snp fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR)); 6913221474Snp fwr->len16_pkd = htobe32(FW_LEN16(*fwr)); 6914221474Snp fwr->tid_to_iq = 6915221474Snp htobe32(V_FW_FILTER_WR_TID(ftid) | 6916221474Snp V_FW_FILTER_WR_RQTYPE(f->fs.type) | 6917221474Snp V_FW_FILTER_WR_NOREPLY(0) | 6918221474Snp V_FW_FILTER_WR_IQ(f->fs.iq)); 6919221474Snp fwr->del_filter_to_l2tix = 6920221474Snp htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) | 6921221474Snp V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) | 6922221474Snp V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) | 6923221474Snp V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) | 6924221474Snp V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) | 6925221474Snp V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) | 6926221474Snp V_FW_FILTER_WR_DMAC(f->fs.newdmac) | 6927221474Snp V_FW_FILTER_WR_SMAC(f->fs.newsmac) | 6928221474Snp V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT || 6929221474Snp f->fs.newvlan == VLAN_REWRITE) | 6930221474Snp V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE || 6931221474Snp f->fs.newvlan == VLAN_REWRITE) | 6932221474Snp V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) | 6933221474Snp V_FW_FILTER_WR_TXCHAN(f->fs.eport) | 6934221474Snp V_FW_FILTER_WR_PRIO(f->fs.prio) | 6935222509Snp V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0)); 6936221474Snp fwr->ethtype = htobe16(f->fs.val.ethtype); 6937221474Snp fwr->ethtypem = htobe16(f->fs.mask.ethtype); 6938221474Snp fwr->frag_to_ovlan_vldm = 6939221474Snp (V_FW_FILTER_WR_FRAG(f->fs.val.frag) | 6940221474Snp V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) | 6941228561Snp V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) | 6942228561Snp V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.vnic_vld) | 6943228561Snp V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) | 6944228561Snp V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.vnic_vld)); 6945221474Snp fwr->smac_sel = 0; 6946221474Snp fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) | 6947228561Snp V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id)); 6948221474Snp fwr->maci_to_matchtypem = 6949221474Snp htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) | 6950221474Snp V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) | 6951221474Snp V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) | 6952221474Snp V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) | 6953221474Snp V_FW_FILTER_WR_PORT(f->fs.val.iport) | 6954221474Snp V_FW_FILTER_WR_PORTM(f->fs.mask.iport) | 6955221474Snp V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) | 6956221474Snp V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype)); 6957221474Snp fwr->ptcl = f->fs.val.proto; 6958221474Snp fwr->ptclm = f->fs.mask.proto; 6959221474Snp fwr->ttyp = f->fs.val.tos; 6960221474Snp fwr->ttypm = f->fs.mask.tos; 6961228561Snp fwr->ivlan = htobe16(f->fs.val.vlan); 6962228561Snp fwr->ivlanm = htobe16(f->fs.mask.vlan); 6963228561Snp fwr->ovlan = htobe16(f->fs.val.vnic); 6964228561Snp fwr->ovlanm = htobe16(f->fs.mask.vnic); 6965221474Snp bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip)); 6966221474Snp bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm)); 6967221474Snp bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip)); 6968221474Snp bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm)); 6969221474Snp fwr->lp = htobe16(f->fs.val.dport); 6970221474Snp fwr->lpm = htobe16(f->fs.mask.dport); 6971221474Snp fwr->fp = htobe16(f->fs.val.sport); 6972221474Snp fwr->fpm = htobe16(f->fs.mask.sport); 6973221474Snp if (f->fs.newsmac) 6974221474Snp bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma)); 6975221474Snp 6976221474Snp f->pending = 1; 6977221474Snp sc->tids.ftids_in_use++; 6978228561Snp 6979237263Snp t4_wrq_tx(sc, wr); 6980228561Snp return (0); 6981221474Snp} 6982221474Snp 6983221474Snpstatic int 6984221474Snpdel_filter_wr(struct adapter *sc, int fidx) 6985221474Snp{ 6986221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 6987237263Snp struct wrqe *wr; 6988221474Snp struct fw_filter_wr *fwr; 6989228561Snp unsigned int ftid; 6990221474Snp 6991221474Snp ftid = sc->tids.ftid_base + fidx; 6992221474Snp 6993237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 6994237263Snp if (wr == NULL) 6995221474Snp return (ENOMEM); 6996237263Snp fwr = wrtod(wr); 6997221474Snp bzero(fwr, sizeof (*fwr)); 6998221474Snp 6999228561Snp t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id); 7000221474Snp 7001221474Snp f->pending = 1; 7002237263Snp t4_wrq_tx(sc, wr); 7003228561Snp return (0); 7004221474Snp} 7005221474Snp 7006239338Snpint 7007239338Snpt4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 7008221474Snp{ 7009228561Snp struct adapter *sc = iq->adapter; 7010228561Snp const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1); 7011221474Snp unsigned int idx = GET_TID(rpl); 7012221474Snp 7013228561Snp KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__, 7014228561Snp rss->opcode)); 7015228561Snp 7016221474Snp if (idx >= sc->tids.ftid_base && 7017221474Snp (idx -= sc->tids.ftid_base) < sc->tids.nftids) { 7018221474Snp unsigned int rc = G_COOKIE(rpl->cookie); 7019221474Snp struct filter_entry *f = &sc->tids.ftid_tab[idx]; 7020221474Snp 7021245274Snp mtx_lock(&sc->tids.ftid_lock); 7022228561Snp if (rc == FW_FILTER_WR_FLT_ADDED) { 7023245274Snp KASSERT(f->pending, ("%s: filter[%u] isn't pending.", 7024245274Snp __func__, idx)); 7025221474Snp f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff; 7026221474Snp f->pending = 0; /* asynchronous setup completed */ 7027221474Snp f->valid = 1; 7028231120Snp } else { 7029231120Snp if (rc != FW_FILTER_WR_FLT_DELETED) { 7030231120Snp /* Add or delete failed, display an error */ 7031231120Snp log(LOG_ERR, 7032231120Snp "filter %u setup failed with error %u\n", 7033231120Snp idx, rc); 7034231120Snp } 7035228561Snp 7036231120Snp clear_filter(f); 7037231120Snp sc->tids.ftids_in_use--; 7038221474Snp } 7039245274Snp wakeup(&sc->tids.ftid_tab); 7040245274Snp mtx_unlock(&sc->tids.ftid_lock); 7041221474Snp } 7042228561Snp 7043228561Snp return (0); 7044221474Snp} 7045221474Snp 7046222973Snpstatic int 7047222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt) 7048222973Snp{ 7049245274Snp int rc; 7050222973Snp 7051222973Snp if (cntxt->cid > M_CTXTQID) 7052245274Snp return (EINVAL); 7053222973Snp 7054222973Snp if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS && 7055222973Snp cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM) 7056245274Snp return (EINVAL); 7057222973Snp 7058246575Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ctxt"); 7059246575Snp if (rc) 7060246575Snp return (rc); 7061246575Snp 7062222973Snp if (sc->flags & FW_OK) { 7063246575Snp rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id, 7064246575Snp &cntxt->data[0]); 7065246575Snp if (rc == 0) 7066246575Snp goto done; 7067222973Snp } 7068222973Snp 7069245274Snp /* 7070245274Snp * Read via firmware failed or wasn't even attempted. Read directly via 7071245274Snp * the backdoor. 7072245274Snp */ 7073246575Snp rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id, &cntxt->data[0]); 7074246575Snpdone: 7075246575Snp end_synchronized_op(sc, 0); 7076245274Snp return (rc); 7077245274Snp} 7078222973Snp 7079245274Snpstatic int 7080245274Snpload_fw(struct adapter *sc, struct t4_data *fw) 7081245274Snp{ 7082245274Snp int rc; 7083245274Snp uint8_t *fw_data; 7084245274Snp 7085245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ldfw"); 7086245274Snp if (rc) 7087245274Snp return (rc); 7088245274Snp 7089245274Snp if (sc->flags & FULL_INIT_DONE) { 7090245274Snp rc = EBUSY; 7091245274Snp goto done; 7092222973Snp } 7093222973Snp 7094245274Snp fw_data = malloc(fw->len, M_CXGBE, M_WAITOK); 7095245274Snp if (fw_data == NULL) { 7096245274Snp rc = ENOMEM; 7097245274Snp goto done; 7098245274Snp } 7099245274Snp 7100245274Snp rc = copyin(fw->data, fw_data, fw->len); 7101245274Snp if (rc == 0) 7102245274Snp rc = -t4_load_fw(sc, fw_data, fw->len); 7103245274Snp 7104245274Snp free(fw_data, M_CXGBE); 7105245274Snpdone: 7106245274Snp end_synchronized_op(sc, 0); 7107222973Snp return (rc); 7108222973Snp} 7109222973Snp 7110228561Snpstatic int 7111248925Snpread_card_mem(struct adapter *sc, int win, struct t4_mem_range *mr) 7112228561Snp{ 7113248925Snp uint32_t addr, off, remaining, i, n; 7114228561Snp uint32_t *buf, *b; 7115248925Snp uint32_t mw_base, mw_aperture; 7116228561Snp int rc; 7117248925Snp uint8_t *dst; 7118228561Snp 7119248925Snp rc = validate_mem_range(sc, mr->addr, mr->len); 7120248925Snp if (rc != 0) 7121248925Snp return (rc); 7122228561Snp 7123248925Snp memwin_info(sc, win, &mw_base, &mw_aperture); 7124248925Snp buf = b = malloc(min(mr->len, mw_aperture), M_CXGBE, M_WAITOK); 7125248925Snp addr = mr->addr; 7126228561Snp remaining = mr->len; 7127248925Snp dst = (void *)mr->data; 7128228561Snp 7129228561Snp while (remaining) { 7130248925Snp off = position_memwin(sc, win, addr); 7131228561Snp 7132228561Snp /* number of bytes that we'll copy in the inner loop */ 7133248925Snp n = min(remaining, mw_aperture - off); 7134248925Snp for (i = 0; i < n; i += 4) 7135248925Snp *b++ = t4_read_reg(sc, mw_base + off + i); 7136228561Snp 7137248925Snp rc = copyout(buf, dst, n); 7138248925Snp if (rc != 0) 7139248925Snp break; 7140228561Snp 7141248925Snp b = buf; 7142248925Snp dst += n; 7143248925Snp remaining -= n; 7144248925Snp addr += n; 7145228561Snp } 7146228561Snp 7147228561Snp free(buf, M_CXGBE); 7148228561Snp return (rc); 7149228561Snp} 7150228561Snp 7151241399Snpstatic int 7152241399Snpread_i2c(struct adapter *sc, struct t4_i2c_data *i2cd) 7153241399Snp{ 7154241399Snp int rc; 7155241399Snp 7156241399Snp if (i2cd->len == 0 || i2cd->port_id >= sc->params.nports) 7157241399Snp return (EINVAL); 7158241399Snp 7159241399Snp if (i2cd->len > 1) { 7160241399Snp /* XXX: need fw support for longer reads in one go */ 7161241399Snp return (ENOTSUP); 7162241399Snp } 7163241399Snp 7164245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4i2crd"); 7165245274Snp if (rc) 7166245274Snp return (rc); 7167241399Snp rc = -t4_i2c_rd(sc, sc->mbox, i2cd->port_id, i2cd->dev_addr, 7168241399Snp i2cd->offset, &i2cd->data[0]); 7169245274Snp end_synchronized_op(sc, 0); 7170241399Snp 7171241399Snp return (rc); 7172241399Snp} 7173241399Snp 7174218792Snpint 7175218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap) 7176218792Snp{ 7177222102Snp int i; 7178218792Snp 7179222102Snp return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0); 7180218792Snp} 7181218792Snp 7182218792Snpint 7183218792Snpt4_os_pci_save_state(struct adapter *sc) 7184218792Snp{ 7185218792Snp device_t dev; 7186218792Snp struct pci_devinfo *dinfo; 7187218792Snp 7188218792Snp dev = sc->dev; 7189218792Snp dinfo = device_get_ivars(dev); 7190218792Snp 7191218792Snp pci_cfg_save(dev, dinfo, 0); 7192218792Snp return (0); 7193218792Snp} 7194218792Snp 7195218792Snpint 7196218792Snpt4_os_pci_restore_state(struct adapter *sc) 7197218792Snp{ 7198218792Snp device_t dev; 7199218792Snp struct pci_devinfo *dinfo; 7200218792Snp 7201218792Snp dev = sc->dev; 7202218792Snp dinfo = device_get_ivars(dev); 7203218792Snp 7204218792Snp pci_cfg_restore(dev, dinfo); 7205218792Snp return (0); 7206218792Snp} 7207219299Snp 7208218792Snpvoid 7209218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx) 7210218792Snp{ 7211218792Snp struct port_info *pi = sc->port[idx]; 7212218792Snp static const char *mod_str[] = { 7213220232Snp NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM" 7214218792Snp }; 7215218792Snp 7216218792Snp if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 7217218792Snp if_printf(pi->ifp, "transceiver unplugged.\n"); 7218220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) 7219220232Snp if_printf(pi->ifp, "unknown transceiver inserted.\n"); 7220220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) 7221220232Snp if_printf(pi->ifp, "unsupported transceiver inserted.\n"); 7222240452Snp else if (pi->mod_type > 0 && pi->mod_type < nitems(mod_str)) { 7223218792Snp if_printf(pi->ifp, "%s transceiver inserted.\n", 7224218792Snp mod_str[pi->mod_type]); 7225219299Snp } else { 7226219299Snp if_printf(pi->ifp, "transceiver (type %d) inserted.\n", 7227219299Snp pi->mod_type); 7228219299Snp } 7229218792Snp} 7230218792Snp 7231218792Snpvoid 7232252747Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat, int reason) 7233218792Snp{ 7234218792Snp struct port_info *pi = sc->port[idx]; 7235218792Snp struct ifnet *ifp = pi->ifp; 7236218792Snp 7237218792Snp if (link_stat) { 7238252747Snp pi->linkdnrc = -1; 7239218792Snp ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed); 7240218792Snp if_link_state_change(ifp, LINK_STATE_UP); 7241252747Snp } else { 7242252747Snp if (reason >= 0) 7243252747Snp pi->linkdnrc = reason; 7244218792Snp if_link_state_change(ifp, LINK_STATE_DOWN); 7245252747Snp } 7246218792Snp} 7247218792Snp 7248228561Snpvoid 7249228561Snpt4_iterate(void (*func)(struct adapter *, void *), void *arg) 7250228561Snp{ 7251228561Snp struct adapter *sc; 7252228561Snp 7253228561Snp mtx_lock(&t4_list_lock); 7254228561Snp SLIST_FOREACH(sc, &t4_list, link) { 7255228561Snp /* 7256228561Snp * func should not make any assumptions about what state sc is 7257228561Snp * in - the only guarantee is that sc->sc_lock is a valid lock. 7258228561Snp */ 7259228561Snp func(sc, arg); 7260228561Snp } 7261228561Snp mtx_unlock(&t4_list_lock); 7262228561Snp} 7263228561Snp 7264218792Snpstatic int 7265218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td) 7266218792Snp{ 7267218792Snp return (0); 7268218792Snp} 7269218792Snp 7270218792Snpstatic int 7271218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td) 7272218792Snp{ 7273218792Snp return (0); 7274218792Snp} 7275218792Snp 7276218792Snpstatic int 7277218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag, 7278218792Snp struct thread *td) 7279218792Snp{ 7280218792Snp int rc; 7281218792Snp struct adapter *sc = dev->si_drv1; 7282218792Snp 7283218792Snp rc = priv_check(td, PRIV_DRIVER); 7284218792Snp if (rc != 0) 7285218792Snp return (rc); 7286218792Snp 7287218792Snp switch (cmd) { 7288220410Snp case CHELSIO_T4_GETREG: { 7289220410Snp struct t4_reg *edata = (struct t4_reg *)data; 7290220410Snp 7291218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 7292218792Snp return (EFAULT); 7293220410Snp 7294220410Snp if (edata->size == 4) 7295220410Snp edata->val = t4_read_reg(sc, edata->addr); 7296220410Snp else if (edata->size == 8) 7297220410Snp edata->val = t4_read_reg64(sc, edata->addr); 7298220410Snp else 7299220410Snp return (EINVAL); 7300220410Snp 7301218792Snp break; 7302218792Snp } 7303220410Snp case CHELSIO_T4_SETREG: { 7304220410Snp struct t4_reg *edata = (struct t4_reg *)data; 7305220410Snp 7306218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 7307218792Snp return (EFAULT); 7308220410Snp 7309220410Snp if (edata->size == 4) { 7310220410Snp if (edata->val & 0xffffffff00000000) 7311220410Snp return (EINVAL); 7312220410Snp t4_write_reg(sc, edata->addr, (uint32_t) edata->val); 7313220410Snp } else if (edata->size == 8) 7314220410Snp t4_write_reg64(sc, edata->addr, edata->val); 7315220410Snp else 7316220410Snp return (EINVAL); 7317218792Snp break; 7318218792Snp } 7319218792Snp case CHELSIO_T4_REGDUMP: { 7320218792Snp struct t4_regdump *regs = (struct t4_regdump *)data; 7321248925Snp int reglen = is_t4(sc) ? T4_REGDUMP_SIZE : T5_REGDUMP_SIZE; 7322218792Snp uint8_t *buf; 7323218792Snp 7324218792Snp if (regs->len < reglen) { 7325218792Snp regs->len = reglen; /* hint to the caller */ 7326218792Snp return (ENOBUFS); 7327218792Snp } 7328218792Snp 7329218792Snp regs->len = reglen; 7330218792Snp buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO); 7331218792Snp t4_get_regs(sc, regs, buf); 7332218792Snp rc = copyout(buf, regs->data, reglen); 7333218792Snp free(buf, M_CXGBE); 7334218792Snp break; 7335218792Snp } 7336221474Snp case CHELSIO_T4_GET_FILTER_MODE: 7337221474Snp rc = get_filter_mode(sc, (uint32_t *)data); 7338221474Snp break; 7339221474Snp case CHELSIO_T4_SET_FILTER_MODE: 7340221474Snp rc = set_filter_mode(sc, *(uint32_t *)data); 7341221474Snp break; 7342221474Snp case CHELSIO_T4_GET_FILTER: 7343221474Snp rc = get_filter(sc, (struct t4_filter *)data); 7344221474Snp break; 7345221474Snp case CHELSIO_T4_SET_FILTER: 7346221474Snp rc = set_filter(sc, (struct t4_filter *)data); 7347221474Snp break; 7348221474Snp case CHELSIO_T4_DEL_FILTER: 7349221474Snp rc = del_filter(sc, (struct t4_filter *)data); 7350221474Snp break; 7351222973Snp case CHELSIO_T4_GET_SGE_CONTEXT: 7352222973Snp rc = get_sge_context(sc, (struct t4_sge_context *)data); 7353222973Snp break; 7354245274Snp case CHELSIO_T4_LOAD_FW: 7355245274Snp rc = load_fw(sc, (struct t4_data *)data); 7356228561Snp break; 7357228561Snp case CHELSIO_T4_GET_MEM: 7358248925Snp rc = read_card_mem(sc, 2, (struct t4_mem_range *)data); 7359228561Snp break; 7360241399Snp case CHELSIO_T4_GET_I2C: 7361241399Snp rc = read_i2c(sc, (struct t4_i2c_data *)data); 7362241399Snp break; 7363241409Snp case CHELSIO_T4_CLEAR_STATS: { 7364245518Snp int i; 7365241409Snp u_int port_id = *(uint32_t *)data; 7366245518Snp struct port_info *pi; 7367241409Snp 7368241409Snp if (port_id >= sc->params.nports) 7369241409Snp return (EINVAL); 7370241409Snp 7371245518Snp /* MAC stats */ 7372241409Snp t4_clr_port_stats(sc, port_id); 7373245518Snp 7374245518Snp pi = sc->port[port_id]; 7375245518Snp if (pi->flags & PORT_INIT_DONE) { 7376245518Snp struct sge_rxq *rxq; 7377245518Snp struct sge_txq *txq; 7378245518Snp struct sge_wrq *wrq; 7379245518Snp 7380245518Snp for_each_rxq(pi, i, rxq) { 7381245518Snp#if defined(INET) || defined(INET6) 7382245518Snp rxq->lro.lro_queued = 0; 7383245518Snp rxq->lro.lro_flushed = 0; 7384245518Snp#endif 7385245518Snp rxq->rxcsum = 0; 7386245518Snp rxq->vlan_extraction = 0; 7387245518Snp } 7388245518Snp 7389245518Snp for_each_txq(pi, i, txq) { 7390245518Snp txq->txcsum = 0; 7391245518Snp txq->tso_wrs = 0; 7392245518Snp txq->vlan_insertion = 0; 7393245518Snp txq->imm_wrs = 0; 7394245518Snp txq->sgl_wrs = 0; 7395245518Snp txq->txpkt_wrs = 0; 7396245518Snp txq->txpkts_wrs = 0; 7397245518Snp txq->txpkts_pkts = 0; 7398246093Snp txq->br->br_drops = 0; 7399245518Snp txq->no_dmamap = 0; 7400245518Snp txq->no_desc = 0; 7401245518Snp } 7402245518Snp 7403245518Snp#ifdef TCP_OFFLOAD 7404245518Snp /* nothing to clear for each ofld_rxq */ 7405245518Snp 7406245518Snp for_each_ofld_txq(pi, i, wrq) { 7407245518Snp wrq->tx_wrs = 0; 7408245518Snp wrq->no_desc = 0; 7409245518Snp } 7410245518Snp#endif 7411245518Snp wrq = &sc->sge.ctrlq[pi->port_id]; 7412245518Snp wrq->tx_wrs = 0; 7413245518Snp wrq->no_desc = 0; 7414245518Snp } 7415241409Snp break; 7416241409Snp } 7417218792Snp default: 7418218792Snp rc = EINVAL; 7419218792Snp } 7420218792Snp 7421218792Snp return (rc); 7422218792Snp} 7423218792Snp 7424237263Snp#ifdef TCP_OFFLOAD 7425219392Snpstatic int 7426228561Snptoe_capability(struct port_info *pi, int enable) 7427228561Snp{ 7428228561Snp int rc; 7429228561Snp struct adapter *sc = pi->adapter; 7430228561Snp 7431245274Snp ASSERT_SYNCHRONIZED_OP(sc); 7432228561Snp 7433228561Snp if (!is_offload(sc)) 7434228561Snp return (ENODEV); 7435228561Snp 7436228561Snp if (enable) { 7437237263Snp if (!(sc->flags & FULL_INIT_DONE)) { 7438245274Snp rc = cxgbe_init_synchronized(pi); 7439245274Snp if (rc) 7440245274Snp return (rc); 7441237263Snp } 7442237263Snp 7443228561Snp if (isset(&sc->offload_map, pi->port_id)) 7444228561Snp return (0); 7445228561Snp 7446237263Snp if (!(sc->flags & TOM_INIT_DONE)) { 7447237263Snp rc = t4_activate_uld(sc, ULD_TOM); 7448237263Snp if (rc == EAGAIN) { 7449237263Snp log(LOG_WARNING, 7450237263Snp "You must kldload t4_tom.ko before trying " 7451237263Snp "to enable TOE on a cxgbe interface.\n"); 7452237263Snp } 7453228561Snp if (rc != 0) 7454228561Snp return (rc); 7455237263Snp KASSERT(sc->tom_softc != NULL, 7456237263Snp ("%s: TOM activated but softc NULL", __func__)); 7457237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 7458237263Snp ("%s: TOM activated but flag not set", __func__)); 7459228561Snp } 7460228561Snp 7461228561Snp setbit(&sc->offload_map, pi->port_id); 7462228561Snp } else { 7463228561Snp if (!isset(&sc->offload_map, pi->port_id)) 7464228561Snp return (0); 7465228561Snp 7466237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 7467237263Snp ("%s: TOM never initialized?", __func__)); 7468228561Snp clrbit(&sc->offload_map, pi->port_id); 7469228561Snp } 7470228561Snp 7471228561Snp return (0); 7472228561Snp} 7473228561Snp 7474228561Snp/* 7475228561Snp * Add an upper layer driver to the global list. 7476228561Snp */ 7477228561Snpint 7478228561Snpt4_register_uld(struct uld_info *ui) 7479228561Snp{ 7480228561Snp int rc = 0; 7481228561Snp struct uld_info *u; 7482228561Snp 7483228561Snp mtx_lock(&t4_uld_list_lock); 7484228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 7485228561Snp if (u->uld_id == ui->uld_id) { 7486228561Snp rc = EEXIST; 7487228561Snp goto done; 7488228561Snp } 7489228561Snp } 7490228561Snp 7491228561Snp SLIST_INSERT_HEAD(&t4_uld_list, ui, link); 7492228561Snp ui->refcount = 0; 7493228561Snpdone: 7494228561Snp mtx_unlock(&t4_uld_list_lock); 7495228561Snp return (rc); 7496228561Snp} 7497228561Snp 7498228561Snpint 7499228561Snpt4_unregister_uld(struct uld_info *ui) 7500228561Snp{ 7501228561Snp int rc = EINVAL; 7502228561Snp struct uld_info *u; 7503228561Snp 7504228561Snp mtx_lock(&t4_uld_list_lock); 7505228561Snp 7506228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 7507228561Snp if (u == ui) { 7508228561Snp if (ui->refcount > 0) { 7509228561Snp rc = EBUSY; 7510228561Snp goto done; 7511228561Snp } 7512228561Snp 7513228561Snp SLIST_REMOVE(&t4_uld_list, ui, uld_info, link); 7514228561Snp rc = 0; 7515228561Snp goto done; 7516228561Snp } 7517228561Snp } 7518228561Snpdone: 7519228561Snp mtx_unlock(&t4_uld_list_lock); 7520228561Snp return (rc); 7521228561Snp} 7522228561Snp 7523237263Snpint 7524237263Snpt4_activate_uld(struct adapter *sc, int id) 7525228561Snp{ 7526228561Snp int rc = EAGAIN; 7527228561Snp struct uld_info *ui; 7528228561Snp 7529245274Snp ASSERT_SYNCHRONIZED_OP(sc); 7530245274Snp 7531228561Snp mtx_lock(&t4_uld_list_lock); 7532228561Snp 7533228561Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 7534228561Snp if (ui->uld_id == id) { 7535237263Snp rc = ui->activate(sc); 7536237263Snp if (rc == 0) 7537228561Snp ui->refcount++; 7538228561Snp goto done; 7539228561Snp } 7540228561Snp } 7541228561Snpdone: 7542228561Snp mtx_unlock(&t4_uld_list_lock); 7543228561Snp 7544228561Snp return (rc); 7545228561Snp} 7546228561Snp 7547237263Snpint 7548237263Snpt4_deactivate_uld(struct adapter *sc, int id) 7549228561Snp{ 7550237263Snp int rc = EINVAL; 7551237263Snp struct uld_info *ui; 7552228561Snp 7553245274Snp ASSERT_SYNCHRONIZED_OP(sc); 7554245274Snp 7555228561Snp mtx_lock(&t4_uld_list_lock); 7556228561Snp 7557237263Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 7558237263Snp if (ui->uld_id == id) { 7559237263Snp rc = ui->deactivate(sc); 7560237263Snp if (rc == 0) 7561237263Snp ui->refcount--; 7562237263Snp goto done; 7563237263Snp } 7564228561Snp } 7565228561Snpdone: 7566228561Snp mtx_unlock(&t4_uld_list_lock); 7567228561Snp 7568228561Snp return (rc); 7569228561Snp} 7570228561Snp#endif 7571228561Snp 7572228561Snp/* 7573228561Snp * Come up with reasonable defaults for some of the tunables, provided they're 7574228561Snp * not set by the user (in which case we'll use the values as is). 7575228561Snp */ 7576228561Snpstatic void 7577228561Snptweak_tunables(void) 7578228561Snp{ 7579228561Snp int nc = mp_ncpus; /* our snapshot of the number of CPUs */ 7580228561Snp 7581228561Snp if (t4_ntxq10g < 1) 7582228561Snp t4_ntxq10g = min(nc, NTXQ_10G); 7583228561Snp 7584228561Snp if (t4_ntxq1g < 1) 7585228561Snp t4_ntxq1g = min(nc, NTXQ_1G); 7586228561Snp 7587228561Snp if (t4_nrxq10g < 1) 7588228561Snp t4_nrxq10g = min(nc, NRXQ_10G); 7589228561Snp 7590228561Snp if (t4_nrxq1g < 1) 7591228561Snp t4_nrxq1g = min(nc, NRXQ_1G); 7592228561Snp 7593237263Snp#ifdef TCP_OFFLOAD 7594228561Snp if (t4_nofldtxq10g < 1) 7595228561Snp t4_nofldtxq10g = min(nc, NOFLDTXQ_10G); 7596228561Snp 7597228561Snp if (t4_nofldtxq1g < 1) 7598228561Snp t4_nofldtxq1g = min(nc, NOFLDTXQ_1G); 7599228561Snp 7600228561Snp if (t4_nofldrxq10g < 1) 7601228561Snp t4_nofldrxq10g = min(nc, NOFLDRXQ_10G); 7602228561Snp 7603228561Snp if (t4_nofldrxq1g < 1) 7604228561Snp t4_nofldrxq1g = min(nc, NOFLDRXQ_1G); 7605238028Snp 7606238028Snp if (t4_toecaps_allowed == -1) 7607238028Snp t4_toecaps_allowed = FW_CAPS_CONFIG_TOE; 7608238028Snp#else 7609238028Snp if (t4_toecaps_allowed == -1) 7610238028Snp t4_toecaps_allowed = 0; 7611228561Snp#endif 7612228561Snp 7613228561Snp if (t4_tmr_idx_10g < 0 || t4_tmr_idx_10g >= SGE_NTIMERS) 7614228561Snp t4_tmr_idx_10g = TMR_IDX_10G; 7615228561Snp 7616228561Snp if (t4_pktc_idx_10g < -1 || t4_pktc_idx_10g >= SGE_NCOUNTERS) 7617228561Snp t4_pktc_idx_10g = PKTC_IDX_10G; 7618228561Snp 7619228561Snp if (t4_tmr_idx_1g < 0 || t4_tmr_idx_1g >= SGE_NTIMERS) 7620228561Snp t4_tmr_idx_1g = TMR_IDX_1G; 7621228561Snp 7622228561Snp if (t4_pktc_idx_1g < -1 || t4_pktc_idx_1g >= SGE_NCOUNTERS) 7623228561Snp t4_pktc_idx_1g = PKTC_IDX_1G; 7624228561Snp 7625228561Snp if (t4_qsize_txq < 128) 7626228561Snp t4_qsize_txq = 128; 7627228561Snp 7628228561Snp if (t4_qsize_rxq < 128) 7629228561Snp t4_qsize_rxq = 128; 7630228561Snp while (t4_qsize_rxq & 7) 7631228561Snp t4_qsize_rxq++; 7632228561Snp 7633228561Snp t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX; 7634228561Snp} 7635228561Snp 7636228561Snpstatic int 7637249370Snpmod_event(module_t mod, int cmd, void *arg) 7638219392Snp{ 7639228561Snp int rc = 0; 7640249370Snp static int loaded = 0; 7641219392Snp 7642228561Snp switch (cmd) { 7643228561Snp case MOD_LOAD: 7644249370Snp if (atomic_fetchadd_int(&loaded, 1)) 7645249370Snp break; 7646219392Snp t4_sge_modload(); 7647228561Snp mtx_init(&t4_list_lock, "T4 adapters", 0, MTX_DEF); 7648228561Snp SLIST_INIT(&t4_list); 7649237263Snp#ifdef TCP_OFFLOAD 7650228561Snp mtx_init(&t4_uld_list_lock, "T4 ULDs", 0, MTX_DEF); 7651228561Snp SLIST_INIT(&t4_uld_list); 7652228561Snp#endif 7653228561Snp tweak_tunables(); 7654228561Snp break; 7655219392Snp 7656228561Snp case MOD_UNLOAD: 7657249370Snp if (atomic_fetchadd_int(&loaded, -1) > 1) 7658249370Snp break; 7659237263Snp#ifdef TCP_OFFLOAD 7660228561Snp mtx_lock(&t4_uld_list_lock); 7661228561Snp if (!SLIST_EMPTY(&t4_uld_list)) { 7662228561Snp rc = EBUSY; 7663228561Snp mtx_unlock(&t4_uld_list_lock); 7664228561Snp break; 7665228561Snp } 7666228561Snp mtx_unlock(&t4_uld_list_lock); 7667228561Snp mtx_destroy(&t4_uld_list_lock); 7668228561Snp#endif 7669228561Snp mtx_lock(&t4_list_lock); 7670228561Snp if (!SLIST_EMPTY(&t4_list)) { 7671228561Snp rc = EBUSY; 7672228561Snp mtx_unlock(&t4_list_lock); 7673228561Snp break; 7674228561Snp } 7675228561Snp mtx_unlock(&t4_list_lock); 7676228561Snp mtx_destroy(&t4_list_lock); 7677228561Snp break; 7678228561Snp } 7679228561Snp 7680228561Snp return (rc); 7681219392Snp} 7682219392Snp 7683248925Snpstatic devclass_t t4_devclass, t5_devclass; 7684248925Snpstatic devclass_t cxgbe_devclass, cxl_devclass; 7685218792Snp 7686249370SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, mod_event, 0); 7687218792SnpMODULE_VERSION(t4nex, 1); 7688250697SkibMODULE_DEPEND(t4nex, firmware, 1, 1, 1); 7689218792Snp 7690249370SnpDRIVER_MODULE(t5nex, pci, t5_driver, t5_devclass, mod_event, 0); 7691248925SnpMODULE_VERSION(t5nex, 1); 7692250697SkibMODULE_DEPEND(t5nex, firmware, 1, 1, 1); 7693248925Snp 7694218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0); 7695218792SnpMODULE_VERSION(cxgbe, 1); 7696248925Snp 7697248925SnpDRIVER_MODULE(cxl, t5nex, cxl_driver, cxl_devclass, 0, 0); 7698248925SnpMODULE_VERSION(cxl, 1); 7699