t4_main.c revision 248925
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 248925 2013-03-30 02:26:20Z 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" 258248925Snpstatic char t4_cfg_file[32] = DEFAULT_CF; 259228561SnpTUNABLE_STR("hw.cxgbe.config_file", t4_cfg_file, sizeof(t4_cfg_file)); 260218792Snp 261228561Snp/* 262247347Snp * Firmware auto-install by driver during attach (0, 1, 2 = prohibited, allowed, 263247347Snp * encouraged respectively). 264247347Snp */ 265247347Snpstatic unsigned int t4_fw_install = 1; 266247347SnpTUNABLE_INT("hw.cxgbe.fw_install", &t4_fw_install); 267247347Snp 268247347Snp/* 269228561Snp * ASIC features that will be used. Disable the ones you don't want so that the 270228561Snp * chip resources aren't wasted on features that will not be used. 271228561Snp */ 272228561Snpstatic int t4_linkcaps_allowed = 0; /* No DCBX, PPP, etc. by default */ 273228561SnpTUNABLE_INT("hw.cxgbe.linkcaps_allowed", &t4_linkcaps_allowed); 274221474Snp 275228561Snpstatic int t4_niccaps_allowed = FW_CAPS_CONFIG_NIC; 276228561SnpTUNABLE_INT("hw.cxgbe.niccaps_allowed", &t4_niccaps_allowed); 277228561Snp 278238028Snpstatic int t4_toecaps_allowed = -1; 279228561SnpTUNABLE_INT("hw.cxgbe.toecaps_allowed", &t4_toecaps_allowed); 280228561Snp 281228561Snpstatic int t4_rdmacaps_allowed = 0; 282228561SnpTUNABLE_INT("hw.cxgbe.rdmacaps_allowed", &t4_rdmacaps_allowed); 283228561Snp 284228561Snpstatic int t4_iscsicaps_allowed = 0; 285228561SnpTUNABLE_INT("hw.cxgbe.iscsicaps_allowed", &t4_iscsicaps_allowed); 286228561Snp 287228561Snpstatic int t4_fcoecaps_allowed = 0; 288228561SnpTUNABLE_INT("hw.cxgbe.fcoecaps_allowed", &t4_fcoecaps_allowed); 289228561Snp 290248925Snpstatic int t5_write_combine = 0; 291248925SnpTUNABLE_INT("hw.cxl.write_combine", &t5_write_combine); 292248925Snp 293218792Snpstruct intrs_and_queues { 294219944Snp int intr_type; /* INTx, MSI, or MSI-X */ 295218792Snp int nirq; /* Number of vectors */ 296228561Snp int intr_flags; 297218792Snp int ntxq10g; /* # of NIC txq's for each 10G port */ 298218792Snp int nrxq10g; /* # of NIC rxq's for each 10G port */ 299218792Snp int ntxq1g; /* # of NIC txq's for each 1G port */ 300218792Snp int nrxq1g; /* # of NIC rxq's for each 1G port */ 301237263Snp#ifdef TCP_OFFLOAD 302228561Snp int nofldtxq10g; /* # of TOE txq's for each 10G port */ 303228561Snp int nofldrxq10g; /* # of TOE rxq's for each 10G port */ 304228561Snp int nofldtxq1g; /* # of TOE txq's for each 1G port */ 305228561Snp int nofldrxq1g; /* # of TOE rxq's for each 1G port */ 306228561Snp#endif 307218792Snp}; 308218792Snp 309221474Snpstruct filter_entry { 310221474Snp uint32_t valid:1; /* filter allocated and valid */ 311221474Snp uint32_t locked:1; /* filter is administratively locked */ 312221474Snp uint32_t pending:1; /* filter action is pending firmware reply */ 313221474Snp uint32_t smtidx:8; /* Source MAC Table index for smac */ 314222509Snp struct l2t_entry *l2t; /* Layer Two Table entry for dmac */ 315221474Snp 316221474Snp struct t4_filter_specification fs; 317221474Snp}; 318221474Snp 319218792Snpenum { 320218792Snp XGMAC_MTU = (1 << 0), 321218792Snp XGMAC_PROMISC = (1 << 1), 322218792Snp XGMAC_ALLMULTI = (1 << 2), 323218792Snp XGMAC_VLANEX = (1 << 3), 324218792Snp XGMAC_UCADDR = (1 << 4), 325218792Snp XGMAC_MCADDRS = (1 << 5), 326218792Snp 327218792Snp XGMAC_ALL = 0xffff 328218792Snp}; 329218792Snp 330248925Snpstatic int map_bars_0_and_4(struct adapter *); 331248925Snpstatic int map_bar_2(struct adapter *); 332218792Snpstatic void setup_memwin(struct adapter *); 333248925Snpstatic int validate_mem_range(struct adapter *, uint32_t, int); 334248925Snpstatic int validate_mt_off_len(struct adapter *, int, uint32_t, int, 335248925Snp uint32_t *); 336248925Snpstatic void memwin_info(struct adapter *, int, uint32_t *, uint32_t *); 337248925Snpstatic uint32_t position_memwin(struct adapter *, int, uint32_t); 338218792Snpstatic int cfg_itype_and_nqueues(struct adapter *, int, int, 339218792Snp struct intrs_and_queues *); 340218792Snpstatic int prep_firmware(struct adapter *); 341248925Snpstatic int partition_resources(struct adapter *, const struct firmware *, 342248925Snp const char *); 343228561Snpstatic int get_params__pre_init(struct adapter *); 344228561Snpstatic int get_params__post_init(struct adapter *); 345247291Snpstatic int set_params__post_init(struct adapter *); 346218792Snpstatic void t4_set_desc(struct adapter *); 347218792Snpstatic void build_medialist(struct port_info *); 348218792Snpstatic int update_mac_settings(struct port_info *, int); 349218792Snpstatic int cxgbe_init_synchronized(struct port_info *); 350218792Snpstatic int cxgbe_uninit_synchronized(struct port_info *); 351240453Snpstatic int setup_intr_handlers(struct adapter *); 352228561Snpstatic int adapter_full_init(struct adapter *); 353228561Snpstatic int adapter_full_uninit(struct adapter *); 354228561Snpstatic int port_full_init(struct port_info *); 355228561Snpstatic int port_full_uninit(struct port_info *); 356228561Snpstatic void quiesce_eq(struct adapter *, struct sge_eq *); 357228561Snpstatic void quiesce_iq(struct adapter *, struct sge_iq *); 358228561Snpstatic void quiesce_fl(struct adapter *, struct sge_fl *); 359218792Snpstatic int t4_alloc_irq(struct adapter *, struct irq *, int rid, 360228561Snp driver_intr_t *, void *, char *); 361218792Snpstatic int t4_free_irq(struct adapter *, struct irq *); 362218792Snpstatic void reg_block_dump(struct adapter *, uint8_t *, unsigned int, 363218792Snp unsigned int); 364218792Snpstatic void t4_get_regs(struct adapter *, struct t4_regdump *, uint8_t *); 365218792Snpstatic void cxgbe_tick(void *); 366237263Snpstatic void cxgbe_vlan_config(void *, struct ifnet *, uint16_t); 367228561Snpstatic int cpl_not_handled(struct sge_iq *, const struct rss_header *, 368228561Snp struct mbuf *); 369237263Snpstatic int an_not_handled(struct sge_iq *, const struct rsp_ctrl *); 370239336Snpstatic int fw_msg_not_handled(struct adapter *, const __be64 *); 371218792Snpstatic int t4_sysctls(struct adapter *); 372218792Snpstatic int cxgbe_sysctls(struct port_info *); 373219436Snpstatic int sysctl_int_array(SYSCTL_HANDLER_ARGS); 374228561Snpstatic int sysctl_bitfield(SYSCTL_HANDLER_ARGS); 375218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS); 376218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS); 377218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS); 378218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS); 379218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS); 380231115Snp#ifdef SBUF_DRAIN 381228561Snpstatic int sysctl_cctrl(SYSCTL_HANDLER_ARGS); 382247122Snpstatic int sysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS); 383247122Snpstatic int sysctl_cim_la(SYSCTL_HANDLER_ARGS); 384247122Snpstatic int sysctl_cim_qcfg(SYSCTL_HANDLER_ARGS); 385228561Snpstatic int sysctl_cpl_stats(SYSCTL_HANDLER_ARGS); 386228561Snpstatic int sysctl_ddp_stats(SYSCTL_HANDLER_ARGS); 387222551Snpstatic int sysctl_devlog(SYSCTL_HANDLER_ARGS); 388228561Snpstatic int sysctl_fcoe_stats(SYSCTL_HANDLER_ARGS); 389228561Snpstatic int sysctl_hw_sched(SYSCTL_HANDLER_ARGS); 390228561Snpstatic int sysctl_lb_stats(SYSCTL_HANDLER_ARGS); 391228561Snpstatic int sysctl_meminfo(SYSCTL_HANDLER_ARGS); 392228561Snpstatic int sysctl_path_mtus(SYSCTL_HANDLER_ARGS); 393228561Snpstatic int sysctl_pm_stats(SYSCTL_HANDLER_ARGS); 394228561Snpstatic int sysctl_rdma_stats(SYSCTL_HANDLER_ARGS); 395228561Snpstatic int sysctl_tcp_stats(SYSCTL_HANDLER_ARGS); 396228561Snpstatic int sysctl_tids(SYSCTL_HANDLER_ARGS); 397228561Snpstatic int sysctl_tp_err_stats(SYSCTL_HANDLER_ARGS); 398228561Snpstatic int sysctl_tx_rate(SYSCTL_HANDLER_ARGS); 399248925Snpstatic int sysctl_wrwc_stats(SYSCTL_HANDLER_ARGS); 400231115Snp#endif 401219286Snpstatic inline void txq_start(struct ifnet *, struct sge_txq *); 402221474Snpstatic uint32_t fconf_to_mode(uint32_t); 403221474Snpstatic uint32_t mode_to_fconf(uint32_t); 404221474Snpstatic uint32_t fspec_to_fconf(struct t4_filter_specification *); 405221474Snpstatic int get_filter_mode(struct adapter *, uint32_t *); 406221474Snpstatic int set_filter_mode(struct adapter *, uint32_t); 407222552Snpstatic inline uint64_t get_filter_hits(struct adapter *, uint32_t); 408221474Snpstatic int get_filter(struct adapter *, struct t4_filter *); 409221474Snpstatic int set_filter(struct adapter *, struct t4_filter *); 410221474Snpstatic int del_filter(struct adapter *, struct t4_filter *); 411222509Snpstatic void clear_filter(struct filter_entry *); 412221474Snpstatic int set_filter_wr(struct adapter *, int); 413221474Snpstatic int del_filter_wr(struct adapter *, int); 414222973Snpstatic int get_sge_context(struct adapter *, struct t4_sge_context *); 415245274Snpstatic int load_fw(struct adapter *, struct t4_data *); 416248925Snpstatic int read_card_mem(struct adapter *, int, struct t4_mem_range *); 417241399Snpstatic int read_i2c(struct adapter *, struct t4_i2c_data *); 418237263Snp#ifdef TCP_OFFLOAD 419228561Snpstatic int toe_capability(struct port_info *, int); 420228561Snp#endif 421219392Snpstatic int t4_mod_event(module_t, int, void *); 422218792Snp 423248925Snpstruct { 424218792Snp uint16_t device; 425218792Snp char *desc; 426218792Snp} t4_pciids[] = { 427237587Snp {0xa000, "Chelsio Terminator 4 FPGA"}, 428237587Snp {0x4400, "Chelsio T440-dbg"}, 429237587Snp {0x4401, "Chelsio T420-CR"}, 430237587Snp {0x4402, "Chelsio T422-CR"}, 431237587Snp {0x4403, "Chelsio T440-CR"}, 432237587Snp {0x4404, "Chelsio T420-BCH"}, 433237587Snp {0x4405, "Chelsio T440-BCH"}, 434237587Snp {0x4406, "Chelsio T440-CH"}, 435237587Snp {0x4407, "Chelsio T420-SO"}, 436237587Snp {0x4408, "Chelsio T420-CX"}, 437237587Snp {0x4409, "Chelsio T420-BT"}, 438237587Snp {0x440a, "Chelsio T404-BT"}, 439244580Snp {0x440e, "Chelsio T440-LP-CR"}, 440248925Snp}, t5_pciids[] = { 441248925Snp {0xb000, "Chelsio Terminator 5 FPGA"}, 442248925Snp {0x5400, "Chelsio T580-dbg"}, 443218792Snp}; 444218792Snp 445237263Snp#ifdef TCP_OFFLOAD 446237263Snp/* 447237263Snp * service_iq() has an iq and needs the fl. Offset of fl from the iq should be 448237263Snp * exactly the same for both rxq and ofld_rxq. 449237263Snp */ 450237263SnpCTASSERT(offsetof(struct sge_ofld_rxq, iq) == offsetof(struct sge_rxq, iq)); 451228561SnpCTASSERT(offsetof(struct sge_ofld_rxq, fl) == offsetof(struct sge_rxq, fl)); 452228561Snp#endif 453228561Snp 454239336Snp/* No easy way to include t4_msg.h before adapter.h so we check this way */ 455240452SnpCTASSERT(nitems(((struct adapter *)0)->cpl_handler) == NUM_CPL_CMDS); 456240452SnpCTASSERT(nitems(((struct adapter *)0)->fw_msg_handler) == NUM_FW6_TYPES); 457239336Snp 458218792Snpstatic int 459218792Snpt4_probe(device_t dev) 460218792Snp{ 461218792Snp int i; 462218792Snp uint16_t v = pci_get_vendor(dev); 463218792Snp uint16_t d = pci_get_device(dev); 464237587Snp uint8_t f = pci_get_function(dev); 465218792Snp 466218792Snp if (v != PCI_VENDOR_ID_CHELSIO) 467218792Snp return (ENXIO); 468218792Snp 469237587Snp /* Attach only to PF0 of the FPGA */ 470237587Snp if (d == 0xa000 && f != 0) 471237587Snp return (ENXIO); 472237587Snp 473240452Snp for (i = 0; i < nitems(t4_pciids); i++) { 474237587Snp if (d == t4_pciids[i].device) { 475218792Snp device_set_desc(dev, t4_pciids[i].desc); 476218792Snp return (BUS_PROBE_DEFAULT); 477218792Snp } 478218792Snp } 479218792Snp 480218792Snp return (ENXIO); 481218792Snp} 482218792Snp 483218792Snpstatic int 484248925Snpt5_probe(device_t dev) 485248925Snp{ 486248925Snp int i; 487248925Snp uint16_t v = pci_get_vendor(dev); 488248925Snp uint16_t d = pci_get_device(dev); 489248925Snp uint8_t f = pci_get_function(dev); 490248925Snp 491248925Snp if (v != PCI_VENDOR_ID_CHELSIO) 492248925Snp return (ENXIO); 493248925Snp 494248925Snp /* Attach only to PF0 of the FPGA */ 495248925Snp if (d == 0xb000 && f != 0) 496248925Snp return (ENXIO); 497248925Snp 498248925Snp for (i = 0; i < nitems(t5_pciids); i++) { 499248925Snp if (d == t5_pciids[i].device) { 500248925Snp device_set_desc(dev, t5_pciids[i].desc); 501248925Snp return (BUS_PROBE_DEFAULT); 502248925Snp } 503248925Snp } 504248925Snp 505248925Snp return (ENXIO); 506248925Snp} 507248925Snp 508248925Snpstatic int 509218792Snpt4_attach(device_t dev) 510218792Snp{ 511218792Snp struct adapter *sc; 512218792Snp int rc = 0, i, n10g, n1g, rqidx, tqidx; 513218792Snp struct intrs_and_queues iaq; 514218792Snp struct sge *s; 515237263Snp#ifdef TCP_OFFLOAD 516228561Snp int ofld_rqidx, ofld_tqidx; 517228561Snp#endif 518218792Snp 519218792Snp sc = device_get_softc(dev); 520218792Snp sc->dev = dev; 521218792Snp 522218792Snp pci_enable_busmaster(dev); 523222085Snp if (pci_find_cap(dev, PCIY_EXPRESS, &i) == 0) { 524228561Snp uint32_t v; 525228561Snp 526222085Snp pci_set_max_read_req(dev, 4096); 527240680Sgavin v = pci_read_config(dev, i + PCIER_DEVICE_CTL, 2); 528240680Sgavin v |= PCIEM_CTL_RELAXED_ORD_ENABLE; 529240680Sgavin pci_write_config(dev, i + PCIER_DEVICE_CTL, v, 2); 530222085Snp } 531222085Snp 532218792Snp snprintf(sc->lockname, sizeof(sc->lockname), "%s", 533218792Snp device_get_nameunit(dev)); 534218792Snp mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF); 535228561Snp mtx_lock(&t4_list_lock); 536228561Snp SLIST_INSERT_HEAD(&t4_list, sc, link); 537228561Snp mtx_unlock(&t4_list_lock); 538218792Snp 539228561Snp mtx_init(&sc->sfl_lock, "starving freelists", 0, MTX_DEF); 540228561Snp TAILQ_INIT(&sc->sfl); 541228561Snp callout_init(&sc->sfl_callout, CALLOUT_MPSAFE); 542228561Snp 543248925Snp rc = map_bars_0_and_4(sc); 544218792Snp if (rc != 0) 545218792Snp goto done; /* error message displayed already */ 546218792Snp 547237587Snp /* 548237587Snp * This is the real PF# to which we're attaching. Works from within PCI 549237587Snp * passthrough environments too, where pci_get_function() could return a 550237587Snp * different PF# depending on the passthrough configuration. We need to 551237587Snp * use the real PF# in all our communication with the firmware. 552237587Snp */ 553237587Snp sc->pf = G_SOURCEPF(t4_read_reg(sc, A_PL_WHOAMI)); 554237587Snp sc->mbox = sc->pf; 555237587Snp 556218792Snp memset(sc->chan_map, 0xff, sizeof(sc->chan_map)); 557237263Snp sc->an_handler = an_not_handled; 558240452Snp for (i = 0; i < nitems(sc->cpl_handler); i++) 559228561Snp sc->cpl_handler[i] = cpl_not_handled; 560240452Snp for (i = 0; i < nitems(sc->fw_msg_handler); i++) 561239336Snp sc->fw_msg_handler[i] = fw_msg_not_handled; 562239338Snp t4_register_cpl_handler(sc, CPL_SET_TCB_RPL, t4_filter_rpl); 563248925Snp t4_init_sge_cpl_handlers(sc); 564218792Snp 565218792Snp /* Prepare the adapter for operation */ 566218792Snp rc = -t4_prep_adapter(sc); 567218792Snp if (rc != 0) { 568218792Snp device_printf(dev, "failed to prepare adapter: %d.\n", rc); 569218792Snp goto done; 570218792Snp } 571218792Snp 572228561Snp /* 573228561Snp * Do this really early, with the memory windows set up even before the 574228561Snp * character device. The userland tool's register i/o and mem read 575228561Snp * will work even in "recovery mode". 576228561Snp */ 577228561Snp setup_memwin(sc); 578248925Snp sc->cdev = make_dev(is_t4(sc) ? &t4_cdevsw : &t5_cdevsw, 579248925Snp device_get_unit(dev), UID_ROOT, GID_WHEEL, 0600, "%s", 580248925Snp device_get_nameunit(dev)); 581248925Snp if (sc->cdev == NULL) 582248925Snp device_printf(dev, "failed to create nexus char device.\n"); 583248925Snp else 584248925Snp sc->cdev->si_drv1 = sc; 585218792Snp 586228561Snp /* Go no further if recovery mode has been requested. */ 587228561Snp if (TUNABLE_INT_FETCH("hw.cxgbe.sos", &i) && i != 0) { 588228561Snp device_printf(dev, "recovery mode.\n"); 589228561Snp goto done; 590228561Snp } 591228561Snp 592218792Snp /* Prepare the firmware for operation */ 593218792Snp rc = prep_firmware(sc); 594218792Snp if (rc != 0) 595218792Snp goto done; /* error message displayed already */ 596218792Snp 597248925Snp rc = get_params__post_init(sc); 598228561Snp if (rc != 0) 599228561Snp goto done; /* error message displayed already */ 600222551Snp 601248925Snp rc = set_params__post_init(sc); 602228561Snp if (rc != 0) 603228561Snp goto done; /* error message displayed already */ 604218792Snp 605248925Snp rc = map_bar_2(sc); 606228561Snp if (rc != 0) 607228561Snp goto done; /* error message displayed already */ 608218792Snp 609228561Snp for (i = 0; i < NCHAN; i++) 610228561Snp sc->params.tp.tx_modq[i] = i; 611218792Snp 612218792Snp rc = t4_create_dma_tag(sc); 613218792Snp if (rc != 0) 614218792Snp goto done; /* error message displayed already */ 615218792Snp 616218792Snp /* 617218792Snp * First pass over all the ports - allocate VIs and initialize some 618218792Snp * basic parameters like mac address, port type, etc. We also figure 619218792Snp * out whether a port is 10G or 1G and use that information when 620218792Snp * calculating how many interrupts to attempt to allocate. 621218792Snp */ 622218792Snp n10g = n1g = 0; 623218792Snp for_each_port(sc, i) { 624218792Snp struct port_info *pi; 625218792Snp 626218792Snp pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK); 627218792Snp sc->port[i] = pi; 628218792Snp 629218792Snp /* These must be set before t4_port_init */ 630218792Snp pi->adapter = sc; 631218792Snp pi->port_id = i; 632218792Snp 633218792Snp /* Allocate the vi and initialize parameters like mac addr */ 634218792Snp rc = -t4_port_init(pi, sc->mbox, sc->pf, 0); 635218792Snp if (rc != 0) { 636218792Snp device_printf(dev, "unable to initialize port %d: %d\n", 637218792Snp i, rc); 638218792Snp free(pi, M_CXGBE); 639222510Snp sc->port[i] = NULL; 640222510Snp goto done; 641218792Snp } 642218792Snp 643218792Snp snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d", 644218792Snp device_get_nameunit(dev), i); 645218792Snp mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF); 646218792Snp 647218792Snp if (is_10G_port(pi)) { 648218792Snp n10g++; 649228561Snp pi->tmr_idx = t4_tmr_idx_10g; 650228561Snp pi->pktc_idx = t4_pktc_idx_10g; 651218792Snp } else { 652218792Snp n1g++; 653228561Snp pi->tmr_idx = t4_tmr_idx_1g; 654228561Snp pi->pktc_idx = t4_pktc_idx_1g; 655218792Snp } 656218792Snp 657218792Snp pi->xact_addr_filt = -1; 658218792Snp 659228561Snp pi->qsize_rxq = t4_qsize_rxq; 660228561Snp pi->qsize_txq = t4_qsize_txq; 661218792Snp 662248925Snp pi->dev = device_add_child(dev, is_t4(sc) ? "cxgbe" : "cxl", -1); 663218792Snp if (pi->dev == NULL) { 664218792Snp device_printf(dev, 665218792Snp "failed to add device for port %d.\n", i); 666218792Snp rc = ENXIO; 667218792Snp goto done; 668218792Snp } 669218792Snp device_set_softc(pi->dev, pi); 670218792Snp } 671218792Snp 672218792Snp /* 673218792Snp * Interrupt type, # of interrupts, # of rx/tx queues, etc. 674218792Snp */ 675218792Snp rc = cfg_itype_and_nqueues(sc, n10g, n1g, &iaq); 676218792Snp if (rc != 0) 677218792Snp goto done; /* error message displayed already */ 678218792Snp 679218792Snp sc->intr_type = iaq.intr_type; 680218792Snp sc->intr_count = iaq.nirq; 681228561Snp sc->flags |= iaq.intr_flags; 682218792Snp 683218792Snp s = &sc->sge; 684218792Snp s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g; 685218792Snp s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g; 686220873Snp s->neq = s->ntxq + s->nrxq; /* the free list in an rxq is an eq */ 687228561Snp s->neq += sc->params.nports + 1;/* ctrl queues: 1 per port + 1 mgmt */ 688218792Snp s->niq = s->nrxq + 1; /* 1 extra for firmware event queue */ 689222510Snp 690237263Snp#ifdef TCP_OFFLOAD 691228561Snp if (is_offload(sc)) { 692228561Snp 693228561Snp s->nofldrxq = n10g * iaq.nofldrxq10g + n1g * iaq.nofldrxq1g; 694228561Snp s->nofldtxq = n10g * iaq.nofldtxq10g + n1g * iaq.nofldtxq1g; 695228561Snp s->neq += s->nofldtxq + s->nofldrxq; 696228561Snp s->niq += s->nofldrxq; 697228561Snp 698228561Snp s->ofld_rxq = malloc(s->nofldrxq * sizeof(struct sge_ofld_rxq), 699228561Snp M_CXGBE, M_ZERO | M_WAITOK); 700228561Snp s->ofld_txq = malloc(s->nofldtxq * sizeof(struct sge_wrq), 701228561Snp M_CXGBE, M_ZERO | M_WAITOK); 702228561Snp } 703228561Snp#endif 704228561Snp 705228561Snp s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_wrq), M_CXGBE, 706220873Snp M_ZERO | M_WAITOK); 707218792Snp s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE, 708218792Snp M_ZERO | M_WAITOK); 709218792Snp s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE, 710218792Snp M_ZERO | M_WAITOK); 711218792Snp s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE, 712218792Snp M_ZERO | M_WAITOK); 713218792Snp s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE, 714218792Snp M_ZERO | M_WAITOK); 715218792Snp 716218792Snp sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE, 717218792Snp M_ZERO | M_WAITOK); 718218792Snp 719228561Snp t4_init_l2t(sc, M_WAITOK); 720222509Snp 721218792Snp /* 722218792Snp * Second pass over the ports. This time we know the number of rx and 723218792Snp * tx queues that each port should get. 724218792Snp */ 725218792Snp rqidx = tqidx = 0; 726237263Snp#ifdef TCP_OFFLOAD 727228561Snp ofld_rqidx = ofld_tqidx = 0; 728228561Snp#endif 729218792Snp for_each_port(sc, i) { 730218792Snp struct port_info *pi = sc->port[i]; 731218792Snp 732218792Snp if (pi == NULL) 733218792Snp continue; 734218792Snp 735218792Snp pi->first_rxq = rqidx; 736218792Snp pi->first_txq = tqidx; 737228561Snp if (is_10G_port(pi)) { 738228561Snp pi->nrxq = iaq.nrxq10g; 739228561Snp pi->ntxq = iaq.ntxq10g; 740228561Snp } else { 741228561Snp pi->nrxq = iaq.nrxq1g; 742228561Snp pi->ntxq = iaq.ntxq1g; 743228561Snp } 744218792Snp 745218792Snp rqidx += pi->nrxq; 746218792Snp tqidx += pi->ntxq; 747228561Snp 748237263Snp#ifdef TCP_OFFLOAD 749228561Snp if (is_offload(sc)) { 750228561Snp pi->first_ofld_rxq = ofld_rqidx; 751228561Snp pi->first_ofld_txq = ofld_tqidx; 752228561Snp if (is_10G_port(pi)) { 753228561Snp pi->nofldrxq = iaq.nofldrxq10g; 754228561Snp pi->nofldtxq = iaq.nofldtxq10g; 755228561Snp } else { 756228561Snp pi->nofldrxq = iaq.nofldrxq1g; 757228561Snp pi->nofldtxq = iaq.nofldtxq1g; 758228561Snp } 759228561Snp ofld_rqidx += pi->nofldrxq; 760228561Snp ofld_tqidx += pi->nofldtxq; 761228561Snp } 762228561Snp#endif 763218792Snp } 764218792Snp 765240453Snp rc = setup_intr_handlers(sc); 766240453Snp if (rc != 0) { 767240453Snp device_printf(dev, 768240453Snp "failed to setup interrupt handlers: %d\n", rc); 769240453Snp goto done; 770240453Snp } 771240453Snp 772218792Snp rc = bus_generic_attach(dev); 773218792Snp if (rc != 0) { 774218792Snp device_printf(dev, 775218792Snp "failed to attach all child ports: %d\n", rc); 776218792Snp goto done; 777218792Snp } 778218792Snp 779218792Snp device_printf(dev, 780228561Snp "PCIe x%d, %d ports, %d %s interrupt%s, %d eq, %d iq\n", 781228561Snp sc->params.pci.width, sc->params.nports, sc->intr_count, 782228561Snp sc->intr_type == INTR_MSIX ? "MSI-X" : 783228561Snp (sc->intr_type == INTR_MSI ? "MSI" : "INTx"), 784228561Snp sc->intr_count > 1 ? "s" : "", sc->sge.neq, sc->sge.niq); 785228561Snp 786218792Snp t4_set_desc(sc); 787218792Snp 788218792Snpdone: 789228561Snp if (rc != 0 && sc->cdev) { 790228561Snp /* cdev was created and so cxgbetool works; recover that way. */ 791228561Snp device_printf(dev, 792228561Snp "error during attach, adapter is now in recovery mode.\n"); 793228561Snp rc = 0; 794228561Snp } 795228561Snp 796218792Snp if (rc != 0) 797218792Snp t4_detach(dev); 798228561Snp else 799228561Snp t4_sysctls(sc); 800218792Snp 801218792Snp return (rc); 802218792Snp} 803218792Snp 804218792Snp/* 805218792Snp * Idempotent 806218792Snp */ 807218792Snpstatic int 808218792Snpt4_detach(device_t dev) 809218792Snp{ 810218792Snp struct adapter *sc; 811218792Snp struct port_info *pi; 812228561Snp int i, rc; 813218792Snp 814218792Snp sc = device_get_softc(dev); 815218792Snp 816228561Snp if (sc->flags & FULL_INIT_DONE) 817228561Snp t4_intr_disable(sc); 818228561Snp 819228561Snp if (sc->cdev) { 820218792Snp destroy_dev(sc->cdev); 821228561Snp sc->cdev = NULL; 822228561Snp } 823218792Snp 824228561Snp rc = bus_generic_detach(dev); 825228561Snp if (rc) { 826228561Snp device_printf(dev, 827228561Snp "failed to detach child devices: %d\n", rc); 828228561Snp return (rc); 829228561Snp } 830228561Snp 831240453Snp for (i = 0; i < sc->intr_count; i++) 832240453Snp t4_free_irq(sc, &sc->irq[i]); 833240453Snp 834218792Snp for (i = 0; i < MAX_NPORTS; i++) { 835218792Snp pi = sc->port[i]; 836218792Snp if (pi) { 837218792Snp t4_free_vi(pi->adapter, sc->mbox, sc->pf, 0, pi->viid); 838218792Snp if (pi->dev) 839218792Snp device_delete_child(dev, pi->dev); 840218792Snp 841218792Snp mtx_destroy(&pi->pi_lock); 842218792Snp free(pi, M_CXGBE); 843218792Snp } 844218792Snp } 845218792Snp 846228561Snp if (sc->flags & FULL_INIT_DONE) 847228561Snp adapter_full_uninit(sc); 848228561Snp 849218792Snp if (sc->flags & FW_OK) 850218792Snp t4_fw_bye(sc, sc->mbox); 851218792Snp 852219944Snp if (sc->intr_type == INTR_MSI || sc->intr_type == INTR_MSIX) 853218792Snp pci_release_msi(dev); 854218792Snp 855218792Snp if (sc->regs_res) 856218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid, 857218792Snp sc->regs_res); 858218792Snp 859248925Snp if (sc->udbs_res) 860248925Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->udbs_rid, 861248925Snp sc->udbs_res); 862248925Snp 863218792Snp if (sc->msix_res) 864218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid, 865218792Snp sc->msix_res); 866218792Snp 867222509Snp if (sc->l2t) 868222509Snp t4_free_l2t(sc->l2t); 869222509Snp 870237263Snp#ifdef TCP_OFFLOAD 871228561Snp free(sc->sge.ofld_rxq, M_CXGBE); 872228561Snp free(sc->sge.ofld_txq, M_CXGBE); 873228561Snp#endif 874218792Snp free(sc->irq, M_CXGBE); 875218792Snp free(sc->sge.rxq, M_CXGBE); 876218792Snp free(sc->sge.txq, M_CXGBE); 877220873Snp free(sc->sge.ctrlq, M_CXGBE); 878218792Snp free(sc->sge.iqmap, M_CXGBE); 879218792Snp free(sc->sge.eqmap, M_CXGBE); 880221474Snp free(sc->tids.ftid_tab, M_CXGBE); 881218792Snp t4_destroy_dma_tag(sc); 882228561Snp if (mtx_initialized(&sc->sc_lock)) { 883228561Snp mtx_lock(&t4_list_lock); 884228561Snp SLIST_REMOVE(&t4_list, sc, adapter, link); 885228561Snp mtx_unlock(&t4_list_lock); 886228561Snp mtx_destroy(&sc->sc_lock); 887228561Snp } 888218792Snp 889245274Snp if (mtx_initialized(&sc->tids.ftid_lock)) 890245274Snp mtx_destroy(&sc->tids.ftid_lock); 891228561Snp if (mtx_initialized(&sc->sfl_lock)) 892228561Snp mtx_destroy(&sc->sfl_lock); 893228561Snp 894218792Snp bzero(sc, sizeof(*sc)); 895218792Snp 896218792Snp return (0); 897218792Snp} 898218792Snp 899218792Snp 900218792Snpstatic int 901218792Snpcxgbe_probe(device_t dev) 902218792Snp{ 903218792Snp char buf[128]; 904218792Snp struct port_info *pi = device_get_softc(dev); 905218792Snp 906228561Snp snprintf(buf, sizeof(buf), "port %d", pi->port_id); 907218792Snp device_set_desc_copy(dev, buf); 908218792Snp 909218792Snp return (BUS_PROBE_DEFAULT); 910218792Snp} 911218792Snp 912218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \ 913218792Snp IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \ 914237831Snp IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6) 915237819Snp#define T4_CAP_ENABLE (T4_CAP) 916218792Snp 917218792Snpstatic int 918218792Snpcxgbe_attach(device_t dev) 919218792Snp{ 920218792Snp struct port_info *pi = device_get_softc(dev); 921218792Snp struct ifnet *ifp; 922218792Snp 923218792Snp /* Allocate an ifnet and set it up */ 924218792Snp ifp = if_alloc(IFT_ETHER); 925218792Snp if (ifp == NULL) { 926218792Snp device_printf(dev, "Cannot allocate ifnet\n"); 927218792Snp return (ENOMEM); 928218792Snp } 929218792Snp pi->ifp = ifp; 930218792Snp ifp->if_softc = pi; 931218792Snp 932218792Snp callout_init(&pi->tick, CALLOUT_MPSAFE); 933218792Snp 934218792Snp if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 935218792Snp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 936218792Snp 937218792Snp ifp->if_init = cxgbe_init; 938218792Snp ifp->if_ioctl = cxgbe_ioctl; 939218792Snp ifp->if_transmit = cxgbe_transmit; 940218792Snp ifp->if_qflush = cxgbe_qflush; 941218792Snp 942218792Snp ifp->if_capabilities = T4_CAP; 943237263Snp#ifdef TCP_OFFLOAD 944228561Snp if (is_offload(pi->adapter)) 945245933Snp ifp->if_capabilities |= IFCAP_TOE; 946228561Snp#endif 947218792Snp ifp->if_capenable = T4_CAP_ENABLE; 948237799Snp ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO | 949237799Snp CSUM_UDP_IPV6 | CSUM_TCP_IPV6; 950218792Snp 951218792Snp /* Initialize ifmedia for this port */ 952218792Snp ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change, 953218792Snp cxgbe_media_status); 954218792Snp build_medialist(pi); 955218792Snp 956237263Snp pi->vlan_c = EVENTHANDLER_REGISTER(vlan_config, cxgbe_vlan_config, ifp, 957237263Snp EVENTHANDLER_PRI_ANY); 958237263Snp 959218792Snp ether_ifattach(ifp, pi->hw_addr); 960218792Snp 961237263Snp#ifdef TCP_OFFLOAD 962228561Snp if (is_offload(pi->adapter)) { 963228561Snp device_printf(dev, 964228561Snp "%d txq, %d rxq (NIC); %d txq, %d rxq (TOE)\n", 965228561Snp pi->ntxq, pi->nrxq, pi->nofldtxq, pi->nofldrxq); 966228561Snp } else 967218792Snp#endif 968228561Snp device_printf(dev, "%d txq, %d rxq\n", pi->ntxq, pi->nrxq); 969218792Snp 970218792Snp cxgbe_sysctls(pi); 971218792Snp 972218792Snp return (0); 973218792Snp} 974218792Snp 975218792Snpstatic int 976218792Snpcxgbe_detach(device_t dev) 977218792Snp{ 978218792Snp struct port_info *pi = device_get_softc(dev); 979218792Snp struct adapter *sc = pi->adapter; 980228561Snp struct ifnet *ifp = pi->ifp; 981218792Snp 982218792Snp /* Tell if_ioctl and if_init that the port is going away */ 983218792Snp ADAPTER_LOCK(sc); 984218792Snp SET_DOOMED(pi); 985218792Snp wakeup(&sc->flags); 986218792Snp while (IS_BUSY(sc)) 987218792Snp mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0); 988218792Snp SET_BUSY(sc); 989245274Snp#ifdef INVARIANTS 990245274Snp sc->last_op = "t4detach"; 991245274Snp sc->last_op_thr = curthread; 992245274Snp#endif 993218792Snp ADAPTER_UNLOCK(sc); 994218792Snp 995237263Snp if (pi->vlan_c) 996237263Snp EVENTHANDLER_DEREGISTER(vlan_config, pi->vlan_c); 997237263Snp 998228561Snp PORT_LOCK(pi); 999228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1000228561Snp callout_stop(&pi->tick); 1001228561Snp PORT_UNLOCK(pi); 1002228561Snp callout_drain(&pi->tick); 1003218792Snp 1004228561Snp /* Let detach proceed even if these fail. */ 1005228561Snp cxgbe_uninit_synchronized(pi); 1006228561Snp port_full_uninit(pi); 1007219286Snp 1008218792Snp ifmedia_removeall(&pi->media); 1009218792Snp ether_ifdetach(pi->ifp); 1010218792Snp if_free(pi->ifp); 1011218792Snp 1012218792Snp ADAPTER_LOCK(sc); 1013218792Snp CLR_BUSY(sc); 1014245274Snp wakeup(&sc->flags); 1015218792Snp ADAPTER_UNLOCK(sc); 1016218792Snp 1017218792Snp return (0); 1018218792Snp} 1019218792Snp 1020218792Snpstatic void 1021218792Snpcxgbe_init(void *arg) 1022218792Snp{ 1023218792Snp struct port_info *pi = arg; 1024218792Snp struct adapter *sc = pi->adapter; 1025218792Snp 1026245274Snp if (begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4init") != 0) 1027245274Snp return; 1028245274Snp cxgbe_init_synchronized(pi); 1029245274Snp end_synchronized_op(sc, 0); 1030218792Snp} 1031218792Snp 1032218792Snpstatic int 1033218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) 1034218792Snp{ 1035218792Snp int rc = 0, mtu, flags; 1036218792Snp struct port_info *pi = ifp->if_softc; 1037218792Snp struct adapter *sc = pi->adapter; 1038218792Snp struct ifreq *ifr = (struct ifreq *)data; 1039218792Snp uint32_t mask; 1040218792Snp 1041218792Snp switch (cmd) { 1042218792Snp case SIOCSIFMTU: 1043245274Snp mtu = ifr->ifr_mtu; 1044245274Snp if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) 1045245274Snp return (EINVAL); 1046245274Snp 1047245274Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4mtu"); 1048245274Snp if (rc) 1049218792Snp return (rc); 1050245274Snp ifp->if_mtu = mtu; 1051245274Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1052245274Snp t4_update_fl_bufsize(ifp); 1053245274Snp rc = update_mac_settings(pi, XGMAC_MTU); 1054218792Snp } 1055245274Snp end_synchronized_op(sc, 0); 1056218792Snp break; 1057218792Snp 1058218792Snp case SIOCSIFFLAGS: 1059245274Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4flg"); 1060245274Snp if (rc) 1061245274Snp return (rc); 1062245274Snp 1063218792Snp if (ifp->if_flags & IFF_UP) { 1064218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1065218792Snp flags = pi->if_flags; 1066218792Snp if ((ifp->if_flags ^ flags) & 1067218792Snp (IFF_PROMISC | IFF_ALLMULTI)) { 1068218792Snp rc = update_mac_settings(pi, 1069218792Snp XGMAC_PROMISC | XGMAC_ALLMULTI); 1070218792Snp } 1071218792Snp } else 1072245274Snp rc = cxgbe_init_synchronized(pi); 1073218792Snp pi->if_flags = ifp->if_flags; 1074218792Snp } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1075245274Snp rc = cxgbe_uninit_synchronized(pi); 1076245274Snp end_synchronized_op(sc, 0); 1077218792Snp break; 1078218792Snp 1079218792Snp case SIOCADDMULTI: 1080245274Snp case SIOCDELMULTI: /* these two are called with a mutex held :-( */ 1081245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK, "t4multi"); 1082218792Snp if (rc) 1083245274Snp return (rc); 1084245274Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1085218792Snp rc = update_mac_settings(pi, XGMAC_MCADDRS); 1086245274Snp end_synchronized_op(sc, LOCK_HELD); 1087218792Snp break; 1088218792Snp 1089218792Snp case SIOCSIFCAP: 1090245274Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4cap"); 1091218792Snp if (rc) 1092245274Snp return (rc); 1093218792Snp 1094218792Snp mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1095218792Snp if (mask & IFCAP_TXCSUM) { 1096218792Snp ifp->if_capenable ^= IFCAP_TXCSUM; 1097218792Snp ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 1098218792Snp 1099237831Snp if (IFCAP_TSO4 & ifp->if_capenable && 1100218792Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1101237799Snp ifp->if_capenable &= ~IFCAP_TSO4; 1102218792Snp if_printf(ifp, 1103237831Snp "tso4 disabled due to -txcsum.\n"); 1104218792Snp } 1105218792Snp } 1106237799Snp if (mask & IFCAP_TXCSUM_IPV6) { 1107237799Snp ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 1108237799Snp ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); 1109237799Snp 1110237799Snp if (IFCAP_TSO6 & ifp->if_capenable && 1111237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1112237799Snp ifp->if_capenable &= ~IFCAP_TSO6; 1113237799Snp if_printf(ifp, 1114237799Snp "tso6 disabled due to -txcsum6.\n"); 1115237799Snp } 1116237799Snp } 1117218792Snp if (mask & IFCAP_RXCSUM) 1118218792Snp ifp->if_capenable ^= IFCAP_RXCSUM; 1119237799Snp if (mask & IFCAP_RXCSUM_IPV6) 1120237799Snp ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 1121237799Snp 1122237799Snp /* 1123237799Snp * Note that we leave CSUM_TSO alone (it is always set). The 1124237799Snp * kernel takes both IFCAP_TSOx and CSUM_TSO into account before 1125237799Snp * sending a TSO request our way, so it's sufficient to toggle 1126237799Snp * IFCAP_TSOx only. 1127237799Snp */ 1128218792Snp if (mask & IFCAP_TSO4) { 1129237799Snp if (!(IFCAP_TSO4 & ifp->if_capenable) && 1130237799Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1131237799Snp if_printf(ifp, "enable txcsum first.\n"); 1132237799Snp rc = EAGAIN; 1133237799Snp goto fail; 1134237799Snp } 1135218792Snp ifp->if_capenable ^= IFCAP_TSO4; 1136218792Snp } 1137237799Snp if (mask & IFCAP_TSO6) { 1138237799Snp if (!(IFCAP_TSO6 & ifp->if_capenable) && 1139237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1140237799Snp if_printf(ifp, "enable txcsum6 first.\n"); 1141237799Snp rc = EAGAIN; 1142237799Snp goto fail; 1143237799Snp } 1144237799Snp ifp->if_capenable ^= IFCAP_TSO6; 1145237799Snp } 1146218792Snp if (mask & IFCAP_LRO) { 1147237819Snp#if defined(INET) || defined(INET6) 1148218792Snp int i; 1149218792Snp struct sge_rxq *rxq; 1150218792Snp 1151218792Snp ifp->if_capenable ^= IFCAP_LRO; 1152218792Snp for_each_rxq(pi, i, rxq) { 1153218792Snp if (ifp->if_capenable & IFCAP_LRO) 1154228561Snp rxq->iq.flags |= IQ_LRO_ENABLED; 1155218792Snp else 1156228561Snp rxq->iq.flags &= ~IQ_LRO_ENABLED; 1157218792Snp } 1158218792Snp#endif 1159218792Snp } 1160237263Snp#ifdef TCP_OFFLOAD 1161228561Snp if (mask & IFCAP_TOE) { 1162228561Snp int enable = (ifp->if_capenable ^ mask) & IFCAP_TOE; 1163228561Snp 1164228561Snp rc = toe_capability(pi, enable); 1165228561Snp if (rc != 0) 1166228561Snp goto fail; 1167228561Snp 1168228561Snp ifp->if_capenable ^= mask; 1169218792Snp } 1170218792Snp#endif 1171218792Snp if (mask & IFCAP_VLAN_HWTAGGING) { 1172218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1173245274Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1174218792Snp rc = update_mac_settings(pi, XGMAC_VLANEX); 1175218792Snp } 1176218792Snp if (mask & IFCAP_VLAN_MTU) { 1177218792Snp ifp->if_capenable ^= IFCAP_VLAN_MTU; 1178218792Snp 1179218792Snp /* Need to find out how to disable auto-mtu-inflation */ 1180218792Snp } 1181218792Snp if (mask & IFCAP_VLAN_HWTSO) 1182218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1183218792Snp if (mask & IFCAP_VLAN_HWCSUM) 1184218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 1185218792Snp 1186218792Snp#ifdef VLAN_CAPABILITIES 1187218792Snp VLAN_CAPABILITIES(ifp); 1188218792Snp#endif 1189245274Snpfail: 1190245274Snp end_synchronized_op(sc, 0); 1191218792Snp break; 1192218792Snp 1193218792Snp case SIOCSIFMEDIA: 1194218792Snp case SIOCGIFMEDIA: 1195218792Snp ifmedia_ioctl(ifp, ifr, &pi->media, cmd); 1196218792Snp break; 1197218792Snp 1198218792Snp default: 1199218792Snp rc = ether_ioctl(ifp, cmd, data); 1200218792Snp } 1201218792Snp 1202218792Snp return (rc); 1203218792Snp} 1204218792Snp 1205218792Snpstatic int 1206218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m) 1207218792Snp{ 1208218792Snp struct port_info *pi = ifp->if_softc; 1209218792Snp struct adapter *sc = pi->adapter; 1210218792Snp struct sge_txq *txq = &sc->sge.txq[pi->first_txq]; 1211218792Snp struct buf_ring *br; 1212218792Snp int rc; 1213218792Snp 1214218792Snp M_ASSERTPKTHDR(m); 1215218792Snp 1216228561Snp if (__predict_false(pi->link_cfg.link_ok == 0)) { 1217218792Snp m_freem(m); 1218228561Snp return (ENETDOWN); 1219218792Snp } 1220218792Snp 1221218792Snp if (m->m_flags & M_FLOWID) 1222218792Snp txq += (m->m_pkthdr.flowid % pi->ntxq); 1223220873Snp br = txq->br; 1224218792Snp 1225218792Snp if (TXQ_TRYLOCK(txq) == 0) { 1226228561Snp struct sge_eq *eq = &txq->eq; 1227228561Snp 1228218792Snp /* 1229228561Snp * It is possible that t4_eth_tx finishes up and releases the 1230228561Snp * lock between the TRYLOCK above and the drbr_enqueue here. We 1231228561Snp * need to make sure that this mbuf doesn't just sit there in 1232228561Snp * the drbr. 1233218792Snp */ 1234218792Snp 1235228561Snp rc = drbr_enqueue(ifp, br, m); 1236228561Snp if (rc == 0 && callout_pending(&eq->tx_callout) == 0 && 1237228561Snp !(eq->flags & EQ_DOOMED)) 1238228561Snp callout_reset(&eq->tx_callout, 1, t4_tx_callout, eq); 1239228561Snp return (rc); 1240218792Snp } 1241218792Snp 1242218792Snp /* 1243218792Snp * txq->m is the mbuf that is held up due to a temporary shortage of 1244218792Snp * resources and it should be put on the wire first. Then what's in 1245218792Snp * drbr and finally the mbuf that was just passed in to us. 1246218792Snp * 1247218792Snp * Return code should indicate the fate of the mbuf that was passed in 1248218792Snp * this time. 1249218792Snp */ 1250218792Snp 1251218792Snp TXQ_LOCK_ASSERT_OWNED(txq); 1252218792Snp if (drbr_needs_enqueue(ifp, br) || txq->m) { 1253218792Snp 1254218792Snp /* Queued for transmission. */ 1255218792Snp 1256218792Snp rc = drbr_enqueue(ifp, br, m); 1257218792Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 1258218792Snp (void) t4_eth_tx(ifp, txq, m); 1259218792Snp TXQ_UNLOCK(txq); 1260218792Snp return (rc); 1261218792Snp } 1262218792Snp 1263218792Snp /* Direct transmission. */ 1264218792Snp rc = t4_eth_tx(ifp, txq, m); 1265218792Snp if (rc != 0 && txq->m) 1266218792Snp rc = 0; /* held, will be transmitted soon (hopefully) */ 1267218792Snp 1268218792Snp TXQ_UNLOCK(txq); 1269218792Snp return (rc); 1270218792Snp} 1271218792Snp 1272218792Snpstatic void 1273218792Snpcxgbe_qflush(struct ifnet *ifp) 1274218792Snp{ 1275218792Snp struct port_info *pi = ifp->if_softc; 1276220649Snp struct sge_txq *txq; 1277220649Snp int i; 1278220649Snp struct mbuf *m; 1279218792Snp 1280228561Snp /* queues do not exist if !PORT_INIT_DONE. */ 1281228561Snp if (pi->flags & PORT_INIT_DONE) { 1282220649Snp for_each_txq(pi, i, txq) { 1283220649Snp TXQ_LOCK(txq); 1284220649Snp m_freem(txq->m); 1285228561Snp txq->m = NULL; 1286220873Snp while ((m = buf_ring_dequeue_sc(txq->br)) != NULL) 1287220649Snp m_freem(m); 1288220649Snp TXQ_UNLOCK(txq); 1289220649Snp } 1290220649Snp } 1291220649Snp if_qflush(ifp); 1292218792Snp} 1293218792Snp 1294218792Snpstatic int 1295218792Snpcxgbe_media_change(struct ifnet *ifp) 1296218792Snp{ 1297218792Snp struct port_info *pi = ifp->if_softc; 1298218792Snp 1299218792Snp device_printf(pi->dev, "%s unimplemented.\n", __func__); 1300218792Snp 1301218792Snp return (EOPNOTSUPP); 1302218792Snp} 1303218792Snp 1304218792Snpstatic void 1305218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1306218792Snp{ 1307218792Snp struct port_info *pi = ifp->if_softc; 1308218792Snp struct ifmedia_entry *cur = pi->media.ifm_cur; 1309218792Snp int speed = pi->link_cfg.speed; 1310218792Snp int data = (pi->port_type << 8) | pi->mod_type; 1311218792Snp 1312218792Snp if (cur->ifm_data != data) { 1313218792Snp build_medialist(pi); 1314218792Snp cur = pi->media.ifm_cur; 1315218792Snp } 1316218792Snp 1317218792Snp ifmr->ifm_status = IFM_AVALID; 1318218792Snp if (!pi->link_cfg.link_ok) 1319218792Snp return; 1320218792Snp 1321218792Snp ifmr->ifm_status |= IFM_ACTIVE; 1322218792Snp 1323218792Snp /* active and current will differ iff current media is autoselect. */ 1324218792Snp if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO) 1325218792Snp return; 1326218792Snp 1327218792Snp ifmr->ifm_active = IFM_ETHER | IFM_FDX; 1328218792Snp if (speed == SPEED_10000) 1329218792Snp ifmr->ifm_active |= IFM_10G_T; 1330218792Snp else if (speed == SPEED_1000) 1331218792Snp ifmr->ifm_active |= IFM_1000_T; 1332218792Snp else if (speed == SPEED_100) 1333218792Snp ifmr->ifm_active |= IFM_100_TX; 1334218792Snp else if (speed == SPEED_10) 1335218792Snp ifmr->ifm_active |= IFM_10_T; 1336218792Snp else 1337218792Snp KASSERT(0, ("%s: link up but speed unknown (%u)", __func__, 1338218792Snp speed)); 1339218792Snp} 1340218792Snp 1341218792Snpvoid 1342218792Snpt4_fatal_err(struct adapter *sc) 1343218792Snp{ 1344218792Snp t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0); 1345218792Snp t4_intr_disable(sc); 1346218792Snp log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n", 1347218792Snp device_get_nameunit(sc->dev)); 1348218792Snp} 1349218792Snp 1350218792Snpstatic int 1351248925Snpmap_bars_0_and_4(struct adapter *sc) 1352218792Snp{ 1353218792Snp sc->regs_rid = PCIR_BAR(0); 1354218792Snp sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1355218792Snp &sc->regs_rid, RF_ACTIVE); 1356218792Snp if (sc->regs_res == NULL) { 1357218792Snp device_printf(sc->dev, "cannot map registers.\n"); 1358218792Snp return (ENXIO); 1359218792Snp } 1360218792Snp sc->bt = rman_get_bustag(sc->regs_res); 1361218792Snp sc->bh = rman_get_bushandle(sc->regs_res); 1362218792Snp sc->mmio_len = rman_get_size(sc->regs_res); 1363248925Snp setbit(&sc->doorbells, DOORBELL_KDB); 1364218792Snp 1365218792Snp sc->msix_rid = PCIR_BAR(4); 1366218792Snp sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1367218792Snp &sc->msix_rid, RF_ACTIVE); 1368218792Snp if (sc->msix_res == NULL) { 1369218792Snp device_printf(sc->dev, "cannot map MSI-X BAR.\n"); 1370218792Snp return (ENXIO); 1371218792Snp } 1372218792Snp 1373218792Snp return (0); 1374218792Snp} 1375218792Snp 1376248925Snpstatic int 1377248925Snpmap_bar_2(struct adapter *sc) 1378248925Snp{ 1379248925Snp 1380248925Snp /* 1381248925Snp * T4: only iWARP driver uses the userspace doorbells. There is no need 1382248925Snp * to map it if RDMA is disabled. 1383248925Snp */ 1384248925Snp if (is_t4(sc) && sc->rdmacaps == 0) 1385248925Snp return (0); 1386248925Snp 1387248925Snp sc->udbs_rid = PCIR_BAR(2); 1388248925Snp sc->udbs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1389248925Snp &sc->udbs_rid, RF_ACTIVE); 1390248925Snp if (sc->udbs_res == NULL) { 1391248925Snp device_printf(sc->dev, "cannot map doorbell BAR.\n"); 1392248925Snp return (ENXIO); 1393248925Snp } 1394248925Snp sc->udbs_base = rman_get_virtual(sc->udbs_res); 1395248925Snp 1396248925Snp if (is_t5(sc)) { 1397248925Snp setbit(&sc->doorbells, DOORBELL_UDB); 1398248925Snp#if defined(__i386__) || defined(__amd64__) 1399248925Snp if (t5_write_combine) { 1400248925Snp int rc; 1401248925Snp 1402248925Snp /* 1403248925Snp * Enable write combining on BAR2. This is the 1404248925Snp * userspace doorbell BAR and is split into 128B 1405248925Snp * (UDBS_SEG_SIZE) doorbell regions, each associated 1406248925Snp * with an egress queue. The first 64B has the doorbell 1407248925Snp * and the second 64B can be used to submit a tx work 1408248925Snp * request with an implicit doorbell. 1409248925Snp */ 1410248925Snp 1411248925Snp rc = pmap_change_attr((vm_offset_t)sc->udbs_base, 1412248925Snp rman_get_size(sc->udbs_res), PAT_WRITE_COMBINING); 1413248925Snp if (rc == 0) { 1414248925Snp clrbit(&sc->doorbells, DOORBELL_UDB); 1415248925Snp setbit(&sc->doorbells, DOORBELL_WRWC); 1416248925Snp setbit(&sc->doorbells, DOORBELL_UDBWC); 1417248925Snp } else { 1418248925Snp device_printf(sc->dev, 1419248925Snp "couldn't enable write combining: %d\n", 1420248925Snp rc); 1421248925Snp } 1422248925Snp 1423248925Snp t4_write_reg(sc, A_SGE_STAT_CFG, 1424248925Snp V_STATSOURCE_T5(7) | V_STATMODE(0)); 1425248925Snp } 1426248925Snp#endif 1427248925Snp } 1428248925Snp 1429248925Snp return (0); 1430248925Snp} 1431248925Snp 1432248925Snpstatic const struct memwin t4_memwin[] = { 1433248925Snp { MEMWIN0_BASE, MEMWIN0_APERTURE }, 1434248925Snp { MEMWIN1_BASE, MEMWIN1_APERTURE }, 1435248925Snp { MEMWIN2_BASE_T4, MEMWIN2_APERTURE_T4 } 1436248925Snp}; 1437248925Snp 1438248925Snpstatic const struct memwin t5_memwin[] = { 1439248925Snp { MEMWIN0_BASE, MEMWIN0_APERTURE }, 1440248925Snp { MEMWIN1_BASE, MEMWIN1_APERTURE }, 1441248925Snp { MEMWIN2_BASE_T5, MEMWIN2_APERTURE_T5 }, 1442248925Snp}; 1443248925Snp 1444218792Snpstatic void 1445218792Snpsetup_memwin(struct adapter *sc) 1446218792Snp{ 1447248925Snp const struct memwin *mw; 1448248925Snp int i, n; 1449237587Snp uint32_t bar0; 1450218792Snp 1451248925Snp if (is_t4(sc)) { 1452248925Snp /* 1453248925Snp * Read low 32b of bar0 indirectly via the hardware backdoor 1454248925Snp * mechanism. Works from within PCI passthrough environments 1455248925Snp * too, where rman_get_start() can return a different value. We 1456248925Snp * need to program the T4 memory window decoders with the actual 1457248925Snp * addresses that will be coming across the PCIe link. 1458248925Snp */ 1459248925Snp bar0 = t4_hw_pci_read_cfg4(sc, PCIR_BAR(0)); 1460248925Snp bar0 &= (uint32_t) PCIM_BAR_MEM_BASE; 1461218792Snp 1462248925Snp mw = &t4_memwin[0]; 1463248925Snp n = nitems(t4_memwin); 1464248925Snp } else { 1465248925Snp /* T5 uses the relative offset inside the PCIe BAR */ 1466248925Snp bar0 = 0; 1467218792Snp 1468248925Snp mw = &t5_memwin[0]; 1469248925Snp n = nitems(t5_memwin); 1470248925Snp } 1471218792Snp 1472248925Snp for (i = 0; i < n; i++, mw++) { 1473248925Snp t4_write_reg(sc, 1474248925Snp PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, i), 1475248925Snp (mw->base + bar0) | V_BIR(0) | 1476248925Snp V_WINDOW(ilog2(mw->aperture) - 10)); 1477248925Snp } 1478237587Snp 1479237587Snp /* flush */ 1480237587Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2)); 1481218792Snp} 1482218792Snp 1483248925Snp/* 1484248925Snp * Verify that the memory range specified by the addr/len pair is valid and lies 1485248925Snp * entirely within a single region (EDCx or MCx). 1486248925Snp */ 1487218792Snpstatic int 1488248925Snpvalidate_mem_range(struct adapter *sc, uint32_t addr, int len) 1489248925Snp{ 1490248925Snp uint32_t em, addr_len, maddr, mlen; 1491248925Snp 1492248925Snp /* Memory can only be accessed in naturally aligned 4 byte units */ 1493248925Snp if (addr & 3 || len & 3 || len == 0) 1494248925Snp return (EINVAL); 1495248925Snp 1496248925Snp /* Enabled memories */ 1497248925Snp em = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 1498248925Snp if (em & F_EDRAM0_ENABLE) { 1499248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM0_BAR); 1500248925Snp maddr = G_EDRAM0_BASE(addr_len) << 20; 1501248925Snp mlen = G_EDRAM0_SIZE(addr_len) << 20; 1502248925Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1503248925Snp addr + len <= maddr + mlen) 1504248925Snp return (0); 1505248925Snp } 1506248925Snp if (em & F_EDRAM1_ENABLE) { 1507248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM1_BAR); 1508248925Snp maddr = G_EDRAM1_BASE(addr_len) << 20; 1509248925Snp mlen = G_EDRAM1_SIZE(addr_len) << 20; 1510248925Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1511248925Snp addr + len <= maddr + mlen) 1512248925Snp return (0); 1513248925Snp } 1514248925Snp if (em & F_EXT_MEM_ENABLE) { 1515248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 1516248925Snp maddr = G_EXT_MEM_BASE(addr_len) << 20; 1517248925Snp mlen = G_EXT_MEM_SIZE(addr_len) << 20; 1518248925Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1519248925Snp addr + len <= maddr + mlen) 1520248925Snp return (0); 1521248925Snp } 1522248925Snp if (!is_t4(sc) && em & F_EXT_MEM1_ENABLE) { 1523248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 1524248925Snp maddr = G_EXT_MEM1_BASE(addr_len) << 20; 1525248925Snp mlen = G_EXT_MEM1_SIZE(addr_len) << 20; 1526248925Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1527248925Snp addr + len <= maddr + mlen) 1528248925Snp return (0); 1529248925Snp } 1530248925Snp 1531248925Snp return (EFAULT); 1532248925Snp} 1533248925Snp 1534248925Snp/* 1535248925Snp * Verify that the memory range specified by the memtype/offset/len pair is 1536248925Snp * valid and lies entirely within the memtype specified. The global address of 1537248925Snp * the start of the range is returned in addr. 1538248925Snp */ 1539248925Snpstatic int 1540248925Snpvalidate_mt_off_len(struct adapter *sc, int mtype, uint32_t off, int len, 1541248925Snp uint32_t *addr) 1542248925Snp{ 1543248925Snp uint32_t em, addr_len, maddr, mlen; 1544248925Snp 1545248925Snp /* Memory can only be accessed in naturally aligned 4 byte units */ 1546248925Snp if (off & 3 || len & 3 || len == 0) 1547248925Snp return (EINVAL); 1548248925Snp 1549248925Snp em = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 1550248925Snp switch (mtype) { 1551248925Snp case MEM_EDC0: 1552248925Snp if (!(em & F_EDRAM0_ENABLE)) 1553248925Snp return (EINVAL); 1554248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM0_BAR); 1555248925Snp maddr = G_EDRAM0_BASE(addr_len) << 20; 1556248925Snp mlen = G_EDRAM0_SIZE(addr_len) << 20; 1557248925Snp break; 1558248925Snp case MEM_EDC1: 1559248925Snp if (!(em & F_EDRAM1_ENABLE)) 1560248925Snp return (EINVAL); 1561248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM1_BAR); 1562248925Snp maddr = G_EDRAM1_BASE(addr_len) << 20; 1563248925Snp mlen = G_EDRAM1_SIZE(addr_len) << 20; 1564248925Snp break; 1565248925Snp case MEM_MC: 1566248925Snp if (!(em & F_EXT_MEM_ENABLE)) 1567248925Snp return (EINVAL); 1568248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 1569248925Snp maddr = G_EXT_MEM_BASE(addr_len) << 20; 1570248925Snp mlen = G_EXT_MEM_SIZE(addr_len) << 20; 1571248925Snp break; 1572248925Snp case MEM_MC1: 1573248925Snp if (is_t4(sc) || !(em & F_EXT_MEM1_ENABLE)) 1574248925Snp return (EINVAL); 1575248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 1576248925Snp maddr = G_EXT_MEM1_BASE(addr_len) << 20; 1577248925Snp mlen = G_EXT_MEM1_SIZE(addr_len) << 20; 1578248925Snp break; 1579248925Snp default: 1580248925Snp return (EINVAL); 1581248925Snp } 1582248925Snp 1583248925Snp if (mlen > 0 && off < mlen && off + len <= mlen) { 1584248925Snp *addr = maddr + off; /* global address */ 1585248925Snp return (0); 1586248925Snp } 1587248925Snp 1588248925Snp return (EFAULT); 1589248925Snp} 1590248925Snp 1591248925Snpstatic void 1592248925Snpmemwin_info(struct adapter *sc, int win, uint32_t *base, uint32_t *aperture) 1593248925Snp{ 1594248925Snp const struct memwin *mw; 1595248925Snp 1596248925Snp if (is_t4(sc)) { 1597248925Snp KASSERT(win >= 0 && win < nitems(t4_memwin), 1598248925Snp ("%s: incorrect memwin# (%d)", __func__, win)); 1599248925Snp mw = &t4_memwin[win]; 1600248925Snp } else { 1601248925Snp KASSERT(win >= 0 && win < nitems(t5_memwin), 1602248925Snp ("%s: incorrect memwin# (%d)", __func__, win)); 1603248925Snp mw = &t5_memwin[win]; 1604248925Snp } 1605248925Snp 1606248925Snp if (base != NULL) 1607248925Snp *base = mw->base; 1608248925Snp if (aperture != NULL) 1609248925Snp *aperture = mw->aperture; 1610248925Snp} 1611248925Snp 1612248925Snp/* 1613248925Snp * Positions the memory window such that it can be used to access the specified 1614248925Snp * address in the chip's address space. The return value is the offset of addr 1615248925Snp * from the start of the window. 1616248925Snp */ 1617248925Snpstatic uint32_t 1618248925Snpposition_memwin(struct adapter *sc, int n, uint32_t addr) 1619248925Snp{ 1620248925Snp uint32_t start, pf; 1621248925Snp uint32_t reg; 1622248925Snp 1623248925Snp KASSERT(n >= 0 && n <= 3, 1624248925Snp ("%s: invalid window %d.", __func__, n)); 1625248925Snp KASSERT((addr & 3) == 0, 1626248925Snp ("%s: addr (0x%x) is not at a 4B boundary.", __func__, addr)); 1627248925Snp 1628248925Snp if (is_t4(sc)) { 1629248925Snp pf = 0; 1630248925Snp start = addr & ~0xf; /* start must be 16B aligned */ 1631248925Snp } else { 1632248925Snp pf = V_PFNUM(sc->pf); 1633248925Snp start = addr & ~0x7f; /* start must be 128B aligned */ 1634248925Snp } 1635248925Snp reg = PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, n); 1636248925Snp 1637248925Snp t4_write_reg(sc, reg, start | pf); 1638248925Snp t4_read_reg(sc, reg); 1639248925Snp 1640248925Snp return (addr - start); 1641248925Snp} 1642248925Snp 1643248925Snpstatic int 1644218792Snpcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g, 1645218792Snp struct intrs_and_queues *iaq) 1646218792Snp{ 1647228561Snp int rc, itype, navail, nrxq10g, nrxq1g, n; 1648228561Snp int nofldrxq10g = 0, nofldrxq1g = 0; 1649218792Snp 1650218792Snp bzero(iaq, sizeof(*iaq)); 1651218792Snp 1652228561Snp iaq->ntxq10g = t4_ntxq10g; 1653228561Snp iaq->ntxq1g = t4_ntxq1g; 1654228561Snp iaq->nrxq10g = nrxq10g = t4_nrxq10g; 1655228561Snp iaq->nrxq1g = nrxq1g = t4_nrxq1g; 1656237263Snp#ifdef TCP_OFFLOAD 1657237463Snp if (is_offload(sc)) { 1658237463Snp iaq->nofldtxq10g = t4_nofldtxq10g; 1659237463Snp iaq->nofldtxq1g = t4_nofldtxq1g; 1660237463Snp iaq->nofldrxq10g = nofldrxq10g = t4_nofldrxq10g; 1661237463Snp iaq->nofldrxq1g = nofldrxq1g = t4_nofldrxq1g; 1662237463Snp } 1663228561Snp#endif 1664228561Snp 1665219944Snp for (itype = INTR_MSIX; itype; itype >>= 1) { 1666218792Snp 1667228561Snp if ((itype & t4_intr_types) == 0) 1668218792Snp continue; /* not allowed */ 1669218792Snp 1670219944Snp if (itype == INTR_MSIX) 1671218792Snp navail = pci_msix_count(sc->dev); 1672219944Snp else if (itype == INTR_MSI) 1673218792Snp navail = pci_msi_count(sc->dev); 1674218792Snp else 1675218792Snp navail = 1; 1676228561Snprestart: 1677218792Snp if (navail == 0) 1678218792Snp continue; 1679218792Snp 1680218792Snp iaq->intr_type = itype; 1681228561Snp iaq->intr_flags = 0; 1682218792Snp 1683228561Snp /* 1684228561Snp * Best option: an interrupt vector for errors, one for the 1685228561Snp * firmware event queue, and one each for each rxq (NIC as well 1686228561Snp * as offload). 1687228561Snp */ 1688228561Snp iaq->nirq = T4_EXTRA_INTR; 1689228561Snp iaq->nirq += n10g * (nrxq10g + nofldrxq10g); 1690228561Snp iaq->nirq += n1g * (nrxq1g + nofldrxq1g); 1691228561Snp if (iaq->nirq <= navail && 1692228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) { 1693228561Snp iaq->intr_flags |= INTR_DIRECT; 1694228561Snp goto allocate; 1695228561Snp } 1696218792Snp 1697228561Snp /* 1698228561Snp * Second best option: an interrupt vector for errors, one for 1699228561Snp * the firmware event queue, and one each for either NIC or 1700228561Snp * offload rxq's. 1701228561Snp */ 1702228561Snp iaq->nirq = T4_EXTRA_INTR; 1703228561Snp iaq->nirq += n10g * max(nrxq10g, nofldrxq10g); 1704228561Snp iaq->nirq += n1g * max(nrxq1g, nofldrxq1g); 1705228561Snp if (iaq->nirq <= navail && 1706228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) 1707228561Snp goto allocate; 1708218792Snp 1709228561Snp /* 1710228561Snp * Next best option: an interrupt vector for errors, one for the 1711228561Snp * firmware event queue, and at least one per port. At this 1712228561Snp * point we know we'll have to downsize nrxq or nofldrxq to fit 1713228561Snp * what's available to us. 1714228561Snp */ 1715228561Snp iaq->nirq = T4_EXTRA_INTR; 1716228561Snp iaq->nirq += n10g + n1g; 1717228561Snp if (iaq->nirq <= navail) { 1718228561Snp int leftover = navail - iaq->nirq; 1719218792Snp 1720228561Snp if (n10g > 0) { 1721228561Snp int target = max(nrxq10g, nofldrxq10g); 1722219944Snp 1723228561Snp n = 1; 1724228561Snp while (n < target && leftover >= n10g) { 1725228561Snp leftover -= n10g; 1726228561Snp iaq->nirq += n10g; 1727228561Snp n++; 1728228561Snp } 1729228561Snp iaq->nrxq10g = min(n, nrxq10g); 1730237263Snp#ifdef TCP_OFFLOAD 1731237463Snp if (is_offload(sc)) 1732237463Snp iaq->nofldrxq10g = min(n, nofldrxq10g); 1733228561Snp#endif 1734228561Snp } 1735218792Snp 1736228561Snp if (n1g > 0) { 1737228561Snp int target = max(nrxq1g, nofldrxq1g); 1738219944Snp 1739228561Snp n = 1; 1740228561Snp while (n < target && leftover >= n1g) { 1741228561Snp leftover -= n1g; 1742228561Snp iaq->nirq += n1g; 1743228561Snp n++; 1744219944Snp } 1745228561Snp iaq->nrxq1g = min(n, nrxq1g); 1746237263Snp#ifdef TCP_OFFLOAD 1747237463Snp if (is_offload(sc)) 1748237463Snp iaq->nofldrxq1g = min(n, nofldrxq1g); 1749228561Snp#endif 1750219944Snp } 1751219944Snp 1752228561Snp if (itype != INTR_MSI || powerof2(iaq->nirq)) 1753228561Snp goto allocate; 1754218792Snp } 1755218792Snp 1756228561Snp /* 1757228561Snp * Least desirable option: one interrupt vector for everything. 1758228561Snp */ 1759228561Snp iaq->nirq = iaq->nrxq10g = iaq->nrxq1g = 1; 1760237263Snp#ifdef TCP_OFFLOAD 1761237463Snp if (is_offload(sc)) 1762237463Snp iaq->nofldrxq10g = iaq->nofldrxq1g = 1; 1763228561Snp#endif 1764228561Snp 1765228561Snpallocate: 1766218792Snp navail = iaq->nirq; 1767218792Snp rc = 0; 1768219944Snp if (itype == INTR_MSIX) 1769218792Snp rc = pci_alloc_msix(sc->dev, &navail); 1770219944Snp else if (itype == INTR_MSI) 1771218792Snp rc = pci_alloc_msi(sc->dev, &navail); 1772218792Snp 1773218792Snp if (rc == 0) { 1774218792Snp if (navail == iaq->nirq) 1775218792Snp return (0); 1776218792Snp 1777218792Snp /* 1778218792Snp * Didn't get the number requested. Use whatever number 1779218792Snp * the kernel is willing to allocate (it's in navail). 1780218792Snp */ 1781228561Snp device_printf(sc->dev, "fewer vectors than requested, " 1782228561Snp "type=%d, req=%d, rcvd=%d; will downshift req.\n", 1783228561Snp itype, iaq->nirq, navail); 1784218792Snp pci_release_msi(sc->dev); 1785228561Snp goto restart; 1786218792Snp } 1787218792Snp 1788218792Snp device_printf(sc->dev, 1789218792Snp "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n", 1790218792Snp itype, rc, iaq->nirq, navail); 1791218792Snp } 1792218792Snp 1793218792Snp device_printf(sc->dev, 1794218792Snp "failed to find a usable interrupt type. " 1795228561Snp "allowed=%d, msi-x=%d, msi=%d, intx=1", t4_intr_types, 1796218792Snp pci_msix_count(sc->dev), pci_msi_count(sc->dev)); 1797218792Snp 1798218792Snp return (ENXIO); 1799218792Snp} 1800218792Snp 1801248925Snp#define FW_VERSION(chip) ( \ 1802248925Snp V_FW_HDR_FW_VER_MAJOR(FW_VERSION_MAJOR_##chip) | \ 1803248925Snp V_FW_HDR_FW_VER_MINOR(FW_VERSION_MINOR_##chip) | \ 1804248925Snp V_FW_HDR_FW_VER_MICRO(FW_VERSION_MICRO_##chip) | \ 1805248925Snp V_FW_HDR_FW_VER_BUILD(FW_VERSION_BUILD_##chip)) 1806248925Snp#define FW_INTFVER(chip, intf) (FW_HDR_INTFVER_##intf) 1807248925Snp 1808248925Snpstruct fw_info { 1809248925Snp uint8_t chip; 1810248925Snp char *kld_name; 1811248925Snp char *fw_mod_name; 1812248925Snp struct fw_hdr fw_hdr; /* XXX: waste of space, need a sparse struct */ 1813248925Snp} fw_info[] = { 1814248925Snp { 1815248925Snp .chip = CHELSIO_T4, 1816248925Snp .kld_name = "t4fw_cfg", 1817248925Snp .fw_mod_name = "t4fw", 1818248925Snp .fw_hdr = { 1819248925Snp .chip = FW_HDR_CHIP_T4, 1820248925Snp .fw_ver = htobe32_const(FW_VERSION(T4)), 1821248925Snp .intfver_nic = FW_INTFVER(T4, NIC), 1822248925Snp .intfver_vnic = FW_INTFVER(T4, VNIC), 1823248925Snp .intfver_ofld = FW_INTFVER(T4, OFLD), 1824248925Snp .intfver_ri = FW_INTFVER(T4, RI), 1825248925Snp .intfver_iscsipdu = FW_INTFVER(T4, ISCSIPDU), 1826248925Snp .intfver_iscsi = FW_INTFVER(T4, ISCSI), 1827248925Snp .intfver_fcoepdu = FW_INTFVER(T4, FCOEPDU), 1828248925Snp .intfver_fcoe = FW_INTFVER(T4, FCOE), 1829248925Snp }, 1830248925Snp }, { 1831248925Snp .chip = CHELSIO_T5, 1832248925Snp .kld_name = "t5fw_cfg", 1833248925Snp .fw_mod_name = "t5fw", 1834248925Snp .fw_hdr = { 1835248925Snp .chip = FW_HDR_CHIP_T5, 1836248925Snp .fw_ver = htobe32_const(FW_VERSION(T5)), 1837248925Snp .intfver_nic = FW_INTFVER(T5, NIC), 1838248925Snp .intfver_vnic = FW_INTFVER(T5, VNIC), 1839248925Snp .intfver_ofld = FW_INTFVER(T5, OFLD), 1840248925Snp .intfver_ri = FW_INTFVER(T5, RI), 1841248925Snp .intfver_iscsipdu = FW_INTFVER(T5, ISCSIPDU), 1842248925Snp .intfver_iscsi = FW_INTFVER(T5, ISCSI), 1843248925Snp .intfver_fcoepdu = FW_INTFVER(T5, FCOEPDU), 1844248925Snp .intfver_fcoe = FW_INTFVER(T5, FCOE), 1845248925Snp }, 1846248925Snp } 1847248925Snp}; 1848248925Snp 1849248925Snpstatic struct fw_info * 1850248925Snpfind_fw_info(int chip) 1851248925Snp{ 1852248925Snp int i; 1853248925Snp 1854248925Snp for (i = 0; i < nitems(fw_info); i++) { 1855248925Snp if (fw_info[i].chip == chip) 1856248925Snp return (&fw_info[i]); 1857248925Snp } 1858248925Snp return (NULL); 1859248925Snp} 1860248925Snp 1861218792Snp/* 1862248925Snp * Is the given firmware API compatible with the one the driver was compiled 1863248925Snp * with? 1864247347Snp */ 1865247347Snpstatic int 1866248925Snpfw_compatible(const struct fw_hdr *hdr1, const struct fw_hdr *hdr2) 1867247347Snp{ 1868247347Snp 1869248925Snp /* short circuit if it's the exact same firmware version */ 1870248925Snp if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver) 1871247347Snp return (1); 1872247347Snp 1873247347Snp /* 1874247347Snp * XXX: Is this too conservative? Perhaps I should limit this to the 1875247347Snp * features that are supported in the driver. 1876247347Snp */ 1877248925Snp#define SAME_INTF(x) (hdr1->intfver_##x == hdr2->intfver_##x) 1878248925Snp if (hdr1->chip == hdr2->chip && SAME_INTF(nic) && SAME_INTF(vnic) && 1879248925Snp SAME_INTF(ofld) && SAME_INTF(ri) && SAME_INTF(iscsipdu) && 1880248925Snp SAME_INTF(iscsi) && SAME_INTF(fcoepdu) && SAME_INTF(fcoe)) 1881247347Snp return (1); 1882248925Snp#undef SAME_INTF 1883247347Snp 1884247347Snp return (0); 1885247347Snp} 1886247347Snp 1887247347Snp/* 1888248925Snp * Establish contact with the firmware and determine if we are the master driver 1889248925Snp * or not, and whether we are responsible for chip initialization. 1890218792Snp */ 1891218792Snpstatic int 1892218792Snpprep_firmware(struct adapter *sc) 1893218792Snp{ 1894248925Snp const struct firmware *fw = NULL, *default_cfg; 1895248925Snp int rc, pf, card_fw_usable, kld_fw_usable, need_fw_reset = 1; 1896218792Snp enum dev_state state; 1897248925Snp struct fw_info *fw_info; 1898248925Snp struct fw_hdr *card_fw; /* fw on the card */ 1899248925Snp const struct fw_hdr *kld_fw; /* fw in the KLD */ 1900248925Snp const struct fw_hdr *drv_fw; /* fw header the driver was compiled 1901248925Snp against */ 1902218792Snp 1903248925Snp /* Contact firmware. */ 1904248925Snp rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state); 1905248925Snp if (rc < 0 || state == DEV_STATE_ERR) { 1906248925Snp rc = -rc; 1907248925Snp device_printf(sc->dev, 1908248925Snp "failed to connect to the firmware: %d, %d.\n", rc, state); 1909248925Snp return (rc); 1910248925Snp } 1911248925Snp pf = rc; 1912248925Snp if (pf == sc->mbox) 1913248925Snp sc->flags |= MASTER_PF; 1914248925Snp else if (state == DEV_STATE_UNINIT) { 1915248925Snp /* 1916248925Snp * We didn't get to be the master so we definitely won't be 1917248925Snp * configuring the chip. It's a bug if someone else hasn't 1918248925Snp * configured it already. 1919248925Snp */ 1920248925Snp device_printf(sc->dev, "couldn't be master(%d), " 1921248925Snp "device not already initialized either(%d).\n", rc, state); 1922248925Snp return (EDOOFUS); 1923248925Snp } 1924228561Snp 1925248925Snp /* This is the firmware whose headers the driver was compiled against */ 1926248925Snp fw_info = find_fw_info(chip_id(sc)); 1927248925Snp if (fw_info == NULL) { 1928248925Snp device_printf(sc->dev, 1929248925Snp "unable to look up firmware information for chip %d.\n", 1930248925Snp chip_id(sc)); 1931248925Snp return (EINVAL); 1932248925Snp } 1933248925Snp drv_fw = &fw_info->fw_hdr; 1934248925Snp 1935248925Snp /* 1936248925Snp * The firmware KLD contains many modules. The KLD name is also the 1937248925Snp * name of the module that contains the default config file. 1938248925Snp */ 1939248925Snp default_cfg = firmware_get(fw_info->kld_name); 1940248925Snp 1941247347Snp /* Read the header of the firmware on the card */ 1942247347Snp card_fw = malloc(sizeof(*card_fw), M_CXGBE, M_ZERO | M_WAITOK); 1943247347Snp rc = -t4_read_flash(sc, FLASH_FW_START, 1944247347Snp sizeof (*card_fw) / sizeof (uint32_t), (uint32_t *)card_fw, 1); 1945247347Snp if (rc == 0) 1946248925Snp card_fw_usable = fw_compatible(drv_fw, (const void*)card_fw); 1947247347Snp else { 1948247347Snp device_printf(sc->dev, 1949247347Snp "Unable to read card's firmware header: %d\n", rc); 1950247347Snp card_fw_usable = 0; 1951247347Snp } 1952218792Snp 1953247347Snp /* This is the firmware in the KLD */ 1954248925Snp fw = firmware_get(fw_info->fw_mod_name); 1955247347Snp if (fw != NULL) { 1956247347Snp kld_fw = (const void *)fw->data; 1957248925Snp kld_fw_usable = fw_compatible(drv_fw, kld_fw); 1958247347Snp } else { 1959247347Snp kld_fw = NULL; 1960247347Snp kld_fw_usable = 0; 1961247347Snp } 1962219287Snp 1963248925Snp if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver && 1964248925Snp (!kld_fw_usable || kld_fw->fw_ver == drv_fw->fw_ver || 1965248925Snp t4_fw_install == 0)) { 1966248925Snp /* 1967248925Snp * Common case: the firmware on the card is an exact match and 1968248925Snp * the KLD is an exact match too, or the KLD is 1969248925Snp * absent/incompatible, or we're prohibited from using it. Note 1970248925Snp * that t4_fw_install = 2 is ignored here -- use cxgbetool 1971248925Snp * loadfw if you want to reinstall the same firmware as the one 1972248925Snp * on the card. 1973248925Snp */ 1974248925Snp } else if (kld_fw_usable && state == DEV_STATE_UNINIT && 1975248925Snp (!card_fw_usable || 1976248925Snp be32toh(kld_fw->fw_ver) > be32toh(card_fw->fw_ver) || 1977247347Snp (t4_fw_install == 2 && kld_fw->fw_ver != card_fw->fw_ver))) { 1978247347Snp uint32_t v = ntohl(kld_fw->fw_ver); 1979219287Snp 1980247347Snp device_printf(sc->dev, 1981247347Snp "installing firmware %d.%d.%d.%d on card.\n", 1982247347Snp G_FW_HDR_FW_VER_MAJOR(v), G_FW_HDR_FW_VER_MINOR(v), 1983247347Snp G_FW_HDR_FW_VER_MICRO(v), G_FW_HDR_FW_VER_BUILD(v)); 1984218792Snp 1985247347Snp rc = -t4_load_fw(sc, fw->data, fw->datasize); 1986247347Snp if (rc != 0) { 1987247347Snp device_printf(sc->dev, 1988247347Snp "failed to install firmware: %d\n", rc); 1989228561Snp goto done; 1990219287Snp } 1991219287Snp 1992247347Snp /* Installed successfully, update the cached header too. */ 1993247347Snp memcpy(card_fw, kld_fw, sizeof(*card_fw)); 1994247347Snp card_fw_usable = 1; 1995248925Snp need_fw_reset = 0; /* already reset as part of load_fw */ 1996247347Snp } 1997219287Snp 1998247347Snp if (!card_fw_usable) { 1999248925Snp uint32_t d, c, k; 2000247347Snp 2001248925Snp d = ntohl(drv_fw->fw_ver); 2002247347Snp c = ntohl(card_fw->fw_ver); 2003247347Snp k = kld_fw ? ntohl(kld_fw->fw_ver) : 0; 2004247347Snp 2005247347Snp device_printf(sc->dev, "Cannot find a usable firmware: " 2006248925Snp "fw_install %d, chip state %d, " 2007248925Snp "driver compiled with %d.%d.%d.%d, " 2008247347Snp "card has %d.%d.%d.%d, KLD has %d.%d.%d.%d\n", 2009248925Snp t4_fw_install, state, 2010248925Snp G_FW_HDR_FW_VER_MAJOR(d), G_FW_HDR_FW_VER_MINOR(d), 2011248925Snp G_FW_HDR_FW_VER_MICRO(d), G_FW_HDR_FW_VER_BUILD(d), 2012247347Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 2013247347Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), 2014247347Snp G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k), 2015247347Snp G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k)); 2016248925Snp rc = EINVAL; 2017247347Snp goto done; 2018218792Snp } 2019218792Snp 2020247347Snp /* We're using whatever's on the card and it's known to be good. */ 2021247347Snp sc->params.fw_vers = ntohl(card_fw->fw_ver); 2022247347Snp snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u", 2023247347Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 2024247347Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 2025247347Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 2026247347Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 2027247347Snp 2028218792Snp /* Reset device */ 2029248925Snp if (need_fw_reset && 2030248925Snp (rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST)) != 0) { 2031218792Snp device_printf(sc->dev, "firmware reset failed: %d.\n", rc); 2032218792Snp if (rc != ETIMEDOUT && rc != EIO) 2033218792Snp t4_fw_bye(sc, sc->mbox); 2034228561Snp goto done; 2035218792Snp } 2036248925Snp sc->flags |= FW_OK; 2037218792Snp 2038248925Snp rc = get_params__pre_init(sc); 2039248925Snp if (rc != 0) 2040248925Snp goto done; /* error message displayed already */ 2041248925Snp 2042228561Snp /* Partition adapter resources as specified in the config file. */ 2043248925Snp if (state == DEV_STATE_UNINIT) { 2044228561Snp 2045248925Snp KASSERT(sc->flags & MASTER_PF, 2046248925Snp ("%s: trying to change chip settings when not master.", 2047248925Snp __func__)); 2048228561Snp 2049248925Snp rc = partition_resources(sc, default_cfg, fw_info->kld_name); 2050228561Snp if (rc != 0) 2051228561Snp goto done; /* error message displayed already */ 2052248925Snp 2053248925Snp t4_tweak_chip_settings(sc); 2054248925Snp 2055248925Snp /* get basic stuff going */ 2056248925Snp rc = -t4_fw_initialize(sc, sc->mbox); 2057248925Snp if (rc != 0) { 2058248925Snp device_printf(sc->dev, "fw init failed: %d.\n", rc); 2059248925Snp goto done; 2060248925Snp } 2061245936Snp } else { 2062248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "pf%d", pf); 2063248925Snp sc->cfcsum = 0; 2064228561Snp } 2065228561Snp 2066228561Snpdone: 2067247347Snp free(card_fw, M_CXGBE); 2068228561Snp if (fw != NULL) 2069228561Snp firmware_put(fw, FIRMWARE_UNLOAD); 2070228561Snp if (default_cfg != NULL) 2071228561Snp firmware_put(default_cfg, FIRMWARE_UNLOAD); 2072228561Snp 2073228561Snp return (rc); 2074218792Snp} 2075218792Snp 2076228561Snp#define FW_PARAM_DEV(param) \ 2077228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ 2078228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) 2079228561Snp#define FW_PARAM_PFVF(param) \ 2080228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ 2081228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)) 2082228561Snp 2083228561Snp/* 2084248925Snp * Partition chip resources for use between various PFs, VFs, etc. 2085228561Snp */ 2086218792Snpstatic int 2087248925Snppartition_resources(struct adapter *sc, const struct firmware *default_cfg, 2088248925Snp const char *name_prefix) 2089222551Snp{ 2090248925Snp const struct firmware *cfg = NULL; 2091248925Snp int rc = 0; 2092248925Snp struct fw_caps_config_cmd caps; 2093248925Snp uint32_t mtype, moff, finicsum, cfcsum; 2094222551Snp 2095248925Snp /* 2096248925Snp * Figure out what configuration file to use. Pick the default config 2097248925Snp * file for the card if the user hasn't specified one explicitly. 2098248925Snp */ 2099248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", t4_cfg_file); 2100248925Snp if (strncmp(t4_cfg_file, DEFAULT_CF, sizeof(t4_cfg_file)) == 0) { 2101248925Snp /* Card specific overrides go here. */ 2102248925Snp if (pci_get_device(sc->dev) == 0x440a) 2103248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), UWIRE_CF); 2104222551Snp } 2105222551Snp 2106248925Snp /* 2107248925Snp * We need to load another module if the profile is anything except 2108248925Snp * "default" or "flash". 2109248925Snp */ 2110248925Snp if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) != 0 && 2111248925Snp strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) { 2112248925Snp char s[32]; 2113248925Snp 2114248925Snp snprintf(s, sizeof(s), "%s_%s", name_prefix, sc->cfg_file); 2115248925Snp cfg = firmware_get(s); 2116248925Snp if (cfg == NULL) { 2117248925Snp device_printf(sc->dev, "unable to load module \"%s\" " 2118248925Snp "for configuration profile \"%s\", ", 2119248925Snp s, sc->cfg_file); 2120248925Snp if (default_cfg != NULL) { 2121248925Snp device_printf(sc->dev, "will use the default " 2122248925Snp "config file instead.\n"); 2123248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), 2124248925Snp "%s", DEFAULT_CF); 2125248925Snp } else { 2126248925Snp device_printf(sc->dev, "will use the config " 2127248925Snp "file on the card's flash instead.\n"); 2128248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), 2129248925Snp "%s", FLASH_CF); 2130248925Snp } 2131248925Snp } 2132228561Snp } 2133222551Snp 2134248925Snp if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) == 0 && 2135248925Snp default_cfg == NULL) { 2136228561Snp device_printf(sc->dev, 2137248925Snp "default config file not available, will use the config " 2138248925Snp "file on the card's flash instead.\n"); 2139248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", FLASH_CF); 2140228561Snp } 2141228561Snp 2142248925Snp if (strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) { 2143248925Snp u_int cflen, i, n; 2144248925Snp const uint32_t *cfdata; 2145248925Snp uint32_t param, val, addr, off, mw_base, mw_aperture; 2146228561Snp 2147248925Snp KASSERT(cfg != NULL || default_cfg != NULL, 2148248925Snp ("%s: no config to upload", __func__)); 2149228561Snp 2150248925Snp /* 2151248925Snp * Ask the firmware where it wants us to upload the config file. 2152248925Snp */ 2153248925Snp param = FW_PARAM_DEV(CF); 2154248925Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 2155248925Snp if (rc != 0) { 2156248925Snp /* No support for config file? Shouldn't happen. */ 2157248925Snp device_printf(sc->dev, 2158248925Snp "failed to query config file location: %d.\n", rc); 2159248925Snp goto done; 2160248925Snp } 2161248925Snp mtype = G_FW_PARAMS_PARAM_Y(val); 2162248925Snp moff = G_FW_PARAMS_PARAM_Z(val) << 16; 2163228561Snp 2164248925Snp /* 2165248925Snp * XXX: sheer laziness. We deliberately added 4 bytes of 2166248925Snp * useless stuffing/comments at the end of the config file so 2167248925Snp * it's ok to simply throw away the last remaining bytes when 2168248925Snp * the config file is not an exact multiple of 4. This also 2169248925Snp * helps with the validate_mt_off_len check. 2170248925Snp */ 2171248925Snp if (cfg != NULL) { 2172248925Snp cflen = cfg->datasize & ~3; 2173248925Snp cfdata = cfg->data; 2174248925Snp } else { 2175248925Snp cflen = default_cfg->datasize & ~3; 2176248925Snp cfdata = default_cfg->data; 2177248925Snp } 2178222551Snp 2179248925Snp if (cflen > FLASH_CFG_MAX_SIZE) { 2180248925Snp device_printf(sc->dev, 2181248925Snp "config file too long (%d, max allowed is %d). " 2182248925Snp "Will try to use the config on the card, if any.\n", 2183248925Snp cflen, FLASH_CFG_MAX_SIZE); 2184248925Snp goto use_config_on_flash; 2185248925Snp } 2186218792Snp 2187248925Snp rc = validate_mt_off_len(sc, mtype, moff, cflen, &addr); 2188248925Snp if (rc != 0) { 2189248925Snp device_printf(sc->dev, 2190248925Snp "%s: addr (%d/0x%x) or len %d is not valid: %d. " 2191248925Snp "Will try to use the config on the card, if any.\n", 2192248925Snp __func__, mtype, moff, cflen, rc); 2193248925Snp goto use_config_on_flash; 2194248925Snp } 2195248925Snp 2196248925Snp memwin_info(sc, 2, &mw_base, &mw_aperture); 2197248925Snp while (cflen) { 2198248925Snp off = position_memwin(sc, 2, addr); 2199248925Snp n = min(cflen, mw_aperture - off); 2200248925Snp for (i = 0; i < n; i += 4) 2201248925Snp t4_write_reg(sc, mw_base + off + i, *cfdata++); 2202248925Snp cflen -= n; 2203248925Snp addr += n; 2204248925Snp } 2205248925Snp } else { 2206248925Snpuse_config_on_flash: 2207228561Snp mtype = FW_MEMTYPE_CF_FLASH; 2208248925Snp moff = t4_flash_cfg_addr(sc); 2209228561Snp } 2210228561Snp 2211228561Snp bzero(&caps, sizeof(caps)); 2212228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2213218792Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2214228561Snp caps.cfvalid_to_len16 = htobe32(F_FW_CAPS_CONFIG_CMD_CFVALID | 2215228561Snp V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) | 2216248925Snp V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(moff >> 16) | FW_LEN16(caps)); 2217228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 2218228561Snp if (rc != 0) { 2219228561Snp device_printf(sc->dev, 2220248925Snp "failed to pre-process config file: %d (mtype %d).\n", rc, 2221248925Snp mtype); 2222248925Snp goto done; 2223228561Snp } 2224218792Snp 2225228561Snp finicsum = be32toh(caps.finicsum); 2226228561Snp cfcsum = be32toh(caps.cfcsum); 2227228561Snp if (finicsum != cfcsum) { 2228228561Snp device_printf(sc->dev, 2229228561Snp "WARNING: config file checksum mismatch: %08x %08x\n", 2230228561Snp finicsum, cfcsum); 2231228561Snp } 2232228561Snp sc->cfcsum = cfcsum; 2233218792Snp 2234228561Snp#define LIMIT_CAPS(x) do { \ 2235228561Snp caps.x &= htobe16(t4_##x##_allowed); \ 2236228561Snp sc->x = htobe16(caps.x); \ 2237228561Snp} while (0) 2238228561Snp 2239228561Snp /* 2240228561Snp * Let the firmware know what features will (not) be used so it can tune 2241228561Snp * things accordingly. 2242228561Snp */ 2243228561Snp LIMIT_CAPS(linkcaps); 2244228561Snp LIMIT_CAPS(niccaps); 2245228561Snp LIMIT_CAPS(toecaps); 2246228561Snp LIMIT_CAPS(rdmacaps); 2247228561Snp LIMIT_CAPS(iscsicaps); 2248228561Snp LIMIT_CAPS(fcoecaps); 2249228561Snp#undef LIMIT_CAPS 2250228561Snp 2251228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2252218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE); 2253228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 2254228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), NULL); 2255228561Snp if (rc != 0) { 2256228561Snp device_printf(sc->dev, 2257228561Snp "failed to process config file: %d.\n", rc); 2258228561Snp } 2259248925Snpdone: 2260248925Snp if (cfg != NULL) 2261248925Snp firmware_put(cfg, FIRMWARE_UNLOAD); 2262248925Snp return (rc); 2263218792Snp} 2264218792Snp 2265228561Snp/* 2266248925Snp * Retrieve parameters that are needed (or nice to have) very early. 2267228561Snp */ 2268218792Snpstatic int 2269228561Snpget_params__pre_init(struct adapter *sc) 2270218792Snp{ 2271218792Snp int rc; 2272228561Snp uint32_t param[2], val[2]; 2273228561Snp struct fw_devlog_cmd cmd; 2274228561Snp struct devlog_params *dlog = &sc->params.devlog; 2275218792Snp 2276228561Snp param[0] = FW_PARAM_DEV(PORTVEC); 2277228561Snp param[1] = FW_PARAM_DEV(CCLK); 2278228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 2279218792Snp if (rc != 0) { 2280218792Snp device_printf(sc->dev, 2281228561Snp "failed to query parameters (pre_init): %d.\n", rc); 2282228561Snp return (rc); 2283218792Snp } 2284218792Snp 2285218792Snp sc->params.portvec = val[0]; 2286240452Snp sc->params.nports = bitcount32(val[0]); 2287228561Snp sc->params.vpd.cclk = val[1]; 2288218792Snp 2289228561Snp /* Read device log parameters. */ 2290228561Snp bzero(&cmd, sizeof(cmd)); 2291228561Snp cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) | 2292228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2293228561Snp cmd.retval_len16 = htobe32(FW_LEN16(cmd)); 2294228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &cmd, sizeof(cmd), &cmd); 2295228561Snp if (rc != 0) { 2296228561Snp device_printf(sc->dev, 2297228561Snp "failed to get devlog parameters: %d.\n", rc); 2298228561Snp bzero(dlog, sizeof (*dlog)); 2299228561Snp rc = 0; /* devlog isn't critical for device operation */ 2300228561Snp } else { 2301228561Snp val[0] = be32toh(cmd.memtype_devlog_memaddr16_devlog); 2302228561Snp dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(val[0]); 2303228561Snp dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(val[0]) << 4; 2304228561Snp dlog->size = be32toh(cmd.memsize_devlog); 2305228561Snp } 2306228561Snp 2307228561Snp return (rc); 2308228561Snp} 2309228561Snp 2310228561Snp/* 2311228561Snp * Retrieve various parameters that are of interest to the driver. The device 2312228561Snp * has been initialized by the firmware at this point. 2313228561Snp */ 2314228561Snpstatic int 2315228561Snpget_params__post_init(struct adapter *sc) 2316228561Snp{ 2317228561Snp int rc; 2318228561Snp uint32_t param[7], val[7]; 2319228561Snp struct fw_caps_config_cmd caps; 2320228561Snp 2321228561Snp param[0] = FW_PARAM_PFVF(IQFLINT_START); 2322228561Snp param[1] = FW_PARAM_PFVF(EQ_START); 2323228561Snp param[2] = FW_PARAM_PFVF(FILTER_START); 2324228561Snp param[3] = FW_PARAM_PFVF(FILTER_END); 2325245434Snp param[4] = FW_PARAM_PFVF(L2T_START); 2326245434Snp param[5] = FW_PARAM_PFVF(L2T_END); 2327245434Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2328228561Snp if (rc != 0) { 2329228561Snp device_printf(sc->dev, 2330228561Snp "failed to query parameters (post_init): %d.\n", rc); 2331228561Snp return (rc); 2332228561Snp } 2333228561Snp 2334228561Snp sc->sge.iq_start = val[0]; 2335228561Snp sc->sge.eq_start = val[1]; 2336228561Snp sc->tids.ftid_base = val[2]; 2337228561Snp sc->tids.nftids = val[3] - val[2] + 1; 2338245434Snp sc->vres.l2t.start = val[4]; 2339245434Snp sc->vres.l2t.size = val[5] - val[4] + 1; 2340245434Snp KASSERT(sc->vres.l2t.size <= L2T_SIZE, 2341245434Snp ("%s: L2 table size (%u) larger than expected (%u)", 2342245434Snp __func__, sc->vres.l2t.size, L2T_SIZE)); 2343228561Snp 2344228561Snp /* get capabilites */ 2345228561Snp bzero(&caps, sizeof(caps)); 2346228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2347228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2348228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 2349228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 2350228561Snp if (rc != 0) { 2351228561Snp device_printf(sc->dev, 2352228561Snp "failed to get card capabilities: %d.\n", rc); 2353228561Snp return (rc); 2354228561Snp } 2355228561Snp 2356228561Snp if (caps.toecaps) { 2357218792Snp /* query offload-related parameters */ 2358228561Snp param[0] = FW_PARAM_DEV(NTID); 2359228561Snp param[1] = FW_PARAM_PFVF(SERVER_START); 2360228561Snp param[2] = FW_PARAM_PFVF(SERVER_END); 2361228561Snp param[3] = FW_PARAM_PFVF(TDDP_START); 2362228561Snp param[4] = FW_PARAM_PFVF(TDDP_END); 2363228561Snp param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 2364228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2365218792Snp if (rc != 0) { 2366218792Snp device_printf(sc->dev, 2367218792Snp "failed to query TOE parameters: %d.\n", rc); 2368228561Snp return (rc); 2369218792Snp } 2370218792Snp sc->tids.ntids = val[0]; 2371218792Snp sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS); 2372218792Snp sc->tids.stid_base = val[1]; 2373218792Snp sc->tids.nstids = val[2] - val[1] + 1; 2374218792Snp sc->vres.ddp.start = val[3]; 2375218792Snp sc->vres.ddp.size = val[4] - val[3] + 1; 2376218792Snp sc->params.ofldq_wr_cred = val[5]; 2377218792Snp sc->params.offload = 1; 2378218792Snp } 2379228561Snp if (caps.rdmacaps) { 2380228561Snp param[0] = FW_PARAM_PFVF(STAG_START); 2381228561Snp param[1] = FW_PARAM_PFVF(STAG_END); 2382228561Snp param[2] = FW_PARAM_PFVF(RQ_START); 2383228561Snp param[3] = FW_PARAM_PFVF(RQ_END); 2384228561Snp param[4] = FW_PARAM_PFVF(PBL_START); 2385228561Snp param[5] = FW_PARAM_PFVF(PBL_END); 2386228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2387218792Snp if (rc != 0) { 2388218792Snp device_printf(sc->dev, 2389228561Snp "failed to query RDMA parameters(1): %d.\n", rc); 2390228561Snp return (rc); 2391218792Snp } 2392218792Snp sc->vres.stag.start = val[0]; 2393218792Snp sc->vres.stag.size = val[1] - val[0] + 1; 2394218792Snp sc->vres.rq.start = val[2]; 2395218792Snp sc->vres.rq.size = val[3] - val[2] + 1; 2396218792Snp sc->vres.pbl.start = val[4]; 2397218792Snp sc->vres.pbl.size = val[5] - val[4] + 1; 2398228561Snp 2399228561Snp param[0] = FW_PARAM_PFVF(SQRQ_START); 2400228561Snp param[1] = FW_PARAM_PFVF(SQRQ_END); 2401228561Snp param[2] = FW_PARAM_PFVF(CQ_START); 2402228561Snp param[3] = FW_PARAM_PFVF(CQ_END); 2403228561Snp param[4] = FW_PARAM_PFVF(OCQ_START); 2404228561Snp param[5] = FW_PARAM_PFVF(OCQ_END); 2405228561Snp rc = -t4_query_params(sc, 0, 0, 0, 6, param, val); 2406228561Snp if (rc != 0) { 2407228561Snp device_printf(sc->dev, 2408228561Snp "failed to query RDMA parameters(2): %d.\n", rc); 2409228561Snp return (rc); 2410228561Snp } 2411228561Snp sc->vres.qp.start = val[0]; 2412228561Snp sc->vres.qp.size = val[1] - val[0] + 1; 2413228561Snp sc->vres.cq.start = val[2]; 2414228561Snp sc->vres.cq.size = val[3] - val[2] + 1; 2415228561Snp sc->vres.ocq.start = val[4]; 2416228561Snp sc->vres.ocq.size = val[5] - val[4] + 1; 2417218792Snp } 2418228561Snp if (caps.iscsicaps) { 2419228561Snp param[0] = FW_PARAM_PFVF(ISCSI_START); 2420228561Snp param[1] = FW_PARAM_PFVF(ISCSI_END); 2421228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 2422218792Snp if (rc != 0) { 2423218792Snp device_printf(sc->dev, 2424218792Snp "failed to query iSCSI parameters: %d.\n", rc); 2425228561Snp return (rc); 2426218792Snp } 2427218792Snp sc->vres.iscsi.start = val[0]; 2428218792Snp sc->vres.iscsi.size = val[1] - val[0] + 1; 2429218792Snp } 2430218792Snp 2431248925Snp /* 2432248925Snp * We've got the params we wanted to query via the firmware. Now grab 2433248925Snp * some others directly from the chip. 2434248925Snp */ 2435248925Snp rc = t4_read_chip_settings(sc); 2436228561Snp 2437218792Snp return (rc); 2438218792Snp} 2439218792Snp 2440247291Snpstatic int 2441247291Snpset_params__post_init(struct adapter *sc) 2442247291Snp{ 2443247291Snp uint32_t param, val; 2444247291Snp int rc; 2445247291Snp 2446247291Snp param = FW_PARAM_PFVF(CPLFW4MSG_ENCAP); 2447247291Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 2448247291Snp if (rc == 0) { 2449247291Snp /* ask for encapsulated CPLs */ 2450247291Snp param = FW_PARAM_PFVF(CPLFW4MSG_ENCAP); 2451247291Snp val = 1; 2452247291Snp rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 2453247291Snp if (rc != 0) { 2454247291Snp device_printf(sc->dev, 2455247291Snp "failed to set parameter (post_init): %d.\n", rc); 2456247291Snp return (rc); 2457247291Snp } 2458247291Snp } else if (rc != FW_EINVAL) { 2459247291Snp device_printf(sc->dev, 2460247291Snp "failed to check for encapsulated CPLs: %d.\n", rc); 2461247291Snp } else 2462247291Snp rc = 0; /* the firmware doesn't support the param, no worries */ 2463247291Snp 2464247291Snp return (rc); 2465247291Snp} 2466247291Snp 2467228561Snp#undef FW_PARAM_PFVF 2468228561Snp#undef FW_PARAM_DEV 2469228561Snp 2470218792Snpstatic void 2471218792Snpt4_set_desc(struct adapter *sc) 2472218792Snp{ 2473218792Snp char buf[128]; 2474218792Snp struct adapter_params *p = &sc->params; 2475218792Snp 2476228561Snp snprintf(buf, sizeof(buf), "Chelsio %s %sNIC (rev %d), S/N:%s, E/C:%s", 2477248925Snp p->vpd.id, is_offload(sc) ? "R" : "", chip_rev(sc), p->vpd.sn, 2478248925Snp p->vpd.ec); 2479218792Snp 2480218792Snp device_set_desc_copy(sc->dev, buf); 2481218792Snp} 2482218792Snp 2483218792Snpstatic void 2484218792Snpbuild_medialist(struct port_info *pi) 2485218792Snp{ 2486218792Snp struct ifmedia *media = &pi->media; 2487218792Snp int data, m; 2488218792Snp 2489218792Snp PORT_LOCK(pi); 2490218792Snp 2491218792Snp ifmedia_removeall(media); 2492218792Snp 2493218792Snp m = IFM_ETHER | IFM_FDX; 2494218792Snp data = (pi->port_type << 8) | pi->mod_type; 2495218792Snp 2496218792Snp switch(pi->port_type) { 2497218792Snp case FW_PORT_TYPE_BT_XFI: 2498218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2499218792Snp break; 2500218792Snp 2501218792Snp case FW_PORT_TYPE_BT_XAUI: 2502218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2503218792Snp /* fall through */ 2504218792Snp 2505218792Snp case FW_PORT_TYPE_BT_SGMII: 2506218792Snp ifmedia_add(media, m | IFM_1000_T, data, NULL); 2507218792Snp ifmedia_add(media, m | IFM_100_TX, data, NULL); 2508218792Snp ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL); 2509218792Snp ifmedia_set(media, IFM_ETHER | IFM_AUTO); 2510218792Snp break; 2511218792Snp 2512218792Snp case FW_PORT_TYPE_CX4: 2513218792Snp ifmedia_add(media, m | IFM_10G_CX4, data, NULL); 2514218792Snp ifmedia_set(media, m | IFM_10G_CX4); 2515218792Snp break; 2516218792Snp 2517218792Snp case FW_PORT_TYPE_SFP: 2518218792Snp case FW_PORT_TYPE_FIBER_XFI: 2519218792Snp case FW_PORT_TYPE_FIBER_XAUI: 2520218792Snp switch (pi->mod_type) { 2521218792Snp 2522218792Snp case FW_PORT_MOD_TYPE_LR: 2523218792Snp ifmedia_add(media, m | IFM_10G_LR, data, NULL); 2524218792Snp ifmedia_set(media, m | IFM_10G_LR); 2525218792Snp break; 2526218792Snp 2527218792Snp case FW_PORT_MOD_TYPE_SR: 2528218792Snp ifmedia_add(media, m | IFM_10G_SR, data, NULL); 2529218792Snp ifmedia_set(media, m | IFM_10G_SR); 2530218792Snp break; 2531218792Snp 2532218792Snp case FW_PORT_MOD_TYPE_LRM: 2533218792Snp ifmedia_add(media, m | IFM_10G_LRM, data, NULL); 2534218792Snp ifmedia_set(media, m | IFM_10G_LRM); 2535218792Snp break; 2536218792Snp 2537218792Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2538218792Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2539218792Snp ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL); 2540218792Snp ifmedia_set(media, m | IFM_10G_TWINAX); 2541218792Snp break; 2542218792Snp 2543218792Snp case FW_PORT_MOD_TYPE_NONE: 2544218792Snp m &= ~IFM_FDX; 2545218792Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2546218792Snp ifmedia_set(media, m | IFM_NONE); 2547218792Snp break; 2548218792Snp 2549218792Snp case FW_PORT_MOD_TYPE_NA: 2550218792Snp case FW_PORT_MOD_TYPE_ER: 2551218792Snp default: 2552218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2553218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2554218792Snp break; 2555218792Snp } 2556218792Snp break; 2557218792Snp 2558218792Snp case FW_PORT_TYPE_KX4: 2559218792Snp case FW_PORT_TYPE_KX: 2560218792Snp case FW_PORT_TYPE_KR: 2561218792Snp default: 2562218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2563218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2564218792Snp break; 2565218792Snp } 2566218792Snp 2567218792Snp PORT_UNLOCK(pi); 2568218792Snp} 2569218792Snp 2570231172Snp#define FW_MAC_EXACT_CHUNK 7 2571231172Snp 2572218792Snp/* 2573218792Snp * Program the port's XGMAC based on parameters in ifnet. The caller also 2574218792Snp * indicates which parameters should be programmed (the rest are left alone). 2575218792Snp */ 2576218792Snpstatic int 2577218792Snpupdate_mac_settings(struct port_info *pi, int flags) 2578218792Snp{ 2579218792Snp int rc; 2580218792Snp struct ifnet *ifp = pi->ifp; 2581218792Snp struct adapter *sc = pi->adapter; 2582218792Snp int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1; 2583218792Snp 2584245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2585218792Snp KASSERT(flags, ("%s: not told what to update.", __func__)); 2586218792Snp 2587218792Snp if (flags & XGMAC_MTU) 2588218792Snp mtu = ifp->if_mtu; 2589218792Snp 2590218792Snp if (flags & XGMAC_PROMISC) 2591218792Snp promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0; 2592218792Snp 2593218792Snp if (flags & XGMAC_ALLMULTI) 2594218792Snp allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0; 2595218792Snp 2596218792Snp if (flags & XGMAC_VLANEX) 2597218792Snp vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0; 2598218792Snp 2599218792Snp rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, mtu, promisc, allmulti, 1, 2600218792Snp vlanex, false); 2601218792Snp if (rc) { 2602218792Snp if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, rc); 2603218792Snp return (rc); 2604218792Snp } 2605218792Snp 2606218792Snp if (flags & XGMAC_UCADDR) { 2607218792Snp uint8_t ucaddr[ETHER_ADDR_LEN]; 2608218792Snp 2609218792Snp bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr)); 2610218792Snp rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, 2611218792Snp ucaddr, true, true); 2612218792Snp if (rc < 0) { 2613218792Snp rc = -rc; 2614218792Snp if_printf(ifp, "change_mac failed: %d\n", rc); 2615218792Snp return (rc); 2616218792Snp } else { 2617218792Snp pi->xact_addr_filt = rc; 2618218792Snp rc = 0; 2619218792Snp } 2620218792Snp } 2621218792Snp 2622218792Snp if (flags & XGMAC_MCADDRS) { 2623231172Snp const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK]; 2624218792Snp int del = 1; 2625218792Snp uint64_t hash = 0; 2626218792Snp struct ifmultiaddr *ifma; 2627231172Snp int i = 0, j; 2628218792Snp 2629218792Snp if_maddr_rlock(ifp); 2630218792Snp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2631238054Snp if (ifma->ifma_addr->sa_family != AF_LINK) 2632218792Snp continue; 2633231172Snp mcaddr[i++] = 2634231172Snp LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 2635218792Snp 2636231172Snp if (i == FW_MAC_EXACT_CHUNK) { 2637231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2638231172Snp del, i, mcaddr, NULL, &hash, 0); 2639231172Snp if (rc < 0) { 2640231172Snp rc = -rc; 2641231172Snp for (j = 0; j < i; j++) { 2642231172Snp if_printf(ifp, 2643231172Snp "failed to add mc address" 2644231172Snp " %02x:%02x:%02x:" 2645231172Snp "%02x:%02x:%02x rc=%d\n", 2646231172Snp mcaddr[j][0], mcaddr[j][1], 2647231172Snp mcaddr[j][2], mcaddr[j][3], 2648231172Snp mcaddr[j][4], mcaddr[j][5], 2649231172Snp rc); 2650231172Snp } 2651231172Snp goto mcfail; 2652231172Snp } 2653231172Snp del = 0; 2654231172Snp i = 0; 2655231172Snp } 2656231172Snp } 2657231172Snp if (i > 0) { 2658231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2659231172Snp del, i, mcaddr, NULL, &hash, 0); 2660218792Snp if (rc < 0) { 2661218792Snp rc = -rc; 2662231172Snp for (j = 0; j < i; j++) { 2663231172Snp if_printf(ifp, 2664231172Snp "failed to add mc address" 2665231172Snp " %02x:%02x:%02x:" 2666231172Snp "%02x:%02x:%02x rc=%d\n", 2667231172Snp mcaddr[j][0], mcaddr[j][1], 2668231172Snp mcaddr[j][2], mcaddr[j][3], 2669231172Snp mcaddr[j][4], mcaddr[j][5], 2670231172Snp rc); 2671231172Snp } 2672218792Snp goto mcfail; 2673218792Snp } 2674218792Snp } 2675218792Snp 2676218792Snp rc = -t4_set_addr_hash(sc, sc->mbox, pi->viid, 0, hash, 0); 2677218792Snp if (rc != 0) 2678218792Snp if_printf(ifp, "failed to set mc address hash: %d", rc); 2679218792Snpmcfail: 2680218792Snp if_maddr_runlock(ifp); 2681218792Snp } 2682218792Snp 2683218792Snp return (rc); 2684218792Snp} 2685218792Snp 2686245274Snpint 2687245274Snpbegin_synchronized_op(struct adapter *sc, struct port_info *pi, int flags, 2688245274Snp char *wmesg) 2689218792Snp{ 2690245274Snp int rc, pri; 2691218792Snp 2692245274Snp#ifdef WITNESS 2693245274Snp /* the caller thinks it's ok to sleep, but is it really? */ 2694245274Snp if (flags & SLEEP_OK) 2695245274Snp pause("t4slptst", 1); 2696245274Snp#endif 2697218792Snp 2698245274Snp if (INTR_OK) 2699245274Snp pri = PCATCH; 2700245274Snp else 2701245274Snp pri = 0; 2702245274Snp 2703245274Snp ADAPTER_LOCK(sc); 2704245274Snp for (;;) { 2705245274Snp 2706245274Snp if (pi && IS_DOOMED(pi)) { 2707245274Snp rc = ENXIO; 2708245274Snp goto done; 2709245274Snp } 2710245274Snp 2711245274Snp if (!IS_BUSY(sc)) { 2712245274Snp rc = 0; 2713245274Snp break; 2714245274Snp } 2715245274Snp 2716245274Snp if (!(flags & SLEEP_OK)) { 2717245274Snp rc = EBUSY; 2718245274Snp goto done; 2719245274Snp } 2720245274Snp 2721245274Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, pri, wmesg, 0)) { 2722218792Snp rc = EINTR; 2723218792Snp goto done; 2724218792Snp } 2725218792Snp } 2726245274Snp 2727218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 2728218792Snp SET_BUSY(sc); 2729245274Snp#ifdef INVARIANTS 2730245274Snp sc->last_op = wmesg; 2731245274Snp sc->last_op_thr = curthread; 2732245274Snp#endif 2733218792Snp 2734245274Snpdone: 2735245274Snp if (!(flags & HOLD_LOCK) || rc) 2736245274Snp ADAPTER_UNLOCK(sc); 2737218792Snp 2738245274Snp return (rc); 2739245274Snp} 2740245274Snp 2741245274Snpvoid 2742245274Snpend_synchronized_op(struct adapter *sc, int flags) 2743245274Snp{ 2744245274Snp 2745245274Snp if (flags & LOCK_HELD) 2746245274Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 2747245274Snp else 2748245274Snp ADAPTER_LOCK(sc); 2749245274Snp 2750218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 2751218792Snp CLR_BUSY(sc); 2752245274Snp wakeup(&sc->flags); 2753218792Snp ADAPTER_UNLOCK(sc); 2754218792Snp} 2755218792Snp 2756218792Snpstatic int 2757218792Snpcxgbe_init_synchronized(struct port_info *pi) 2758218792Snp{ 2759218792Snp struct adapter *sc = pi->adapter; 2760218792Snp struct ifnet *ifp = pi->ifp; 2761228561Snp int rc = 0; 2762218792Snp 2763245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2764218792Snp 2765218792Snp if (isset(&sc->open_device_map, pi->port_id)) { 2766218792Snp KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, 2767218792Snp ("mismatch between open_device_map and if_drv_flags")); 2768218792Snp return (0); /* already running */ 2769218792Snp } 2770218792Snp 2771228561Snp if (!(sc->flags & FULL_INIT_DONE) && 2772228561Snp ((rc = adapter_full_init(sc)) != 0)) 2773218792Snp return (rc); /* error message displayed already */ 2774218792Snp 2775228561Snp if (!(pi->flags & PORT_INIT_DONE) && 2776228561Snp ((rc = port_full_init(pi)) != 0)) 2777228561Snp return (rc); /* error message displayed already */ 2778218792Snp 2779218792Snp rc = update_mac_settings(pi, XGMAC_ALL); 2780218792Snp if (rc) 2781218792Snp goto done; /* error message displayed already */ 2782218792Snp 2783218792Snp rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg); 2784218792Snp if (rc != 0) { 2785218792Snp if_printf(ifp, "start_link failed: %d\n", rc); 2786218792Snp goto done; 2787218792Snp } 2788218792Snp 2789218792Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true); 2790218792Snp if (rc != 0) { 2791218792Snp if_printf(ifp, "enable_vi failed: %d\n", rc); 2792218792Snp goto done; 2793218792Snp } 2794218792Snp 2795218792Snp /* all ok */ 2796218792Snp setbit(&sc->open_device_map, pi->port_id); 2797245274Snp PORT_LOCK(pi); 2798218792Snp ifp->if_drv_flags |= IFF_DRV_RUNNING; 2799245274Snp PORT_UNLOCK(pi); 2800218792Snp 2801218792Snp callout_reset(&pi->tick, hz, cxgbe_tick, pi); 2802218792Snpdone: 2803218792Snp if (rc != 0) 2804218792Snp cxgbe_uninit_synchronized(pi); 2805218792Snp 2806218792Snp return (rc); 2807218792Snp} 2808218792Snp 2809218792Snp/* 2810218792Snp * Idempotent. 2811218792Snp */ 2812218792Snpstatic int 2813218792Snpcxgbe_uninit_synchronized(struct port_info *pi) 2814218792Snp{ 2815218792Snp struct adapter *sc = pi->adapter; 2816218792Snp struct ifnet *ifp = pi->ifp; 2817218792Snp int rc; 2818218792Snp 2819245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2820218792Snp 2821218792Snp /* 2822228561Snp * Disable the VI so that all its data in either direction is discarded 2823228561Snp * by the MPS. Leave everything else (the queues, interrupts, and 1Hz 2824228561Snp * tick) intact as the TP can deliver negative advice or data that it's 2825228561Snp * holding in its RAM (for an offloaded connection) even after the VI is 2826228561Snp * disabled. 2827218792Snp */ 2828228561Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false); 2829228561Snp if (rc) { 2830228561Snp if_printf(ifp, "disable_vi failed: %d\n", rc); 2831228561Snp return (rc); 2832228561Snp } 2833228561Snp 2834218792Snp clrbit(&sc->open_device_map, pi->port_id); 2835245274Snp PORT_LOCK(pi); 2836228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2837245274Snp PORT_UNLOCK(pi); 2838218792Snp 2839218792Snp pi->link_cfg.link_ok = 0; 2840218792Snp pi->link_cfg.speed = 0; 2841218792Snp t4_os_link_changed(sc, pi->port_id, 0); 2842218792Snp 2843218792Snp return (0); 2844218792Snp} 2845218792Snp 2846240453Snp/* 2847240453Snp * It is ok for this function to fail midway and return right away. t4_detach 2848240453Snp * will walk the entire sc->irq list and clean up whatever is valid. 2849240453Snp */ 2850218792Snpstatic int 2851240453Snpsetup_intr_handlers(struct adapter *sc) 2852218792Snp{ 2853240453Snp int rc, rid, p, q; 2854222510Snp char s[8]; 2855222510Snp struct irq *irq; 2856228561Snp struct port_info *pi; 2857228561Snp struct sge_rxq *rxq; 2858237263Snp#ifdef TCP_OFFLOAD 2859228561Snp struct sge_ofld_rxq *ofld_rxq; 2860228561Snp#endif 2861218792Snp 2862218792Snp /* 2863218792Snp * Setup interrupts. 2864218792Snp */ 2865222510Snp irq = &sc->irq[0]; 2866222510Snp rid = sc->intr_type == INTR_INTX ? 0 : 1; 2867218792Snp if (sc->intr_count == 1) { 2868228561Snp KASSERT(!(sc->flags & INTR_DIRECT), 2869228561Snp ("%s: single interrupt && INTR_DIRECT?", __func__)); 2870222510Snp 2871240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_all, sc, "all"); 2872240453Snp if (rc != 0) 2873240453Snp return (rc); 2874218792Snp } else { 2875228561Snp /* Multiple interrupts. */ 2876228561Snp KASSERT(sc->intr_count >= T4_EXTRA_INTR + sc->params.nports, 2877228561Snp ("%s: too few intr.", __func__)); 2878228561Snp 2879228561Snp /* The first one is always error intr */ 2880240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_err, sc, "err"); 2881240453Snp if (rc != 0) 2882240453Snp return (rc); 2883222510Snp irq++; 2884222510Snp rid++; 2885218792Snp 2886228561Snp /* The second one is always the firmware event queue */ 2887240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_evt, &sc->sge.fwq, 2888240453Snp "evt"); 2889240453Snp if (rc != 0) 2890240453Snp return (rc); 2891228561Snp irq++; 2892228561Snp rid++; 2893222510Snp 2894228561Snp /* 2895228561Snp * Note that if INTR_DIRECT is not set then either the NIC rx 2896228561Snp * queues or (exclusive or) the TOE rx queueus will be taking 2897228561Snp * direct interrupts. 2898228561Snp * 2899228561Snp * There is no need to check for is_offload(sc) as nofldrxq 2900228561Snp * will be 0 if offload is disabled. 2901228561Snp */ 2902228561Snp for_each_port(sc, p) { 2903228561Snp pi = sc->port[p]; 2904222510Snp 2905237263Snp#ifdef TCP_OFFLOAD 2906228561Snp /* 2907228561Snp * Skip over the NIC queues if they aren't taking direct 2908228561Snp * interrupts. 2909228561Snp */ 2910228561Snp if (!(sc->flags & INTR_DIRECT) && 2911228561Snp pi->nofldrxq > pi->nrxq) 2912228561Snp goto ofld_queues; 2913228561Snp#endif 2914228561Snp rxq = &sc->sge.rxq[pi->first_rxq]; 2915228561Snp for (q = 0; q < pi->nrxq; q++, rxq++) { 2916228561Snp snprintf(s, sizeof(s), "%d.%d", p, q); 2917240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, rxq, 2918240453Snp s); 2919240453Snp if (rc != 0) 2920240453Snp return (rc); 2921222510Snp irq++; 2922222510Snp rid++; 2923218792Snp } 2924218792Snp 2925237263Snp#ifdef TCP_OFFLOAD 2926228561Snp /* 2927228561Snp * Skip over the offload queues if they aren't taking 2928228561Snp * direct interrupts. 2929228561Snp */ 2930228561Snp if (!(sc->flags & INTR_DIRECT)) 2931228561Snp continue; 2932228561Snpofld_queues: 2933228561Snp ofld_rxq = &sc->sge.ofld_rxq[pi->first_ofld_rxq]; 2934228561Snp for (q = 0; q < pi->nofldrxq; q++, ofld_rxq++) { 2935228561Snp snprintf(s, sizeof(s), "%d,%d", p, q); 2936240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, 2937240453Snp ofld_rxq, s); 2938240453Snp if (rc != 0) 2939240453Snp return (rc); 2940228561Snp irq++; 2941228561Snp rid++; 2942218792Snp } 2943228561Snp#endif 2944218792Snp } 2945218792Snp } 2946218792Snp 2947240453Snp return (0); 2948240453Snp} 2949240453Snp 2950240453Snpstatic int 2951240453Snpadapter_full_init(struct adapter *sc) 2952240453Snp{ 2953240453Snp int rc, i; 2954240453Snp 2955240453Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2956240453Snp KASSERT((sc->flags & FULL_INIT_DONE) == 0, 2957240453Snp ("%s: FULL_INIT_DONE already", __func__)); 2958240453Snp 2959240453Snp /* 2960240453Snp * queues that belong to the adapter (not any particular port). 2961240453Snp */ 2962240453Snp rc = t4_setup_adapter_queues(sc); 2963240453Snp if (rc != 0) 2964240453Snp goto done; 2965240453Snp 2966240453Snp for (i = 0; i < nitems(sc->tq); i++) { 2967240453Snp sc->tq[i] = taskqueue_create("t4 taskq", M_NOWAIT, 2968240453Snp taskqueue_thread_enqueue, &sc->tq[i]); 2969240453Snp if (sc->tq[i] == NULL) { 2970240453Snp device_printf(sc->dev, 2971240453Snp "failed to allocate task queue %d\n", i); 2972240453Snp rc = ENOMEM; 2973240453Snp goto done; 2974240453Snp } 2975240453Snp taskqueue_start_threads(&sc->tq[i], 1, PI_NET, "%s tq%d", 2976240453Snp device_get_nameunit(sc->dev), i); 2977240453Snp } 2978240453Snp 2979218792Snp t4_intr_enable(sc); 2980218792Snp sc->flags |= FULL_INIT_DONE; 2981218792Snpdone: 2982218792Snp if (rc != 0) 2983228561Snp adapter_full_uninit(sc); 2984218792Snp 2985218792Snp return (rc); 2986218792Snp} 2987218792Snp 2988218792Snpstatic int 2989228561Snpadapter_full_uninit(struct adapter *sc) 2990218792Snp{ 2991218792Snp int i; 2992218792Snp 2993218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2994218792Snp 2995220873Snp t4_teardown_adapter_queues(sc); 2996218792Snp 2997240452Snp for (i = 0; i < nitems(sc->tq) && sc->tq[i]; i++) { 2998228561Snp taskqueue_free(sc->tq[i]); 2999228561Snp sc->tq[i] = NULL; 3000228561Snp } 3001228561Snp 3002218792Snp sc->flags &= ~FULL_INIT_DONE; 3003218792Snp 3004218792Snp return (0); 3005218792Snp} 3006218792Snp 3007218792Snpstatic int 3008228561Snpport_full_init(struct port_info *pi) 3009228561Snp{ 3010228561Snp struct adapter *sc = pi->adapter; 3011228561Snp struct ifnet *ifp = pi->ifp; 3012228561Snp uint16_t *rss; 3013228561Snp struct sge_rxq *rxq; 3014228561Snp int rc, i; 3015228561Snp 3016245274Snp ASSERT_SYNCHRONIZED_OP(sc); 3017228561Snp KASSERT((pi->flags & PORT_INIT_DONE) == 0, 3018228561Snp ("%s: PORT_INIT_DONE already", __func__)); 3019228561Snp 3020228561Snp sysctl_ctx_init(&pi->ctx); 3021228561Snp pi->flags |= PORT_SYSCTL_CTX; 3022228561Snp 3023228561Snp /* 3024228561Snp * Allocate tx/rx/fl queues for this port. 3025228561Snp */ 3026228561Snp rc = t4_setup_port_queues(pi); 3027228561Snp if (rc != 0) 3028228561Snp goto done; /* error message displayed already */ 3029228561Snp 3030228561Snp /* 3031228561Snp * Setup RSS for this port. 3032228561Snp */ 3033228561Snp rss = malloc(pi->nrxq * sizeof (*rss), M_CXGBE, 3034228561Snp M_ZERO | M_WAITOK); 3035228561Snp for_each_rxq(pi, i, rxq) { 3036228561Snp rss[i] = rxq->iq.abs_id; 3037228561Snp } 3038228561Snp rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, 3039228561Snp pi->rss_size, rss, pi->nrxq); 3040228561Snp free(rss, M_CXGBE); 3041228561Snp if (rc != 0) { 3042228561Snp if_printf(ifp, "rss_config failed: %d\n", rc); 3043228561Snp goto done; 3044228561Snp } 3045228561Snp 3046228561Snp pi->flags |= PORT_INIT_DONE; 3047228561Snpdone: 3048228561Snp if (rc != 0) 3049228561Snp port_full_uninit(pi); 3050228561Snp 3051228561Snp return (rc); 3052228561Snp} 3053228561Snp 3054228561Snp/* 3055228561Snp * Idempotent. 3056228561Snp */ 3057228561Snpstatic int 3058228561Snpport_full_uninit(struct port_info *pi) 3059228561Snp{ 3060228561Snp struct adapter *sc = pi->adapter; 3061228561Snp int i; 3062228561Snp struct sge_rxq *rxq; 3063228561Snp struct sge_txq *txq; 3064237263Snp#ifdef TCP_OFFLOAD 3065228561Snp struct sge_ofld_rxq *ofld_rxq; 3066228561Snp struct sge_wrq *ofld_txq; 3067228561Snp#endif 3068228561Snp 3069228561Snp if (pi->flags & PORT_INIT_DONE) { 3070228561Snp 3071228561Snp /* Need to quiesce queues. XXX: ctrl queues? */ 3072228561Snp 3073228561Snp for_each_txq(pi, i, txq) { 3074228561Snp quiesce_eq(sc, &txq->eq); 3075228561Snp } 3076228561Snp 3077237263Snp#ifdef TCP_OFFLOAD 3078228561Snp for_each_ofld_txq(pi, i, ofld_txq) { 3079228561Snp quiesce_eq(sc, &ofld_txq->eq); 3080228561Snp } 3081228561Snp#endif 3082228561Snp 3083228561Snp for_each_rxq(pi, i, rxq) { 3084228561Snp quiesce_iq(sc, &rxq->iq); 3085228561Snp quiesce_fl(sc, &rxq->fl); 3086228561Snp } 3087228561Snp 3088237263Snp#ifdef TCP_OFFLOAD 3089228561Snp for_each_ofld_rxq(pi, i, ofld_rxq) { 3090228561Snp quiesce_iq(sc, &ofld_rxq->iq); 3091228561Snp quiesce_fl(sc, &ofld_rxq->fl); 3092228561Snp } 3093228561Snp#endif 3094228561Snp } 3095228561Snp 3096228561Snp t4_teardown_port_queues(pi); 3097228561Snp pi->flags &= ~PORT_INIT_DONE; 3098228561Snp 3099228561Snp return (0); 3100228561Snp} 3101228561Snp 3102228561Snpstatic void 3103228561Snpquiesce_eq(struct adapter *sc, struct sge_eq *eq) 3104228561Snp{ 3105228561Snp EQ_LOCK(eq); 3106228561Snp eq->flags |= EQ_DOOMED; 3107228561Snp 3108228561Snp /* 3109228561Snp * Wait for the response to a credit flush if one's 3110228561Snp * pending. 3111228561Snp */ 3112228561Snp while (eq->flags & EQ_CRFLUSHED) 3113228561Snp mtx_sleep(eq, &eq->eq_lock, 0, "crflush", 0); 3114228561Snp EQ_UNLOCK(eq); 3115228561Snp 3116228561Snp callout_drain(&eq->tx_callout); /* XXX: iffy */ 3117228561Snp pause("callout", 10); /* Still iffy */ 3118228561Snp 3119228561Snp taskqueue_drain(sc->tq[eq->tx_chan], &eq->tx_task); 3120228561Snp} 3121228561Snp 3122228561Snpstatic void 3123228561Snpquiesce_iq(struct adapter *sc, struct sge_iq *iq) 3124228561Snp{ 3125228561Snp (void) sc; /* unused */ 3126228561Snp 3127228561Snp /* Synchronize with the interrupt handler */ 3128228561Snp while (!atomic_cmpset_int(&iq->state, IQS_IDLE, IQS_DISABLED)) 3129228561Snp pause("iqfree", 1); 3130228561Snp} 3131228561Snp 3132228561Snpstatic void 3133228561Snpquiesce_fl(struct adapter *sc, struct sge_fl *fl) 3134228561Snp{ 3135228561Snp mtx_lock(&sc->sfl_lock); 3136228561Snp FL_LOCK(fl); 3137228561Snp fl->flags |= FL_DOOMED; 3138228561Snp FL_UNLOCK(fl); 3139228561Snp mtx_unlock(&sc->sfl_lock); 3140228561Snp 3141228561Snp callout_drain(&sc->sfl_callout); 3142228561Snp KASSERT((fl->flags & FL_STARVING) == 0, 3143228561Snp ("%s: still starving", __func__)); 3144228561Snp} 3145228561Snp 3146228561Snpstatic int 3147218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid, 3148228561Snp driver_intr_t *handler, void *arg, char *name) 3149218792Snp{ 3150218792Snp int rc; 3151218792Snp 3152218792Snp irq->rid = rid; 3153218792Snp irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid, 3154218792Snp RF_SHAREABLE | RF_ACTIVE); 3155218792Snp if (irq->res == NULL) { 3156218792Snp device_printf(sc->dev, 3157218792Snp "failed to allocate IRQ for rid %d, name %s.\n", rid, name); 3158218792Snp return (ENOMEM); 3159218792Snp } 3160218792Snp 3161218792Snp rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET, 3162218792Snp NULL, handler, arg, &irq->tag); 3163218792Snp if (rc != 0) { 3164218792Snp device_printf(sc->dev, 3165218792Snp "failed to setup interrupt for rid %d, name %s: %d\n", 3166218792Snp rid, name, rc); 3167218792Snp } else if (name) 3168218792Snp bus_describe_intr(sc->dev, irq->res, irq->tag, name); 3169218792Snp 3170218792Snp return (rc); 3171218792Snp} 3172218792Snp 3173218792Snpstatic int 3174218792Snpt4_free_irq(struct adapter *sc, struct irq *irq) 3175218792Snp{ 3176218792Snp if (irq->tag) 3177218792Snp bus_teardown_intr(sc->dev, irq->res, irq->tag); 3178218792Snp if (irq->res) 3179218792Snp bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res); 3180218792Snp 3181218792Snp bzero(irq, sizeof(*irq)); 3182218792Snp 3183218792Snp return (0); 3184218792Snp} 3185218792Snp 3186218792Snpstatic void 3187218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start, 3188218792Snp unsigned int end) 3189218792Snp{ 3190218792Snp uint32_t *p = (uint32_t *)(buf + start); 3191218792Snp 3192218792Snp for ( ; start <= end; start += sizeof(uint32_t)) 3193218792Snp *p++ = t4_read_reg(sc, start); 3194218792Snp} 3195218792Snp 3196218792Snpstatic void 3197218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf) 3198218792Snp{ 3199248925Snp int i, n; 3200248925Snp const unsigned int *reg_ranges; 3201248925Snp static const unsigned int t4_reg_ranges[] = { 3202218792Snp 0x1008, 0x1108, 3203218792Snp 0x1180, 0x11b4, 3204218792Snp 0x11fc, 0x123c, 3205218792Snp 0x1300, 0x173c, 3206218792Snp 0x1800, 0x18fc, 3207218792Snp 0x3000, 0x30d8, 3208218792Snp 0x30e0, 0x5924, 3209218792Snp 0x5960, 0x59d4, 3210218792Snp 0x5a00, 0x5af8, 3211218792Snp 0x6000, 0x6098, 3212218792Snp 0x6100, 0x6150, 3213218792Snp 0x6200, 0x6208, 3214218792Snp 0x6240, 0x6248, 3215218792Snp 0x6280, 0x6338, 3216218792Snp 0x6370, 0x638c, 3217218792Snp 0x6400, 0x643c, 3218218792Snp 0x6500, 0x6524, 3219218792Snp 0x6a00, 0x6a38, 3220218792Snp 0x6a60, 0x6a78, 3221218792Snp 0x6b00, 0x6b84, 3222218792Snp 0x6bf0, 0x6c84, 3223218792Snp 0x6cf0, 0x6d84, 3224218792Snp 0x6df0, 0x6e84, 3225218792Snp 0x6ef0, 0x6f84, 3226218792Snp 0x6ff0, 0x7084, 3227218792Snp 0x70f0, 0x7184, 3228218792Snp 0x71f0, 0x7284, 3229218792Snp 0x72f0, 0x7384, 3230218792Snp 0x73f0, 0x7450, 3231218792Snp 0x7500, 0x7530, 3232218792Snp 0x7600, 0x761c, 3233218792Snp 0x7680, 0x76cc, 3234218792Snp 0x7700, 0x7798, 3235218792Snp 0x77c0, 0x77fc, 3236218792Snp 0x7900, 0x79fc, 3237218792Snp 0x7b00, 0x7c38, 3238218792Snp 0x7d00, 0x7efc, 3239218792Snp 0x8dc0, 0x8e1c, 3240218792Snp 0x8e30, 0x8e78, 3241218792Snp 0x8ea0, 0x8f6c, 3242218792Snp 0x8fc0, 0x9074, 3243218792Snp 0x90fc, 0x90fc, 3244218792Snp 0x9400, 0x9458, 3245218792Snp 0x9600, 0x96bc, 3246218792Snp 0x9800, 0x9808, 3247218792Snp 0x9820, 0x983c, 3248218792Snp 0x9850, 0x9864, 3249218792Snp 0x9c00, 0x9c6c, 3250218792Snp 0x9c80, 0x9cec, 3251218792Snp 0x9d00, 0x9d6c, 3252218792Snp 0x9d80, 0x9dec, 3253218792Snp 0x9e00, 0x9e6c, 3254218792Snp 0x9e80, 0x9eec, 3255218792Snp 0x9f00, 0x9f6c, 3256218792Snp 0x9f80, 0x9fec, 3257218792Snp 0xd004, 0xd03c, 3258218792Snp 0xdfc0, 0xdfe0, 3259218792Snp 0xe000, 0xea7c, 3260218792Snp 0xf000, 0x11190, 3261237439Snp 0x19040, 0x1906c, 3262237439Snp 0x19078, 0x19080, 3263237439Snp 0x1908c, 0x19124, 3264218792Snp 0x19150, 0x191b0, 3265218792Snp 0x191d0, 0x191e8, 3266218792Snp 0x19238, 0x1924c, 3267218792Snp 0x193f8, 0x19474, 3268218792Snp 0x19490, 0x194f8, 3269218792Snp 0x19800, 0x19f30, 3270218792Snp 0x1a000, 0x1a06c, 3271218792Snp 0x1a0b0, 0x1a120, 3272218792Snp 0x1a128, 0x1a138, 3273218792Snp 0x1a190, 0x1a1c4, 3274218792Snp 0x1a1fc, 0x1a1fc, 3275218792Snp 0x1e040, 0x1e04c, 3276237439Snp 0x1e284, 0x1e28c, 3277218792Snp 0x1e2c0, 0x1e2c0, 3278218792Snp 0x1e2e0, 0x1e2e0, 3279218792Snp 0x1e300, 0x1e384, 3280218792Snp 0x1e3c0, 0x1e3c8, 3281218792Snp 0x1e440, 0x1e44c, 3282237439Snp 0x1e684, 0x1e68c, 3283218792Snp 0x1e6c0, 0x1e6c0, 3284218792Snp 0x1e6e0, 0x1e6e0, 3285218792Snp 0x1e700, 0x1e784, 3286218792Snp 0x1e7c0, 0x1e7c8, 3287218792Snp 0x1e840, 0x1e84c, 3288237439Snp 0x1ea84, 0x1ea8c, 3289218792Snp 0x1eac0, 0x1eac0, 3290218792Snp 0x1eae0, 0x1eae0, 3291218792Snp 0x1eb00, 0x1eb84, 3292218792Snp 0x1ebc0, 0x1ebc8, 3293218792Snp 0x1ec40, 0x1ec4c, 3294237439Snp 0x1ee84, 0x1ee8c, 3295218792Snp 0x1eec0, 0x1eec0, 3296218792Snp 0x1eee0, 0x1eee0, 3297218792Snp 0x1ef00, 0x1ef84, 3298218792Snp 0x1efc0, 0x1efc8, 3299218792Snp 0x1f040, 0x1f04c, 3300237439Snp 0x1f284, 0x1f28c, 3301218792Snp 0x1f2c0, 0x1f2c0, 3302218792Snp 0x1f2e0, 0x1f2e0, 3303218792Snp 0x1f300, 0x1f384, 3304218792Snp 0x1f3c0, 0x1f3c8, 3305218792Snp 0x1f440, 0x1f44c, 3306237439Snp 0x1f684, 0x1f68c, 3307218792Snp 0x1f6c0, 0x1f6c0, 3308218792Snp 0x1f6e0, 0x1f6e0, 3309218792Snp 0x1f700, 0x1f784, 3310218792Snp 0x1f7c0, 0x1f7c8, 3311218792Snp 0x1f840, 0x1f84c, 3312237439Snp 0x1fa84, 0x1fa8c, 3313218792Snp 0x1fac0, 0x1fac0, 3314218792Snp 0x1fae0, 0x1fae0, 3315218792Snp 0x1fb00, 0x1fb84, 3316218792Snp 0x1fbc0, 0x1fbc8, 3317218792Snp 0x1fc40, 0x1fc4c, 3318237439Snp 0x1fe84, 0x1fe8c, 3319218792Snp 0x1fec0, 0x1fec0, 3320218792Snp 0x1fee0, 0x1fee0, 3321218792Snp 0x1ff00, 0x1ff84, 3322218792Snp 0x1ffc0, 0x1ffc8, 3323218792Snp 0x20000, 0x2002c, 3324218792Snp 0x20100, 0x2013c, 3325218792Snp 0x20190, 0x201c8, 3326218792Snp 0x20200, 0x20318, 3327218792Snp 0x20400, 0x20528, 3328218792Snp 0x20540, 0x20614, 3329218792Snp 0x21000, 0x21040, 3330218792Snp 0x2104c, 0x21060, 3331218792Snp 0x210c0, 0x210ec, 3332218792Snp 0x21200, 0x21268, 3333218792Snp 0x21270, 0x21284, 3334218792Snp 0x212fc, 0x21388, 3335218792Snp 0x21400, 0x21404, 3336218792Snp 0x21500, 0x21518, 3337218792Snp 0x2152c, 0x2153c, 3338218792Snp 0x21550, 0x21554, 3339218792Snp 0x21600, 0x21600, 3340218792Snp 0x21608, 0x21628, 3341218792Snp 0x21630, 0x2163c, 3342218792Snp 0x21700, 0x2171c, 3343218792Snp 0x21780, 0x2178c, 3344218792Snp 0x21800, 0x21c38, 3345218792Snp 0x21c80, 0x21d7c, 3346218792Snp 0x21e00, 0x21e04, 3347218792Snp 0x22000, 0x2202c, 3348218792Snp 0x22100, 0x2213c, 3349218792Snp 0x22190, 0x221c8, 3350218792Snp 0x22200, 0x22318, 3351218792Snp 0x22400, 0x22528, 3352218792Snp 0x22540, 0x22614, 3353218792Snp 0x23000, 0x23040, 3354218792Snp 0x2304c, 0x23060, 3355218792Snp 0x230c0, 0x230ec, 3356218792Snp 0x23200, 0x23268, 3357218792Snp 0x23270, 0x23284, 3358218792Snp 0x232fc, 0x23388, 3359218792Snp 0x23400, 0x23404, 3360218792Snp 0x23500, 0x23518, 3361218792Snp 0x2352c, 0x2353c, 3362218792Snp 0x23550, 0x23554, 3363218792Snp 0x23600, 0x23600, 3364218792Snp 0x23608, 0x23628, 3365218792Snp 0x23630, 0x2363c, 3366218792Snp 0x23700, 0x2371c, 3367218792Snp 0x23780, 0x2378c, 3368218792Snp 0x23800, 0x23c38, 3369218792Snp 0x23c80, 0x23d7c, 3370218792Snp 0x23e00, 0x23e04, 3371218792Snp 0x24000, 0x2402c, 3372218792Snp 0x24100, 0x2413c, 3373218792Snp 0x24190, 0x241c8, 3374218792Snp 0x24200, 0x24318, 3375218792Snp 0x24400, 0x24528, 3376218792Snp 0x24540, 0x24614, 3377218792Snp 0x25000, 0x25040, 3378218792Snp 0x2504c, 0x25060, 3379218792Snp 0x250c0, 0x250ec, 3380218792Snp 0x25200, 0x25268, 3381218792Snp 0x25270, 0x25284, 3382218792Snp 0x252fc, 0x25388, 3383218792Snp 0x25400, 0x25404, 3384218792Snp 0x25500, 0x25518, 3385218792Snp 0x2552c, 0x2553c, 3386218792Snp 0x25550, 0x25554, 3387218792Snp 0x25600, 0x25600, 3388218792Snp 0x25608, 0x25628, 3389218792Snp 0x25630, 0x2563c, 3390218792Snp 0x25700, 0x2571c, 3391218792Snp 0x25780, 0x2578c, 3392218792Snp 0x25800, 0x25c38, 3393218792Snp 0x25c80, 0x25d7c, 3394218792Snp 0x25e00, 0x25e04, 3395218792Snp 0x26000, 0x2602c, 3396218792Snp 0x26100, 0x2613c, 3397218792Snp 0x26190, 0x261c8, 3398218792Snp 0x26200, 0x26318, 3399218792Snp 0x26400, 0x26528, 3400218792Snp 0x26540, 0x26614, 3401218792Snp 0x27000, 0x27040, 3402218792Snp 0x2704c, 0x27060, 3403218792Snp 0x270c0, 0x270ec, 3404218792Snp 0x27200, 0x27268, 3405218792Snp 0x27270, 0x27284, 3406218792Snp 0x272fc, 0x27388, 3407218792Snp 0x27400, 0x27404, 3408218792Snp 0x27500, 0x27518, 3409218792Snp 0x2752c, 0x2753c, 3410218792Snp 0x27550, 0x27554, 3411218792Snp 0x27600, 0x27600, 3412218792Snp 0x27608, 0x27628, 3413218792Snp 0x27630, 0x2763c, 3414218792Snp 0x27700, 0x2771c, 3415218792Snp 0x27780, 0x2778c, 3416218792Snp 0x27800, 0x27c38, 3417218792Snp 0x27c80, 0x27d7c, 3418218792Snp 0x27e00, 0x27e04 3419218792Snp }; 3420248925Snp static const unsigned int t5_reg_ranges[] = { 3421248925Snp 0x1008, 0x1148, 3422248925Snp 0x1180, 0x11b4, 3423248925Snp 0x11fc, 0x123c, 3424248925Snp 0x1280, 0x173c, 3425248925Snp 0x1800, 0x18fc, 3426248925Snp 0x3000, 0x3028, 3427248925Snp 0x3060, 0x30d8, 3428248925Snp 0x30e0, 0x30fc, 3429248925Snp 0x3140, 0x357c, 3430248925Snp 0x35a8, 0x35cc, 3431248925Snp 0x35ec, 0x35ec, 3432248925Snp 0x3600, 0x5624, 3433248925Snp 0x56cc, 0x575c, 3434248925Snp 0x580c, 0x5814, 3435248925Snp 0x5890, 0x58bc, 3436248925Snp 0x5940, 0x59dc, 3437248925Snp 0x59fc, 0x5a18, 3438248925Snp 0x5a60, 0x5a9c, 3439248925Snp 0x5b94, 0x5bfc, 3440248925Snp 0x6000, 0x6040, 3441248925Snp 0x6058, 0x614c, 3442248925Snp 0x7700, 0x7798, 3443248925Snp 0x77c0, 0x78fc, 3444248925Snp 0x7b00, 0x7c54, 3445248925Snp 0x7d00, 0x7efc, 3446248925Snp 0x8dc0, 0x8de0, 3447248925Snp 0x8df8, 0x8e84, 3448248925Snp 0x8ea0, 0x8f84, 3449248925Snp 0x8fc0, 0x90f8, 3450248925Snp 0x9400, 0x9470, 3451248925Snp 0x9600, 0x96f4, 3452248925Snp 0x9800, 0x9808, 3453248925Snp 0x9820, 0x983c, 3454248925Snp 0x9850, 0x9864, 3455248925Snp 0x9c00, 0x9c6c, 3456248925Snp 0x9c80, 0x9cec, 3457248925Snp 0x9d00, 0x9d6c, 3458248925Snp 0x9d80, 0x9dec, 3459248925Snp 0x9e00, 0x9e6c, 3460248925Snp 0x9e80, 0x9eec, 3461248925Snp 0x9f00, 0x9f6c, 3462248925Snp 0x9f80, 0xa020, 3463248925Snp 0xd004, 0xd03c, 3464248925Snp 0xdfc0, 0xdfe0, 3465248925Snp 0xe000, 0x11088, 3466248925Snp 0x1109c, 0x1117c, 3467248925Snp 0x11190, 0x11204, 3468248925Snp 0x19040, 0x1906c, 3469248925Snp 0x19078, 0x19080, 3470248925Snp 0x1908c, 0x19124, 3471248925Snp 0x19150, 0x191b0, 3472248925Snp 0x191d0, 0x191e8, 3473248925Snp 0x19238, 0x19290, 3474248925Snp 0x193f8, 0x19474, 3475248925Snp 0x19490, 0x194cc, 3476248925Snp 0x194f0, 0x194f8, 3477248925Snp 0x19c00, 0x19c60, 3478248925Snp 0x19c94, 0x19e10, 3479248925Snp 0x19e50, 0x19f34, 3480248925Snp 0x19f40, 0x19f50, 3481248925Snp 0x19f90, 0x19fe4, 3482248925Snp 0x1a000, 0x1a06c, 3483248925Snp 0x1a0b0, 0x1a120, 3484248925Snp 0x1a128, 0x1a138, 3485248925Snp 0x1a190, 0x1a1c4, 3486248925Snp 0x1a1fc, 0x1a1fc, 3487248925Snp 0x1e008, 0x1e00c, 3488248925Snp 0x1e040, 0x1e04c, 3489248925Snp 0x1e284, 0x1e290, 3490248925Snp 0x1e2c0, 0x1e2c0, 3491248925Snp 0x1e2e0, 0x1e2e0, 3492248925Snp 0x1e300, 0x1e384, 3493248925Snp 0x1e3c0, 0x1e3c8, 3494248925Snp 0x1e408, 0x1e40c, 3495248925Snp 0x1e440, 0x1e44c, 3496248925Snp 0x1e684, 0x1e690, 3497248925Snp 0x1e6c0, 0x1e6c0, 3498248925Snp 0x1e6e0, 0x1e6e0, 3499248925Snp 0x1e700, 0x1e784, 3500248925Snp 0x1e7c0, 0x1e7c8, 3501248925Snp 0x1e808, 0x1e80c, 3502248925Snp 0x1e840, 0x1e84c, 3503248925Snp 0x1ea84, 0x1ea90, 3504248925Snp 0x1eac0, 0x1eac0, 3505248925Snp 0x1eae0, 0x1eae0, 3506248925Snp 0x1eb00, 0x1eb84, 3507248925Snp 0x1ebc0, 0x1ebc8, 3508248925Snp 0x1ec08, 0x1ec0c, 3509248925Snp 0x1ec40, 0x1ec4c, 3510248925Snp 0x1ee84, 0x1ee90, 3511248925Snp 0x1eec0, 0x1eec0, 3512248925Snp 0x1eee0, 0x1eee0, 3513248925Snp 0x1ef00, 0x1ef84, 3514248925Snp 0x1efc0, 0x1efc8, 3515248925Snp 0x1f008, 0x1f00c, 3516248925Snp 0x1f040, 0x1f04c, 3517248925Snp 0x1f284, 0x1f290, 3518248925Snp 0x1f2c0, 0x1f2c0, 3519248925Snp 0x1f2e0, 0x1f2e0, 3520248925Snp 0x1f300, 0x1f384, 3521248925Snp 0x1f3c0, 0x1f3c8, 3522248925Snp 0x1f408, 0x1f40c, 3523248925Snp 0x1f440, 0x1f44c, 3524248925Snp 0x1f684, 0x1f690, 3525248925Snp 0x1f6c0, 0x1f6c0, 3526248925Snp 0x1f6e0, 0x1f6e0, 3527248925Snp 0x1f700, 0x1f784, 3528248925Snp 0x1f7c0, 0x1f7c8, 3529248925Snp 0x1f808, 0x1f80c, 3530248925Snp 0x1f840, 0x1f84c, 3531248925Snp 0x1fa84, 0x1fa90, 3532248925Snp 0x1fac0, 0x1fac0, 3533248925Snp 0x1fae0, 0x1fae0, 3534248925Snp 0x1fb00, 0x1fb84, 3535248925Snp 0x1fbc0, 0x1fbc8, 3536248925Snp 0x1fc08, 0x1fc0c, 3537248925Snp 0x1fc40, 0x1fc4c, 3538248925Snp 0x1fe84, 0x1fe90, 3539248925Snp 0x1fec0, 0x1fec0, 3540248925Snp 0x1fee0, 0x1fee0, 3541248925Snp 0x1ff00, 0x1ff84, 3542248925Snp 0x1ffc0, 0x1ffc8, 3543248925Snp 0x30000, 0x30040, 3544248925Snp 0x30100, 0x30144, 3545248925Snp 0x30190, 0x301d0, 3546248925Snp 0x30200, 0x30318, 3547248925Snp 0x30400, 0x3052c, 3548248925Snp 0x30540, 0x3061c, 3549248925Snp 0x30800, 0x30834, 3550248925Snp 0x308c0, 0x30908, 3551248925Snp 0x30910, 0x309ac, 3552248925Snp 0x30a00, 0x30a04, 3553248925Snp 0x30a0c, 0x30a2c, 3554248925Snp 0x30a44, 0x30a50, 3555248925Snp 0x30a74, 0x30c24, 3556248925Snp 0x30d08, 0x30d14, 3557248925Snp 0x30d1c, 0x30d20, 3558248925Snp 0x30d3c, 0x30d50, 3559248925Snp 0x31200, 0x3120c, 3560248925Snp 0x31220, 0x31220, 3561248925Snp 0x31240, 0x31240, 3562248925Snp 0x31600, 0x31600, 3563248925Snp 0x31608, 0x3160c, 3564248925Snp 0x31a00, 0x31a1c, 3565248925Snp 0x31e04, 0x31e20, 3566248925Snp 0x31e38, 0x31e3c, 3567248925Snp 0x31e80, 0x31e80, 3568248925Snp 0x31e88, 0x31ea8, 3569248925Snp 0x31eb0, 0x31eb4, 3570248925Snp 0x31ec8, 0x31ed4, 3571248925Snp 0x31fb8, 0x32004, 3572248925Snp 0x32208, 0x3223c, 3573248925Snp 0x32248, 0x3227c, 3574248925Snp 0x32288, 0x322bc, 3575248925Snp 0x322c8, 0x322fc, 3576248925Snp 0x32600, 0x32630, 3577248925Snp 0x32a00, 0x32abc, 3578248925Snp 0x32b00, 0x32b70, 3579248925Snp 0x33000, 0x33048, 3580248925Snp 0x33060, 0x3309c, 3581248925Snp 0x330f0, 0x33148, 3582248925Snp 0x33160, 0x3319c, 3583248925Snp 0x331f0, 0x332e4, 3584248925Snp 0x332f8, 0x333e4, 3585248925Snp 0x333f8, 0x33448, 3586248925Snp 0x33460, 0x3349c, 3587248925Snp 0x334f0, 0x33548, 3588248925Snp 0x33560, 0x3359c, 3589248925Snp 0x335f0, 0x336e4, 3590248925Snp 0x336f8, 0x337e4, 3591248925Snp 0x337f8, 0x337fc, 3592248925Snp 0x33814, 0x33814, 3593248925Snp 0x3382c, 0x3382c, 3594248925Snp 0x33880, 0x3388c, 3595248925Snp 0x338e8, 0x338ec, 3596248925Snp 0x33900, 0x33948, 3597248925Snp 0x33960, 0x3399c, 3598248925Snp 0x339f0, 0x33ae4, 3599248925Snp 0x33af8, 0x33b10, 3600248925Snp 0x33b28, 0x33b28, 3601248925Snp 0x33b3c, 0x33b50, 3602248925Snp 0x33bf0, 0x33c10, 3603248925Snp 0x33c28, 0x33c28, 3604248925Snp 0x33c3c, 0x33c50, 3605248925Snp 0x33cf0, 0x33cfc, 3606248925Snp 0x34000, 0x34040, 3607248925Snp 0x34100, 0x34144, 3608248925Snp 0x34190, 0x341d0, 3609248925Snp 0x34200, 0x34318, 3610248925Snp 0x34400, 0x3452c, 3611248925Snp 0x34540, 0x3461c, 3612248925Snp 0x34800, 0x34834, 3613248925Snp 0x348c0, 0x34908, 3614248925Snp 0x34910, 0x349ac, 3615248925Snp 0x34a00, 0x34a04, 3616248925Snp 0x34a0c, 0x34a2c, 3617248925Snp 0x34a44, 0x34a50, 3618248925Snp 0x34a74, 0x34c24, 3619248925Snp 0x34d08, 0x34d14, 3620248925Snp 0x34d1c, 0x34d20, 3621248925Snp 0x34d3c, 0x34d50, 3622248925Snp 0x35200, 0x3520c, 3623248925Snp 0x35220, 0x35220, 3624248925Snp 0x35240, 0x35240, 3625248925Snp 0x35600, 0x35600, 3626248925Snp 0x35608, 0x3560c, 3627248925Snp 0x35a00, 0x35a1c, 3628248925Snp 0x35e04, 0x35e20, 3629248925Snp 0x35e38, 0x35e3c, 3630248925Snp 0x35e80, 0x35e80, 3631248925Snp 0x35e88, 0x35ea8, 3632248925Snp 0x35eb0, 0x35eb4, 3633248925Snp 0x35ec8, 0x35ed4, 3634248925Snp 0x35fb8, 0x36004, 3635248925Snp 0x36208, 0x3623c, 3636248925Snp 0x36248, 0x3627c, 3637248925Snp 0x36288, 0x362bc, 3638248925Snp 0x362c8, 0x362fc, 3639248925Snp 0x36600, 0x36630, 3640248925Snp 0x36a00, 0x36abc, 3641248925Snp 0x36b00, 0x36b70, 3642248925Snp 0x37000, 0x37048, 3643248925Snp 0x37060, 0x3709c, 3644248925Snp 0x370f0, 0x37148, 3645248925Snp 0x37160, 0x3719c, 3646248925Snp 0x371f0, 0x372e4, 3647248925Snp 0x372f8, 0x373e4, 3648248925Snp 0x373f8, 0x37448, 3649248925Snp 0x37460, 0x3749c, 3650248925Snp 0x374f0, 0x37548, 3651248925Snp 0x37560, 0x3759c, 3652248925Snp 0x375f0, 0x376e4, 3653248925Snp 0x376f8, 0x377e4, 3654248925Snp 0x377f8, 0x377fc, 3655248925Snp 0x37814, 0x37814, 3656248925Snp 0x3782c, 0x3782c, 3657248925Snp 0x37880, 0x3788c, 3658248925Snp 0x378e8, 0x378ec, 3659248925Snp 0x37900, 0x37948, 3660248925Snp 0x37960, 0x3799c, 3661248925Snp 0x379f0, 0x37ae4, 3662248925Snp 0x37af8, 0x37b10, 3663248925Snp 0x37b28, 0x37b28, 3664248925Snp 0x37b3c, 0x37b50, 3665248925Snp 0x37bf0, 0x37c10, 3666248925Snp 0x37c28, 0x37c28, 3667248925Snp 0x37c3c, 0x37c50, 3668248925Snp 0x37cf0, 0x37cfc, 3669248925Snp 0x38000, 0x38040, 3670248925Snp 0x38100, 0x38144, 3671248925Snp 0x38190, 0x381d0, 3672248925Snp 0x38200, 0x38318, 3673248925Snp 0x38400, 0x3852c, 3674248925Snp 0x38540, 0x3861c, 3675248925Snp 0x38800, 0x38834, 3676248925Snp 0x388c0, 0x38908, 3677248925Snp 0x38910, 0x389ac, 3678248925Snp 0x38a00, 0x38a04, 3679248925Snp 0x38a0c, 0x38a2c, 3680248925Snp 0x38a44, 0x38a50, 3681248925Snp 0x38a74, 0x38c24, 3682248925Snp 0x38d08, 0x38d14, 3683248925Snp 0x38d1c, 0x38d20, 3684248925Snp 0x38d3c, 0x38d50, 3685248925Snp 0x39200, 0x3920c, 3686248925Snp 0x39220, 0x39220, 3687248925Snp 0x39240, 0x39240, 3688248925Snp 0x39600, 0x39600, 3689248925Snp 0x39608, 0x3960c, 3690248925Snp 0x39a00, 0x39a1c, 3691248925Snp 0x39e04, 0x39e20, 3692248925Snp 0x39e38, 0x39e3c, 3693248925Snp 0x39e80, 0x39e80, 3694248925Snp 0x39e88, 0x39ea8, 3695248925Snp 0x39eb0, 0x39eb4, 3696248925Snp 0x39ec8, 0x39ed4, 3697248925Snp 0x39fb8, 0x3a004, 3698248925Snp 0x3a208, 0x3a23c, 3699248925Snp 0x3a248, 0x3a27c, 3700248925Snp 0x3a288, 0x3a2bc, 3701248925Snp 0x3a2c8, 0x3a2fc, 3702248925Snp 0x3a600, 0x3a630, 3703248925Snp 0x3aa00, 0x3aabc, 3704248925Snp 0x3ab00, 0x3ab70, 3705248925Snp 0x3b000, 0x3b048, 3706248925Snp 0x3b060, 0x3b09c, 3707248925Snp 0x3b0f0, 0x3b148, 3708248925Snp 0x3b160, 0x3b19c, 3709248925Snp 0x3b1f0, 0x3b2e4, 3710248925Snp 0x3b2f8, 0x3b3e4, 3711248925Snp 0x3b3f8, 0x3b448, 3712248925Snp 0x3b460, 0x3b49c, 3713248925Snp 0x3b4f0, 0x3b548, 3714248925Snp 0x3b560, 0x3b59c, 3715248925Snp 0x3b5f0, 0x3b6e4, 3716248925Snp 0x3b6f8, 0x3b7e4, 3717248925Snp 0x3b7f8, 0x3b7fc, 3718248925Snp 0x3b814, 0x3b814, 3719248925Snp 0x3b82c, 0x3b82c, 3720248925Snp 0x3b880, 0x3b88c, 3721248925Snp 0x3b8e8, 0x3b8ec, 3722248925Snp 0x3b900, 0x3b948, 3723248925Snp 0x3b960, 0x3b99c, 3724248925Snp 0x3b9f0, 0x3bae4, 3725248925Snp 0x3baf8, 0x3bb10, 3726248925Snp 0x3bb28, 0x3bb28, 3727248925Snp 0x3bb3c, 0x3bb50, 3728248925Snp 0x3bbf0, 0x3bc10, 3729248925Snp 0x3bc28, 0x3bc28, 3730248925Snp 0x3bc3c, 0x3bc50, 3731248925Snp 0x3bcf0, 0x3bcfc, 3732248925Snp 0x3c000, 0x3c040, 3733248925Snp 0x3c100, 0x3c144, 3734248925Snp 0x3c190, 0x3c1d0, 3735248925Snp 0x3c200, 0x3c318, 3736248925Snp 0x3c400, 0x3c52c, 3737248925Snp 0x3c540, 0x3c61c, 3738248925Snp 0x3c800, 0x3c834, 3739248925Snp 0x3c8c0, 0x3c908, 3740248925Snp 0x3c910, 0x3c9ac, 3741248925Snp 0x3ca00, 0x3ca04, 3742248925Snp 0x3ca0c, 0x3ca2c, 3743248925Snp 0x3ca44, 0x3ca50, 3744248925Snp 0x3ca74, 0x3cc24, 3745248925Snp 0x3cd08, 0x3cd14, 3746248925Snp 0x3cd1c, 0x3cd20, 3747248925Snp 0x3cd3c, 0x3cd50, 3748248925Snp 0x3d200, 0x3d20c, 3749248925Snp 0x3d220, 0x3d220, 3750248925Snp 0x3d240, 0x3d240, 3751248925Snp 0x3d600, 0x3d600, 3752248925Snp 0x3d608, 0x3d60c, 3753248925Snp 0x3da00, 0x3da1c, 3754248925Snp 0x3de04, 0x3de20, 3755248925Snp 0x3de38, 0x3de3c, 3756248925Snp 0x3de80, 0x3de80, 3757248925Snp 0x3de88, 0x3dea8, 3758248925Snp 0x3deb0, 0x3deb4, 3759248925Snp 0x3dec8, 0x3ded4, 3760248925Snp 0x3dfb8, 0x3e004, 3761248925Snp 0x3e208, 0x3e23c, 3762248925Snp 0x3e248, 0x3e27c, 3763248925Snp 0x3e288, 0x3e2bc, 3764248925Snp 0x3e2c8, 0x3e2fc, 3765248925Snp 0x3e600, 0x3e630, 3766248925Snp 0x3ea00, 0x3eabc, 3767248925Snp 0x3eb00, 0x3eb70, 3768248925Snp 0x3f000, 0x3f048, 3769248925Snp 0x3f060, 0x3f09c, 3770248925Snp 0x3f0f0, 0x3f148, 3771248925Snp 0x3f160, 0x3f19c, 3772248925Snp 0x3f1f0, 0x3f2e4, 3773248925Snp 0x3f2f8, 0x3f3e4, 3774248925Snp 0x3f3f8, 0x3f448, 3775248925Snp 0x3f460, 0x3f49c, 3776248925Snp 0x3f4f0, 0x3f548, 3777248925Snp 0x3f560, 0x3f59c, 3778248925Snp 0x3f5f0, 0x3f6e4, 3779248925Snp 0x3f6f8, 0x3f7e4, 3780248925Snp 0x3f7f8, 0x3f7fc, 3781248925Snp 0x3f814, 0x3f814, 3782248925Snp 0x3f82c, 0x3f82c, 3783248925Snp 0x3f880, 0x3f88c, 3784248925Snp 0x3f8e8, 0x3f8ec, 3785248925Snp 0x3f900, 0x3f948, 3786248925Snp 0x3f960, 0x3f99c, 3787248925Snp 0x3f9f0, 0x3fae4, 3788248925Snp 0x3faf8, 0x3fb10, 3789248925Snp 0x3fb28, 0x3fb28, 3790248925Snp 0x3fb3c, 0x3fb50, 3791248925Snp 0x3fbf0, 0x3fc10, 3792248925Snp 0x3fc28, 0x3fc28, 3793248925Snp 0x3fc3c, 0x3fc50, 3794248925Snp 0x3fcf0, 0x3fcfc, 3795248925Snp 0x40000, 0x4000c, 3796248925Snp 0x40040, 0x40068, 3797248925Snp 0x4007c, 0x40144, 3798248925Snp 0x40180, 0x4018c, 3799248925Snp 0x40200, 0x40298, 3800248925Snp 0x402ac, 0x4033c, 3801248925Snp 0x403f8, 0x403fc, 3802248925Snp 0x41300, 0x413c4, 3803248925Snp 0x41400, 0x4141c, 3804248925Snp 0x41480, 0x414d0, 3805248925Snp 0x44000, 0x44078, 3806248925Snp 0x440c0, 0x44278, 3807248925Snp 0x442c0, 0x44478, 3808248925Snp 0x444c0, 0x44678, 3809248925Snp 0x446c0, 0x44878, 3810248925Snp 0x448c0, 0x449fc, 3811248925Snp 0x45000, 0x45068, 3812248925Snp 0x45080, 0x45084, 3813248925Snp 0x450a0, 0x450b0, 3814248925Snp 0x45200, 0x45268, 3815248925Snp 0x45280, 0x45284, 3816248925Snp 0x452a0, 0x452b0, 3817248925Snp 0x460c0, 0x460e4, 3818248925Snp 0x47000, 0x4708c, 3819248925Snp 0x47200, 0x47250, 3820248925Snp 0x47400, 0x47420, 3821248925Snp 0x47600, 0x47618, 3822248925Snp 0x47800, 0x47814, 3823248925Snp 0x48000, 0x4800c, 3824248925Snp 0x48040, 0x48068, 3825248925Snp 0x4807c, 0x48144, 3826248925Snp 0x48180, 0x4818c, 3827248925Snp 0x48200, 0x48298, 3828248925Snp 0x482ac, 0x4833c, 3829248925Snp 0x483f8, 0x483fc, 3830248925Snp 0x49300, 0x493c4, 3831248925Snp 0x49400, 0x4941c, 3832248925Snp 0x49480, 0x494d0, 3833248925Snp 0x4c000, 0x4c078, 3834248925Snp 0x4c0c0, 0x4c278, 3835248925Snp 0x4c2c0, 0x4c478, 3836248925Snp 0x4c4c0, 0x4c678, 3837248925Snp 0x4c6c0, 0x4c878, 3838248925Snp 0x4c8c0, 0x4c9fc, 3839248925Snp 0x4d000, 0x4d068, 3840248925Snp 0x4d080, 0x4d084, 3841248925Snp 0x4d0a0, 0x4d0b0, 3842248925Snp 0x4d200, 0x4d268, 3843248925Snp 0x4d280, 0x4d284, 3844248925Snp 0x4d2a0, 0x4d2b0, 3845248925Snp 0x4e0c0, 0x4e0e4, 3846248925Snp 0x4f000, 0x4f08c, 3847248925Snp 0x4f200, 0x4f250, 3848248925Snp 0x4f400, 0x4f420, 3849248925Snp 0x4f600, 0x4f618, 3850248925Snp 0x4f800, 0x4f814, 3851248925Snp 0x50000, 0x500cc, 3852248925Snp 0x50400, 0x50400, 3853248925Snp 0x50800, 0x508cc, 3854248925Snp 0x50c00, 0x50c00, 3855248925Snp 0x51000, 0x5101c, 3856248925Snp 0x51300, 0x51308, 3857248925Snp }; 3858218792Snp 3859248925Snp if (is_t4(sc)) { 3860248925Snp reg_ranges = &t4_reg_ranges[0]; 3861248925Snp n = nitems(t4_reg_ranges); 3862248925Snp } else { 3863248925Snp reg_ranges = &t5_reg_ranges[0]; 3864248925Snp n = nitems(t5_reg_ranges); 3865248925Snp } 3866248925Snp 3867248925Snp regs->version = chip_id(sc) | chip_rev(sc) << 10; 3868248925Snp for (i = 0; i < n; i += 2) 3869218792Snp reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]); 3870218792Snp} 3871218792Snp 3872218792Snpstatic void 3873218792Snpcxgbe_tick(void *arg) 3874218792Snp{ 3875218792Snp struct port_info *pi = arg; 3876218792Snp struct ifnet *ifp = pi->ifp; 3877218792Snp struct sge_txq *txq; 3878218792Snp int i, drops; 3879218792Snp struct port_stats *s = &pi->stats; 3880218792Snp 3881218792Snp PORT_LOCK(pi); 3882218792Snp if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 3883218792Snp PORT_UNLOCK(pi); 3884218792Snp return; /* without scheduling another callout */ 3885218792Snp } 3886218792Snp 3887218792Snp t4_get_port_stats(pi->adapter, pi->tx_chan, s); 3888218792Snp 3889228561Snp ifp->if_opackets = s->tx_frames - s->tx_pause; 3890228561Snp ifp->if_ipackets = s->rx_frames - s->rx_pause; 3891228561Snp ifp->if_obytes = s->tx_octets - s->tx_pause * 64; 3892228561Snp ifp->if_ibytes = s->rx_octets - s->rx_pause * 64; 3893228561Snp ifp->if_omcasts = s->tx_mcast_frames - s->tx_pause; 3894228561Snp ifp->if_imcasts = s->rx_mcast_frames - s->rx_pause; 3895218792Snp ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 + 3896239259Snp s->rx_ovflow3 + s->rx_trunc0 + s->rx_trunc1 + s->rx_trunc2 + 3897239259Snp s->rx_trunc3; 3898218792Snp 3899218792Snp drops = s->tx_drop; 3900218792Snp for_each_txq(pi, i, txq) 3901220873Snp drops += txq->br->br_drops; 3902218792Snp ifp->if_snd.ifq_drops = drops; 3903218792Snp 3904218792Snp ifp->if_oerrors = s->tx_error_frames; 3905218792Snp ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long + 3906218792Snp s->rx_fcs_err + s->rx_len_err; 3907218792Snp 3908218792Snp callout_schedule(&pi->tick, hz); 3909218792Snp PORT_UNLOCK(pi); 3910218792Snp} 3911218792Snp 3912237263Snpstatic void 3913237263Snpcxgbe_vlan_config(void *arg, struct ifnet *ifp, uint16_t vid) 3914237263Snp{ 3915237263Snp struct ifnet *vlan; 3916237263Snp 3917241494Snp if (arg != ifp || ifp->if_type != IFT_ETHER) 3918237263Snp return; 3919237263Snp 3920237263Snp vlan = VLAN_DEVAT(ifp, vid); 3921237263Snp VLAN_SETCOOKIE(vlan, ifp); 3922237263Snp} 3923237263Snp 3924218792Snpstatic int 3925228561Snpcpl_not_handled(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 3926228561Snp{ 3927237263Snp 3928228561Snp#ifdef INVARIANTS 3929237263Snp panic("%s: opcode 0x%02x on iq %p with payload %p", 3930228561Snp __func__, rss->opcode, iq, m); 3931228561Snp#else 3932239336Snp log(LOG_ERR, "%s: opcode 0x%02x on iq %p with payload %p\n", 3933228561Snp __func__, rss->opcode, iq, m); 3934228561Snp m_freem(m); 3935228561Snp#endif 3936228561Snp return (EDOOFUS); 3937228561Snp} 3938228561Snp 3939228561Snpint 3940228561Snpt4_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h) 3941228561Snp{ 3942228561Snp uintptr_t *loc, new; 3943228561Snp 3944240452Snp if (opcode >= nitems(sc->cpl_handler)) 3945228561Snp return (EINVAL); 3946228561Snp 3947228561Snp new = h ? (uintptr_t)h : (uintptr_t)cpl_not_handled; 3948228561Snp loc = (uintptr_t *) &sc->cpl_handler[opcode]; 3949228561Snp atomic_store_rel_ptr(loc, new); 3950228561Snp 3951228561Snp return (0); 3952228561Snp} 3953228561Snp 3954228561Snpstatic int 3955237263Snpan_not_handled(struct sge_iq *iq, const struct rsp_ctrl *ctrl) 3956237263Snp{ 3957237263Snp 3958237263Snp#ifdef INVARIANTS 3959237263Snp panic("%s: async notification on iq %p (ctrl %p)", __func__, iq, ctrl); 3960237263Snp#else 3961239336Snp log(LOG_ERR, "%s: async notification on iq %p (ctrl %p)\n", 3962237263Snp __func__, iq, ctrl); 3963237263Snp#endif 3964237263Snp return (EDOOFUS); 3965237263Snp} 3966237263Snp 3967237263Snpint 3968237263Snpt4_register_an_handler(struct adapter *sc, an_handler_t h) 3969237263Snp{ 3970237263Snp uintptr_t *loc, new; 3971237263Snp 3972237263Snp new = h ? (uintptr_t)h : (uintptr_t)an_not_handled; 3973237263Snp loc = (uintptr_t *) &sc->an_handler; 3974237263Snp atomic_store_rel_ptr(loc, new); 3975237263Snp 3976237263Snp return (0); 3977237263Snp} 3978237263Snp 3979237263Snpstatic int 3980239336Snpfw_msg_not_handled(struct adapter *sc, const __be64 *rpl) 3981239336Snp{ 3982241733Sed const struct cpl_fw6_msg *cpl = 3983241733Sed __containerof(rpl, struct cpl_fw6_msg, data[0]); 3984239336Snp 3985239336Snp#ifdef INVARIANTS 3986239336Snp panic("%s: fw_msg type %d", __func__, cpl->type); 3987239336Snp#else 3988239336Snp log(LOG_ERR, "%s: fw_msg type %d\n", __func__, cpl->type); 3989239336Snp#endif 3990239336Snp return (EDOOFUS); 3991239336Snp} 3992239336Snp 3993239336Snpint 3994239336Snpt4_register_fw_msg_handler(struct adapter *sc, int type, fw_msg_handler_t h) 3995239336Snp{ 3996239336Snp uintptr_t *loc, new; 3997239336Snp 3998240452Snp if (type >= nitems(sc->fw_msg_handler)) 3999239336Snp return (EINVAL); 4000239336Snp 4001247291Snp /* 4002247291Snp * These are dispatched by the handler for FW{4|6}_CPL_MSG using the CPL 4003247291Snp * handler dispatch table. Reject any attempt to install a handler for 4004247291Snp * this subtype. 4005247291Snp */ 4006247291Snp if (type == FW_TYPE_RSSCPL || type == FW6_TYPE_RSSCPL) 4007247291Snp return (EINVAL); 4008247291Snp 4009239336Snp new = h ? (uintptr_t)h : (uintptr_t)fw_msg_not_handled; 4010239336Snp loc = (uintptr_t *) &sc->fw_msg_handler[type]; 4011239336Snp atomic_store_rel_ptr(loc, new); 4012239336Snp 4013239336Snp return (0); 4014239336Snp} 4015239336Snp 4016239336Snpstatic int 4017218792Snpt4_sysctls(struct adapter *sc) 4018218792Snp{ 4019218792Snp struct sysctl_ctx_list *ctx; 4020218792Snp struct sysctl_oid *oid; 4021228561Snp struct sysctl_oid_list *children, *c0; 4022228561Snp static char *caps[] = { 4023228561Snp "\20\1PPP\2QFC\3DCBX", /* caps[0] linkcaps */ 4024228561Snp "\20\1NIC\2VM\3IDS\4UM\5UM_ISGL", /* caps[1] niccaps */ 4025228561Snp "\20\1TOE", /* caps[2] toecaps */ 4026228561Snp "\20\1RDDP\2RDMAC", /* caps[3] rdmacaps */ 4027228561Snp "\20\1INITIATOR_PDU\2TARGET_PDU" /* caps[4] iscsicaps */ 4028228561Snp "\3INITIATOR_CNXOFLD\4TARGET_CNXOFLD" 4029228561Snp "\5INITIATOR_SSNOFLD\6TARGET_SSNOFLD", 4030228561Snp "\20\1INITIATOR\2TARGET\3CTRL_OFLD" /* caps[5] fcoecaps */ 4031228561Snp }; 4032248925Snp static char *doorbells = {"\20\1UDB\2WRWC\3UDBWC\4KDB"}; 4033218792Snp 4034218792Snp ctx = device_get_sysctl_ctx(sc->dev); 4035228561Snp 4036228561Snp /* 4037228561Snp * dev.t4nex.X. 4038228561Snp */ 4039218792Snp oid = device_get_sysctl_tree(sc->dev); 4040228561Snp c0 = children = SYSCTL_CHILDREN(oid); 4041218792Snp 4042248925Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, NULL, 4043248925Snp sc->params.nports, "# of ports"); 4044218792Snp 4045218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD, 4046248925Snp NULL, chip_rev(sc), "chip hardware revision"); 4047218792Snp 4048218792Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 4049218792Snp CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 4050218792Snp 4051228561Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "cf", 4052245936Snp CTLFLAG_RD, &sc->cfg_file, 0, "configuration file"); 4053218792Snp 4054248925Snp SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cfcsum", CTLFLAG_RD, NULL, 4055248925Snp sc->cfcsum, "config file checksum"); 4056228561Snp 4057248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "doorbells", 4058248925Snp CTLTYPE_STRING | CTLFLAG_RD, doorbells, sc->doorbells, 4059248925Snp sysctl_bitfield, "A", "available doorbells"); 4060248925Snp 4061228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkcaps", 4062228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[0], sc->linkcaps, 4063228561Snp sysctl_bitfield, "A", "available link capabilities"); 4064228561Snp 4065228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "niccaps", 4066228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[1], sc->niccaps, 4067228561Snp sysctl_bitfield, "A", "available NIC capabilities"); 4068228561Snp 4069228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "toecaps", 4070228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[2], sc->toecaps, 4071228561Snp sysctl_bitfield, "A", "available TCP offload capabilities"); 4072228561Snp 4073228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdmacaps", 4074228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[3], sc->rdmacaps, 4075228561Snp sysctl_bitfield, "A", "available RDMA capabilities"); 4076228561Snp 4077228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "iscsicaps", 4078228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[4], sc->iscsicaps, 4079228561Snp sysctl_bitfield, "A", "available iSCSI capabilities"); 4080228561Snp 4081228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoecaps", 4082228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[5], sc->fcoecaps, 4083228561Snp sysctl_bitfield, "A", "available FCoE capabilities"); 4084228561Snp 4085248925Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, NULL, 4086248925Snp sc->params.vpd.cclk, "core clock frequency (in KHz)"); 4087218792Snp 4088219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers", 4089228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.timer_val, 4090228561Snp sizeof(sc->sge.timer_val), sysctl_int_array, "A", 4091228561Snp "interrupt holdoff timer values (us)"); 4092218792Snp 4093219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts", 4094228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.counter_val, 4095228561Snp sizeof(sc->sge.counter_val), sysctl_int_array, "A", 4096228561Snp "interrupt holdoff packet counter values"); 4097218792Snp 4098231115Snp#ifdef SBUF_DRAIN 4099228561Snp /* 4100228561Snp * dev.t4nex.X.misc. Marked CTLFLAG_SKIP to avoid information overload. 4101228561Snp */ 4102228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "misc", 4103228561Snp CTLFLAG_RD | CTLFLAG_SKIP, NULL, 4104228561Snp "logs and miscellaneous information"); 4105228561Snp children = SYSCTL_CHILDREN(oid); 4106228561Snp 4107228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cctrl", 4108228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4109228561Snp sysctl_cctrl, "A", "congestion control"); 4110228561Snp 4111247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp0", 4112247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4113247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 0 (TP0)"); 4114247122Snp 4115247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp1", 4116247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 1, 4117247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 1 (TP1)"); 4118247122Snp 4119247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ulp", 4120247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 2, 4121247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 2 (ULP)"); 4122247122Snp 4123247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge0", 4124247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 3, 4125247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 3 (SGE0)"); 4126247122Snp 4127247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge1", 4128247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 4, 4129247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 4 (SGE1)"); 4130247122Snp 4131247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ncsi", 4132247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 5, 4133247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 5 (NCSI)"); 4134247122Snp 4135247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_la", 4136247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4137247122Snp sysctl_cim_la, "A", "CIM logic analyzer"); 4138247122Snp 4139247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp0", 4140247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0 + CIM_NUM_IBQ, 4141247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 0 (ULP0)"); 4142247122Snp 4143247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp1", 4144247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 1 + CIM_NUM_IBQ, 4145247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 1 (ULP1)"); 4146247122Snp 4147247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp2", 4148247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 2 + CIM_NUM_IBQ, 4149247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 2 (ULP2)"); 4150247122Snp 4151247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp3", 4152247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 3 + CIM_NUM_IBQ, 4153247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 3 (ULP3)"); 4154247122Snp 4155247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge", 4156247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 4 + CIM_NUM_IBQ, 4157247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 4 (SGE)"); 4158247122Snp 4159247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ncsi", 4160247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 5 + CIM_NUM_IBQ, 4161247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 5 (NCSI)"); 4162247122Snp 4163248925Snp if (is_t5(sc)) { 4164248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge0_rx", 4165248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 6 + CIM_NUM_IBQ, 4166248925Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 6 (SGE0-RX)"); 4167248925Snp 4168248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge1_rx", 4169248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 7 + CIM_NUM_IBQ, 4170248925Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 7 (SGE1-RX)"); 4171248925Snp } 4172248925Snp 4173247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_qcfg", 4174247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4175247122Snp sysctl_cim_qcfg, "A", "CIM queue configuration"); 4176247122Snp 4177228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats", 4178228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4179228561Snp sysctl_cpl_stats, "A", "CPL statistics"); 4180228561Snp 4181228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ddp_stats", 4182228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4183228561Snp sysctl_ddp_stats, "A", "DDP statistics"); 4184228561Snp 4185222551Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog", 4186222551Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4187228561Snp sysctl_devlog, "A", "firmware's device log"); 4188222551Snp 4189228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoe_stats", 4190228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4191228561Snp sysctl_fcoe_stats, "A", "FCoE statistics"); 4192228561Snp 4193228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hw_sched", 4194228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4195228561Snp sysctl_hw_sched, "A", "hardware scheduler "); 4196228561Snp 4197228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "l2t", 4198228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4199228561Snp sysctl_l2t, "A", "hardware L2 table"); 4200228561Snp 4201228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats", 4202228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4203228561Snp sysctl_lb_stats, "A", "loopback statistics"); 4204228561Snp 4205228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "meminfo", 4206228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4207228561Snp sysctl_meminfo, "A", "memory regions"); 4208228561Snp 4209228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "path_mtus", 4210228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4211228561Snp sysctl_path_mtus, "A", "path MTUs"); 4212228561Snp 4213228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pm_stats", 4214228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4215228561Snp sysctl_pm_stats, "A", "PM statistics"); 4216228561Snp 4217228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_stats", 4218228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4219228561Snp sysctl_rdma_stats, "A", "RDMA statistics"); 4220228561Snp 4221228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tcp_stats", 4222228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4223228561Snp sysctl_tcp_stats, "A", "TCP statistics"); 4224228561Snp 4225228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tids", 4226228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4227228561Snp sysctl_tids, "A", "TID information"); 4228228561Snp 4229228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_err_stats", 4230228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4231228561Snp sysctl_tp_err_stats, "A", "TP error statistics"); 4232228561Snp 4233228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_rate", 4234228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4235228561Snp sysctl_tx_rate, "A", "Tx rate"); 4236248925Snp 4237248925Snp if (is_t5(sc)) { 4238248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "wrwc_stats", 4239248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4240248925Snp sysctl_wrwc_stats, "A", "work request (WC) statistics"); 4241248925Snp } 4242231115Snp#endif 4243228561Snp 4244237263Snp#ifdef TCP_OFFLOAD 4245228561Snp if (is_offload(sc)) { 4246228561Snp /* 4247228561Snp * dev.t4nex.X.toe. 4248228561Snp */ 4249228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "toe", CTLFLAG_RD, 4250228561Snp NULL, "TOE parameters"); 4251228561Snp children = SYSCTL_CHILDREN(oid); 4252228561Snp 4253228561Snp sc->tt.sndbuf = 256 * 1024; 4254228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "sndbuf", CTLFLAG_RW, 4255228561Snp &sc->tt.sndbuf, 0, "max hardware send buffer size"); 4256228561Snp 4257228561Snp sc->tt.ddp = 0; 4258228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp", CTLFLAG_RW, 4259228561Snp &sc->tt.ddp, 0, "DDP allowed"); 4260239341Snp 4261239341Snp sc->tt.indsz = G_INDICATESIZE(t4_read_reg(sc, A_TP_PARA_REG5)); 4262228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "indsz", CTLFLAG_RW, 4263228561Snp &sc->tt.indsz, 0, "DDP max indicate size allowed"); 4264239341Snp 4265239341Snp sc->tt.ddp_thres = 4266239341Snp G_RXCOALESCESIZE(t4_read_reg(sc, A_TP_PARA_REG2)); 4267228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp_thres", CTLFLAG_RW, 4268228561Snp &sc->tt.ddp_thres, 0, "DDP threshold"); 4269228561Snp } 4270228561Snp#endif 4271228561Snp 4272228561Snp 4273218792Snp return (0); 4274218792Snp} 4275218792Snp 4276218792Snpstatic int 4277218792Snpcxgbe_sysctls(struct port_info *pi) 4278218792Snp{ 4279218792Snp struct sysctl_ctx_list *ctx; 4280218792Snp struct sysctl_oid *oid; 4281218792Snp struct sysctl_oid_list *children; 4282218792Snp 4283218792Snp ctx = device_get_sysctl_ctx(pi->dev); 4284218792Snp 4285218792Snp /* 4286218792Snp * dev.cxgbe.X. 4287218792Snp */ 4288218792Snp oid = device_get_sysctl_tree(pi->dev); 4289218792Snp children = SYSCTL_CHILDREN(oid); 4290218792Snp 4291218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD, 4292218792Snp &pi->nrxq, 0, "# of rx queues"); 4293218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD, 4294218792Snp &pi->ntxq, 0, "# of tx queues"); 4295218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD, 4296218792Snp &pi->first_rxq, 0, "index of first rx queue"); 4297218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD, 4298218792Snp &pi->first_txq, 0, "index of first tx queue"); 4299218792Snp 4300237263Snp#ifdef TCP_OFFLOAD 4301228561Snp if (is_offload(pi->adapter)) { 4302228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldrxq", CTLFLAG_RD, 4303228561Snp &pi->nofldrxq, 0, 4304228561Snp "# of rx queues for offloaded TCP connections"); 4305228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldtxq", CTLFLAG_RD, 4306228561Snp &pi->nofldtxq, 0, 4307228561Snp "# of tx queues for offloaded TCP connections"); 4308228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_rxq", 4309228561Snp CTLFLAG_RD, &pi->first_ofld_rxq, 0, 4310228561Snp "index of first TOE rx queue"); 4311228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_txq", 4312228561Snp CTLFLAG_RD, &pi->first_ofld_txq, 0, 4313228561Snp "index of first TOE tx queue"); 4314228561Snp } 4315228561Snp#endif 4316228561Snp 4317218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx", 4318218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I", 4319218792Snp "holdoff timer index"); 4320218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx", 4321218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I", 4322218792Snp "holdoff packet counter index"); 4323218792Snp 4324218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq", 4325218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I", 4326218792Snp "rx queue size"); 4327218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq", 4328218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I", 4329218792Snp "tx queue size"); 4330218792Snp 4331218792Snp /* 4332218792Snp * dev.cxgbe.X.stats. 4333218792Snp */ 4334218792Snp oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, 4335218792Snp NULL, "port statistics"); 4336218792Snp children = SYSCTL_CHILDREN(oid); 4337218792Snp 4338218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \ 4339218792Snp SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \ 4340218792Snp CTLTYPE_U64 | CTLFLAG_RD, pi->adapter, reg, \ 4341218792Snp sysctl_handle_t4_reg64, "QU", desc) 4342218792Snp 4343218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames", 4344218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L)); 4345218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames", 4346218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L)); 4347218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames", 4348218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L)); 4349218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames", 4350218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L)); 4351218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames", 4352218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L)); 4353218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames", 4354218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L)); 4355218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_64", 4356218792Snp "# of tx frames in this range", 4357218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L)); 4358218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127", 4359218792Snp "# of tx frames in this range", 4360218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L)); 4361218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255", 4362218792Snp "# of tx frames in this range", 4363218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L)); 4364218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511", 4365218792Snp "# of tx frames in this range", 4366218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L)); 4367218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023", 4368218792Snp "# of tx frames in this range", 4369218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L)); 4370218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518", 4371218792Snp "# of tx frames in this range", 4372218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L)); 4373218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max", 4374218792Snp "# of tx frames in this range", 4375218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L)); 4376218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames", 4377218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L)); 4378218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted", 4379218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L)); 4380218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted", 4381218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L)); 4382218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted", 4383218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L)); 4384218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted", 4385218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L)); 4386218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted", 4387218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L)); 4388218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted", 4389218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L)); 4390218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted", 4391218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L)); 4392218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted", 4393218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L)); 4394218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted", 4395218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L)); 4396218792Snp 4397218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames", 4398218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L)); 4399218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames", 4400218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L)); 4401218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames", 4402218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L)); 4403218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames", 4404218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L)); 4405218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames", 4406218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L)); 4407218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU", 4408218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L)); 4409218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames", 4410218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L)); 4411218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err", 4412218792Snp "# of frames received with bad FCS", 4413218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L)); 4414218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_len_err", 4415218792Snp "# of frames received with length error", 4416218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L)); 4417218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors", 4418218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L)); 4419218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received", 4420218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L)); 4421218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_64", 4422218792Snp "# of rx frames in this range", 4423218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L)); 4424218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127", 4425218792Snp "# of rx frames in this range", 4426218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L)); 4427218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255", 4428218792Snp "# of rx frames in this range", 4429218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L)); 4430218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511", 4431218792Snp "# of rx frames in this range", 4432218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L)); 4433218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023", 4434218792Snp "# of rx frames in this range", 4435218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L)); 4436218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518", 4437218792Snp "# of rx frames in this range", 4438218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L)); 4439218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max", 4440218792Snp "# of rx frames in this range", 4441218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L)); 4442218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received", 4443218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L)); 4444218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received", 4445218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L)); 4446218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received", 4447218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L)); 4448218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received", 4449218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L)); 4450218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received", 4451218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L)); 4452218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received", 4453218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L)); 4454218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received", 4455218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L)); 4456218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received", 4457218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L)); 4458218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received", 4459218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L)); 4460218792Snp 4461218792Snp#undef SYSCTL_ADD_T4_REG64 4462218792Snp 4463218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \ 4464218792Snp SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \ 4465218792Snp &pi->stats.name, desc) 4466218792Snp 4467218792Snp /* We get these from port_stats and they may be stale by upto 1s */ 4468218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0, 4469218792Snp "# drops due to buffer-group 0 overflows"); 4470218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1, 4471218792Snp "# drops due to buffer-group 1 overflows"); 4472218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2, 4473218792Snp "# drops due to buffer-group 2 overflows"); 4474218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3, 4475218792Snp "# drops due to buffer-group 3 overflows"); 4476218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc0, 4477218792Snp "# of buffer-group 0 truncated packets"); 4478218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc1, 4479218792Snp "# of buffer-group 1 truncated packets"); 4480218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc2, 4481218792Snp "# of buffer-group 2 truncated packets"); 4482218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc3, 4483218792Snp "# of buffer-group 3 truncated packets"); 4484218792Snp 4485218792Snp#undef SYSCTL_ADD_T4_PORTSTAT 4486218792Snp 4487218792Snp return (0); 4488218792Snp} 4489218792Snp 4490218792Snpstatic int 4491219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS) 4492219436Snp{ 4493219436Snp int rc, *i; 4494219436Snp struct sbuf sb; 4495219436Snp 4496219436Snp sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); 4497219436Snp for (i = arg1; arg2; arg2 -= sizeof(int), i++) 4498219436Snp sbuf_printf(&sb, "%d ", *i); 4499219436Snp sbuf_trim(&sb); 4500219436Snp sbuf_finish(&sb); 4501219436Snp rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 4502219436Snp sbuf_delete(&sb); 4503219436Snp return (rc); 4504219436Snp} 4505219436Snp 4506219436Snpstatic int 4507228561Snpsysctl_bitfield(SYSCTL_HANDLER_ARGS) 4508228561Snp{ 4509228561Snp int rc; 4510228561Snp struct sbuf *sb; 4511228561Snp 4512228561Snp rc = sysctl_wire_old_buffer(req, 0); 4513228561Snp if (rc != 0) 4514228561Snp return(rc); 4515228561Snp 4516228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 4517228561Snp if (sb == NULL) 4518228561Snp return (ENOMEM); 4519228561Snp 4520228561Snp sbuf_printf(sb, "%b", (int)arg2, (char *)arg1); 4521228561Snp rc = sbuf_finish(sb); 4522228561Snp sbuf_delete(sb); 4523228561Snp 4524228561Snp return (rc); 4525228561Snp} 4526228561Snp 4527228561Snpstatic int 4528218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS) 4529218792Snp{ 4530218792Snp struct port_info *pi = arg1; 4531218792Snp struct adapter *sc = pi->adapter; 4532218792Snp int idx, rc, i; 4533245274Snp struct sge_rxq *rxq; 4534245274Snp uint8_t v; 4535218792Snp 4536218792Snp idx = pi->tmr_idx; 4537218792Snp 4538218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 4539218792Snp if (rc != 0 || req->newptr == NULL) 4540218792Snp return (rc); 4541218792Snp 4542218792Snp if (idx < 0 || idx >= SGE_NTIMERS) 4543218792Snp return (EINVAL); 4544218792Snp 4545245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4546245274Snp "t4tmr"); 4547245274Snp if (rc) 4548245274Snp return (rc); 4549228561Snp 4550245274Snp v = V_QINTR_TIMER_IDX(idx) | V_QINTR_CNT_EN(pi->pktc_idx != -1); 4551245274Snp for_each_rxq(pi, i, rxq) { 4552228561Snp#ifdef atomic_store_rel_8 4553245274Snp atomic_store_rel_8(&rxq->iq.intr_params, v); 4554228561Snp#else 4555245274Snp rxq->iq.intr_params = v; 4556228561Snp#endif 4557218792Snp } 4558245274Snp pi->tmr_idx = idx; 4559218792Snp 4560245274Snp end_synchronized_op(sc, LOCK_HELD); 4561245274Snp return (0); 4562218792Snp} 4563218792Snp 4564218792Snpstatic int 4565218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS) 4566218792Snp{ 4567218792Snp struct port_info *pi = arg1; 4568218792Snp struct adapter *sc = pi->adapter; 4569218792Snp int idx, rc; 4570218792Snp 4571218792Snp idx = pi->pktc_idx; 4572218792Snp 4573218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 4574218792Snp if (rc != 0 || req->newptr == NULL) 4575218792Snp return (rc); 4576218792Snp 4577218792Snp if (idx < -1 || idx >= SGE_NCOUNTERS) 4578218792Snp return (EINVAL); 4579218792Snp 4580245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4581245274Snp "t4pktc"); 4582245274Snp if (rc) 4583245274Snp return (rc); 4584245274Snp 4585245274Snp if (pi->flags & PORT_INIT_DONE) 4586228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 4587245274Snp else 4588218792Snp pi->pktc_idx = idx; 4589218792Snp 4590245274Snp end_synchronized_op(sc, LOCK_HELD); 4591218792Snp return (rc); 4592218792Snp} 4593218792Snp 4594218792Snpstatic int 4595218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS) 4596218792Snp{ 4597218792Snp struct port_info *pi = arg1; 4598218792Snp struct adapter *sc = pi->adapter; 4599218792Snp int qsize, rc; 4600218792Snp 4601218792Snp qsize = pi->qsize_rxq; 4602218792Snp 4603218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 4604218792Snp if (rc != 0 || req->newptr == NULL) 4605218792Snp return (rc); 4606218792Snp 4607218792Snp if (qsize < 128 || (qsize & 7)) 4608218792Snp return (EINVAL); 4609218792Snp 4610245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4611245274Snp "t4rxqs"); 4612245274Snp if (rc) 4613245274Snp return (rc); 4614245274Snp 4615245274Snp if (pi->flags & PORT_INIT_DONE) 4616228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 4617245274Snp else 4618218792Snp pi->qsize_rxq = qsize; 4619218792Snp 4620245274Snp end_synchronized_op(sc, LOCK_HELD); 4621218792Snp return (rc); 4622218792Snp} 4623218792Snp 4624218792Snpstatic int 4625218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS) 4626218792Snp{ 4627218792Snp struct port_info *pi = arg1; 4628218792Snp struct adapter *sc = pi->adapter; 4629218792Snp int qsize, rc; 4630218792Snp 4631218792Snp qsize = pi->qsize_txq; 4632218792Snp 4633218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 4634218792Snp if (rc != 0 || req->newptr == NULL) 4635218792Snp return (rc); 4636218792Snp 4637245274Snp /* bufring size must be powerof2 */ 4638245274Snp if (qsize < 128 || !powerof2(qsize)) 4639218792Snp return (EINVAL); 4640218792Snp 4641245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 4642245274Snp "t4txqs"); 4643245274Snp if (rc) 4644245274Snp return (rc); 4645245274Snp 4646245274Snp if (pi->flags & PORT_INIT_DONE) 4647228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 4648245274Snp else 4649218792Snp pi->qsize_txq = qsize; 4650218792Snp 4651245274Snp end_synchronized_op(sc, LOCK_HELD); 4652218792Snp return (rc); 4653218792Snp} 4654218792Snp 4655218792Snpstatic int 4656218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS) 4657218792Snp{ 4658218792Snp struct adapter *sc = arg1; 4659218792Snp int reg = arg2; 4660218792Snp uint64_t val; 4661218792Snp 4662218792Snp val = t4_read_reg64(sc, reg); 4663218792Snp 4664218792Snp return (sysctl_handle_64(oidp, &val, 0, req)); 4665218792Snp} 4666218792Snp 4667231115Snp#ifdef SBUF_DRAIN 4668228561Snpstatic int 4669228561Snpsysctl_cctrl(SYSCTL_HANDLER_ARGS) 4670228561Snp{ 4671228561Snp struct adapter *sc = arg1; 4672228561Snp struct sbuf *sb; 4673228561Snp int rc, i; 4674228561Snp uint16_t incr[NMTUS][NCCTRL_WIN]; 4675228561Snp static const char *dec_fac[] = { 4676228561Snp "0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875", 4677228561Snp "0.9375" 4678228561Snp }; 4679228561Snp 4680228561Snp rc = sysctl_wire_old_buffer(req, 0); 4681228561Snp if (rc != 0) 4682228561Snp return (rc); 4683228561Snp 4684228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 4685228561Snp if (sb == NULL) 4686228561Snp return (ENOMEM); 4687228561Snp 4688228561Snp t4_read_cong_tbl(sc, incr); 4689228561Snp 4690228561Snp for (i = 0; i < NCCTRL_WIN; ++i) { 4691228561Snp sbuf_printf(sb, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i, 4692228561Snp incr[0][i], incr[1][i], incr[2][i], incr[3][i], incr[4][i], 4693228561Snp incr[5][i], incr[6][i], incr[7][i]); 4694228561Snp sbuf_printf(sb, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n", 4695228561Snp incr[8][i], incr[9][i], incr[10][i], incr[11][i], 4696228561Snp incr[12][i], incr[13][i], incr[14][i], incr[15][i], 4697228561Snp sc->params.a_wnd[i], dec_fac[sc->params.b_wnd[i]]); 4698228561Snp } 4699228561Snp 4700228561Snp rc = sbuf_finish(sb); 4701228561Snp sbuf_delete(sb); 4702228561Snp 4703228561Snp return (rc); 4704228561Snp} 4705228561Snp 4706248925Snpstatic const char *qname[CIM_NUM_IBQ + CIM_NUM_OBQ_T5] = { 4707247122Snp "TP0", "TP1", "ULP", "SGE0", "SGE1", "NC-SI", /* ibq's */ 4708248925Snp "ULP0", "ULP1", "ULP2", "ULP3", "SGE", "NC-SI", /* obq's */ 4709248925Snp "SGE0-RX", "SGE1-RX" /* additional obq's (T5 onwards) */ 4710247122Snp}; 4711247122Snp 4712228561Snpstatic int 4713247122Snpsysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS) 4714247122Snp{ 4715247122Snp struct adapter *sc = arg1; 4716247122Snp struct sbuf *sb; 4717247122Snp int rc, i, n, qid = arg2; 4718247122Snp uint32_t *buf, *p; 4719247122Snp char *qtype; 4720248925Snp u_int cim_num_obq = is_t4(sc) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5; 4721247122Snp 4722248925Snp KASSERT(qid >= 0 && qid < CIM_NUM_IBQ + cim_num_obq, 4723247122Snp ("%s: bad qid %d\n", __func__, qid)); 4724247122Snp 4725247122Snp if (qid < CIM_NUM_IBQ) { 4726247122Snp /* inbound queue */ 4727247122Snp qtype = "IBQ"; 4728247122Snp n = 4 * CIM_IBQ_SIZE; 4729247122Snp buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); 4730247122Snp rc = t4_read_cim_ibq(sc, qid, buf, n); 4731247122Snp } else { 4732247122Snp /* outbound queue */ 4733247122Snp qtype = "OBQ"; 4734247122Snp qid -= CIM_NUM_IBQ; 4735248925Snp n = 4 * cim_num_obq * CIM_OBQ_SIZE; 4736247122Snp buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); 4737247122Snp rc = t4_read_cim_obq(sc, qid, buf, n); 4738247122Snp } 4739247122Snp 4740247122Snp if (rc < 0) { 4741247122Snp rc = -rc; 4742247122Snp goto done; 4743247122Snp } 4744247122Snp n = rc * sizeof(uint32_t); /* rc has # of words actually read */ 4745247122Snp 4746247122Snp rc = sysctl_wire_old_buffer(req, 0); 4747247122Snp if (rc != 0) 4748247122Snp goto done; 4749247122Snp 4750248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req); 4751247122Snp if (sb == NULL) { 4752247122Snp rc = ENOMEM; 4753247122Snp goto done; 4754247122Snp } 4755247122Snp 4756247122Snp sbuf_printf(sb, "%s%d %s", qtype , qid, qname[arg2]); 4757247122Snp for (i = 0, p = buf; i < n; i += 16, p += 4) 4758247122Snp sbuf_printf(sb, "\n%#06x: %08x %08x %08x %08x", i, p[0], p[1], 4759247122Snp p[2], p[3]); 4760247122Snp 4761247122Snp rc = sbuf_finish(sb); 4762247122Snp sbuf_delete(sb); 4763247122Snpdone: 4764247122Snp free(buf, M_CXGBE); 4765247122Snp return (rc); 4766247122Snp} 4767247122Snp 4768247122Snpstatic int 4769247122Snpsysctl_cim_la(SYSCTL_HANDLER_ARGS) 4770247122Snp{ 4771247122Snp struct adapter *sc = arg1; 4772247122Snp u_int cfg; 4773247122Snp struct sbuf *sb; 4774247122Snp uint32_t *buf, *p; 4775247122Snp int rc; 4776247122Snp 4777247122Snp rc = -t4_cim_read(sc, A_UP_UP_DBG_LA_CFG, 1, &cfg); 4778247122Snp if (rc != 0) 4779247122Snp return (rc); 4780247122Snp 4781247122Snp rc = sysctl_wire_old_buffer(req, 0); 4782247122Snp if (rc != 0) 4783247122Snp return (rc); 4784247122Snp 4785247122Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 4786247122Snp if (sb == NULL) 4787247122Snp return (ENOMEM); 4788247122Snp 4789247122Snp buf = malloc(sc->params.cim_la_size * sizeof(uint32_t), M_CXGBE, 4790247122Snp M_ZERO | M_WAITOK); 4791247122Snp 4792247122Snp rc = -t4_cim_read_la(sc, buf, NULL); 4793247122Snp if (rc != 0) 4794247122Snp goto done; 4795247122Snp 4796247122Snp sbuf_printf(sb, "Status Data PC%s", 4797247122Snp cfg & F_UPDBGLACAPTPCONLY ? "" : 4798247122Snp " LS0Stat LS0Addr LS0Data"); 4799247122Snp 4800247122Snp KASSERT((sc->params.cim_la_size & 7) == 0, 4801247122Snp ("%s: p will walk off the end of buf", __func__)); 4802247122Snp 4803247122Snp for (p = buf; p < &buf[sc->params.cim_la_size]; p += 8) { 4804247122Snp if (cfg & F_UPDBGLACAPTPCONLY) { 4805247122Snp sbuf_printf(sb, "\n %02x %08x %08x", p[5] & 0xff, 4806247122Snp p[6], p[7]); 4807247122Snp sbuf_printf(sb, "\n %02x %02x%06x %02x%06x", 4808247122Snp (p[3] >> 8) & 0xff, p[3] & 0xff, p[4] >> 8, 4809247122Snp p[4] & 0xff, p[5] >> 8); 4810247122Snp sbuf_printf(sb, "\n %02x %x%07x %x%07x", 4811247122Snp (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, 4812247122Snp p[1] & 0xf, p[2] >> 4); 4813247122Snp } else { 4814247122Snp sbuf_printf(sb, 4815247122Snp "\n %02x %x%07x %x%07x %08x %08x " 4816247122Snp "%08x%08x%08x%08x", 4817247122Snp (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, 4818247122Snp p[1] & 0xf, p[2] >> 4, p[2] & 0xf, p[3], p[4], p[5], 4819247122Snp p[6], p[7]); 4820247122Snp } 4821247122Snp } 4822247122Snp 4823247122Snp rc = sbuf_finish(sb); 4824247122Snp sbuf_delete(sb); 4825247122Snpdone: 4826247122Snp free(buf, M_CXGBE); 4827247122Snp return (rc); 4828247122Snp} 4829247122Snp 4830247122Snpstatic int 4831247122Snpsysctl_cim_qcfg(SYSCTL_HANDLER_ARGS) 4832247122Snp{ 4833247122Snp struct adapter *sc = arg1; 4834247122Snp struct sbuf *sb; 4835247122Snp int rc, i; 4836248925Snp uint16_t base[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; 4837248925Snp uint16_t size[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; 4838247122Snp uint16_t thres[CIM_NUM_IBQ]; 4839248925Snp uint32_t obq_wr[2 * CIM_NUM_OBQ_T5], *wr = obq_wr; 4840248925Snp uint32_t stat[4 * (CIM_NUM_IBQ + CIM_NUM_OBQ_T5)], *p = stat; 4841248925Snp u_int cim_num_obq, ibq_rdaddr, obq_rdaddr, nq; 4842247122Snp 4843248925Snp if (is_t4(sc)) { 4844248925Snp cim_num_obq = CIM_NUM_OBQ; 4845248925Snp ibq_rdaddr = A_UP_IBQ_0_RDADDR; 4846248925Snp obq_rdaddr = A_UP_OBQ_0_REALADDR; 4847248925Snp } else { 4848248925Snp cim_num_obq = CIM_NUM_OBQ_T5; 4849248925Snp ibq_rdaddr = A_UP_IBQ_0_SHADOW_RDADDR; 4850248925Snp obq_rdaddr = A_UP_OBQ_0_SHADOW_REALADDR; 4851248925Snp } 4852248925Snp nq = CIM_NUM_IBQ + cim_num_obq; 4853248925Snp 4854248925Snp rc = -t4_cim_read(sc, ibq_rdaddr, 4 * nq, stat); 4855247122Snp if (rc == 0) 4856248925Snp rc = -t4_cim_read(sc, obq_rdaddr, 2 * cim_num_obq, obq_wr); 4857247122Snp if (rc != 0) 4858247122Snp return (rc); 4859247122Snp 4860247122Snp t4_read_cimq_cfg(sc, base, size, thres); 4861247122Snp 4862247122Snp rc = sysctl_wire_old_buffer(req, 0); 4863247122Snp if (rc != 0) 4864247122Snp return (rc); 4865247122Snp 4866248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req); 4867247122Snp if (sb == NULL) 4868247122Snp return (ENOMEM); 4869247122Snp 4870247122Snp sbuf_printf(sb, "Queue Base Size Thres RdPtr WrPtr SOP EOP Avail"); 4871247122Snp 4872247122Snp for (i = 0; i < CIM_NUM_IBQ; i++, p += 4) 4873248925Snp sbuf_printf(sb, "\n%7s %5x %5u %5u %6x %4x %4u %4u %5u", 4874247122Snp qname[i], base[i], size[i], thres[i], G_IBQRDADDR(p[0]), 4875247122Snp G_IBQWRADDR(p[1]), G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), 4876247122Snp G_QUEREMFLITS(p[2]) * 16); 4877248925Snp for ( ; i < nq; i++, p += 4, wr += 2) 4878248925Snp sbuf_printf(sb, "\n%7s %5x %5u %12x %4x %4u %4u %5u", qname[i], 4879247122Snp base[i], size[i], G_QUERDADDR(p[0]) & 0x3fff, 4880247122Snp wr[0] - base[i], G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), 4881247122Snp G_QUEREMFLITS(p[2]) * 16); 4882247122Snp 4883247122Snp rc = sbuf_finish(sb); 4884247122Snp sbuf_delete(sb); 4885247122Snp 4886247122Snp return (rc); 4887247122Snp} 4888247122Snp 4889247122Snpstatic int 4890228561Snpsysctl_cpl_stats(SYSCTL_HANDLER_ARGS) 4891228561Snp{ 4892228561Snp struct adapter *sc = arg1; 4893228561Snp struct sbuf *sb; 4894228561Snp int rc; 4895228561Snp struct tp_cpl_stats stats; 4896228561Snp 4897228561Snp rc = sysctl_wire_old_buffer(req, 0); 4898228561Snp if (rc != 0) 4899228561Snp return (rc); 4900228561Snp 4901228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4902228561Snp if (sb == NULL) 4903228561Snp return (ENOMEM); 4904228561Snp 4905228561Snp t4_tp_get_cpl_stats(sc, &stats); 4906228561Snp 4907228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 4908228561Snp "channel 3\n"); 4909228561Snp sbuf_printf(sb, "CPL requests: %10u %10u %10u %10u\n", 4910228561Snp stats.req[0], stats.req[1], stats.req[2], stats.req[3]); 4911228561Snp sbuf_printf(sb, "CPL responses: %10u %10u %10u %10u", 4912228561Snp stats.rsp[0], stats.rsp[1], stats.rsp[2], stats.rsp[3]); 4913228561Snp 4914228561Snp rc = sbuf_finish(sb); 4915228561Snp sbuf_delete(sb); 4916228561Snp 4917228561Snp return (rc); 4918228561Snp} 4919228561Snp 4920228561Snpstatic int 4921228561Snpsysctl_ddp_stats(SYSCTL_HANDLER_ARGS) 4922228561Snp{ 4923228561Snp struct adapter *sc = arg1; 4924228561Snp struct sbuf *sb; 4925228561Snp int rc; 4926228561Snp struct tp_usm_stats stats; 4927228561Snp 4928228561Snp rc = sysctl_wire_old_buffer(req, 0); 4929228561Snp if (rc != 0) 4930228561Snp return(rc); 4931228561Snp 4932228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4933228561Snp if (sb == NULL) 4934228561Snp return (ENOMEM); 4935228561Snp 4936228561Snp t4_get_usm_stats(sc, &stats); 4937228561Snp 4938228561Snp sbuf_printf(sb, "Frames: %u\n", stats.frames); 4939228561Snp sbuf_printf(sb, "Octets: %ju\n", stats.octets); 4940228561Snp sbuf_printf(sb, "Drops: %u", stats.drops); 4941228561Snp 4942228561Snp rc = sbuf_finish(sb); 4943228561Snp sbuf_delete(sb); 4944228561Snp 4945228561Snp return (rc); 4946228561Snp} 4947228561Snp 4948222551Snpconst char *devlog_level_strings[] = { 4949222551Snp [FW_DEVLOG_LEVEL_EMERG] = "EMERG", 4950222551Snp [FW_DEVLOG_LEVEL_CRIT] = "CRIT", 4951222551Snp [FW_DEVLOG_LEVEL_ERR] = "ERR", 4952222551Snp [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", 4953222551Snp [FW_DEVLOG_LEVEL_INFO] = "INFO", 4954222551Snp [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" 4955222551Snp}; 4956222551Snp 4957222551Snpconst char *devlog_facility_strings[] = { 4958222551Snp [FW_DEVLOG_FACILITY_CORE] = "CORE", 4959222551Snp [FW_DEVLOG_FACILITY_SCHED] = "SCHED", 4960222551Snp [FW_DEVLOG_FACILITY_TIMER] = "TIMER", 4961222551Snp [FW_DEVLOG_FACILITY_RES] = "RES", 4962222551Snp [FW_DEVLOG_FACILITY_HW] = "HW", 4963222551Snp [FW_DEVLOG_FACILITY_FLR] = "FLR", 4964222551Snp [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", 4965222551Snp [FW_DEVLOG_FACILITY_PHY] = "PHY", 4966222551Snp [FW_DEVLOG_FACILITY_MAC] = "MAC", 4967222551Snp [FW_DEVLOG_FACILITY_PORT] = "PORT", 4968222551Snp [FW_DEVLOG_FACILITY_VI] = "VI", 4969222551Snp [FW_DEVLOG_FACILITY_FILTER] = "FILTER", 4970222551Snp [FW_DEVLOG_FACILITY_ACL] = "ACL", 4971222551Snp [FW_DEVLOG_FACILITY_TM] = "TM", 4972222551Snp [FW_DEVLOG_FACILITY_QFC] = "QFC", 4973222551Snp [FW_DEVLOG_FACILITY_DCB] = "DCB", 4974222551Snp [FW_DEVLOG_FACILITY_ETH] = "ETH", 4975222551Snp [FW_DEVLOG_FACILITY_OFLD] = "OFLD", 4976222551Snp [FW_DEVLOG_FACILITY_RI] = "RI", 4977222551Snp [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", 4978222551Snp [FW_DEVLOG_FACILITY_FCOE] = "FCOE", 4979222551Snp [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", 4980222551Snp [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE" 4981222551Snp}; 4982222551Snp 4983222551Snpstatic int 4984222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS) 4985222551Snp{ 4986222551Snp struct adapter *sc = arg1; 4987222551Snp struct devlog_params *dparams = &sc->params.devlog; 4988222551Snp struct fw_devlog_e *buf, *e; 4989222551Snp int i, j, rc, nentries, first = 0; 4990222551Snp struct sbuf *sb; 4991222551Snp uint64_t ftstamp = UINT64_MAX; 4992222551Snp 4993248925Snp if (dparams->start == 0) { 4994248925Snp dparams->memtype = 0; 4995248925Snp dparams->start = 0x84000; 4996248925Snp dparams->size = 32768; 4997248925Snp } 4998222551Snp 4999222551Snp nentries = dparams->size / sizeof(struct fw_devlog_e); 5000222551Snp 5001222551Snp buf = malloc(dparams->size, M_CXGBE, M_NOWAIT); 5002222551Snp if (buf == NULL) 5003222551Snp return (ENOMEM); 5004222551Snp 5005222551Snp rc = -t4_mem_read(sc, dparams->memtype, dparams->start, dparams->size, 5006222551Snp (void *)buf); 5007222551Snp if (rc != 0) 5008222551Snp goto done; 5009222551Snp 5010222551Snp for (i = 0; i < nentries; i++) { 5011222551Snp e = &buf[i]; 5012222551Snp 5013222551Snp if (e->timestamp == 0) 5014222551Snp break; /* end */ 5015222551Snp 5016222551Snp e->timestamp = be64toh(e->timestamp); 5017222551Snp e->seqno = be32toh(e->seqno); 5018222551Snp for (j = 0; j < 8; j++) 5019222551Snp e->params[j] = be32toh(e->params[j]); 5020222551Snp 5021222551Snp if (e->timestamp < ftstamp) { 5022222551Snp ftstamp = e->timestamp; 5023222551Snp first = i; 5024222551Snp } 5025222551Snp } 5026222551Snp 5027222551Snp if (buf[first].timestamp == 0) 5028222551Snp goto done; /* nothing in the log */ 5029222551Snp 5030222551Snp rc = sysctl_wire_old_buffer(req, 0); 5031222551Snp if (rc != 0) 5032222551Snp goto done; 5033222551Snp 5034222551Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5035228561Snp if (sb == NULL) { 5036228561Snp rc = ENOMEM; 5037228561Snp goto done; 5038228561Snp } 5039228561Snp sbuf_printf(sb, "%10s %15s %8s %8s %s\n", 5040222551Snp "Seq#", "Tstamp", "Level", "Facility", "Message"); 5041222551Snp 5042222551Snp i = first; 5043222551Snp do { 5044222551Snp e = &buf[i]; 5045222551Snp if (e->timestamp == 0) 5046222551Snp break; /* end */ 5047222551Snp 5048222551Snp sbuf_printf(sb, "%10d %15ju %8s %8s ", 5049222551Snp e->seqno, e->timestamp, 5050240452Snp (e->level < nitems(devlog_level_strings) ? 5051222551Snp devlog_level_strings[e->level] : "UNKNOWN"), 5052240452Snp (e->facility < nitems(devlog_facility_strings) ? 5053222551Snp devlog_facility_strings[e->facility] : "UNKNOWN")); 5054222551Snp sbuf_printf(sb, e->fmt, e->params[0], e->params[1], 5055222551Snp e->params[2], e->params[3], e->params[4], 5056222551Snp e->params[5], e->params[6], e->params[7]); 5057222551Snp 5058222551Snp if (++i == nentries) 5059222551Snp i = 0; 5060222551Snp } while (i != first); 5061222551Snp 5062222551Snp rc = sbuf_finish(sb); 5063222551Snp sbuf_delete(sb); 5064222551Snpdone: 5065222551Snp free(buf, M_CXGBE); 5066222551Snp return (rc); 5067222551Snp} 5068222551Snp 5069228561Snpstatic int 5070228561Snpsysctl_fcoe_stats(SYSCTL_HANDLER_ARGS) 5071228561Snp{ 5072228561Snp struct adapter *sc = arg1; 5073228561Snp struct sbuf *sb; 5074228561Snp int rc; 5075228561Snp struct tp_fcoe_stats stats[4]; 5076228561Snp 5077228561Snp rc = sysctl_wire_old_buffer(req, 0); 5078228561Snp if (rc != 0) 5079228561Snp return (rc); 5080228561Snp 5081228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5082228561Snp if (sb == NULL) 5083228561Snp return (ENOMEM); 5084228561Snp 5085228561Snp t4_get_fcoe_stats(sc, 0, &stats[0]); 5086228561Snp t4_get_fcoe_stats(sc, 1, &stats[1]); 5087228561Snp t4_get_fcoe_stats(sc, 2, &stats[2]); 5088228561Snp t4_get_fcoe_stats(sc, 3, &stats[3]); 5089228561Snp 5090228561Snp sbuf_printf(sb, " channel 0 channel 1 " 5091228561Snp "channel 2 channel 3\n"); 5092228561Snp sbuf_printf(sb, "octetsDDP: %16ju %16ju %16ju %16ju\n", 5093228561Snp stats[0].octetsDDP, stats[1].octetsDDP, stats[2].octetsDDP, 5094228561Snp stats[3].octetsDDP); 5095228561Snp sbuf_printf(sb, "framesDDP: %16u %16u %16u %16u\n", stats[0].framesDDP, 5096228561Snp stats[1].framesDDP, stats[2].framesDDP, stats[3].framesDDP); 5097228561Snp sbuf_printf(sb, "framesDrop: %16u %16u %16u %16u", 5098228561Snp stats[0].framesDrop, stats[1].framesDrop, stats[2].framesDrop, 5099228561Snp stats[3].framesDrop); 5100228561Snp 5101228561Snp rc = sbuf_finish(sb); 5102228561Snp sbuf_delete(sb); 5103228561Snp 5104228561Snp return (rc); 5105228561Snp} 5106228561Snp 5107228561Snpstatic int 5108228561Snpsysctl_hw_sched(SYSCTL_HANDLER_ARGS) 5109228561Snp{ 5110228561Snp struct adapter *sc = arg1; 5111228561Snp struct sbuf *sb; 5112228561Snp int rc, i; 5113228561Snp unsigned int map, kbps, ipg, mode; 5114228561Snp unsigned int pace_tab[NTX_SCHED]; 5115228561Snp 5116228561Snp rc = sysctl_wire_old_buffer(req, 0); 5117228561Snp if (rc != 0) 5118228561Snp return (rc); 5119228561Snp 5120228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5121228561Snp if (sb == NULL) 5122228561Snp return (ENOMEM); 5123228561Snp 5124228561Snp map = t4_read_reg(sc, A_TP_TX_MOD_QUEUE_REQ_MAP); 5125228561Snp mode = G_TIMERMODE(t4_read_reg(sc, A_TP_MOD_CONFIG)); 5126228561Snp t4_read_pace_tbl(sc, pace_tab); 5127228561Snp 5128228561Snp sbuf_printf(sb, "Scheduler Mode Channel Rate (Kbps) " 5129228561Snp "Class IPG (0.1 ns) Flow IPG (us)"); 5130228561Snp 5131228561Snp for (i = 0; i < NTX_SCHED; ++i, map >>= 2) { 5132228561Snp t4_get_tx_sched(sc, i, &kbps, &ipg); 5133228561Snp sbuf_printf(sb, "\n %u %-5s %u ", i, 5134228561Snp (mode & (1 << i)) ? "flow" : "class", map & 3); 5135228561Snp if (kbps) 5136228561Snp sbuf_printf(sb, "%9u ", kbps); 5137228561Snp else 5138228561Snp sbuf_printf(sb, " disabled "); 5139228561Snp 5140228561Snp if (ipg) 5141228561Snp sbuf_printf(sb, "%13u ", ipg); 5142228561Snp else 5143228561Snp sbuf_printf(sb, " disabled "); 5144228561Snp 5145228561Snp if (pace_tab[i]) 5146228561Snp sbuf_printf(sb, "%10u", pace_tab[i]); 5147228561Snp else 5148228561Snp sbuf_printf(sb, " disabled"); 5149228561Snp } 5150228561Snp 5151228561Snp rc = sbuf_finish(sb); 5152228561Snp sbuf_delete(sb); 5153228561Snp 5154228561Snp return (rc); 5155228561Snp} 5156228561Snp 5157228561Snpstatic int 5158228561Snpsysctl_lb_stats(SYSCTL_HANDLER_ARGS) 5159228561Snp{ 5160228561Snp struct adapter *sc = arg1; 5161228561Snp struct sbuf *sb; 5162228561Snp int rc, i, j; 5163228561Snp uint64_t *p0, *p1; 5164228561Snp struct lb_port_stats s[2]; 5165228561Snp static const char *stat_name[] = { 5166228561Snp "OctetsOK:", "FramesOK:", "BcastFrames:", "McastFrames:", 5167228561Snp "UcastFrames:", "ErrorFrames:", "Frames64:", "Frames65To127:", 5168228561Snp "Frames128To255:", "Frames256To511:", "Frames512To1023:", 5169228561Snp "Frames1024To1518:", "Frames1519ToMax:", "FramesDropped:", 5170228561Snp "BG0FramesDropped:", "BG1FramesDropped:", "BG2FramesDropped:", 5171228561Snp "BG3FramesDropped:", "BG0FramesTrunc:", "BG1FramesTrunc:", 5172228561Snp "BG2FramesTrunc:", "BG3FramesTrunc:" 5173228561Snp }; 5174228561Snp 5175228561Snp rc = sysctl_wire_old_buffer(req, 0); 5176228561Snp if (rc != 0) 5177228561Snp return (rc); 5178228561Snp 5179228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5180228561Snp if (sb == NULL) 5181228561Snp return (ENOMEM); 5182228561Snp 5183228561Snp memset(s, 0, sizeof(s)); 5184228561Snp 5185228561Snp for (i = 0; i < 4; i += 2) { 5186228561Snp t4_get_lb_stats(sc, i, &s[0]); 5187228561Snp t4_get_lb_stats(sc, i + 1, &s[1]); 5188228561Snp 5189228561Snp p0 = &s[0].octets; 5190228561Snp p1 = &s[1].octets; 5191228561Snp sbuf_printf(sb, "%s Loopback %u" 5192228561Snp " Loopback %u", i == 0 ? "" : "\n", i, i + 1); 5193228561Snp 5194240452Snp for (j = 0; j < nitems(stat_name); j++) 5195228561Snp sbuf_printf(sb, "\n%-17s %20ju %20ju", stat_name[j], 5196228561Snp *p0++, *p1++); 5197228561Snp } 5198228561Snp 5199228561Snp rc = sbuf_finish(sb); 5200228561Snp sbuf_delete(sb); 5201228561Snp 5202228561Snp return (rc); 5203228561Snp} 5204228561Snp 5205228561Snpstruct mem_desc { 5206228561Snp unsigned int base; 5207228561Snp unsigned int limit; 5208228561Snp unsigned int idx; 5209228561Snp}; 5210228561Snp 5211228561Snpstatic int 5212228561Snpmem_desc_cmp(const void *a, const void *b) 5213228561Snp{ 5214228561Snp return ((const struct mem_desc *)a)->base - 5215228561Snp ((const struct mem_desc *)b)->base; 5216228561Snp} 5217228561Snp 5218228561Snpstatic void 5219228561Snpmem_region_show(struct sbuf *sb, const char *name, unsigned int from, 5220228561Snp unsigned int to) 5221228561Snp{ 5222228561Snp unsigned int size; 5223228561Snp 5224228561Snp size = to - from + 1; 5225228561Snp if (size == 0) 5226228561Snp return; 5227228561Snp 5228228561Snp /* XXX: need humanize_number(3) in libkern for a more readable 'size' */ 5229228561Snp sbuf_printf(sb, "%-15s %#x-%#x [%u]\n", name, from, to, size); 5230228561Snp} 5231228561Snp 5232228561Snpstatic int 5233228561Snpsysctl_meminfo(SYSCTL_HANDLER_ARGS) 5234228561Snp{ 5235228561Snp struct adapter *sc = arg1; 5236228561Snp struct sbuf *sb; 5237228561Snp int rc, i, n; 5238248925Snp uint32_t lo, hi, used, alloc; 5239248925Snp static const char *memory[] = {"EDC0:", "EDC1:", "MC:", "MC0:", "MC1:"}; 5240228561Snp static const char *region[] = { 5241228561Snp "DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:", 5242228561Snp "Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:", 5243228561Snp "Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:", 5244228561Snp "TDDP region:", "TPT region:", "STAG region:", "RQ region:", 5245248925Snp "RQUDP region:", "PBL region:", "TXPBL region:", 5246248925Snp "DBVFIFO region:", "ULPRX state:", "ULPTX state:", 5247248925Snp "On-chip queues:" 5248228561Snp }; 5249248925Snp struct mem_desc avail[4]; 5250240452Snp struct mem_desc mem[nitems(region) + 3]; /* up to 3 holes */ 5251228561Snp struct mem_desc *md = mem; 5252228561Snp 5253228561Snp rc = sysctl_wire_old_buffer(req, 0); 5254228561Snp if (rc != 0) 5255228561Snp return (rc); 5256228561Snp 5257228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5258228561Snp if (sb == NULL) 5259228561Snp return (ENOMEM); 5260228561Snp 5261240452Snp for (i = 0; i < nitems(mem); i++) { 5262228561Snp mem[i].limit = 0; 5263228561Snp mem[i].idx = i; 5264228561Snp } 5265228561Snp 5266228561Snp /* Find and sort the populated memory ranges */ 5267228561Snp i = 0; 5268228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 5269228561Snp if (lo & F_EDRAM0_ENABLE) { 5270228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 5271228561Snp avail[i].base = G_EDRAM0_BASE(hi) << 20; 5272228561Snp avail[i].limit = avail[i].base + (G_EDRAM0_SIZE(hi) << 20); 5273228561Snp avail[i].idx = 0; 5274228561Snp i++; 5275228561Snp } 5276228561Snp if (lo & F_EDRAM1_ENABLE) { 5277228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 5278228561Snp avail[i].base = G_EDRAM1_BASE(hi) << 20; 5279228561Snp avail[i].limit = avail[i].base + (G_EDRAM1_SIZE(hi) << 20); 5280228561Snp avail[i].idx = 1; 5281228561Snp i++; 5282228561Snp } 5283228561Snp if (lo & F_EXT_MEM_ENABLE) { 5284228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 5285228561Snp avail[i].base = G_EXT_MEM_BASE(hi) << 20; 5286248925Snp avail[i].limit = avail[i].base + 5287248925Snp (G_EXT_MEM_SIZE(hi) << 20); 5288248925Snp avail[i].idx = is_t4(sc) ? 2 : 3; /* Call it MC for T4 */ 5289228561Snp i++; 5290228561Snp } 5291248925Snp if (!is_t4(sc) && lo & F_EXT_MEM1_ENABLE) { 5292248925Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 5293248925Snp avail[i].base = G_EXT_MEM1_BASE(hi) << 20; 5294248925Snp avail[i].limit = avail[i].base + 5295248925Snp (G_EXT_MEM1_SIZE(hi) << 20); 5296248925Snp avail[i].idx = 4; 5297248925Snp i++; 5298248925Snp } 5299228561Snp if (!i) /* no memory available */ 5300228561Snp return 0; 5301228561Snp qsort(avail, i, sizeof(struct mem_desc), mem_desc_cmp); 5302228561Snp 5303228561Snp (md++)->base = t4_read_reg(sc, A_SGE_DBQ_CTXT_BADDR); 5304228561Snp (md++)->base = t4_read_reg(sc, A_SGE_IMSG_CTXT_BADDR); 5305228561Snp (md++)->base = t4_read_reg(sc, A_SGE_FLM_CACHE_BADDR); 5306228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 5307228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_BASE); 5308228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TIMER_BASE); 5309228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_RX_FLST_BASE); 5310228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_TX_FLST_BASE); 5311228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_PS_FLST_BASE); 5312228561Snp 5313228561Snp /* the next few have explicit upper bounds */ 5314228561Snp md->base = t4_read_reg(sc, A_TP_PMM_TX_BASE); 5315228561Snp md->limit = md->base - 1 + 5316228561Snp t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE) * 5317228561Snp G_PMTXMAXPAGE(t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE)); 5318228561Snp md++; 5319228561Snp 5320228561Snp md->base = t4_read_reg(sc, A_TP_PMM_RX_BASE); 5321228561Snp md->limit = md->base - 1 + 5322228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) * 5323228561Snp G_PMRXMAXPAGE(t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE)); 5324228561Snp md++; 5325228561Snp 5326228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 5327228561Snp hi = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4; 5328228561Snp md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE); 5329228561Snp md->limit = (sc->tids.ntids - hi) * 16 + md->base - 1; 5330228561Snp } else { 5331228561Snp md->base = 0; 5332240452Snp md->idx = nitems(region); /* hide it */ 5333228561Snp } 5334228561Snp md++; 5335228561Snp 5336228561Snp#define ulp_region(reg) \ 5337228561Snp md->base = t4_read_reg(sc, A_ULP_ ## reg ## _LLIMIT);\ 5338228561Snp (md++)->limit = t4_read_reg(sc, A_ULP_ ## reg ## _ULIMIT) 5339228561Snp 5340228561Snp ulp_region(RX_ISCSI); 5341228561Snp ulp_region(RX_TDDP); 5342228561Snp ulp_region(TX_TPT); 5343228561Snp ulp_region(RX_STAG); 5344228561Snp ulp_region(RX_RQ); 5345228561Snp ulp_region(RX_RQUDP); 5346228561Snp ulp_region(RX_PBL); 5347228561Snp ulp_region(TX_PBL); 5348228561Snp#undef ulp_region 5349228561Snp 5350248925Snp md->base = 0; 5351248925Snp md->idx = nitems(region); 5352248925Snp if (!is_t4(sc) && t4_read_reg(sc, A_SGE_CONTROL2) & F_VFIFO_ENABLE) { 5353248925Snp md->base = G_BASEADDR(t4_read_reg(sc, A_SGE_DBVFIFO_BADDR)); 5354248925Snp md->limit = md->base + (G_DBVFIFO_SIZE((t4_read_reg(sc, 5355248925Snp A_SGE_DBVFIFO_SIZE))) << 2) - 1; 5356248925Snp } 5357248925Snp md++; 5358248925Snp 5359228561Snp md->base = t4_read_reg(sc, A_ULP_RX_CTX_BASE); 5360228561Snp md->limit = md->base + sc->tids.ntids - 1; 5361228561Snp md++; 5362228561Snp md->base = t4_read_reg(sc, A_ULP_TX_ERR_TABLE_BASE); 5363228561Snp md->limit = md->base + sc->tids.ntids - 1; 5364228561Snp md++; 5365228561Snp 5366228561Snp md->base = sc->vres.ocq.start; 5367228561Snp if (sc->vres.ocq.size) 5368228561Snp md->limit = md->base + sc->vres.ocq.size - 1; 5369228561Snp else 5370240452Snp md->idx = nitems(region); /* hide it */ 5371228561Snp md++; 5372228561Snp 5373228561Snp /* add any address-space holes, there can be up to 3 */ 5374228561Snp for (n = 0; n < i - 1; n++) 5375228561Snp if (avail[n].limit < avail[n + 1].base) 5376228561Snp (md++)->base = avail[n].limit; 5377228561Snp if (avail[n].limit) 5378228561Snp (md++)->base = avail[n].limit; 5379228561Snp 5380228561Snp n = md - mem; 5381228561Snp qsort(mem, n, sizeof(struct mem_desc), mem_desc_cmp); 5382228561Snp 5383228561Snp for (lo = 0; lo < i; lo++) 5384228561Snp mem_region_show(sb, memory[avail[lo].idx], avail[lo].base, 5385228561Snp avail[lo].limit - 1); 5386228561Snp 5387228561Snp sbuf_printf(sb, "\n"); 5388228561Snp for (i = 0; i < n; i++) { 5389240452Snp if (mem[i].idx >= nitems(region)) 5390228561Snp continue; /* skip holes */ 5391228561Snp if (!mem[i].limit) 5392228561Snp mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0; 5393228561Snp mem_region_show(sb, region[mem[i].idx], mem[i].base, 5394228561Snp mem[i].limit); 5395228561Snp } 5396228561Snp 5397228561Snp sbuf_printf(sb, "\n"); 5398228561Snp lo = t4_read_reg(sc, A_CIM_SDRAM_BASE_ADDR); 5399228561Snp hi = t4_read_reg(sc, A_CIM_SDRAM_ADDR_SIZE) + lo - 1; 5400228561Snp mem_region_show(sb, "uP RAM:", lo, hi); 5401228561Snp 5402228561Snp lo = t4_read_reg(sc, A_CIM_EXTMEM2_BASE_ADDR); 5403228561Snp hi = t4_read_reg(sc, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1; 5404228561Snp mem_region_show(sb, "uP Extmem2:", lo, hi); 5405228561Snp 5406228561Snp lo = t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE); 5407228561Snp sbuf_printf(sb, "\n%u Rx pages of size %uKiB for %u channels\n", 5408228561Snp G_PMRXMAXPAGE(lo), 5409228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) >> 10, 5410228561Snp (lo & F_PMRXNUMCHN) ? 2 : 1); 5411228561Snp 5412228561Snp lo = t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE); 5413228561Snp hi = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE); 5414228561Snp sbuf_printf(sb, "%u Tx pages of size %u%ciB for %u channels\n", 5415228561Snp G_PMTXMAXPAGE(lo), 5416228561Snp hi >= (1 << 20) ? (hi >> 20) : (hi >> 10), 5417228561Snp hi >= (1 << 20) ? 'M' : 'K', 1 << G_PMTXNUMCHN(lo)); 5418228561Snp sbuf_printf(sb, "%u p-structs\n", 5419228561Snp t4_read_reg(sc, A_TP_CMM_MM_MAX_PSTRUCT)); 5420228561Snp 5421228561Snp for (i = 0; i < 4; i++) { 5422228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV0 + i * 4); 5423248925Snp if (is_t4(sc)) { 5424248925Snp used = G_USED(lo); 5425248925Snp alloc = G_ALLOC(lo); 5426248925Snp } else { 5427248925Snp used = G_T5_USED(lo); 5428248925Snp alloc = G_T5_ALLOC(lo); 5429248925Snp } 5430228561Snp sbuf_printf(sb, "\nPort %d using %u pages out of %u allocated", 5431248925Snp i, used, alloc); 5432228561Snp } 5433228561Snp for (i = 0; i < 4; i++) { 5434228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV4 + i * 4); 5435248925Snp if (is_t4(sc)) { 5436248925Snp used = G_USED(lo); 5437248925Snp alloc = G_ALLOC(lo); 5438248925Snp } else { 5439248925Snp used = G_T5_USED(lo); 5440248925Snp alloc = G_T5_ALLOC(lo); 5441248925Snp } 5442228561Snp sbuf_printf(sb, 5443228561Snp "\nLoopback %d using %u pages out of %u allocated", 5444248925Snp i, used, alloc); 5445228561Snp } 5446228561Snp 5447228561Snp rc = sbuf_finish(sb); 5448228561Snp sbuf_delete(sb); 5449228561Snp 5450228561Snp return (rc); 5451228561Snp} 5452228561Snp 5453228561Snpstatic int 5454228561Snpsysctl_path_mtus(SYSCTL_HANDLER_ARGS) 5455228561Snp{ 5456228561Snp struct adapter *sc = arg1; 5457228561Snp struct sbuf *sb; 5458228561Snp int rc; 5459228561Snp uint16_t mtus[NMTUS]; 5460228561Snp 5461228561Snp rc = sysctl_wire_old_buffer(req, 0); 5462228561Snp if (rc != 0) 5463228561Snp return (rc); 5464228561Snp 5465228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5466228561Snp if (sb == NULL) 5467228561Snp return (ENOMEM); 5468228561Snp 5469228561Snp t4_read_mtu_tbl(sc, mtus, NULL); 5470228561Snp 5471228561Snp sbuf_printf(sb, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", 5472228561Snp mtus[0], mtus[1], mtus[2], mtus[3], mtus[4], mtus[5], mtus[6], 5473228561Snp mtus[7], mtus[8], mtus[9], mtus[10], mtus[11], mtus[12], mtus[13], 5474228561Snp mtus[14], mtus[15]); 5475228561Snp 5476228561Snp rc = sbuf_finish(sb); 5477228561Snp sbuf_delete(sb); 5478228561Snp 5479228561Snp return (rc); 5480228561Snp} 5481228561Snp 5482228561Snpstatic int 5483228561Snpsysctl_pm_stats(SYSCTL_HANDLER_ARGS) 5484228561Snp{ 5485228561Snp struct adapter *sc = arg1; 5486228561Snp struct sbuf *sb; 5487228561Snp int rc, i; 5488228561Snp uint32_t tx_cnt[PM_NSTATS], rx_cnt[PM_NSTATS]; 5489228561Snp uint64_t tx_cyc[PM_NSTATS], rx_cyc[PM_NSTATS]; 5490228561Snp static const char *pm_stats[] = { 5491228561Snp "Read:", "Write bypass:", "Write mem:", "Flush:", "FIFO wait:" 5492228561Snp }; 5493228561Snp 5494228561Snp rc = sysctl_wire_old_buffer(req, 0); 5495228561Snp if (rc != 0) 5496228561Snp return (rc); 5497228561Snp 5498228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5499228561Snp if (sb == NULL) 5500228561Snp return (ENOMEM); 5501228561Snp 5502228561Snp t4_pmtx_get_stats(sc, tx_cnt, tx_cyc); 5503228561Snp t4_pmrx_get_stats(sc, rx_cnt, rx_cyc); 5504228561Snp 5505228561Snp sbuf_printf(sb, " Tx count Tx cycles " 5506228561Snp "Rx count Rx cycles"); 5507228561Snp for (i = 0; i < PM_NSTATS; i++) 5508228561Snp sbuf_printf(sb, "\n%-13s %10u %20ju %10u %20ju", 5509228561Snp pm_stats[i], tx_cnt[i], tx_cyc[i], rx_cnt[i], rx_cyc[i]); 5510228561Snp 5511228561Snp rc = sbuf_finish(sb); 5512228561Snp sbuf_delete(sb); 5513228561Snp 5514228561Snp return (rc); 5515228561Snp} 5516228561Snp 5517228561Snpstatic int 5518228561Snpsysctl_rdma_stats(SYSCTL_HANDLER_ARGS) 5519228561Snp{ 5520228561Snp struct adapter *sc = arg1; 5521228561Snp struct sbuf *sb; 5522228561Snp int rc; 5523228561Snp struct tp_rdma_stats stats; 5524228561Snp 5525228561Snp rc = sysctl_wire_old_buffer(req, 0); 5526228561Snp if (rc != 0) 5527228561Snp return (rc); 5528228561Snp 5529228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5530228561Snp if (sb == NULL) 5531228561Snp return (ENOMEM); 5532228561Snp 5533228561Snp t4_tp_get_rdma_stats(sc, &stats); 5534228561Snp sbuf_printf(sb, "NoRQEModDefferals: %u\n", stats.rqe_dfr_mod); 5535228561Snp sbuf_printf(sb, "NoRQEPktDefferals: %u", stats.rqe_dfr_pkt); 5536228561Snp 5537228561Snp rc = sbuf_finish(sb); 5538228561Snp sbuf_delete(sb); 5539228561Snp 5540228561Snp return (rc); 5541228561Snp} 5542228561Snp 5543228561Snpstatic int 5544228561Snpsysctl_tcp_stats(SYSCTL_HANDLER_ARGS) 5545228561Snp{ 5546228561Snp struct adapter *sc = arg1; 5547228561Snp struct sbuf *sb; 5548228561Snp int rc; 5549228561Snp struct tp_tcp_stats v4, v6; 5550228561Snp 5551228561Snp rc = sysctl_wire_old_buffer(req, 0); 5552228561Snp if (rc != 0) 5553228561Snp return (rc); 5554228561Snp 5555228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5556228561Snp if (sb == NULL) 5557228561Snp return (ENOMEM); 5558228561Snp 5559228561Snp t4_tp_get_tcp_stats(sc, &v4, &v6); 5560228561Snp sbuf_printf(sb, 5561228561Snp " IP IPv6\n"); 5562228561Snp sbuf_printf(sb, "OutRsts: %20u %20u\n", 5563228561Snp v4.tcpOutRsts, v6.tcpOutRsts); 5564228561Snp sbuf_printf(sb, "InSegs: %20ju %20ju\n", 5565228561Snp v4.tcpInSegs, v6.tcpInSegs); 5566228561Snp sbuf_printf(sb, "OutSegs: %20ju %20ju\n", 5567228561Snp v4.tcpOutSegs, v6.tcpOutSegs); 5568228561Snp sbuf_printf(sb, "RetransSegs: %20ju %20ju", 5569228561Snp v4.tcpRetransSegs, v6.tcpRetransSegs); 5570228561Snp 5571228561Snp rc = sbuf_finish(sb); 5572228561Snp sbuf_delete(sb); 5573228561Snp 5574228561Snp return (rc); 5575228561Snp} 5576228561Snp 5577228561Snpstatic int 5578228561Snpsysctl_tids(SYSCTL_HANDLER_ARGS) 5579228561Snp{ 5580228561Snp struct adapter *sc = arg1; 5581228561Snp struct sbuf *sb; 5582228561Snp int rc; 5583228561Snp struct tid_info *t = &sc->tids; 5584228561Snp 5585228561Snp rc = sysctl_wire_old_buffer(req, 0); 5586228561Snp if (rc != 0) 5587228561Snp return (rc); 5588228561Snp 5589228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5590228561Snp if (sb == NULL) 5591228561Snp return (ENOMEM); 5592228561Snp 5593228561Snp if (t->natids) { 5594228561Snp sbuf_printf(sb, "ATID range: 0-%u, in use: %u\n", t->natids - 1, 5595228561Snp t->atids_in_use); 5596228561Snp } 5597228561Snp 5598228561Snp if (t->ntids) { 5599228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 5600228561Snp uint32_t b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4; 5601228561Snp 5602228561Snp if (b) { 5603228561Snp sbuf_printf(sb, "TID range: 0-%u, %u-%u", b - 1, 5604228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 5605228561Snp t->ntids - 1); 5606228561Snp } else { 5607228561Snp sbuf_printf(sb, "TID range: %u-%u", 5608228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 5609228561Snp t->ntids - 1); 5610228561Snp } 5611228561Snp } else 5612228561Snp sbuf_printf(sb, "TID range: 0-%u", t->ntids - 1); 5613228561Snp sbuf_printf(sb, ", in use: %u\n", 5614228561Snp atomic_load_acq_int(&t->tids_in_use)); 5615228561Snp } 5616228561Snp 5617228561Snp if (t->nstids) { 5618228561Snp sbuf_printf(sb, "STID range: %u-%u, in use: %u\n", t->stid_base, 5619228561Snp t->stid_base + t->nstids - 1, t->stids_in_use); 5620228561Snp } 5621228561Snp 5622228561Snp if (t->nftids) { 5623228561Snp sbuf_printf(sb, "FTID range: %u-%u\n", t->ftid_base, 5624228561Snp t->ftid_base + t->nftids - 1); 5625228561Snp } 5626228561Snp 5627228561Snp sbuf_printf(sb, "HW TID usage: %u IP users, %u IPv6 users", 5628228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV4), 5629228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV6)); 5630228561Snp 5631228561Snp rc = sbuf_finish(sb); 5632228561Snp sbuf_delete(sb); 5633228561Snp 5634228561Snp return (rc); 5635228561Snp} 5636228561Snp 5637228561Snpstatic int 5638228561Snpsysctl_tp_err_stats(SYSCTL_HANDLER_ARGS) 5639228561Snp{ 5640228561Snp struct adapter *sc = arg1; 5641228561Snp struct sbuf *sb; 5642228561Snp int rc; 5643228561Snp struct tp_err_stats stats; 5644228561Snp 5645228561Snp rc = sysctl_wire_old_buffer(req, 0); 5646228561Snp if (rc != 0) 5647228561Snp return (rc); 5648228561Snp 5649228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5650228561Snp if (sb == NULL) 5651228561Snp return (ENOMEM); 5652228561Snp 5653228561Snp t4_tp_get_err_stats(sc, &stats); 5654228561Snp 5655228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 5656228561Snp "channel 3\n"); 5657228561Snp sbuf_printf(sb, "macInErrs: %10u %10u %10u %10u\n", 5658228561Snp stats.macInErrs[0], stats.macInErrs[1], stats.macInErrs[2], 5659228561Snp stats.macInErrs[3]); 5660228561Snp sbuf_printf(sb, "hdrInErrs: %10u %10u %10u %10u\n", 5661228561Snp stats.hdrInErrs[0], stats.hdrInErrs[1], stats.hdrInErrs[2], 5662228561Snp stats.hdrInErrs[3]); 5663228561Snp sbuf_printf(sb, "tcpInErrs: %10u %10u %10u %10u\n", 5664228561Snp stats.tcpInErrs[0], stats.tcpInErrs[1], stats.tcpInErrs[2], 5665228561Snp stats.tcpInErrs[3]); 5666228561Snp sbuf_printf(sb, "tcp6InErrs: %10u %10u %10u %10u\n", 5667228561Snp stats.tcp6InErrs[0], stats.tcp6InErrs[1], stats.tcp6InErrs[2], 5668228561Snp stats.tcp6InErrs[3]); 5669228561Snp sbuf_printf(sb, "tnlCongDrops: %10u %10u %10u %10u\n", 5670228561Snp stats.tnlCongDrops[0], stats.tnlCongDrops[1], stats.tnlCongDrops[2], 5671228561Snp stats.tnlCongDrops[3]); 5672228561Snp sbuf_printf(sb, "tnlTxDrops: %10u %10u %10u %10u\n", 5673228561Snp stats.tnlTxDrops[0], stats.tnlTxDrops[1], stats.tnlTxDrops[2], 5674228561Snp stats.tnlTxDrops[3]); 5675228561Snp sbuf_printf(sb, "ofldVlanDrops: %10u %10u %10u %10u\n", 5676228561Snp stats.ofldVlanDrops[0], stats.ofldVlanDrops[1], 5677228561Snp stats.ofldVlanDrops[2], stats.ofldVlanDrops[3]); 5678228561Snp sbuf_printf(sb, "ofldChanDrops: %10u %10u %10u %10u\n\n", 5679228561Snp stats.ofldChanDrops[0], stats.ofldChanDrops[1], 5680228561Snp stats.ofldChanDrops[2], stats.ofldChanDrops[3]); 5681228561Snp sbuf_printf(sb, "ofldNoNeigh: %u\nofldCongDefer: %u", 5682228561Snp stats.ofldNoNeigh, stats.ofldCongDefer); 5683228561Snp 5684228561Snp rc = sbuf_finish(sb); 5685228561Snp sbuf_delete(sb); 5686228561Snp 5687228561Snp return (rc); 5688228561Snp} 5689228561Snp 5690228561Snpstatic int 5691228561Snpsysctl_tx_rate(SYSCTL_HANDLER_ARGS) 5692228561Snp{ 5693228561Snp struct adapter *sc = arg1; 5694228561Snp struct sbuf *sb; 5695228561Snp int rc; 5696228561Snp u64 nrate[NCHAN], orate[NCHAN]; 5697228561Snp 5698228561Snp rc = sysctl_wire_old_buffer(req, 0); 5699228561Snp if (rc != 0) 5700228561Snp return (rc); 5701228561Snp 5702228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5703228561Snp if (sb == NULL) 5704228561Snp return (ENOMEM); 5705228561Snp 5706228561Snp t4_get_chan_txrate(sc, nrate, orate); 5707228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 5708228561Snp "channel 3\n"); 5709228561Snp sbuf_printf(sb, "NIC B/s: %10ju %10ju %10ju %10ju\n", 5710228561Snp nrate[0], nrate[1], nrate[2], nrate[3]); 5711228561Snp sbuf_printf(sb, "Offload B/s: %10ju %10ju %10ju %10ju", 5712228561Snp orate[0], orate[1], orate[2], orate[3]); 5713228561Snp 5714228561Snp rc = sbuf_finish(sb); 5715228561Snp sbuf_delete(sb); 5716228561Snp 5717228561Snp return (rc); 5718228561Snp} 5719248925Snp 5720248925Snpstatic int 5721248925Snpsysctl_wrwc_stats(SYSCTL_HANDLER_ARGS) 5722248925Snp{ 5723248925Snp struct adapter *sc = arg1; 5724248925Snp struct sbuf *sb; 5725248925Snp int rc, v; 5726248925Snp 5727248925Snp rc = sysctl_wire_old_buffer(req, 0); 5728248925Snp if (rc != 0) 5729248925Snp return (rc); 5730248925Snp 5731248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5732248925Snp if (sb == NULL) 5733248925Snp return (ENOMEM); 5734248925Snp 5735248925Snp v = t4_read_reg(sc, A_SGE_STAT_CFG); 5736248925Snp if (G_STATSOURCE_T5(v) == 7) { 5737248925Snp if (G_STATMODE(v) == 0) { 5738248925Snp sbuf_printf(sb, "\ntotal %d, incomplete %d", 5739248925Snp t4_read_reg(sc, A_SGE_STAT_TOTAL), 5740248925Snp t4_read_reg(sc, A_SGE_STAT_MATCH)); 5741248925Snp } else if (G_STATMODE(v) == 1) { 5742248925Snp sbuf_printf(sb, "\ntotal %d, data overflow %d", 5743248925Snp t4_read_reg(sc, A_SGE_STAT_TOTAL), 5744248925Snp t4_read_reg(sc, A_SGE_STAT_MATCH)); 5745248925Snp } 5746248925Snp } 5747248925Snp rc = sbuf_finish(sb); 5748248925Snp sbuf_delete(sb); 5749248925Snp 5750248925Snp return (rc); 5751248925Snp} 5752231115Snp#endif 5753228561Snp 5754219286Snpstatic inline void 5755219286Snptxq_start(struct ifnet *ifp, struct sge_txq *txq) 5756219286Snp{ 5757219286Snp struct buf_ring *br; 5758219286Snp struct mbuf *m; 5759219286Snp 5760219286Snp TXQ_LOCK_ASSERT_OWNED(txq); 5761219286Snp 5762220873Snp br = txq->br; 5763219286Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 5764219286Snp if (m) 5765219286Snp t4_eth_tx(ifp, txq, m); 5766219286Snp} 5767219286Snp 5768219286Snpvoid 5769228561Snpt4_tx_callout(void *arg) 5770219286Snp{ 5771228561Snp struct sge_eq *eq = arg; 5772228561Snp struct adapter *sc; 5773219286Snp 5774228561Snp if (EQ_TRYLOCK(eq) == 0) 5775228561Snp goto reschedule; 5776228561Snp 5777228561Snp if (eq->flags & EQ_STALLED && !can_resume_tx(eq)) { 5778228561Snp EQ_UNLOCK(eq); 5779228561Snpreschedule: 5780228561Snp if (__predict_true(!(eq->flags && EQ_DOOMED))) 5781228561Snp callout_schedule(&eq->tx_callout, 1); 5782228561Snp return; 5783228561Snp } 5784228561Snp 5785228561Snp EQ_LOCK_ASSERT_OWNED(eq); 5786228561Snp 5787228561Snp if (__predict_true((eq->flags & EQ_DOOMED) == 0)) { 5788228561Snp 5789228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 5790228561Snp struct sge_txq *txq = arg; 5791228561Snp struct port_info *pi = txq->ifp->if_softc; 5792228561Snp 5793228561Snp sc = pi->adapter; 5794228561Snp } else { 5795228561Snp struct sge_wrq *wrq = arg; 5796228561Snp 5797228561Snp sc = wrq->adapter; 5798228561Snp } 5799228561Snp 5800228561Snp taskqueue_enqueue(sc->tq[eq->tx_chan], &eq->tx_task); 5801228561Snp } 5802228561Snp 5803228561Snp EQ_UNLOCK(eq); 5804228561Snp} 5805228561Snp 5806228561Snpvoid 5807228561Snpt4_tx_task(void *arg, int count) 5808228561Snp{ 5809228561Snp struct sge_eq *eq = arg; 5810228561Snp 5811228561Snp EQ_LOCK(eq); 5812228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 5813228561Snp struct sge_txq *txq = arg; 5814220649Snp txq_start(txq->ifp, txq); 5815228561Snp } else { 5816228561Snp struct sge_wrq *wrq = arg; 5817228561Snp t4_wrq_tx_locked(wrq->adapter, wrq, NULL); 5818228561Snp } 5819228561Snp EQ_UNLOCK(eq); 5820219286Snp} 5821219286Snp 5822221474Snpstatic uint32_t 5823221474Snpfconf_to_mode(uint32_t fconf) 5824221474Snp{ 5825221474Snp uint32_t mode; 5826221474Snp 5827221474Snp mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR | 5828221474Snp T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT; 5829221474Snp 5830221474Snp if (fconf & F_FRAGMENTATION) 5831221474Snp mode |= T4_FILTER_IP_FRAGMENT; 5832221474Snp 5833221474Snp if (fconf & F_MPSHITTYPE) 5834221474Snp mode |= T4_FILTER_MPS_HIT_TYPE; 5835221474Snp 5836221474Snp if (fconf & F_MACMATCH) 5837221474Snp mode |= T4_FILTER_MAC_IDX; 5838221474Snp 5839221474Snp if (fconf & F_ETHERTYPE) 5840221474Snp mode |= T4_FILTER_ETH_TYPE; 5841221474Snp 5842221474Snp if (fconf & F_PROTOCOL) 5843221474Snp mode |= T4_FILTER_IP_PROTO; 5844221474Snp 5845221474Snp if (fconf & F_TOS) 5846221474Snp mode |= T4_FILTER_IP_TOS; 5847221474Snp 5848221474Snp if (fconf & F_VLAN) 5849228561Snp mode |= T4_FILTER_VLAN; 5850221474Snp 5851221474Snp if (fconf & F_VNIC_ID) 5852228561Snp mode |= T4_FILTER_VNIC; 5853221474Snp 5854221474Snp if (fconf & F_PORT) 5855221474Snp mode |= T4_FILTER_PORT; 5856221474Snp 5857221474Snp if (fconf & F_FCOE) 5858221474Snp mode |= T4_FILTER_FCoE; 5859221474Snp 5860221474Snp return (mode); 5861221474Snp} 5862221474Snp 5863221474Snpstatic uint32_t 5864221474Snpmode_to_fconf(uint32_t mode) 5865221474Snp{ 5866221474Snp uint32_t fconf = 0; 5867221474Snp 5868221474Snp if (mode & T4_FILTER_IP_FRAGMENT) 5869221474Snp fconf |= F_FRAGMENTATION; 5870221474Snp 5871221474Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 5872221474Snp fconf |= F_MPSHITTYPE; 5873221474Snp 5874221474Snp if (mode & T4_FILTER_MAC_IDX) 5875221474Snp fconf |= F_MACMATCH; 5876221474Snp 5877221474Snp if (mode & T4_FILTER_ETH_TYPE) 5878221474Snp fconf |= F_ETHERTYPE; 5879221474Snp 5880221474Snp if (mode & T4_FILTER_IP_PROTO) 5881221474Snp fconf |= F_PROTOCOL; 5882221474Snp 5883221474Snp if (mode & T4_FILTER_IP_TOS) 5884221474Snp fconf |= F_TOS; 5885221474Snp 5886228561Snp if (mode & T4_FILTER_VLAN) 5887221474Snp fconf |= F_VLAN; 5888221474Snp 5889228561Snp if (mode & T4_FILTER_VNIC) 5890221474Snp fconf |= F_VNIC_ID; 5891221474Snp 5892221474Snp if (mode & T4_FILTER_PORT) 5893221474Snp fconf |= F_PORT; 5894221474Snp 5895221474Snp if (mode & T4_FILTER_FCoE) 5896221474Snp fconf |= F_FCOE; 5897221474Snp 5898221474Snp return (fconf); 5899221474Snp} 5900221474Snp 5901221474Snpstatic uint32_t 5902221474Snpfspec_to_fconf(struct t4_filter_specification *fs) 5903221474Snp{ 5904221474Snp uint32_t fconf = 0; 5905221474Snp 5906221474Snp if (fs->val.frag || fs->mask.frag) 5907221474Snp fconf |= F_FRAGMENTATION; 5908221474Snp 5909221474Snp if (fs->val.matchtype || fs->mask.matchtype) 5910221474Snp fconf |= F_MPSHITTYPE; 5911221474Snp 5912221474Snp if (fs->val.macidx || fs->mask.macidx) 5913221474Snp fconf |= F_MACMATCH; 5914221474Snp 5915221474Snp if (fs->val.ethtype || fs->mask.ethtype) 5916221474Snp fconf |= F_ETHERTYPE; 5917221474Snp 5918221474Snp if (fs->val.proto || fs->mask.proto) 5919221474Snp fconf |= F_PROTOCOL; 5920221474Snp 5921221474Snp if (fs->val.tos || fs->mask.tos) 5922221474Snp fconf |= F_TOS; 5923221474Snp 5924228561Snp if (fs->val.vlan_vld || fs->mask.vlan_vld) 5925221474Snp fconf |= F_VLAN; 5926221474Snp 5927228561Snp if (fs->val.vnic_vld || fs->mask.vnic_vld) 5928221474Snp fconf |= F_VNIC_ID; 5929221474Snp 5930221474Snp if (fs->val.iport || fs->mask.iport) 5931221474Snp fconf |= F_PORT; 5932221474Snp 5933221474Snp if (fs->val.fcoe || fs->mask.fcoe) 5934221474Snp fconf |= F_FCOE; 5935221474Snp 5936221474Snp return (fconf); 5937221474Snp} 5938221474Snp 5939221474Snpstatic int 5940221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode) 5941221474Snp{ 5942245274Snp int rc; 5943221474Snp uint32_t fconf; 5944221474Snp 5945245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 5946245274Snp "t4getfm"); 5947245274Snp if (rc) 5948245274Snp return (rc); 5949245274Snp 5950221474Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1, 5951221474Snp A_TP_VLAN_PRI_MAP); 5952221474Snp 5953228561Snp if (sc->filter_mode != fconf) { 5954228561Snp log(LOG_WARNING, "%s: cached filter mode out of sync %x %x.\n", 5955228561Snp device_get_nameunit(sc->dev), sc->filter_mode, fconf); 5956228561Snp sc->filter_mode = fconf; 5957228561Snp } 5958221474Snp 5959228561Snp *mode = fconf_to_mode(sc->filter_mode); 5960228561Snp 5961245274Snp end_synchronized_op(sc, LOCK_HELD); 5962221474Snp return (0); 5963221474Snp} 5964221474Snp 5965221474Snpstatic int 5966221474Snpset_filter_mode(struct adapter *sc, uint32_t mode) 5967221474Snp{ 5968221474Snp uint32_t fconf; 5969221474Snp int rc; 5970221474Snp 5971221474Snp fconf = mode_to_fconf(mode); 5972221474Snp 5973245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 5974245274Snp "t4setfm"); 5975245274Snp if (rc) 5976245274Snp return (rc); 5977221474Snp 5978221474Snp if (sc->tids.ftids_in_use > 0) { 5979221474Snp rc = EBUSY; 5980221474Snp goto done; 5981221474Snp } 5982221474Snp 5983237263Snp#ifdef TCP_OFFLOAD 5984228561Snp if (sc->offload_map) { 5985228561Snp rc = EBUSY; 5986228561Snp goto done; 5987228561Snp } 5988228561Snp#endif 5989228561Snp 5990228561Snp#ifdef notyet 5991221474Snp rc = -t4_set_filter_mode(sc, fconf); 5992228561Snp if (rc == 0) 5993228561Snp sc->filter_mode = fconf; 5994228561Snp#else 5995228561Snp rc = ENOTSUP; 5996228561Snp#endif 5997228561Snp 5998221474Snpdone: 5999245274Snp end_synchronized_op(sc, LOCK_HELD); 6000221474Snp return (rc); 6001221474Snp} 6002221474Snp 6003222552Snpstatic inline uint64_t 6004222552Snpget_filter_hits(struct adapter *sc, uint32_t fid) 6005222552Snp{ 6006248925Snp uint32_t mw_base, off, tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 6007222552Snp uint64_t hits; 6008222552Snp 6009248925Snp memwin_info(sc, 0, &mw_base, NULL); 6010248925Snp off = position_memwin(sc, 0, 6011222552Snp tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE); 6012248925Snp hits = t4_read_reg64(sc, mw_base + off + 16); 6013222552Snp 6014222552Snp return (be64toh(hits)); 6015222552Snp} 6016222552Snp 6017221474Snpstatic int 6018221474Snpget_filter(struct adapter *sc, struct t4_filter *t) 6019221474Snp{ 6020245274Snp int i, rc, nfilters = sc->tids.nftids; 6021221474Snp struct filter_entry *f; 6022221474Snp 6023245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 6024245274Snp "t4getf"); 6025245274Snp if (rc) 6026245274Snp return (rc); 6027221474Snp 6028221474Snp if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL || 6029221474Snp t->idx >= nfilters) { 6030221474Snp t->idx = 0xffffffff; 6031245274Snp goto done; 6032221474Snp } 6033221474Snp 6034221474Snp f = &sc->tids.ftid_tab[t->idx]; 6035221474Snp for (i = t->idx; i < nfilters; i++, f++) { 6036221474Snp if (f->valid) { 6037221474Snp t->idx = i; 6038222509Snp t->l2tidx = f->l2t ? f->l2t->idx : 0; 6039222509Snp t->smtidx = f->smtidx; 6040222552Snp if (f->fs.hitcnts) 6041222552Snp t->hits = get_filter_hits(sc, t->idx); 6042222552Snp else 6043222552Snp t->hits = UINT64_MAX; 6044221474Snp t->fs = f->fs; 6045221474Snp 6046245274Snp goto done; 6047221474Snp } 6048221474Snp } 6049221474Snp 6050221474Snp t->idx = 0xffffffff; 6051245274Snpdone: 6052245274Snp end_synchronized_op(sc, LOCK_HELD); 6053221474Snp return (0); 6054221474Snp} 6055221474Snp 6056221474Snpstatic int 6057221474Snpset_filter(struct adapter *sc, struct t4_filter *t) 6058221474Snp{ 6059221474Snp unsigned int nfilters, nports; 6060221474Snp struct filter_entry *f; 6061245274Snp int i, rc; 6062221474Snp 6063245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setf"); 6064245274Snp if (rc) 6065245274Snp return (rc); 6066221474Snp 6067221474Snp nfilters = sc->tids.nftids; 6068221474Snp nports = sc->params.nports; 6069221474Snp 6070245274Snp if (nfilters == 0) { 6071245274Snp rc = ENOTSUP; 6072245274Snp goto done; 6073245274Snp } 6074221474Snp 6075245274Snp if (!(sc->flags & FULL_INIT_DONE)) { 6076245274Snp rc = EAGAIN; 6077245274Snp goto done; 6078245274Snp } 6079221474Snp 6080245274Snp if (t->idx >= nfilters) { 6081245274Snp rc = EINVAL; 6082245274Snp goto done; 6083245274Snp } 6084221474Snp 6085221474Snp /* Validate against the global filter mode */ 6086245274Snp if ((sc->filter_mode | fspec_to_fconf(&t->fs)) != sc->filter_mode) { 6087245274Snp rc = E2BIG; 6088245274Snp goto done; 6089245274Snp } 6090221474Snp 6091245274Snp if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) { 6092245274Snp rc = EINVAL; 6093245274Snp goto done; 6094245274Snp } 6095221474Snp 6096245274Snp if (t->fs.val.iport >= nports) { 6097245274Snp rc = EINVAL; 6098245274Snp goto done; 6099245274Snp } 6100221474Snp 6101221474Snp /* Can't specify an iq if not steering to it */ 6102245274Snp if (!t->fs.dirsteer && t->fs.iq) { 6103245274Snp rc = EINVAL; 6104245274Snp goto done; 6105245274Snp } 6106221474Snp 6107221474Snp /* IPv6 filter idx must be 4 aligned */ 6108221474Snp if (t->fs.type == 1 && 6109245274Snp ((t->idx & 0x3) || t->idx + 4 >= nfilters)) { 6110245274Snp rc = EINVAL; 6111245274Snp goto done; 6112245274Snp } 6113221474Snp 6114221474Snp if (sc->tids.ftid_tab == NULL) { 6115221474Snp KASSERT(sc->tids.ftids_in_use == 0, 6116221474Snp ("%s: no memory allocated but filters_in_use > 0", 6117221474Snp __func__)); 6118221474Snp 6119221474Snp sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) * 6120221474Snp nfilters, M_CXGBE, M_NOWAIT | M_ZERO); 6121245274Snp if (sc->tids.ftid_tab == NULL) { 6122245274Snp rc = ENOMEM; 6123245274Snp goto done; 6124245274Snp } 6125245274Snp mtx_init(&sc->tids.ftid_lock, "T4 filters", 0, MTX_DEF); 6126221474Snp } 6127221474Snp 6128221474Snp for (i = 0; i < 4; i++) { 6129221474Snp f = &sc->tids.ftid_tab[t->idx + i]; 6130221474Snp 6131245274Snp if (f->pending || f->valid) { 6132245274Snp rc = EBUSY; 6133245274Snp goto done; 6134245274Snp } 6135245274Snp if (f->locked) { 6136245274Snp rc = EPERM; 6137245274Snp goto done; 6138245274Snp } 6139221474Snp 6140221474Snp if (t->fs.type == 0) 6141221474Snp break; 6142221474Snp } 6143221474Snp 6144221474Snp f = &sc->tids.ftid_tab[t->idx]; 6145221474Snp f->fs = t->fs; 6146221474Snp 6147245274Snp rc = set_filter_wr(sc, t->idx); 6148245274Snpdone: 6149245274Snp end_synchronized_op(sc, 0); 6150245274Snp 6151245274Snp if (rc == 0) { 6152245274Snp mtx_lock(&sc->tids.ftid_lock); 6153245274Snp for (;;) { 6154245274Snp if (f->pending == 0) { 6155245274Snp rc = f->valid ? 0 : EIO; 6156245274Snp break; 6157245274Snp } 6158245274Snp 6159245274Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 6160245274Snp PCATCH, "t4setfw", 0)) { 6161245274Snp rc = EINPROGRESS; 6162245274Snp break; 6163245274Snp } 6164245274Snp } 6165245274Snp mtx_unlock(&sc->tids.ftid_lock); 6166245274Snp } 6167245274Snp return (rc); 6168221474Snp} 6169221474Snp 6170221474Snpstatic int 6171221474Snpdel_filter(struct adapter *sc, struct t4_filter *t) 6172221474Snp{ 6173221474Snp unsigned int nfilters; 6174221474Snp struct filter_entry *f; 6175245274Snp int rc; 6176221474Snp 6177245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4delf"); 6178245274Snp if (rc) 6179245274Snp return (rc); 6180221474Snp 6181221474Snp nfilters = sc->tids.nftids; 6182221474Snp 6183245274Snp if (nfilters == 0) { 6184245274Snp rc = ENOTSUP; 6185245274Snp goto done; 6186245274Snp } 6187221474Snp 6188221474Snp if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 || 6189245274Snp t->idx >= nfilters) { 6190245274Snp rc = EINVAL; 6191245274Snp goto done; 6192245274Snp } 6193221474Snp 6194245274Snp if (!(sc->flags & FULL_INIT_DONE)) { 6195245274Snp rc = EAGAIN; 6196245274Snp goto done; 6197245274Snp } 6198221474Snp 6199221474Snp f = &sc->tids.ftid_tab[t->idx]; 6200221474Snp 6201245274Snp if (f->pending) { 6202245274Snp rc = EBUSY; 6203245274Snp goto done; 6204245274Snp } 6205245274Snp if (f->locked) { 6206245274Snp rc = EPERM; 6207245274Snp goto done; 6208245274Snp } 6209221474Snp 6210221474Snp if (f->valid) { 6211221474Snp t->fs = f->fs; /* extra info for the caller */ 6212245274Snp rc = del_filter_wr(sc, t->idx); 6213221474Snp } 6214221474Snp 6215245274Snpdone: 6216245274Snp end_synchronized_op(sc, 0); 6217245274Snp 6218245274Snp if (rc == 0) { 6219245274Snp mtx_lock(&sc->tids.ftid_lock); 6220245274Snp for (;;) { 6221245274Snp if (f->pending == 0) { 6222245274Snp rc = f->valid ? EIO : 0; 6223245274Snp break; 6224245274Snp } 6225245274Snp 6226245274Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 6227245274Snp PCATCH, "t4delfw", 0)) { 6228245274Snp rc = EINPROGRESS; 6229245274Snp break; 6230245274Snp } 6231245274Snp } 6232245274Snp mtx_unlock(&sc->tids.ftid_lock); 6233245274Snp } 6234245274Snp 6235245274Snp return (rc); 6236221474Snp} 6237221474Snp 6238221474Snpstatic void 6239222509Snpclear_filter(struct filter_entry *f) 6240221474Snp{ 6241222509Snp if (f->l2t) 6242222509Snp t4_l2t_release(f->l2t); 6243222509Snp 6244221474Snp bzero(f, sizeof (*f)); 6245221474Snp} 6246221474Snp 6247221474Snpstatic int 6248221474Snpset_filter_wr(struct adapter *sc, int fidx) 6249221474Snp{ 6250221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 6251237263Snp struct wrqe *wr; 6252221474Snp struct fw_filter_wr *fwr; 6253221474Snp unsigned int ftid; 6254221474Snp 6255245274Snp ASSERT_SYNCHRONIZED_OP(sc); 6256221474Snp 6257222509Snp if (f->fs.newdmac || f->fs.newvlan) { 6258222509Snp /* This filter needs an L2T entry; allocate one. */ 6259222509Snp f->l2t = t4_l2t_alloc_switching(sc->l2t); 6260222509Snp if (f->l2t == NULL) 6261222509Snp return (EAGAIN); 6262222509Snp if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport, 6263222509Snp f->fs.dmac)) { 6264222509Snp t4_l2t_release(f->l2t); 6265222509Snp f->l2t = NULL; 6266222509Snp return (ENOMEM); 6267222509Snp } 6268222509Snp } 6269221474Snp 6270221474Snp ftid = sc->tids.ftid_base + fidx; 6271221474Snp 6272237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 6273237263Snp if (wr == NULL) 6274221474Snp return (ENOMEM); 6275221474Snp 6276237263Snp fwr = wrtod(wr); 6277221474Snp bzero(fwr, sizeof (*fwr)); 6278221474Snp 6279221474Snp fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR)); 6280221474Snp fwr->len16_pkd = htobe32(FW_LEN16(*fwr)); 6281221474Snp fwr->tid_to_iq = 6282221474Snp htobe32(V_FW_FILTER_WR_TID(ftid) | 6283221474Snp V_FW_FILTER_WR_RQTYPE(f->fs.type) | 6284221474Snp V_FW_FILTER_WR_NOREPLY(0) | 6285221474Snp V_FW_FILTER_WR_IQ(f->fs.iq)); 6286221474Snp fwr->del_filter_to_l2tix = 6287221474Snp htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) | 6288221474Snp V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) | 6289221474Snp V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) | 6290221474Snp V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) | 6291221474Snp V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) | 6292221474Snp V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) | 6293221474Snp V_FW_FILTER_WR_DMAC(f->fs.newdmac) | 6294221474Snp V_FW_FILTER_WR_SMAC(f->fs.newsmac) | 6295221474Snp V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT || 6296221474Snp f->fs.newvlan == VLAN_REWRITE) | 6297221474Snp V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE || 6298221474Snp f->fs.newvlan == VLAN_REWRITE) | 6299221474Snp V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) | 6300221474Snp V_FW_FILTER_WR_TXCHAN(f->fs.eport) | 6301221474Snp V_FW_FILTER_WR_PRIO(f->fs.prio) | 6302222509Snp V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0)); 6303221474Snp fwr->ethtype = htobe16(f->fs.val.ethtype); 6304221474Snp fwr->ethtypem = htobe16(f->fs.mask.ethtype); 6305221474Snp fwr->frag_to_ovlan_vldm = 6306221474Snp (V_FW_FILTER_WR_FRAG(f->fs.val.frag) | 6307221474Snp V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) | 6308228561Snp V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) | 6309228561Snp V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.vnic_vld) | 6310228561Snp V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) | 6311228561Snp V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.vnic_vld)); 6312221474Snp fwr->smac_sel = 0; 6313221474Snp fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) | 6314228561Snp V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id)); 6315221474Snp fwr->maci_to_matchtypem = 6316221474Snp htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) | 6317221474Snp V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) | 6318221474Snp V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) | 6319221474Snp V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) | 6320221474Snp V_FW_FILTER_WR_PORT(f->fs.val.iport) | 6321221474Snp V_FW_FILTER_WR_PORTM(f->fs.mask.iport) | 6322221474Snp V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) | 6323221474Snp V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype)); 6324221474Snp fwr->ptcl = f->fs.val.proto; 6325221474Snp fwr->ptclm = f->fs.mask.proto; 6326221474Snp fwr->ttyp = f->fs.val.tos; 6327221474Snp fwr->ttypm = f->fs.mask.tos; 6328228561Snp fwr->ivlan = htobe16(f->fs.val.vlan); 6329228561Snp fwr->ivlanm = htobe16(f->fs.mask.vlan); 6330228561Snp fwr->ovlan = htobe16(f->fs.val.vnic); 6331228561Snp fwr->ovlanm = htobe16(f->fs.mask.vnic); 6332221474Snp bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip)); 6333221474Snp bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm)); 6334221474Snp bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip)); 6335221474Snp bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm)); 6336221474Snp fwr->lp = htobe16(f->fs.val.dport); 6337221474Snp fwr->lpm = htobe16(f->fs.mask.dport); 6338221474Snp fwr->fp = htobe16(f->fs.val.sport); 6339221474Snp fwr->fpm = htobe16(f->fs.mask.sport); 6340221474Snp if (f->fs.newsmac) 6341221474Snp bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma)); 6342221474Snp 6343221474Snp f->pending = 1; 6344221474Snp sc->tids.ftids_in_use++; 6345228561Snp 6346237263Snp t4_wrq_tx(sc, wr); 6347228561Snp return (0); 6348221474Snp} 6349221474Snp 6350221474Snpstatic int 6351221474Snpdel_filter_wr(struct adapter *sc, int fidx) 6352221474Snp{ 6353221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 6354237263Snp struct wrqe *wr; 6355221474Snp struct fw_filter_wr *fwr; 6356228561Snp unsigned int ftid; 6357221474Snp 6358221474Snp ftid = sc->tids.ftid_base + fidx; 6359221474Snp 6360237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 6361237263Snp if (wr == NULL) 6362221474Snp return (ENOMEM); 6363237263Snp fwr = wrtod(wr); 6364221474Snp bzero(fwr, sizeof (*fwr)); 6365221474Snp 6366228561Snp t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id); 6367221474Snp 6368221474Snp f->pending = 1; 6369237263Snp t4_wrq_tx(sc, wr); 6370228561Snp return (0); 6371221474Snp} 6372221474Snp 6373239338Snpint 6374239338Snpt4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 6375221474Snp{ 6376228561Snp struct adapter *sc = iq->adapter; 6377228561Snp const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1); 6378221474Snp unsigned int idx = GET_TID(rpl); 6379221474Snp 6380228561Snp KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__, 6381228561Snp rss->opcode)); 6382228561Snp 6383221474Snp if (idx >= sc->tids.ftid_base && 6384221474Snp (idx -= sc->tids.ftid_base) < sc->tids.nftids) { 6385221474Snp unsigned int rc = G_COOKIE(rpl->cookie); 6386221474Snp struct filter_entry *f = &sc->tids.ftid_tab[idx]; 6387221474Snp 6388245274Snp mtx_lock(&sc->tids.ftid_lock); 6389228561Snp if (rc == FW_FILTER_WR_FLT_ADDED) { 6390245274Snp KASSERT(f->pending, ("%s: filter[%u] isn't pending.", 6391245274Snp __func__, idx)); 6392221474Snp f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff; 6393221474Snp f->pending = 0; /* asynchronous setup completed */ 6394221474Snp f->valid = 1; 6395231120Snp } else { 6396231120Snp if (rc != FW_FILTER_WR_FLT_DELETED) { 6397231120Snp /* Add or delete failed, display an error */ 6398231120Snp log(LOG_ERR, 6399231120Snp "filter %u setup failed with error %u\n", 6400231120Snp idx, rc); 6401231120Snp } 6402228561Snp 6403231120Snp clear_filter(f); 6404231120Snp sc->tids.ftids_in_use--; 6405221474Snp } 6406245274Snp wakeup(&sc->tids.ftid_tab); 6407245274Snp mtx_unlock(&sc->tids.ftid_lock); 6408221474Snp } 6409228561Snp 6410228561Snp return (0); 6411221474Snp} 6412221474Snp 6413222973Snpstatic int 6414222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt) 6415222973Snp{ 6416245274Snp int rc; 6417222973Snp 6418222973Snp if (cntxt->cid > M_CTXTQID) 6419245274Snp return (EINVAL); 6420222973Snp 6421222973Snp if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS && 6422222973Snp cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM) 6423245274Snp return (EINVAL); 6424222973Snp 6425246575Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ctxt"); 6426246575Snp if (rc) 6427246575Snp return (rc); 6428246575Snp 6429222973Snp if (sc->flags & FW_OK) { 6430246575Snp rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id, 6431246575Snp &cntxt->data[0]); 6432246575Snp if (rc == 0) 6433246575Snp goto done; 6434222973Snp } 6435222973Snp 6436245274Snp /* 6437245274Snp * Read via firmware failed or wasn't even attempted. Read directly via 6438245274Snp * the backdoor. 6439245274Snp */ 6440246575Snp rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id, &cntxt->data[0]); 6441246575Snpdone: 6442246575Snp end_synchronized_op(sc, 0); 6443245274Snp return (rc); 6444245274Snp} 6445222973Snp 6446245274Snpstatic int 6447245274Snpload_fw(struct adapter *sc, struct t4_data *fw) 6448245274Snp{ 6449245274Snp int rc; 6450245274Snp uint8_t *fw_data; 6451245274Snp 6452245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ldfw"); 6453245274Snp if (rc) 6454245274Snp return (rc); 6455245274Snp 6456245274Snp if (sc->flags & FULL_INIT_DONE) { 6457245274Snp rc = EBUSY; 6458245274Snp goto done; 6459222973Snp } 6460222973Snp 6461245274Snp fw_data = malloc(fw->len, M_CXGBE, M_WAITOK); 6462245274Snp if (fw_data == NULL) { 6463245274Snp rc = ENOMEM; 6464245274Snp goto done; 6465245274Snp } 6466245274Snp 6467245274Snp rc = copyin(fw->data, fw_data, fw->len); 6468245274Snp if (rc == 0) 6469245274Snp rc = -t4_load_fw(sc, fw_data, fw->len); 6470245274Snp 6471245274Snp free(fw_data, M_CXGBE); 6472245274Snpdone: 6473245274Snp end_synchronized_op(sc, 0); 6474222973Snp return (rc); 6475222973Snp} 6476222973Snp 6477228561Snpstatic int 6478248925Snpread_card_mem(struct adapter *sc, int win, struct t4_mem_range *mr) 6479228561Snp{ 6480248925Snp uint32_t addr, off, remaining, i, n; 6481228561Snp uint32_t *buf, *b; 6482248925Snp uint32_t mw_base, mw_aperture; 6483228561Snp int rc; 6484248925Snp uint8_t *dst; 6485228561Snp 6486248925Snp rc = validate_mem_range(sc, mr->addr, mr->len); 6487248925Snp if (rc != 0) 6488248925Snp return (rc); 6489228561Snp 6490248925Snp memwin_info(sc, win, &mw_base, &mw_aperture); 6491248925Snp buf = b = malloc(min(mr->len, mw_aperture), M_CXGBE, M_WAITOK); 6492248925Snp addr = mr->addr; 6493228561Snp remaining = mr->len; 6494248925Snp dst = (void *)mr->data; 6495228561Snp 6496228561Snp while (remaining) { 6497248925Snp off = position_memwin(sc, win, addr); 6498228561Snp 6499228561Snp /* number of bytes that we'll copy in the inner loop */ 6500248925Snp n = min(remaining, mw_aperture - off); 6501248925Snp for (i = 0; i < n; i += 4) 6502248925Snp *b++ = t4_read_reg(sc, mw_base + off + i); 6503228561Snp 6504248925Snp rc = copyout(buf, dst, n); 6505248925Snp if (rc != 0) 6506248925Snp break; 6507228561Snp 6508248925Snp b = buf; 6509248925Snp dst += n; 6510248925Snp remaining -= n; 6511248925Snp addr += n; 6512228561Snp } 6513228561Snp 6514228561Snp free(buf, M_CXGBE); 6515228561Snp return (rc); 6516228561Snp} 6517228561Snp 6518241399Snpstatic int 6519241399Snpread_i2c(struct adapter *sc, struct t4_i2c_data *i2cd) 6520241399Snp{ 6521241399Snp int rc; 6522241399Snp 6523241399Snp if (i2cd->len == 0 || i2cd->port_id >= sc->params.nports) 6524241399Snp return (EINVAL); 6525241399Snp 6526241399Snp if (i2cd->len > 1) { 6527241399Snp /* XXX: need fw support for longer reads in one go */ 6528241399Snp return (ENOTSUP); 6529241399Snp } 6530241399Snp 6531245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4i2crd"); 6532245274Snp if (rc) 6533245274Snp return (rc); 6534241399Snp rc = -t4_i2c_rd(sc, sc->mbox, i2cd->port_id, i2cd->dev_addr, 6535241399Snp i2cd->offset, &i2cd->data[0]); 6536245274Snp end_synchronized_op(sc, 0); 6537241399Snp 6538241399Snp return (rc); 6539241399Snp} 6540241399Snp 6541218792Snpint 6542218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap) 6543218792Snp{ 6544222102Snp int i; 6545218792Snp 6546222102Snp return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0); 6547218792Snp} 6548218792Snp 6549218792Snpint 6550218792Snpt4_os_pci_save_state(struct adapter *sc) 6551218792Snp{ 6552218792Snp device_t dev; 6553218792Snp struct pci_devinfo *dinfo; 6554218792Snp 6555218792Snp dev = sc->dev; 6556218792Snp dinfo = device_get_ivars(dev); 6557218792Snp 6558218792Snp pci_cfg_save(dev, dinfo, 0); 6559218792Snp return (0); 6560218792Snp} 6561218792Snp 6562218792Snpint 6563218792Snpt4_os_pci_restore_state(struct adapter *sc) 6564218792Snp{ 6565218792Snp device_t dev; 6566218792Snp struct pci_devinfo *dinfo; 6567218792Snp 6568218792Snp dev = sc->dev; 6569218792Snp dinfo = device_get_ivars(dev); 6570218792Snp 6571218792Snp pci_cfg_restore(dev, dinfo); 6572218792Snp return (0); 6573218792Snp} 6574219299Snp 6575218792Snpvoid 6576218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx) 6577218792Snp{ 6578218792Snp struct port_info *pi = sc->port[idx]; 6579218792Snp static const char *mod_str[] = { 6580220232Snp NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM" 6581218792Snp }; 6582218792Snp 6583218792Snp if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 6584218792Snp if_printf(pi->ifp, "transceiver unplugged.\n"); 6585220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) 6586220232Snp if_printf(pi->ifp, "unknown transceiver inserted.\n"); 6587220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) 6588220232Snp if_printf(pi->ifp, "unsupported transceiver inserted.\n"); 6589240452Snp else if (pi->mod_type > 0 && pi->mod_type < nitems(mod_str)) { 6590218792Snp if_printf(pi->ifp, "%s transceiver inserted.\n", 6591218792Snp mod_str[pi->mod_type]); 6592219299Snp } else { 6593219299Snp if_printf(pi->ifp, "transceiver (type %d) inserted.\n", 6594219299Snp pi->mod_type); 6595219299Snp } 6596218792Snp} 6597218792Snp 6598218792Snpvoid 6599218792Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat) 6600218792Snp{ 6601218792Snp struct port_info *pi = sc->port[idx]; 6602218792Snp struct ifnet *ifp = pi->ifp; 6603218792Snp 6604218792Snp if (link_stat) { 6605218792Snp ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed); 6606218792Snp if_link_state_change(ifp, LINK_STATE_UP); 6607218792Snp } else 6608218792Snp if_link_state_change(ifp, LINK_STATE_DOWN); 6609218792Snp} 6610218792Snp 6611228561Snpvoid 6612228561Snpt4_iterate(void (*func)(struct adapter *, void *), void *arg) 6613228561Snp{ 6614228561Snp struct adapter *sc; 6615228561Snp 6616228561Snp mtx_lock(&t4_list_lock); 6617228561Snp SLIST_FOREACH(sc, &t4_list, link) { 6618228561Snp /* 6619228561Snp * func should not make any assumptions about what state sc is 6620228561Snp * in - the only guarantee is that sc->sc_lock is a valid lock. 6621228561Snp */ 6622228561Snp func(sc, arg); 6623228561Snp } 6624228561Snp mtx_unlock(&t4_list_lock); 6625228561Snp} 6626228561Snp 6627218792Snpstatic int 6628218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td) 6629218792Snp{ 6630218792Snp return (0); 6631218792Snp} 6632218792Snp 6633218792Snpstatic int 6634218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td) 6635218792Snp{ 6636218792Snp return (0); 6637218792Snp} 6638218792Snp 6639218792Snpstatic int 6640218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag, 6641218792Snp struct thread *td) 6642218792Snp{ 6643218792Snp int rc; 6644218792Snp struct adapter *sc = dev->si_drv1; 6645218792Snp 6646218792Snp rc = priv_check(td, PRIV_DRIVER); 6647218792Snp if (rc != 0) 6648218792Snp return (rc); 6649218792Snp 6650218792Snp switch (cmd) { 6651220410Snp case CHELSIO_T4_GETREG: { 6652220410Snp struct t4_reg *edata = (struct t4_reg *)data; 6653220410Snp 6654218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 6655218792Snp return (EFAULT); 6656220410Snp 6657220410Snp if (edata->size == 4) 6658220410Snp edata->val = t4_read_reg(sc, edata->addr); 6659220410Snp else if (edata->size == 8) 6660220410Snp edata->val = t4_read_reg64(sc, edata->addr); 6661220410Snp else 6662220410Snp return (EINVAL); 6663220410Snp 6664218792Snp break; 6665218792Snp } 6666220410Snp case CHELSIO_T4_SETREG: { 6667220410Snp struct t4_reg *edata = (struct t4_reg *)data; 6668220410Snp 6669218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 6670218792Snp return (EFAULT); 6671220410Snp 6672220410Snp if (edata->size == 4) { 6673220410Snp if (edata->val & 0xffffffff00000000) 6674220410Snp return (EINVAL); 6675220410Snp t4_write_reg(sc, edata->addr, (uint32_t) edata->val); 6676220410Snp } else if (edata->size == 8) 6677220410Snp t4_write_reg64(sc, edata->addr, edata->val); 6678220410Snp else 6679220410Snp return (EINVAL); 6680218792Snp break; 6681218792Snp } 6682218792Snp case CHELSIO_T4_REGDUMP: { 6683218792Snp struct t4_regdump *regs = (struct t4_regdump *)data; 6684248925Snp int reglen = is_t4(sc) ? T4_REGDUMP_SIZE : T5_REGDUMP_SIZE; 6685218792Snp uint8_t *buf; 6686218792Snp 6687218792Snp if (regs->len < reglen) { 6688218792Snp regs->len = reglen; /* hint to the caller */ 6689218792Snp return (ENOBUFS); 6690218792Snp } 6691218792Snp 6692218792Snp regs->len = reglen; 6693218792Snp buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO); 6694218792Snp t4_get_regs(sc, regs, buf); 6695218792Snp rc = copyout(buf, regs->data, reglen); 6696218792Snp free(buf, M_CXGBE); 6697218792Snp break; 6698218792Snp } 6699221474Snp case CHELSIO_T4_GET_FILTER_MODE: 6700221474Snp rc = get_filter_mode(sc, (uint32_t *)data); 6701221474Snp break; 6702221474Snp case CHELSIO_T4_SET_FILTER_MODE: 6703221474Snp rc = set_filter_mode(sc, *(uint32_t *)data); 6704221474Snp break; 6705221474Snp case CHELSIO_T4_GET_FILTER: 6706221474Snp rc = get_filter(sc, (struct t4_filter *)data); 6707221474Snp break; 6708221474Snp case CHELSIO_T4_SET_FILTER: 6709221474Snp rc = set_filter(sc, (struct t4_filter *)data); 6710221474Snp break; 6711221474Snp case CHELSIO_T4_DEL_FILTER: 6712221474Snp rc = del_filter(sc, (struct t4_filter *)data); 6713221474Snp break; 6714222973Snp case CHELSIO_T4_GET_SGE_CONTEXT: 6715222973Snp rc = get_sge_context(sc, (struct t4_sge_context *)data); 6716222973Snp break; 6717245274Snp case CHELSIO_T4_LOAD_FW: 6718245274Snp rc = load_fw(sc, (struct t4_data *)data); 6719228561Snp break; 6720228561Snp case CHELSIO_T4_GET_MEM: 6721248925Snp rc = read_card_mem(sc, 2, (struct t4_mem_range *)data); 6722228561Snp break; 6723241399Snp case CHELSIO_T4_GET_I2C: 6724241399Snp rc = read_i2c(sc, (struct t4_i2c_data *)data); 6725241399Snp break; 6726241409Snp case CHELSIO_T4_CLEAR_STATS: { 6727245518Snp int i; 6728241409Snp u_int port_id = *(uint32_t *)data; 6729245518Snp struct port_info *pi; 6730241409Snp 6731241409Snp if (port_id >= sc->params.nports) 6732241409Snp return (EINVAL); 6733241409Snp 6734245518Snp /* MAC stats */ 6735241409Snp t4_clr_port_stats(sc, port_id); 6736245518Snp 6737245518Snp pi = sc->port[port_id]; 6738245518Snp if (pi->flags & PORT_INIT_DONE) { 6739245518Snp struct sge_rxq *rxq; 6740245518Snp struct sge_txq *txq; 6741245518Snp struct sge_wrq *wrq; 6742245518Snp 6743245518Snp for_each_rxq(pi, i, rxq) { 6744245518Snp#if defined(INET) || defined(INET6) 6745245518Snp rxq->lro.lro_queued = 0; 6746245518Snp rxq->lro.lro_flushed = 0; 6747245518Snp#endif 6748245518Snp rxq->rxcsum = 0; 6749245518Snp rxq->vlan_extraction = 0; 6750245518Snp } 6751245518Snp 6752245518Snp for_each_txq(pi, i, txq) { 6753245518Snp txq->txcsum = 0; 6754245518Snp txq->tso_wrs = 0; 6755245518Snp txq->vlan_insertion = 0; 6756245518Snp txq->imm_wrs = 0; 6757245518Snp txq->sgl_wrs = 0; 6758245518Snp txq->txpkt_wrs = 0; 6759245518Snp txq->txpkts_wrs = 0; 6760245518Snp txq->txpkts_pkts = 0; 6761246093Snp txq->br->br_drops = 0; 6762245518Snp txq->no_dmamap = 0; 6763245518Snp txq->no_desc = 0; 6764245518Snp } 6765245518Snp 6766245518Snp#ifdef TCP_OFFLOAD 6767245518Snp /* nothing to clear for each ofld_rxq */ 6768245518Snp 6769245518Snp for_each_ofld_txq(pi, i, wrq) { 6770245518Snp wrq->tx_wrs = 0; 6771245518Snp wrq->no_desc = 0; 6772245518Snp } 6773245518Snp#endif 6774245518Snp wrq = &sc->sge.ctrlq[pi->port_id]; 6775245518Snp wrq->tx_wrs = 0; 6776245518Snp wrq->no_desc = 0; 6777245518Snp } 6778241409Snp break; 6779241409Snp } 6780218792Snp default: 6781218792Snp rc = EINVAL; 6782218792Snp } 6783218792Snp 6784218792Snp return (rc); 6785218792Snp} 6786218792Snp 6787237263Snp#ifdef TCP_OFFLOAD 6788219392Snpstatic int 6789228561Snptoe_capability(struct port_info *pi, int enable) 6790228561Snp{ 6791228561Snp int rc; 6792228561Snp struct adapter *sc = pi->adapter; 6793228561Snp 6794245274Snp ASSERT_SYNCHRONIZED_OP(sc); 6795228561Snp 6796228561Snp if (!is_offload(sc)) 6797228561Snp return (ENODEV); 6798228561Snp 6799228561Snp if (enable) { 6800237263Snp if (!(sc->flags & FULL_INIT_DONE)) { 6801245274Snp rc = cxgbe_init_synchronized(pi); 6802245274Snp if (rc) 6803245274Snp return (rc); 6804237263Snp } 6805237263Snp 6806228561Snp if (isset(&sc->offload_map, pi->port_id)) 6807228561Snp return (0); 6808228561Snp 6809237263Snp if (!(sc->flags & TOM_INIT_DONE)) { 6810237263Snp rc = t4_activate_uld(sc, ULD_TOM); 6811237263Snp if (rc == EAGAIN) { 6812237263Snp log(LOG_WARNING, 6813237263Snp "You must kldload t4_tom.ko before trying " 6814237263Snp "to enable TOE on a cxgbe interface.\n"); 6815237263Snp } 6816228561Snp if (rc != 0) 6817228561Snp return (rc); 6818237263Snp KASSERT(sc->tom_softc != NULL, 6819237263Snp ("%s: TOM activated but softc NULL", __func__)); 6820237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 6821237263Snp ("%s: TOM activated but flag not set", __func__)); 6822228561Snp } 6823228561Snp 6824228561Snp setbit(&sc->offload_map, pi->port_id); 6825228561Snp } else { 6826228561Snp if (!isset(&sc->offload_map, pi->port_id)) 6827228561Snp return (0); 6828228561Snp 6829237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 6830237263Snp ("%s: TOM never initialized?", __func__)); 6831228561Snp clrbit(&sc->offload_map, pi->port_id); 6832228561Snp } 6833228561Snp 6834228561Snp return (0); 6835228561Snp} 6836228561Snp 6837228561Snp/* 6838228561Snp * Add an upper layer driver to the global list. 6839228561Snp */ 6840228561Snpint 6841228561Snpt4_register_uld(struct uld_info *ui) 6842228561Snp{ 6843228561Snp int rc = 0; 6844228561Snp struct uld_info *u; 6845228561Snp 6846228561Snp mtx_lock(&t4_uld_list_lock); 6847228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 6848228561Snp if (u->uld_id == ui->uld_id) { 6849228561Snp rc = EEXIST; 6850228561Snp goto done; 6851228561Snp } 6852228561Snp } 6853228561Snp 6854228561Snp SLIST_INSERT_HEAD(&t4_uld_list, ui, link); 6855228561Snp ui->refcount = 0; 6856228561Snpdone: 6857228561Snp mtx_unlock(&t4_uld_list_lock); 6858228561Snp return (rc); 6859228561Snp} 6860228561Snp 6861228561Snpint 6862228561Snpt4_unregister_uld(struct uld_info *ui) 6863228561Snp{ 6864228561Snp int rc = EINVAL; 6865228561Snp struct uld_info *u; 6866228561Snp 6867228561Snp mtx_lock(&t4_uld_list_lock); 6868228561Snp 6869228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 6870228561Snp if (u == ui) { 6871228561Snp if (ui->refcount > 0) { 6872228561Snp rc = EBUSY; 6873228561Snp goto done; 6874228561Snp } 6875228561Snp 6876228561Snp SLIST_REMOVE(&t4_uld_list, ui, uld_info, link); 6877228561Snp rc = 0; 6878228561Snp goto done; 6879228561Snp } 6880228561Snp } 6881228561Snpdone: 6882228561Snp mtx_unlock(&t4_uld_list_lock); 6883228561Snp return (rc); 6884228561Snp} 6885228561Snp 6886237263Snpint 6887237263Snpt4_activate_uld(struct adapter *sc, int id) 6888228561Snp{ 6889228561Snp int rc = EAGAIN; 6890228561Snp struct uld_info *ui; 6891228561Snp 6892245274Snp ASSERT_SYNCHRONIZED_OP(sc); 6893245274Snp 6894228561Snp mtx_lock(&t4_uld_list_lock); 6895228561Snp 6896228561Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 6897228561Snp if (ui->uld_id == id) { 6898237263Snp rc = ui->activate(sc); 6899237263Snp if (rc == 0) 6900228561Snp ui->refcount++; 6901228561Snp goto done; 6902228561Snp } 6903228561Snp } 6904228561Snpdone: 6905228561Snp mtx_unlock(&t4_uld_list_lock); 6906228561Snp 6907228561Snp return (rc); 6908228561Snp} 6909228561Snp 6910237263Snpint 6911237263Snpt4_deactivate_uld(struct adapter *sc, int id) 6912228561Snp{ 6913237263Snp int rc = EINVAL; 6914237263Snp struct uld_info *ui; 6915228561Snp 6916245274Snp ASSERT_SYNCHRONIZED_OP(sc); 6917245274Snp 6918228561Snp mtx_lock(&t4_uld_list_lock); 6919228561Snp 6920237263Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 6921237263Snp if (ui->uld_id == id) { 6922237263Snp rc = ui->deactivate(sc); 6923237263Snp if (rc == 0) 6924237263Snp ui->refcount--; 6925237263Snp goto done; 6926237263Snp } 6927228561Snp } 6928228561Snpdone: 6929228561Snp mtx_unlock(&t4_uld_list_lock); 6930228561Snp 6931228561Snp return (rc); 6932228561Snp} 6933228561Snp#endif 6934228561Snp 6935228561Snp/* 6936228561Snp * Come up with reasonable defaults for some of the tunables, provided they're 6937228561Snp * not set by the user (in which case we'll use the values as is). 6938228561Snp */ 6939228561Snpstatic void 6940228561Snptweak_tunables(void) 6941228561Snp{ 6942228561Snp int nc = mp_ncpus; /* our snapshot of the number of CPUs */ 6943228561Snp 6944228561Snp if (t4_ntxq10g < 1) 6945228561Snp t4_ntxq10g = min(nc, NTXQ_10G); 6946228561Snp 6947228561Snp if (t4_ntxq1g < 1) 6948228561Snp t4_ntxq1g = min(nc, NTXQ_1G); 6949228561Snp 6950228561Snp if (t4_nrxq10g < 1) 6951228561Snp t4_nrxq10g = min(nc, NRXQ_10G); 6952228561Snp 6953228561Snp if (t4_nrxq1g < 1) 6954228561Snp t4_nrxq1g = min(nc, NRXQ_1G); 6955228561Snp 6956237263Snp#ifdef TCP_OFFLOAD 6957228561Snp if (t4_nofldtxq10g < 1) 6958228561Snp t4_nofldtxq10g = min(nc, NOFLDTXQ_10G); 6959228561Snp 6960228561Snp if (t4_nofldtxq1g < 1) 6961228561Snp t4_nofldtxq1g = min(nc, NOFLDTXQ_1G); 6962228561Snp 6963228561Snp if (t4_nofldrxq10g < 1) 6964228561Snp t4_nofldrxq10g = min(nc, NOFLDRXQ_10G); 6965228561Snp 6966228561Snp if (t4_nofldrxq1g < 1) 6967228561Snp t4_nofldrxq1g = min(nc, NOFLDRXQ_1G); 6968238028Snp 6969238028Snp if (t4_toecaps_allowed == -1) 6970238028Snp t4_toecaps_allowed = FW_CAPS_CONFIG_TOE; 6971238028Snp#else 6972238028Snp if (t4_toecaps_allowed == -1) 6973238028Snp t4_toecaps_allowed = 0; 6974228561Snp#endif 6975228561Snp 6976228561Snp if (t4_tmr_idx_10g < 0 || t4_tmr_idx_10g >= SGE_NTIMERS) 6977228561Snp t4_tmr_idx_10g = TMR_IDX_10G; 6978228561Snp 6979228561Snp if (t4_pktc_idx_10g < -1 || t4_pktc_idx_10g >= SGE_NCOUNTERS) 6980228561Snp t4_pktc_idx_10g = PKTC_IDX_10G; 6981228561Snp 6982228561Snp if (t4_tmr_idx_1g < 0 || t4_tmr_idx_1g >= SGE_NTIMERS) 6983228561Snp t4_tmr_idx_1g = TMR_IDX_1G; 6984228561Snp 6985228561Snp if (t4_pktc_idx_1g < -1 || t4_pktc_idx_1g >= SGE_NCOUNTERS) 6986228561Snp t4_pktc_idx_1g = PKTC_IDX_1G; 6987228561Snp 6988228561Snp if (t4_qsize_txq < 128) 6989228561Snp t4_qsize_txq = 128; 6990228561Snp 6991228561Snp if (t4_qsize_rxq < 128) 6992228561Snp t4_qsize_rxq = 128; 6993228561Snp while (t4_qsize_rxq & 7) 6994228561Snp t4_qsize_rxq++; 6995228561Snp 6996228561Snp t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX; 6997228561Snp} 6998228561Snp 6999228561Snpstatic int 7000219392Snpt4_mod_event(module_t mod, int cmd, void *arg) 7001219392Snp{ 7002228561Snp int rc = 0; 7003219392Snp 7004228561Snp switch (cmd) { 7005228561Snp case MOD_LOAD: 7006219392Snp t4_sge_modload(); 7007228561Snp mtx_init(&t4_list_lock, "T4 adapters", 0, MTX_DEF); 7008228561Snp SLIST_INIT(&t4_list); 7009237263Snp#ifdef TCP_OFFLOAD 7010228561Snp mtx_init(&t4_uld_list_lock, "T4 ULDs", 0, MTX_DEF); 7011228561Snp SLIST_INIT(&t4_uld_list); 7012228561Snp#endif 7013228561Snp tweak_tunables(); 7014228561Snp break; 7015219392Snp 7016228561Snp case MOD_UNLOAD: 7017237263Snp#ifdef TCP_OFFLOAD 7018228561Snp mtx_lock(&t4_uld_list_lock); 7019228561Snp if (!SLIST_EMPTY(&t4_uld_list)) { 7020228561Snp rc = EBUSY; 7021228561Snp mtx_unlock(&t4_uld_list_lock); 7022228561Snp break; 7023228561Snp } 7024228561Snp mtx_unlock(&t4_uld_list_lock); 7025228561Snp mtx_destroy(&t4_uld_list_lock); 7026228561Snp#endif 7027228561Snp mtx_lock(&t4_list_lock); 7028228561Snp if (!SLIST_EMPTY(&t4_list)) { 7029228561Snp rc = EBUSY; 7030228561Snp mtx_unlock(&t4_list_lock); 7031228561Snp break; 7032228561Snp } 7033228561Snp mtx_unlock(&t4_list_lock); 7034228561Snp mtx_destroy(&t4_list_lock); 7035228561Snp break; 7036228561Snp } 7037228561Snp 7038228561Snp return (rc); 7039219392Snp} 7040219392Snp 7041248925Snpstatic devclass_t t4_devclass, t5_devclass; 7042248925Snpstatic devclass_t cxgbe_devclass, cxl_devclass; 7043218792Snp 7044219392SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, t4_mod_event, 0); 7045218792SnpMODULE_VERSION(t4nex, 1); 7046218792Snp 7047248925SnpDRIVER_MODULE(t5nex, pci, t5_driver, t5_devclass, 0, 0); 7048248925SnpMODULE_VERSION(t5nex, 1); 7049248925Snp 7050218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0); 7051218792SnpMODULE_VERSION(cxgbe, 1); 7052248925Snp 7053248925SnpDRIVER_MODULE(cxl, t5nex, cxl_driver, cxl_devclass, 0, 0); 7054248925SnpMODULE_VERSION(cxl, 1); 7055