1218792Snp/*- 2218792Snp * Copyright (c) 2011 Chelsio Communications, Inc. 3218792Snp * All rights reserved. 4218792Snp * Written by: Navdeep Parhar <np@FreeBSD.org> 5218792Snp * 6218792Snp * Redistribution and use in source and binary forms, with or without 7218792Snp * modification, are permitted provided that the following conditions 8218792Snp * are met: 9218792Snp * 1. Redistributions of source code must retain the above copyright 10218792Snp * notice, this list of conditions and the following disclaimer. 11218792Snp * 2. Redistributions in binary form must reproduce the above copyright 12218792Snp * notice, this list of conditions and the following disclaimer in the 13218792Snp * documentation and/or other materials provided with the distribution. 14218792Snp * 15218792Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16218792Snp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17218792Snp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18218792Snp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19218792Snp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20218792Snp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21218792Snp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22218792Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23218792Snp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24218792Snp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25218792Snp * SUCH DAMAGE. 26218792Snp */ 27218792Snp 28218792Snp#include <sys/cdefs.h> 29218792Snp__FBSDID("$FreeBSD$"); 30218792Snp 31218792Snp#include "opt_inet.h" 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 */ 163255006Snpstatic struct sx t4_list_lock; 164259241SnpSLIST_HEAD(, adapter) t4_list; 165237263Snp#ifdef TCP_OFFLOAD 166255006Snpstatic struct sx t4_uld_list_lock; 167259241SnpSLIST_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 200264493Sscottlstatic int t4_rsrv_noflowq = 0; 201264493SscottlTUNABLE_INT("hw.cxgbe.rsrv_noflowq", &t4_rsrv_noflowq); 202264493Sscottl 203237263Snp#ifdef TCP_OFFLOAD 204228561Snp#define NOFLDTXQ_10G 8 205228561Snpstatic int t4_nofldtxq10g = -1; 206228561SnpTUNABLE_INT("hw.cxgbe.nofldtxq10g", &t4_nofldtxq10g); 207228561Snp 208228561Snp#define NOFLDRXQ_10G 2 209228561Snpstatic int t4_nofldrxq10g = -1; 210228561SnpTUNABLE_INT("hw.cxgbe.nofldrxq10g", &t4_nofldrxq10g); 211228561Snp 212228561Snp#define NOFLDTXQ_1G 2 213228561Snpstatic int t4_nofldtxq1g = -1; 214228561SnpTUNABLE_INT("hw.cxgbe.nofldtxq1g", &t4_nofldtxq1g); 215228561Snp 216228561Snp#define NOFLDRXQ_1G 1 217228561Snpstatic int t4_nofldrxq1g = -1; 218228561SnpTUNABLE_INT("hw.cxgbe.nofldrxq1g", &t4_nofldrxq1g); 219228561Snp#endif 220228561Snp 221270297Snp#ifdef DEV_NETMAP 222270297Snp#define NNMTXQ_10G 2 223270297Snpstatic int t4_nnmtxq10g = -1; 224270297SnpTUNABLE_INT("hw.cxgbe.nnmtxq10g", &t4_nnmtxq10g); 225270297Snp 226270297Snp#define NNMRXQ_10G 2 227270297Snpstatic int t4_nnmrxq10g = -1; 228270297SnpTUNABLE_INT("hw.cxgbe.nnmrxq10g", &t4_nnmrxq10g); 229270297Snp 230270297Snp#define NNMTXQ_1G 1 231270297Snpstatic int t4_nnmtxq1g = -1; 232270297SnpTUNABLE_INT("hw.cxgbe.nnmtxq1g", &t4_nnmtxq1g); 233270297Snp 234270297Snp#define NNMRXQ_1G 1 235270297Snpstatic int t4_nnmrxq1g = -1; 236270297SnpTUNABLE_INT("hw.cxgbe.nnmrxq1g", &t4_nnmrxq1g); 237270297Snp#endif 238270297Snp 239218792Snp/* 240218792Snp * Holdoff parameters for 10G and 1G ports. 241218792Snp */ 242228561Snp#define TMR_IDX_10G 1 243228561Snpstatic int t4_tmr_idx_10g = TMR_IDX_10G; 244228561SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_10G", &t4_tmr_idx_10g); 245218792Snp 246234833Snp#define PKTC_IDX_10G (-1) 247228561Snpstatic int t4_pktc_idx_10g = PKTC_IDX_10G; 248228561SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_10G", &t4_pktc_idx_10g); 249218792Snp 250228561Snp#define TMR_IDX_1G 1 251228561Snpstatic int t4_tmr_idx_1g = TMR_IDX_1G; 252228561SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_1G", &t4_tmr_idx_1g); 253218792Snp 254234833Snp#define PKTC_IDX_1G (-1) 255228561Snpstatic int t4_pktc_idx_1g = PKTC_IDX_1G; 256228561SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_1G", &t4_pktc_idx_1g); 257218792Snp 258218792Snp/* 259218792Snp * Size (# of entries) of each tx and rx queue. 260218792Snp */ 261228561Snpstatic unsigned int t4_qsize_txq = TX_EQ_QSIZE; 262228561SnpTUNABLE_INT("hw.cxgbe.qsize_txq", &t4_qsize_txq); 263218792Snp 264228561Snpstatic unsigned int t4_qsize_rxq = RX_IQ_QSIZE; 265228561SnpTUNABLE_INT("hw.cxgbe.qsize_rxq", &t4_qsize_rxq); 266218792Snp 267218792Snp/* 268228561Snp * Interrupt types allowed (bits 0, 1, 2 = INTx, MSI, MSI-X respectively). 269218792Snp */ 270228561Snpstatic int t4_intr_types = INTR_MSIX | INTR_MSI | INTR_INTX; 271228561SnpTUNABLE_INT("hw.cxgbe.interrupt_types", &t4_intr_types); 272218792Snp 273218792Snp/* 274228561Snp * Configuration file. 275218792Snp */ 276248925Snp#define DEFAULT_CF "default" 277248925Snp#define FLASH_CF "flash" 278248925Snp#define UWIRE_CF "uwire" 279249376Snp#define FPGA_CF "fpga" 280248925Snpstatic char t4_cfg_file[32] = DEFAULT_CF; 281228561SnpTUNABLE_STR("hw.cxgbe.config_file", t4_cfg_file, sizeof(t4_cfg_file)); 282218792Snp 283228561Snp/* 284271961Snp * PAUSE settings (bit 0, 1 = rx_pause, tx_pause respectively). 285271961Snp * rx_pause = 1 to heed incoming PAUSE frames, 0 to ignore them. 286271961Snp * tx_pause = 1 to emit PAUSE frames when the rx FIFO reaches its high water 287271961Snp * mark or when signalled to do so, 0 to never emit PAUSE. 288271961Snp */ 289271961Snpstatic int t4_pause_settings = PAUSE_TX | PAUSE_RX; 290271961SnpTUNABLE_INT("hw.cxgbe.pause_settings", &t4_pause_settings); 291271961Snp 292271961Snp/* 293247347Snp * Firmware auto-install by driver during attach (0, 1, 2 = prohibited, allowed, 294247347Snp * encouraged respectively). 295247347Snp */ 296247347Snpstatic unsigned int t4_fw_install = 1; 297247347SnpTUNABLE_INT("hw.cxgbe.fw_install", &t4_fw_install); 298247347Snp 299247347Snp/* 300228561Snp * ASIC features that will be used. Disable the ones you don't want so that the 301228561Snp * chip resources aren't wasted on features that will not be used. 302228561Snp */ 303228561Snpstatic int t4_linkcaps_allowed = 0; /* No DCBX, PPP, etc. by default */ 304228561SnpTUNABLE_INT("hw.cxgbe.linkcaps_allowed", &t4_linkcaps_allowed); 305221474Snp 306228561Snpstatic int t4_niccaps_allowed = FW_CAPS_CONFIG_NIC; 307228561SnpTUNABLE_INT("hw.cxgbe.niccaps_allowed", &t4_niccaps_allowed); 308228561Snp 309238028Snpstatic int t4_toecaps_allowed = -1; 310228561SnpTUNABLE_INT("hw.cxgbe.toecaps_allowed", &t4_toecaps_allowed); 311228561Snp 312228561Snpstatic int t4_rdmacaps_allowed = 0; 313228561SnpTUNABLE_INT("hw.cxgbe.rdmacaps_allowed", &t4_rdmacaps_allowed); 314228561Snp 315228561Snpstatic int t4_iscsicaps_allowed = 0; 316228561SnpTUNABLE_INT("hw.cxgbe.iscsicaps_allowed", &t4_iscsicaps_allowed); 317228561Snp 318228561Snpstatic int t4_fcoecaps_allowed = 0; 319228561SnpTUNABLE_INT("hw.cxgbe.fcoecaps_allowed", &t4_fcoecaps_allowed); 320228561Snp 321248925Snpstatic int t5_write_combine = 0; 322248925SnpTUNABLE_INT("hw.cxl.write_combine", &t5_write_combine); 323248925Snp 324218792Snpstruct intrs_and_queues { 325270297Snp uint16_t intr_type; /* INTx, MSI, or MSI-X */ 326270297Snp uint16_t nirq; /* Total # of vectors */ 327270297Snp uint16_t intr_flags_10g;/* Interrupt flags for each 10G port */ 328270297Snp uint16_t intr_flags_1g; /* Interrupt flags for each 1G port */ 329270297Snp uint16_t ntxq10g; /* # of NIC txq's for each 10G port */ 330270297Snp uint16_t nrxq10g; /* # of NIC rxq's for each 10G port */ 331270297Snp uint16_t ntxq1g; /* # of NIC txq's for each 1G port */ 332270297Snp uint16_t nrxq1g; /* # of NIC rxq's for each 1G port */ 333270297Snp uint16_t rsrv_noflowq; /* Flag whether to reserve queue 0 */ 334237263Snp#ifdef TCP_OFFLOAD 335270297Snp uint16_t nofldtxq10g; /* # of TOE txq's for each 10G port */ 336270297Snp uint16_t nofldrxq10g; /* # of TOE rxq's for each 10G port */ 337270297Snp uint16_t nofldtxq1g; /* # of TOE txq's for each 1G port */ 338270297Snp uint16_t nofldrxq1g; /* # of TOE rxq's for each 1G port */ 339228561Snp#endif 340270297Snp#ifdef DEV_NETMAP 341270297Snp uint16_t nnmtxq10g; /* # of netmap txq's for each 10G port */ 342270297Snp uint16_t nnmrxq10g; /* # of netmap rxq's for each 10G port */ 343270297Snp uint16_t nnmtxq1g; /* # of netmap txq's for each 1G port */ 344270297Snp uint16_t nnmrxq1g; /* # of netmap rxq's for each 1G port */ 345270297Snp#endif 346218792Snp}; 347218792Snp 348221474Snpstruct filter_entry { 349221474Snp uint32_t valid:1; /* filter allocated and valid */ 350221474Snp uint32_t locked:1; /* filter is administratively locked */ 351221474Snp uint32_t pending:1; /* filter action is pending firmware reply */ 352221474Snp uint32_t smtidx:8; /* Source MAC Table index for smac */ 353222509Snp struct l2t_entry *l2t; /* Layer Two Table entry for dmac */ 354221474Snp 355221474Snp struct t4_filter_specification fs; 356221474Snp}; 357221474Snp 358248925Snpstatic int map_bars_0_and_4(struct adapter *); 359248925Snpstatic int map_bar_2(struct adapter *); 360218792Snpstatic void setup_memwin(struct adapter *); 361248925Snpstatic int validate_mem_range(struct adapter *, uint32_t, int); 362256791Snpstatic int fwmtype_to_hwmtype(int); 363248925Snpstatic int validate_mt_off_len(struct adapter *, int, uint32_t, int, 364248925Snp uint32_t *); 365248925Snpstatic void memwin_info(struct adapter *, int, uint32_t *, uint32_t *); 366248925Snpstatic uint32_t position_memwin(struct adapter *, int, uint32_t); 367218792Snpstatic int cfg_itype_and_nqueues(struct adapter *, int, int, 368218792Snp struct intrs_and_queues *); 369218792Snpstatic int prep_firmware(struct adapter *); 370248925Snpstatic int partition_resources(struct adapter *, const struct firmware *, 371248925Snp const char *); 372228561Snpstatic int get_params__pre_init(struct adapter *); 373228561Snpstatic int get_params__post_init(struct adapter *); 374247291Snpstatic int set_params__post_init(struct adapter *); 375218792Snpstatic void t4_set_desc(struct adapter *); 376270297Snpstatic void build_medialist(struct port_info *, struct ifmedia *); 377218792Snpstatic int cxgbe_init_synchronized(struct port_info *); 378218792Snpstatic int cxgbe_uninit_synchronized(struct port_info *); 379240453Snpstatic int setup_intr_handlers(struct adapter *); 380228561Snpstatic void quiesce_eq(struct adapter *, struct sge_eq *); 381228561Snpstatic void quiesce_iq(struct adapter *, struct sge_iq *); 382228561Snpstatic void quiesce_fl(struct adapter *, struct sge_fl *); 383218792Snpstatic int t4_alloc_irq(struct adapter *, struct irq *, int rid, 384228561Snp driver_intr_t *, void *, char *); 385218792Snpstatic int t4_free_irq(struct adapter *, struct irq *); 386218792Snpstatic void reg_block_dump(struct adapter *, uint8_t *, unsigned int, 387218792Snp unsigned int); 388218792Snpstatic void t4_get_regs(struct adapter *, struct t4_regdump *, uint8_t *); 389218792Snpstatic void cxgbe_tick(void *); 390237263Snpstatic void cxgbe_vlan_config(void *, struct ifnet *, uint16_t); 391228561Snpstatic int cpl_not_handled(struct sge_iq *, const struct rss_header *, 392228561Snp struct mbuf *); 393237263Snpstatic int an_not_handled(struct sge_iq *, const struct rsp_ctrl *); 394239336Snpstatic int fw_msg_not_handled(struct adapter *, const __be64 *); 395218792Snpstatic int t4_sysctls(struct adapter *); 396218792Snpstatic int cxgbe_sysctls(struct port_info *); 397219436Snpstatic int sysctl_int_array(SYSCTL_HANDLER_ARGS); 398228561Snpstatic int sysctl_bitfield(SYSCTL_HANDLER_ARGS); 399252747Snpstatic int sysctl_btphy(SYSCTL_HANDLER_ARGS); 400264493Sscottlstatic int sysctl_noflowq(SYSCTL_HANDLER_ARGS); 401218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS); 402218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS); 403218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS); 404218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS); 405271961Snpstatic int sysctl_pause_settings(SYSCTL_HANDLER_ARGS); 406218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS); 407253890Snpstatic int sysctl_temperature(SYSCTL_HANDLER_ARGS); 408231115Snp#ifdef SBUF_DRAIN 409228561Snpstatic int sysctl_cctrl(SYSCTL_HANDLER_ARGS); 410247122Snpstatic int sysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS); 411247122Snpstatic int sysctl_cim_la(SYSCTL_HANDLER_ARGS); 412251213Snpstatic int sysctl_cim_ma_la(SYSCTL_HANDLER_ARGS); 413251213Snpstatic int sysctl_cim_pif_la(SYSCTL_HANDLER_ARGS); 414247122Snpstatic int sysctl_cim_qcfg(SYSCTL_HANDLER_ARGS); 415228561Snpstatic int sysctl_cpl_stats(SYSCTL_HANDLER_ARGS); 416228561Snpstatic int sysctl_ddp_stats(SYSCTL_HANDLER_ARGS); 417222551Snpstatic int sysctl_devlog(SYSCTL_HANDLER_ARGS); 418228561Snpstatic int sysctl_fcoe_stats(SYSCTL_HANDLER_ARGS); 419228561Snpstatic int sysctl_hw_sched(SYSCTL_HANDLER_ARGS); 420228561Snpstatic int sysctl_lb_stats(SYSCTL_HANDLER_ARGS); 421253701Snpstatic int sysctl_linkdnrc(SYSCTL_HANDLER_ARGS); 422228561Snpstatic int sysctl_meminfo(SYSCTL_HANDLER_ARGS); 423251213Snpstatic int sysctl_mps_tcam(SYSCTL_HANDLER_ARGS); 424228561Snpstatic int sysctl_path_mtus(SYSCTL_HANDLER_ARGS); 425228561Snpstatic int sysctl_pm_stats(SYSCTL_HANDLER_ARGS); 426228561Snpstatic int sysctl_rdma_stats(SYSCTL_HANDLER_ARGS); 427228561Snpstatic int sysctl_tcp_stats(SYSCTL_HANDLER_ARGS); 428228561Snpstatic int sysctl_tids(SYSCTL_HANDLER_ARGS); 429228561Snpstatic int sysctl_tp_err_stats(SYSCTL_HANDLER_ARGS); 430251213Snpstatic int sysctl_tp_la(SYSCTL_HANDLER_ARGS); 431228561Snpstatic int sysctl_tx_rate(SYSCTL_HANDLER_ARGS); 432251213Snpstatic int sysctl_ulprx_la(SYSCTL_HANDLER_ARGS); 433249392Snpstatic int sysctl_wcwr_stats(SYSCTL_HANDLER_ARGS); 434231115Snp#endif 435219286Snpstatic inline void txq_start(struct ifnet *, struct sge_txq *); 436221474Snpstatic uint32_t fconf_to_mode(uint32_t); 437221474Snpstatic uint32_t mode_to_fconf(uint32_t); 438221474Snpstatic uint32_t fspec_to_fconf(struct t4_filter_specification *); 439221474Snpstatic int get_filter_mode(struct adapter *, uint32_t *); 440221474Snpstatic int set_filter_mode(struct adapter *, uint32_t); 441222552Snpstatic inline uint64_t get_filter_hits(struct adapter *, uint32_t); 442221474Snpstatic int get_filter(struct adapter *, struct t4_filter *); 443221474Snpstatic int set_filter(struct adapter *, struct t4_filter *); 444221474Snpstatic int del_filter(struct adapter *, struct t4_filter *); 445222509Snpstatic void clear_filter(struct filter_entry *); 446221474Snpstatic int set_filter_wr(struct adapter *, int); 447221474Snpstatic int del_filter_wr(struct adapter *, int); 448222973Snpstatic int get_sge_context(struct adapter *, struct t4_sge_context *); 449245274Snpstatic int load_fw(struct adapter *, struct t4_data *); 450248925Snpstatic int read_card_mem(struct adapter *, int, struct t4_mem_range *); 451241399Snpstatic int read_i2c(struct adapter *, struct t4_i2c_data *); 452259142Snpstatic int set_sched_class(struct adapter *, struct t4_sched_params *); 453259142Snpstatic int set_sched_queue(struct adapter *, struct t4_sched_queue *); 454237263Snp#ifdef TCP_OFFLOAD 455228561Snpstatic int toe_capability(struct port_info *, int); 456228561Snp#endif 457249370Snpstatic int mod_event(module_t, int, void *); 458218792Snp 459248925Snpstruct { 460218792Snp uint16_t device; 461218792Snp char *desc; 462218792Snp} t4_pciids[] = { 463237587Snp {0xa000, "Chelsio Terminator 4 FPGA"}, 464237587Snp {0x4400, "Chelsio T440-dbg"}, 465237587Snp {0x4401, "Chelsio T420-CR"}, 466237587Snp {0x4402, "Chelsio T422-CR"}, 467237587Snp {0x4403, "Chelsio T440-CR"}, 468237587Snp {0x4404, "Chelsio T420-BCH"}, 469237587Snp {0x4405, "Chelsio T440-BCH"}, 470237587Snp {0x4406, "Chelsio T440-CH"}, 471237587Snp {0x4407, "Chelsio T420-SO"}, 472237587Snp {0x4408, "Chelsio T420-CX"}, 473237587Snp {0x4409, "Chelsio T420-BT"}, 474237587Snp {0x440a, "Chelsio T404-BT"}, 475244580Snp {0x440e, "Chelsio T440-LP-CR"}, 476248925Snp}, t5_pciids[] = { 477248925Snp {0xb000, "Chelsio Terminator 5 FPGA"}, 478248925Snp {0x5400, "Chelsio T580-dbg"}, 479253699Snp {0x5401, "Chelsio T520-CR"}, /* 2 x 10G */ 480253699Snp {0x5402, "Chelsio T522-CR"}, /* 2 x 10G, 2 X 1G */ 481253217Snp {0x5403, "Chelsio T540-CR"}, /* 4 x 10G */ 482253699Snp {0x5407, "Chelsio T520-SO"}, /* 2 x 10G, nomem */ 483253699Snp {0x5409, "Chelsio T520-BT"}, /* 2 x 10GBaseT */ 484253699Snp {0x540a, "Chelsio T504-BT"}, /* 4 x 1G */ 485253699Snp {0x540d, "Chelsio T580-CR"}, /* 2 x 40G */ 486253699Snp {0x540e, "Chelsio T540-LP-CR"}, /* 4 x 10G */ 487250093Snp {0x5410, "Chelsio T580-LP-CR"}, /* 2 x 40G */ 488253699Snp {0x5411, "Chelsio T520-LL-CR"}, /* 2 x 10G */ 489253699Snp {0x5412, "Chelsio T560-CR"}, /* 1 x 40G, 2 x 10G */ 490253699Snp {0x5414, "Chelsio T580-LP-SO-CR"}, /* 2 x 40G, nomem */ 491249393Snp#ifdef notyet 492249393Snp {0x5404, "Chelsio T520-BCH"}, 493249393Snp {0x5405, "Chelsio T540-BCH"}, 494249393Snp {0x5406, "Chelsio T540-CH"}, 495253699Snp {0x5408, "Chelsio T520-CX"}, 496249393Snp {0x540b, "Chelsio B520-SR"}, 497249393Snp {0x540c, "Chelsio B504-BT"}, 498249393Snp {0x540f, "Chelsio Amsterdam"}, 499253699Snp {0x5413, "Chelsio T580-CHR"}, 500249393Snp#endif 501218792Snp}; 502218792Snp 503237263Snp#ifdef TCP_OFFLOAD 504237263Snp/* 505237263Snp * service_iq() has an iq and needs the fl. Offset of fl from the iq should be 506237263Snp * exactly the same for both rxq and ofld_rxq. 507237263Snp */ 508237263SnpCTASSERT(offsetof(struct sge_ofld_rxq, iq) == offsetof(struct sge_rxq, iq)); 509228561SnpCTASSERT(offsetof(struct sge_ofld_rxq, fl) == offsetof(struct sge_rxq, fl)); 510228561Snp#endif 511228561Snp 512239336Snp/* No easy way to include t4_msg.h before adapter.h so we check this way */ 513240452SnpCTASSERT(nitems(((struct adapter *)0)->cpl_handler) == NUM_CPL_CMDS); 514240452SnpCTASSERT(nitems(((struct adapter *)0)->fw_msg_handler) == NUM_FW6_TYPES); 515239336Snp 516265425SnpCTASSERT(sizeof(struct cluster_metadata) <= CL_METADATA_SIZE); 517265425Snp 518218792Snpstatic int 519218792Snpt4_probe(device_t dev) 520218792Snp{ 521218792Snp int i; 522218792Snp uint16_t v = pci_get_vendor(dev); 523218792Snp uint16_t d = pci_get_device(dev); 524237587Snp uint8_t f = pci_get_function(dev); 525218792Snp 526218792Snp if (v != PCI_VENDOR_ID_CHELSIO) 527218792Snp return (ENXIO); 528218792Snp 529237587Snp /* Attach only to PF0 of the FPGA */ 530237587Snp if (d == 0xa000 && f != 0) 531237587Snp return (ENXIO); 532237587Snp 533240452Snp for (i = 0; i < nitems(t4_pciids); i++) { 534237587Snp if (d == t4_pciids[i].device) { 535218792Snp device_set_desc(dev, t4_pciids[i].desc); 536218792Snp return (BUS_PROBE_DEFAULT); 537218792Snp } 538218792Snp } 539218792Snp 540218792Snp return (ENXIO); 541218792Snp} 542218792Snp 543218792Snpstatic int 544248925Snpt5_probe(device_t dev) 545248925Snp{ 546248925Snp int i; 547248925Snp uint16_t v = pci_get_vendor(dev); 548248925Snp uint16_t d = pci_get_device(dev); 549248925Snp uint8_t f = pci_get_function(dev); 550248925Snp 551248925Snp if (v != PCI_VENDOR_ID_CHELSIO) 552248925Snp return (ENXIO); 553248925Snp 554248925Snp /* Attach only to PF0 of the FPGA */ 555248925Snp if (d == 0xb000 && f != 0) 556248925Snp return (ENXIO); 557248925Snp 558248925Snp for (i = 0; i < nitems(t5_pciids); i++) { 559248925Snp if (d == t5_pciids[i].device) { 560248925Snp device_set_desc(dev, t5_pciids[i].desc); 561248925Snp return (BUS_PROBE_DEFAULT); 562248925Snp } 563248925Snp } 564248925Snp 565248925Snp return (ENXIO); 566248925Snp} 567248925Snp 568248925Snpstatic int 569218792Snpt4_attach(device_t dev) 570218792Snp{ 571218792Snp struct adapter *sc; 572218792Snp int rc = 0, i, n10g, n1g, rqidx, tqidx; 573218792Snp struct intrs_and_queues iaq; 574218792Snp struct sge *s; 575237263Snp#ifdef TCP_OFFLOAD 576228561Snp int ofld_rqidx, ofld_tqidx; 577228561Snp#endif 578270297Snp#ifdef DEV_NETMAP 579270297Snp int nm_rqidx, nm_tqidx; 580270297Snp#endif 581218792Snp 582218792Snp sc = device_get_softc(dev); 583218792Snp sc->dev = dev; 584218792Snp 585218792Snp pci_enable_busmaster(dev); 586222085Snp if (pci_find_cap(dev, PCIY_EXPRESS, &i) == 0) { 587228561Snp uint32_t v; 588228561Snp 589222085Snp pci_set_max_read_req(dev, 4096); 590240680Sgavin v = pci_read_config(dev, i + PCIER_DEVICE_CTL, 2); 591240680Sgavin v |= PCIEM_CTL_RELAXED_ORD_ENABLE; 592240680Sgavin pci_write_config(dev, i + PCIER_DEVICE_CTL, v, 2); 593222085Snp } 594222085Snp 595253691Snp sc->traceq = -1; 596253691Snp mtx_init(&sc->ifp_lock, sc->ifp_lockname, 0, MTX_DEF); 597253691Snp snprintf(sc->ifp_lockname, sizeof(sc->ifp_lockname), "%s tracer", 598253691Snp device_get_nameunit(dev)); 599253691Snp 600218792Snp snprintf(sc->lockname, sizeof(sc->lockname), "%s", 601218792Snp device_get_nameunit(dev)); 602218792Snp mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF); 603255006Snp sx_xlock(&t4_list_lock); 604228561Snp SLIST_INSERT_HEAD(&t4_list, sc, link); 605255006Snp sx_xunlock(&t4_list_lock); 606218792Snp 607228561Snp mtx_init(&sc->sfl_lock, "starving freelists", 0, MTX_DEF); 608228561Snp TAILQ_INIT(&sc->sfl); 609228561Snp callout_init(&sc->sfl_callout, CALLOUT_MPSAFE); 610228561Snp 611248925Snp rc = map_bars_0_and_4(sc); 612218792Snp if (rc != 0) 613218792Snp goto done; /* error message displayed already */ 614218792Snp 615237587Snp /* 616237587Snp * This is the real PF# to which we're attaching. Works from within PCI 617237587Snp * passthrough environments too, where pci_get_function() could return a 618237587Snp * different PF# depending on the passthrough configuration. We need to 619237587Snp * use the real PF# in all our communication with the firmware. 620237587Snp */ 621237587Snp sc->pf = G_SOURCEPF(t4_read_reg(sc, A_PL_WHOAMI)); 622237587Snp sc->mbox = sc->pf; 623237587Snp 624218792Snp memset(sc->chan_map, 0xff, sizeof(sc->chan_map)); 625237263Snp sc->an_handler = an_not_handled; 626240452Snp for (i = 0; i < nitems(sc->cpl_handler); i++) 627228561Snp sc->cpl_handler[i] = cpl_not_handled; 628240452Snp for (i = 0; i < nitems(sc->fw_msg_handler); i++) 629239336Snp sc->fw_msg_handler[i] = fw_msg_not_handled; 630239338Snp t4_register_cpl_handler(sc, CPL_SET_TCB_RPL, t4_filter_rpl); 631253691Snp t4_register_cpl_handler(sc, CPL_TRACE_PKT, t4_trace_pkt); 632253691Snp t4_register_cpl_handler(sc, CPL_TRACE_PKT_T5, t5_trace_pkt); 633248925Snp t4_init_sge_cpl_handlers(sc); 634218792Snp 635218792Snp /* Prepare the adapter for operation */ 636218792Snp rc = -t4_prep_adapter(sc); 637218792Snp if (rc != 0) { 638218792Snp device_printf(dev, "failed to prepare adapter: %d.\n", rc); 639218792Snp goto done; 640218792Snp } 641218792Snp 642228561Snp /* 643228561Snp * Do this really early, with the memory windows set up even before the 644228561Snp * character device. The userland tool's register i/o and mem read 645228561Snp * will work even in "recovery mode". 646228561Snp */ 647228561Snp setup_memwin(sc); 648248925Snp sc->cdev = make_dev(is_t4(sc) ? &t4_cdevsw : &t5_cdevsw, 649248925Snp device_get_unit(dev), UID_ROOT, GID_WHEEL, 0600, "%s", 650248925Snp device_get_nameunit(dev)); 651248925Snp if (sc->cdev == NULL) 652248925Snp device_printf(dev, "failed to create nexus char device.\n"); 653248925Snp else 654248925Snp sc->cdev->si_drv1 = sc; 655218792Snp 656228561Snp /* Go no further if recovery mode has been requested. */ 657228561Snp if (TUNABLE_INT_FETCH("hw.cxgbe.sos", &i) && i != 0) { 658228561Snp device_printf(dev, "recovery mode.\n"); 659228561Snp goto done; 660228561Snp } 661228561Snp 662218792Snp /* Prepare the firmware for operation */ 663218792Snp rc = prep_firmware(sc); 664218792Snp if (rc != 0) 665218792Snp goto done; /* error message displayed already */ 666218792Snp 667248925Snp rc = get_params__post_init(sc); 668228561Snp if (rc != 0) 669228561Snp goto done; /* error message displayed already */ 670222551Snp 671248925Snp rc = set_params__post_init(sc); 672228561Snp if (rc != 0) 673228561Snp goto done; /* error message displayed already */ 674218792Snp 675248925Snp rc = map_bar_2(sc); 676228561Snp if (rc != 0) 677228561Snp goto done; /* error message displayed already */ 678218792Snp 679218792Snp rc = t4_create_dma_tag(sc); 680218792Snp if (rc != 0) 681218792Snp goto done; /* error message displayed already */ 682218792Snp 683218792Snp /* 684218792Snp * First pass over all the ports - allocate VIs and initialize some 685218792Snp * basic parameters like mac address, port type, etc. We also figure 686218792Snp * out whether a port is 10G or 1G and use that information when 687218792Snp * calculating how many interrupts to attempt to allocate. 688218792Snp */ 689218792Snp n10g = n1g = 0; 690218792Snp for_each_port(sc, i) { 691218792Snp struct port_info *pi; 692218792Snp 693218792Snp pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK); 694218792Snp sc->port[i] = pi; 695218792Snp 696218792Snp /* These must be set before t4_port_init */ 697218792Snp pi->adapter = sc; 698218792Snp pi->port_id = i; 699218792Snp 700218792Snp /* Allocate the vi and initialize parameters like mac addr */ 701218792Snp rc = -t4_port_init(pi, sc->mbox, sc->pf, 0); 702218792Snp if (rc != 0) { 703218792Snp device_printf(dev, "unable to initialize port %d: %d\n", 704218792Snp i, rc); 705218792Snp free(pi, M_CXGBE); 706222510Snp sc->port[i] = NULL; 707222510Snp goto done; 708218792Snp } 709271961Snp 710271961Snp pi->link_cfg.requested_fc &= ~(PAUSE_TX | PAUSE_RX); 711271961Snp pi->link_cfg.requested_fc |= t4_pause_settings; 712271961Snp pi->link_cfg.fc &= ~(PAUSE_TX | PAUSE_RX); 713271961Snp pi->link_cfg.fc |= t4_pause_settings; 714271961Snp 715270297Snp rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg); 716270297Snp if (rc != 0) { 717270297Snp device_printf(dev, "port %d l1cfg failed: %d\n", i, rc); 718270297Snp free(pi, M_CXGBE); 719270297Snp sc->port[i] = NULL; 720270297Snp goto done; 721270297Snp } 722218792Snp 723218792Snp snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d", 724218792Snp device_get_nameunit(dev), i); 725218792Snp mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF); 726253691Snp sc->chan_map[pi->tx_chan] = i; 727218792Snp 728250092Snp if (is_10G_port(pi) || is_40G_port(pi)) { 729218792Snp n10g++; 730228561Snp pi->tmr_idx = t4_tmr_idx_10g; 731228561Snp pi->pktc_idx = t4_pktc_idx_10g; 732218792Snp } else { 733218792Snp n1g++; 734228561Snp pi->tmr_idx = t4_tmr_idx_1g; 735228561Snp pi->pktc_idx = t4_pktc_idx_1g; 736218792Snp } 737218792Snp 738218792Snp pi->xact_addr_filt = -1; 739252747Snp pi->linkdnrc = -1; 740218792Snp 741228561Snp pi->qsize_rxq = t4_qsize_rxq; 742228561Snp pi->qsize_txq = t4_qsize_txq; 743218792Snp 744248925Snp pi->dev = device_add_child(dev, is_t4(sc) ? "cxgbe" : "cxl", -1); 745218792Snp if (pi->dev == NULL) { 746218792Snp device_printf(dev, 747218792Snp "failed to add device for port %d.\n", i); 748218792Snp rc = ENXIO; 749218792Snp goto done; 750218792Snp } 751218792Snp device_set_softc(pi->dev, pi); 752218792Snp } 753218792Snp 754218792Snp /* 755218792Snp * Interrupt type, # of interrupts, # of rx/tx queues, etc. 756218792Snp */ 757218792Snp rc = cfg_itype_and_nqueues(sc, n10g, n1g, &iaq); 758218792Snp if (rc != 0) 759218792Snp goto done; /* error message displayed already */ 760218792Snp 761218792Snp sc->intr_type = iaq.intr_type; 762218792Snp sc->intr_count = iaq.nirq; 763218792Snp 764218792Snp s = &sc->sge; 765218792Snp s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g; 766218792Snp s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g; 767220873Snp s->neq = s->ntxq + s->nrxq; /* the free list in an rxq is an eq */ 768228561Snp s->neq += sc->params.nports + 1;/* ctrl queues: 1 per port + 1 mgmt */ 769218792Snp s->niq = s->nrxq + 1; /* 1 extra for firmware event queue */ 770237263Snp#ifdef TCP_OFFLOAD 771228561Snp if (is_offload(sc)) { 772228561Snp s->nofldrxq = n10g * iaq.nofldrxq10g + n1g * iaq.nofldrxq1g; 773228561Snp s->nofldtxq = n10g * iaq.nofldtxq10g + n1g * iaq.nofldtxq1g; 774228561Snp s->neq += s->nofldtxq + s->nofldrxq; 775228561Snp s->niq += s->nofldrxq; 776228561Snp 777228561Snp s->ofld_rxq = malloc(s->nofldrxq * sizeof(struct sge_ofld_rxq), 778228561Snp M_CXGBE, M_ZERO | M_WAITOK); 779228561Snp s->ofld_txq = malloc(s->nofldtxq * sizeof(struct sge_wrq), 780228561Snp M_CXGBE, M_ZERO | M_WAITOK); 781228561Snp } 782228561Snp#endif 783270297Snp#ifdef DEV_NETMAP 784270297Snp s->nnmrxq = n10g * iaq.nnmrxq10g + n1g * iaq.nnmrxq1g; 785270297Snp s->nnmtxq = n10g * iaq.nnmtxq10g + n1g * iaq.nnmtxq1g; 786270297Snp s->neq += s->nnmtxq + s->nnmrxq; 787270297Snp s->niq += s->nnmrxq; 788228561Snp 789270297Snp s->nm_rxq = malloc(s->nnmrxq * sizeof(struct sge_nm_rxq), 790270297Snp M_CXGBE, M_ZERO | M_WAITOK); 791270297Snp s->nm_txq = malloc(s->nnmtxq * sizeof(struct sge_nm_txq), 792270297Snp M_CXGBE, M_ZERO | M_WAITOK); 793270297Snp#endif 794270297Snp 795228561Snp s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_wrq), M_CXGBE, 796220873Snp M_ZERO | M_WAITOK); 797218792Snp s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE, 798218792Snp M_ZERO | M_WAITOK); 799218792Snp s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE, 800218792Snp M_ZERO | M_WAITOK); 801218792Snp s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE, 802218792Snp M_ZERO | M_WAITOK); 803218792Snp s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE, 804218792Snp M_ZERO | M_WAITOK); 805218792Snp 806218792Snp sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE, 807218792Snp M_ZERO | M_WAITOK); 808218792Snp 809228561Snp t4_init_l2t(sc, M_WAITOK); 810222509Snp 811218792Snp /* 812218792Snp * Second pass over the ports. This time we know the number of rx and 813218792Snp * tx queues that each port should get. 814218792Snp */ 815218792Snp rqidx = tqidx = 0; 816237263Snp#ifdef TCP_OFFLOAD 817228561Snp ofld_rqidx = ofld_tqidx = 0; 818228561Snp#endif 819270297Snp#ifdef DEV_NETMAP 820270297Snp nm_rqidx = nm_tqidx = 0; 821270297Snp#endif 822218792Snp for_each_port(sc, i) { 823218792Snp struct port_info *pi = sc->port[i]; 824218792Snp 825218792Snp if (pi == NULL) 826218792Snp continue; 827218792Snp 828218792Snp pi->first_rxq = rqidx; 829218792Snp pi->first_txq = tqidx; 830250092Snp if (is_10G_port(pi) || is_40G_port(pi)) { 831270297Snp pi->flags |= iaq.intr_flags_10g; 832228561Snp pi->nrxq = iaq.nrxq10g; 833228561Snp pi->ntxq = iaq.ntxq10g; 834228561Snp } else { 835270297Snp pi->flags |= iaq.intr_flags_1g; 836228561Snp pi->nrxq = iaq.nrxq1g; 837228561Snp pi->ntxq = iaq.ntxq1g; 838228561Snp } 839218792Snp 840264493Sscottl if (pi->ntxq > 1) 841264493Sscottl pi->rsrv_noflowq = iaq.rsrv_noflowq ? 1 : 0; 842264493Sscottl else 843264493Sscottl pi->rsrv_noflowq = 0; 844264493Sscottl 845218792Snp rqidx += pi->nrxq; 846218792Snp tqidx += pi->ntxq; 847237263Snp#ifdef TCP_OFFLOAD 848228561Snp if (is_offload(sc)) { 849228561Snp pi->first_ofld_rxq = ofld_rqidx; 850228561Snp pi->first_ofld_txq = ofld_tqidx; 851250092Snp if (is_10G_port(pi) || is_40G_port(pi)) { 852228561Snp pi->nofldrxq = iaq.nofldrxq10g; 853228561Snp pi->nofldtxq = iaq.nofldtxq10g; 854228561Snp } else { 855228561Snp pi->nofldrxq = iaq.nofldrxq1g; 856228561Snp pi->nofldtxq = iaq.nofldtxq1g; 857228561Snp } 858228561Snp ofld_rqidx += pi->nofldrxq; 859228561Snp ofld_tqidx += pi->nofldtxq; 860228561Snp } 861228561Snp#endif 862270297Snp#ifdef DEV_NETMAP 863270297Snp pi->first_nm_rxq = nm_rqidx; 864270297Snp pi->first_nm_txq = nm_tqidx; 865270297Snp if (is_10G_port(pi) || is_40G_port(pi)) { 866270297Snp pi->nnmrxq = iaq.nnmrxq10g; 867270297Snp pi->nnmtxq = iaq.nnmtxq10g; 868270297Snp } else { 869270297Snp pi->nnmrxq = iaq.nnmrxq1g; 870270297Snp pi->nnmtxq = iaq.nnmtxq1g; 871270297Snp } 872270297Snp nm_rqidx += pi->nnmrxq; 873270297Snp nm_tqidx += pi->nnmtxq; 874270297Snp#endif 875218792Snp } 876218792Snp 877240453Snp rc = setup_intr_handlers(sc); 878240453Snp if (rc != 0) { 879240453Snp device_printf(dev, 880240453Snp "failed to setup interrupt handlers: %d\n", rc); 881240453Snp goto done; 882240453Snp } 883240453Snp 884218792Snp rc = bus_generic_attach(dev); 885218792Snp if (rc != 0) { 886218792Snp device_printf(dev, 887218792Snp "failed to attach all child ports: %d\n", rc); 888218792Snp goto done; 889218792Snp } 890218792Snp 891218792Snp device_printf(dev, 892228561Snp "PCIe x%d, %d ports, %d %s interrupt%s, %d eq, %d iq\n", 893228561Snp sc->params.pci.width, sc->params.nports, sc->intr_count, 894228561Snp sc->intr_type == INTR_MSIX ? "MSI-X" : 895228561Snp (sc->intr_type == INTR_MSI ? "MSI" : "INTx"), 896228561Snp sc->intr_count > 1 ? "s" : "", sc->sge.neq, sc->sge.niq); 897228561Snp 898218792Snp t4_set_desc(sc); 899218792Snp 900218792Snpdone: 901228561Snp if (rc != 0 && sc->cdev) { 902228561Snp /* cdev was created and so cxgbetool works; recover that way. */ 903228561Snp device_printf(dev, 904228561Snp "error during attach, adapter is now in recovery mode.\n"); 905228561Snp rc = 0; 906228561Snp } 907228561Snp 908218792Snp if (rc != 0) 909218792Snp t4_detach(dev); 910228561Snp else 911228561Snp t4_sysctls(sc); 912218792Snp 913218792Snp return (rc); 914218792Snp} 915218792Snp 916218792Snp/* 917218792Snp * Idempotent 918218792Snp */ 919218792Snpstatic int 920218792Snpt4_detach(device_t dev) 921218792Snp{ 922218792Snp struct adapter *sc; 923218792Snp struct port_info *pi; 924228561Snp int i, rc; 925218792Snp 926218792Snp sc = device_get_softc(dev); 927218792Snp 928228561Snp if (sc->flags & FULL_INIT_DONE) 929228561Snp t4_intr_disable(sc); 930228561Snp 931228561Snp if (sc->cdev) { 932218792Snp destroy_dev(sc->cdev); 933228561Snp sc->cdev = NULL; 934228561Snp } 935218792Snp 936228561Snp rc = bus_generic_detach(dev); 937228561Snp if (rc) { 938228561Snp device_printf(dev, 939228561Snp "failed to detach child devices: %d\n", rc); 940228561Snp return (rc); 941228561Snp } 942228561Snp 943240453Snp for (i = 0; i < sc->intr_count; i++) 944240453Snp t4_free_irq(sc, &sc->irq[i]); 945240453Snp 946218792Snp for (i = 0; i < MAX_NPORTS; i++) { 947218792Snp pi = sc->port[i]; 948218792Snp if (pi) { 949270297Snp t4_free_vi(sc, sc->mbox, sc->pf, 0, pi->viid); 950218792Snp if (pi->dev) 951218792Snp device_delete_child(dev, pi->dev); 952218792Snp 953218792Snp mtx_destroy(&pi->pi_lock); 954218792Snp free(pi, M_CXGBE); 955218792Snp } 956218792Snp } 957218792Snp 958228561Snp if (sc->flags & FULL_INIT_DONE) 959228561Snp adapter_full_uninit(sc); 960228561Snp 961218792Snp if (sc->flags & FW_OK) 962218792Snp t4_fw_bye(sc, sc->mbox); 963218792Snp 964219944Snp if (sc->intr_type == INTR_MSI || sc->intr_type == INTR_MSIX) 965218792Snp pci_release_msi(dev); 966218792Snp 967218792Snp if (sc->regs_res) 968218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid, 969218792Snp sc->regs_res); 970218792Snp 971248925Snp if (sc->udbs_res) 972248925Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->udbs_rid, 973248925Snp sc->udbs_res); 974248925Snp 975218792Snp if (sc->msix_res) 976218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid, 977218792Snp sc->msix_res); 978218792Snp 979222509Snp if (sc->l2t) 980222509Snp t4_free_l2t(sc->l2t); 981222509Snp 982237263Snp#ifdef TCP_OFFLOAD 983228561Snp free(sc->sge.ofld_rxq, M_CXGBE); 984228561Snp free(sc->sge.ofld_txq, M_CXGBE); 985228561Snp#endif 986270297Snp#ifdef DEV_NETMAP 987270297Snp free(sc->sge.nm_rxq, M_CXGBE); 988270297Snp free(sc->sge.nm_txq, M_CXGBE); 989270297Snp#endif 990218792Snp free(sc->irq, M_CXGBE); 991218792Snp free(sc->sge.rxq, M_CXGBE); 992218792Snp free(sc->sge.txq, M_CXGBE); 993220873Snp free(sc->sge.ctrlq, M_CXGBE); 994218792Snp free(sc->sge.iqmap, M_CXGBE); 995218792Snp free(sc->sge.eqmap, M_CXGBE); 996221474Snp free(sc->tids.ftid_tab, M_CXGBE); 997218792Snp t4_destroy_dma_tag(sc); 998228561Snp if (mtx_initialized(&sc->sc_lock)) { 999255006Snp sx_xlock(&t4_list_lock); 1000228561Snp SLIST_REMOVE(&t4_list, sc, adapter, link); 1001255006Snp sx_xunlock(&t4_list_lock); 1002228561Snp mtx_destroy(&sc->sc_lock); 1003228561Snp } 1004218792Snp 1005245274Snp if (mtx_initialized(&sc->tids.ftid_lock)) 1006245274Snp mtx_destroy(&sc->tids.ftid_lock); 1007228561Snp if (mtx_initialized(&sc->sfl_lock)) 1008228561Snp mtx_destroy(&sc->sfl_lock); 1009253691Snp if (mtx_initialized(&sc->ifp_lock)) 1010253691Snp mtx_destroy(&sc->ifp_lock); 1011228561Snp 1012218792Snp bzero(sc, sizeof(*sc)); 1013218792Snp 1014218792Snp return (0); 1015218792Snp} 1016218792Snp 1017218792Snpstatic int 1018218792Snpcxgbe_probe(device_t dev) 1019218792Snp{ 1020218792Snp char buf[128]; 1021218792Snp struct port_info *pi = device_get_softc(dev); 1022218792Snp 1023228561Snp snprintf(buf, sizeof(buf), "port %d", pi->port_id); 1024218792Snp device_set_desc_copy(dev, buf); 1025218792Snp 1026218792Snp return (BUS_PROBE_DEFAULT); 1027218792Snp} 1028218792Snp 1029218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \ 1030218792Snp IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \ 1031256218Sglebius IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6 | IFCAP_HWSTATS) 1032237819Snp#define T4_CAP_ENABLE (T4_CAP) 1033218792Snp 1034218792Snpstatic int 1035218792Snpcxgbe_attach(device_t dev) 1036218792Snp{ 1037218792Snp struct port_info *pi = device_get_softc(dev); 1038218792Snp struct ifnet *ifp; 1039270297Snp char *s; 1040270297Snp int n, o; 1041218792Snp 1042218792Snp /* Allocate an ifnet and set it up */ 1043218792Snp ifp = if_alloc(IFT_ETHER); 1044218792Snp if (ifp == NULL) { 1045218792Snp device_printf(dev, "Cannot allocate ifnet\n"); 1046218792Snp return (ENOMEM); 1047218792Snp } 1048218792Snp pi->ifp = ifp; 1049218792Snp ifp->if_softc = pi; 1050218792Snp 1051218792Snp callout_init(&pi->tick, CALLOUT_MPSAFE); 1052218792Snp 1053218792Snp if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 1054218792Snp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 1055218792Snp 1056218792Snp ifp->if_init = cxgbe_init; 1057218792Snp ifp->if_ioctl = cxgbe_ioctl; 1058218792Snp ifp->if_transmit = cxgbe_transmit; 1059218792Snp ifp->if_qflush = cxgbe_qflush; 1060218792Snp 1061218792Snp ifp->if_capabilities = T4_CAP; 1062237263Snp#ifdef TCP_OFFLOAD 1063228561Snp if (is_offload(pi->adapter)) 1064245933Snp ifp->if_capabilities |= IFCAP_TOE; 1065228561Snp#endif 1066218792Snp ifp->if_capenable = T4_CAP_ENABLE; 1067237799Snp ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO | 1068237799Snp CSUM_UDP_IPV6 | CSUM_TCP_IPV6; 1069218792Snp 1070218792Snp /* Initialize ifmedia for this port */ 1071218792Snp ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change, 1072218792Snp cxgbe_media_status); 1073270297Snp build_medialist(pi, &pi->media); 1074218792Snp 1075237263Snp pi->vlan_c = EVENTHANDLER_REGISTER(vlan_config, cxgbe_vlan_config, ifp, 1076237263Snp EVENTHANDLER_PRI_ANY); 1077237263Snp 1078218792Snp ether_ifattach(ifp, pi->hw_addr); 1079218792Snp 1080270297Snp n = 128; 1081270297Snp s = malloc(n, M_CXGBE, M_WAITOK); 1082270297Snp o = snprintf(s, n, "%d txq, %d rxq (NIC)", pi->ntxq, pi->nrxq); 1083270297Snp MPASS(n > o); 1084237263Snp#ifdef TCP_OFFLOAD 1085228561Snp if (is_offload(pi->adapter)) { 1086270297Snp o += snprintf(s + o, n - o, "; %d txq, %d rxq (TOE)", 1087270297Snp pi->nofldtxq, pi->nofldrxq); 1088270297Snp MPASS(n > o); 1089270297Snp } 1090218792Snp#endif 1091270297Snp#ifdef DEV_NETMAP 1092270297Snp o += snprintf(s + o, n - o, "; %d txq, %d rxq (netmap)", pi->nnmtxq, 1093270297Snp pi->nnmrxq); 1094270297Snp MPASS(n > o); 1095270297Snp#endif 1096270297Snp device_printf(dev, "%s\n", s); 1097270297Snp free(s, M_CXGBE); 1098218792Snp 1099270297Snp#ifdef DEV_NETMAP 1100270297Snp /* nm_media handled here to keep implementation private to this file */ 1101270297Snp ifmedia_init(&pi->nm_media, IFM_IMASK, cxgbe_media_change, 1102270297Snp cxgbe_media_status); 1103270297Snp build_medialist(pi, &pi->nm_media); 1104270297Snp create_netmap_ifnet(pi); /* logs errors it something fails */ 1105270297Snp#endif 1106218792Snp cxgbe_sysctls(pi); 1107218792Snp 1108218792Snp return (0); 1109218792Snp} 1110218792Snp 1111218792Snpstatic int 1112218792Snpcxgbe_detach(device_t dev) 1113218792Snp{ 1114218792Snp struct port_info *pi = device_get_softc(dev); 1115218792Snp struct adapter *sc = pi->adapter; 1116228561Snp struct ifnet *ifp = pi->ifp; 1117218792Snp 1118218792Snp /* Tell if_ioctl and if_init that the port is going away */ 1119218792Snp ADAPTER_LOCK(sc); 1120218792Snp SET_DOOMED(pi); 1121218792Snp wakeup(&sc->flags); 1122218792Snp while (IS_BUSY(sc)) 1123218792Snp mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0); 1124218792Snp SET_BUSY(sc); 1125245274Snp#ifdef INVARIANTS 1126245274Snp sc->last_op = "t4detach"; 1127245274Snp sc->last_op_thr = curthread; 1128245274Snp#endif 1129218792Snp ADAPTER_UNLOCK(sc); 1130218792Snp 1131253691Snp if (pi->flags & HAS_TRACEQ) { 1132253691Snp sc->traceq = -1; /* cloner should not create ifnet */ 1133253691Snp t4_tracer_port_detach(sc); 1134253691Snp } 1135253691Snp 1136237263Snp if (pi->vlan_c) 1137237263Snp EVENTHANDLER_DEREGISTER(vlan_config, pi->vlan_c); 1138237263Snp 1139228561Snp PORT_LOCK(pi); 1140228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1141228561Snp callout_stop(&pi->tick); 1142228561Snp PORT_UNLOCK(pi); 1143228561Snp callout_drain(&pi->tick); 1144218792Snp 1145228561Snp /* Let detach proceed even if these fail. */ 1146228561Snp cxgbe_uninit_synchronized(pi); 1147228561Snp port_full_uninit(pi); 1148219286Snp 1149218792Snp ifmedia_removeall(&pi->media); 1150218792Snp ether_ifdetach(pi->ifp); 1151218792Snp if_free(pi->ifp); 1152218792Snp 1153270297Snp#ifdef DEV_NETMAP 1154270297Snp /* XXXNM: equivalent of cxgbe_uninit_synchronized to ifdown nm_ifp */ 1155270297Snp destroy_netmap_ifnet(pi); 1156270297Snp#endif 1157270297Snp 1158218792Snp ADAPTER_LOCK(sc); 1159218792Snp CLR_BUSY(sc); 1160245274Snp wakeup(&sc->flags); 1161218792Snp ADAPTER_UNLOCK(sc); 1162218792Snp 1163218792Snp return (0); 1164218792Snp} 1165218792Snp 1166218792Snpstatic void 1167218792Snpcxgbe_init(void *arg) 1168218792Snp{ 1169218792Snp struct port_info *pi = arg; 1170218792Snp struct adapter *sc = pi->adapter; 1171218792Snp 1172245274Snp if (begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4init") != 0) 1173245274Snp return; 1174245274Snp cxgbe_init_synchronized(pi); 1175245274Snp end_synchronized_op(sc, 0); 1176218792Snp} 1177218792Snp 1178218792Snpstatic int 1179218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) 1180218792Snp{ 1181270297Snp int rc = 0, mtu, flags, can_sleep; 1182218792Snp struct port_info *pi = ifp->if_softc; 1183218792Snp struct adapter *sc = pi->adapter; 1184218792Snp struct ifreq *ifr = (struct ifreq *)data; 1185218792Snp uint32_t mask; 1186218792Snp 1187218792Snp switch (cmd) { 1188218792Snp case SIOCSIFMTU: 1189245274Snp mtu = ifr->ifr_mtu; 1190245274Snp if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) 1191245274Snp return (EINVAL); 1192245274Snp 1193245274Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4mtu"); 1194245274Snp if (rc) 1195218792Snp return (rc); 1196245274Snp ifp->if_mtu = mtu; 1197252728Snp if (pi->flags & PORT_INIT_DONE) { 1198245274Snp t4_update_fl_bufsize(ifp); 1199252728Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1200270297Snp rc = update_mac_settings(ifp, XGMAC_MTU); 1201218792Snp } 1202245274Snp end_synchronized_op(sc, 0); 1203218792Snp break; 1204218792Snp 1205218792Snp case SIOCSIFFLAGS: 1206270297Snp can_sleep = 0; 1207270297Snpredo_sifflags: 1208270297Snp rc = begin_synchronized_op(sc, pi, 1209270297Snp can_sleep ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4flg"); 1210245274Snp if (rc) 1211245274Snp return (rc); 1212245274Snp 1213218792Snp if (ifp->if_flags & IFF_UP) { 1214218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1215218792Snp flags = pi->if_flags; 1216218792Snp if ((ifp->if_flags ^ flags) & 1217218792Snp (IFF_PROMISC | IFF_ALLMULTI)) { 1218270297Snp if (can_sleep == 1) { 1219270297Snp end_synchronized_op(sc, 0); 1220270297Snp can_sleep = 0; 1221270297Snp goto redo_sifflags; 1222270297Snp } 1223270297Snp rc = update_mac_settings(ifp, 1224218792Snp XGMAC_PROMISC | XGMAC_ALLMULTI); 1225218792Snp } 1226270297Snp } else { 1227270297Snp if (can_sleep == 0) { 1228270297Snp end_synchronized_op(sc, LOCK_HELD); 1229270297Snp can_sleep = 1; 1230270297Snp goto redo_sifflags; 1231270297Snp } 1232245274Snp rc = cxgbe_init_synchronized(pi); 1233270297Snp } 1234218792Snp pi->if_flags = ifp->if_flags; 1235270297Snp } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1236270297Snp if (can_sleep == 0) { 1237270297Snp end_synchronized_op(sc, LOCK_HELD); 1238270297Snp can_sleep = 1; 1239270297Snp goto redo_sifflags; 1240270297Snp } 1241245274Snp rc = cxgbe_uninit_synchronized(pi); 1242270297Snp } 1243270297Snp end_synchronized_op(sc, can_sleep ? 0 : LOCK_HELD); 1244218792Snp break; 1245218792Snp 1246270297Snp case SIOCADDMULTI: 1247245274Snp case SIOCDELMULTI: /* these two are called with a mutex held :-( */ 1248245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK, "t4multi"); 1249218792Snp if (rc) 1250245274Snp return (rc); 1251245274Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1252270297Snp rc = update_mac_settings(ifp, XGMAC_MCADDRS); 1253245274Snp end_synchronized_op(sc, LOCK_HELD); 1254218792Snp break; 1255218792Snp 1256218792Snp case SIOCSIFCAP: 1257245274Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4cap"); 1258218792Snp if (rc) 1259245274Snp return (rc); 1260218792Snp 1261218792Snp mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1262218792Snp if (mask & IFCAP_TXCSUM) { 1263218792Snp ifp->if_capenable ^= IFCAP_TXCSUM; 1264218792Snp ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 1265218792Snp 1266237831Snp if (IFCAP_TSO4 & ifp->if_capenable && 1267218792Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1268237799Snp ifp->if_capenable &= ~IFCAP_TSO4; 1269218792Snp if_printf(ifp, 1270237831Snp "tso4 disabled due to -txcsum.\n"); 1271218792Snp } 1272218792Snp } 1273237799Snp if (mask & IFCAP_TXCSUM_IPV6) { 1274237799Snp ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 1275237799Snp ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); 1276237799Snp 1277237799Snp if (IFCAP_TSO6 & ifp->if_capenable && 1278237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1279237799Snp ifp->if_capenable &= ~IFCAP_TSO6; 1280237799Snp if_printf(ifp, 1281237799Snp "tso6 disabled due to -txcsum6.\n"); 1282237799Snp } 1283237799Snp } 1284218792Snp if (mask & IFCAP_RXCSUM) 1285218792Snp ifp->if_capenable ^= IFCAP_RXCSUM; 1286237799Snp if (mask & IFCAP_RXCSUM_IPV6) 1287237799Snp ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 1288237799Snp 1289237799Snp /* 1290237799Snp * Note that we leave CSUM_TSO alone (it is always set). The 1291237799Snp * kernel takes both IFCAP_TSOx and CSUM_TSO into account before 1292237799Snp * sending a TSO request our way, so it's sufficient to toggle 1293237799Snp * IFCAP_TSOx only. 1294237799Snp */ 1295218792Snp if (mask & IFCAP_TSO4) { 1296237799Snp if (!(IFCAP_TSO4 & ifp->if_capenable) && 1297237799Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1298237799Snp if_printf(ifp, "enable txcsum first.\n"); 1299237799Snp rc = EAGAIN; 1300237799Snp goto fail; 1301237799Snp } 1302218792Snp ifp->if_capenable ^= IFCAP_TSO4; 1303218792Snp } 1304237799Snp if (mask & IFCAP_TSO6) { 1305237799Snp if (!(IFCAP_TSO6 & ifp->if_capenable) && 1306237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1307237799Snp if_printf(ifp, "enable txcsum6 first.\n"); 1308237799Snp rc = EAGAIN; 1309237799Snp goto fail; 1310237799Snp } 1311237799Snp ifp->if_capenable ^= IFCAP_TSO6; 1312237799Snp } 1313218792Snp if (mask & IFCAP_LRO) { 1314237819Snp#if defined(INET) || defined(INET6) 1315218792Snp int i; 1316218792Snp struct sge_rxq *rxq; 1317218792Snp 1318218792Snp ifp->if_capenable ^= IFCAP_LRO; 1319218792Snp for_each_rxq(pi, i, rxq) { 1320218792Snp if (ifp->if_capenable & IFCAP_LRO) 1321228561Snp rxq->iq.flags |= IQ_LRO_ENABLED; 1322218792Snp else 1323228561Snp rxq->iq.flags &= ~IQ_LRO_ENABLED; 1324218792Snp } 1325218792Snp#endif 1326218792Snp } 1327237263Snp#ifdef TCP_OFFLOAD 1328228561Snp if (mask & IFCAP_TOE) { 1329228561Snp int enable = (ifp->if_capenable ^ mask) & IFCAP_TOE; 1330228561Snp 1331228561Snp rc = toe_capability(pi, enable); 1332228561Snp if (rc != 0) 1333228561Snp goto fail; 1334228561Snp 1335228561Snp ifp->if_capenable ^= mask; 1336218792Snp } 1337218792Snp#endif 1338218792Snp if (mask & IFCAP_VLAN_HWTAGGING) { 1339218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1340245274Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1341270297Snp rc = update_mac_settings(ifp, XGMAC_VLANEX); 1342218792Snp } 1343218792Snp if (mask & IFCAP_VLAN_MTU) { 1344218792Snp ifp->if_capenable ^= IFCAP_VLAN_MTU; 1345218792Snp 1346218792Snp /* Need to find out how to disable auto-mtu-inflation */ 1347218792Snp } 1348218792Snp if (mask & IFCAP_VLAN_HWTSO) 1349218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1350218792Snp if (mask & IFCAP_VLAN_HWCSUM) 1351218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 1352218792Snp 1353218792Snp#ifdef VLAN_CAPABILITIES 1354218792Snp VLAN_CAPABILITIES(ifp); 1355218792Snp#endif 1356245274Snpfail: 1357245274Snp end_synchronized_op(sc, 0); 1358218792Snp break; 1359218792Snp 1360218792Snp case SIOCSIFMEDIA: 1361218792Snp case SIOCGIFMEDIA: 1362218792Snp ifmedia_ioctl(ifp, ifr, &pi->media, cmd); 1363218792Snp break; 1364218792Snp 1365218792Snp default: 1366218792Snp rc = ether_ioctl(ifp, cmd, data); 1367218792Snp } 1368218792Snp 1369218792Snp return (rc); 1370218792Snp} 1371218792Snp 1372218792Snpstatic int 1373218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m) 1374218792Snp{ 1375218792Snp struct port_info *pi = ifp->if_softc; 1376218792Snp struct adapter *sc = pi->adapter; 1377218792Snp struct sge_txq *txq = &sc->sge.txq[pi->first_txq]; 1378218792Snp struct buf_ring *br; 1379218792Snp int rc; 1380218792Snp 1381218792Snp M_ASSERTPKTHDR(m); 1382218792Snp 1383228561Snp if (__predict_false(pi->link_cfg.link_ok == 0)) { 1384218792Snp m_freem(m); 1385228561Snp return (ENETDOWN); 1386218792Snp } 1387218792Snp 1388218792Snp if (m->m_flags & M_FLOWID) 1389264493Sscottl txq += ((m->m_pkthdr.flowid % (pi->ntxq - pi->rsrv_noflowq)) 1390264493Sscottl + pi->rsrv_noflowq); 1391220873Snp br = txq->br; 1392218792Snp 1393218792Snp if (TXQ_TRYLOCK(txq) == 0) { 1394228561Snp struct sge_eq *eq = &txq->eq; 1395228561Snp 1396218792Snp /* 1397228561Snp * It is possible that t4_eth_tx finishes up and releases the 1398228561Snp * lock between the TRYLOCK above and the drbr_enqueue here. We 1399228561Snp * need to make sure that this mbuf doesn't just sit there in 1400228561Snp * the drbr. 1401218792Snp */ 1402218792Snp 1403228561Snp rc = drbr_enqueue(ifp, br, m); 1404228561Snp if (rc == 0 && callout_pending(&eq->tx_callout) == 0 && 1405228561Snp !(eq->flags & EQ_DOOMED)) 1406228561Snp callout_reset(&eq->tx_callout, 1, t4_tx_callout, eq); 1407228561Snp return (rc); 1408218792Snp } 1409218792Snp 1410218792Snp /* 1411218792Snp * txq->m is the mbuf that is held up due to a temporary shortage of 1412218792Snp * resources and it should be put on the wire first. Then what's in 1413218792Snp * drbr and finally the mbuf that was just passed in to us. 1414218792Snp * 1415218792Snp * Return code should indicate the fate of the mbuf that was passed in 1416218792Snp * this time. 1417218792Snp */ 1418218792Snp 1419218792Snp TXQ_LOCK_ASSERT_OWNED(txq); 1420218792Snp if (drbr_needs_enqueue(ifp, br) || txq->m) { 1421218792Snp 1422218792Snp /* Queued for transmission. */ 1423218792Snp 1424218792Snp rc = drbr_enqueue(ifp, br, m); 1425218792Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 1426218792Snp (void) t4_eth_tx(ifp, txq, m); 1427218792Snp TXQ_UNLOCK(txq); 1428218792Snp return (rc); 1429218792Snp } 1430218792Snp 1431218792Snp /* Direct transmission. */ 1432218792Snp rc = t4_eth_tx(ifp, txq, m); 1433218792Snp if (rc != 0 && txq->m) 1434218792Snp rc = 0; /* held, will be transmitted soon (hopefully) */ 1435218792Snp 1436218792Snp TXQ_UNLOCK(txq); 1437218792Snp return (rc); 1438218792Snp} 1439218792Snp 1440218792Snpstatic void 1441218792Snpcxgbe_qflush(struct ifnet *ifp) 1442218792Snp{ 1443218792Snp struct port_info *pi = ifp->if_softc; 1444220649Snp struct sge_txq *txq; 1445220649Snp int i; 1446220649Snp struct mbuf *m; 1447218792Snp 1448228561Snp /* queues do not exist if !PORT_INIT_DONE. */ 1449228561Snp if (pi->flags & PORT_INIT_DONE) { 1450220649Snp for_each_txq(pi, i, txq) { 1451220649Snp TXQ_LOCK(txq); 1452220649Snp m_freem(txq->m); 1453228561Snp txq->m = NULL; 1454220873Snp while ((m = buf_ring_dequeue_sc(txq->br)) != NULL) 1455220649Snp m_freem(m); 1456220649Snp TXQ_UNLOCK(txq); 1457220649Snp } 1458220649Snp } 1459220649Snp if_qflush(ifp); 1460218792Snp} 1461218792Snp 1462218792Snpstatic int 1463218792Snpcxgbe_media_change(struct ifnet *ifp) 1464218792Snp{ 1465218792Snp struct port_info *pi = ifp->if_softc; 1466218792Snp 1467218792Snp device_printf(pi->dev, "%s unimplemented.\n", __func__); 1468218792Snp 1469218792Snp return (EOPNOTSUPP); 1470218792Snp} 1471218792Snp 1472218792Snpstatic void 1473218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1474218792Snp{ 1475218792Snp struct port_info *pi = ifp->if_softc; 1476270297Snp struct ifmedia *media = NULL; 1477270297Snp struct ifmedia_entry *cur; 1478218792Snp int speed = pi->link_cfg.speed; 1479218792Snp int data = (pi->port_type << 8) | pi->mod_type; 1480218792Snp 1481270297Snp if (ifp == pi->ifp) 1482270297Snp media = &pi->media; 1483270297Snp#ifdef DEV_NETMAP 1484270297Snp else if (ifp == pi->nm_ifp) 1485270297Snp media = &pi->nm_media; 1486270297Snp#endif 1487270297Snp MPASS(media != NULL); 1488270297Snp 1489270297Snp cur = media->ifm_cur; 1490218792Snp if (cur->ifm_data != data) { 1491270297Snp build_medialist(pi, media); 1492270297Snp cur = media->ifm_cur; 1493218792Snp } 1494218792Snp 1495218792Snp ifmr->ifm_status = IFM_AVALID; 1496218792Snp if (!pi->link_cfg.link_ok) 1497218792Snp return; 1498218792Snp 1499218792Snp ifmr->ifm_status |= IFM_ACTIVE; 1500218792Snp 1501218792Snp /* active and current will differ iff current media is autoselect. */ 1502218792Snp if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO) 1503218792Snp return; 1504218792Snp 1505218792Snp ifmr->ifm_active = IFM_ETHER | IFM_FDX; 1506218792Snp if (speed == SPEED_10000) 1507218792Snp ifmr->ifm_active |= IFM_10G_T; 1508218792Snp else if (speed == SPEED_1000) 1509218792Snp ifmr->ifm_active |= IFM_1000_T; 1510218792Snp else if (speed == SPEED_100) 1511218792Snp ifmr->ifm_active |= IFM_100_TX; 1512218792Snp else if (speed == SPEED_10) 1513218792Snp ifmr->ifm_active |= IFM_10_T; 1514218792Snp else 1515218792Snp KASSERT(0, ("%s: link up but speed unknown (%u)", __func__, 1516218792Snp speed)); 1517218792Snp} 1518218792Snp 1519218792Snpvoid 1520218792Snpt4_fatal_err(struct adapter *sc) 1521218792Snp{ 1522218792Snp t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0); 1523218792Snp t4_intr_disable(sc); 1524218792Snp log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n", 1525218792Snp device_get_nameunit(sc->dev)); 1526218792Snp} 1527218792Snp 1528218792Snpstatic int 1529248925Snpmap_bars_0_and_4(struct adapter *sc) 1530218792Snp{ 1531218792Snp sc->regs_rid = PCIR_BAR(0); 1532218792Snp sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1533218792Snp &sc->regs_rid, RF_ACTIVE); 1534218792Snp if (sc->regs_res == NULL) { 1535218792Snp device_printf(sc->dev, "cannot map registers.\n"); 1536218792Snp return (ENXIO); 1537218792Snp } 1538218792Snp sc->bt = rman_get_bustag(sc->regs_res); 1539218792Snp sc->bh = rman_get_bushandle(sc->regs_res); 1540218792Snp sc->mmio_len = rman_get_size(sc->regs_res); 1541248925Snp setbit(&sc->doorbells, DOORBELL_KDB); 1542218792Snp 1543218792Snp sc->msix_rid = PCIR_BAR(4); 1544218792Snp sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1545218792Snp &sc->msix_rid, RF_ACTIVE); 1546218792Snp if (sc->msix_res == NULL) { 1547218792Snp device_printf(sc->dev, "cannot map MSI-X BAR.\n"); 1548218792Snp return (ENXIO); 1549218792Snp } 1550218792Snp 1551218792Snp return (0); 1552218792Snp} 1553218792Snp 1554248925Snpstatic int 1555248925Snpmap_bar_2(struct adapter *sc) 1556248925Snp{ 1557248925Snp 1558248925Snp /* 1559248925Snp * T4: only iWARP driver uses the userspace doorbells. There is no need 1560248925Snp * to map it if RDMA is disabled. 1561248925Snp */ 1562248925Snp if (is_t4(sc) && sc->rdmacaps == 0) 1563248925Snp return (0); 1564248925Snp 1565248925Snp sc->udbs_rid = PCIR_BAR(2); 1566248925Snp sc->udbs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1567248925Snp &sc->udbs_rid, RF_ACTIVE); 1568248925Snp if (sc->udbs_res == NULL) { 1569248925Snp device_printf(sc->dev, "cannot map doorbell BAR.\n"); 1570248925Snp return (ENXIO); 1571248925Snp } 1572248925Snp sc->udbs_base = rman_get_virtual(sc->udbs_res); 1573248925Snp 1574248925Snp if (is_t5(sc)) { 1575248925Snp setbit(&sc->doorbells, DOORBELL_UDB); 1576248925Snp#if defined(__i386__) || defined(__amd64__) 1577248925Snp if (t5_write_combine) { 1578248925Snp int rc; 1579248925Snp 1580248925Snp /* 1581248925Snp * Enable write combining on BAR2. This is the 1582248925Snp * userspace doorbell BAR and is split into 128B 1583248925Snp * (UDBS_SEG_SIZE) doorbell regions, each associated 1584248925Snp * with an egress queue. The first 64B has the doorbell 1585248925Snp * and the second 64B can be used to submit a tx work 1586248925Snp * request with an implicit doorbell. 1587248925Snp */ 1588248925Snp 1589248925Snp rc = pmap_change_attr((vm_offset_t)sc->udbs_base, 1590248925Snp rman_get_size(sc->udbs_res), PAT_WRITE_COMBINING); 1591248925Snp if (rc == 0) { 1592248925Snp clrbit(&sc->doorbells, DOORBELL_UDB); 1593249392Snp setbit(&sc->doorbells, DOORBELL_WCWR); 1594248925Snp setbit(&sc->doorbells, DOORBELL_UDBWC); 1595248925Snp } else { 1596248925Snp device_printf(sc->dev, 1597248925Snp "couldn't enable write combining: %d\n", 1598248925Snp rc); 1599248925Snp } 1600248925Snp 1601248925Snp t4_write_reg(sc, A_SGE_STAT_CFG, 1602248925Snp V_STATSOURCE_T5(7) | V_STATMODE(0)); 1603248925Snp } 1604248925Snp#endif 1605248925Snp } 1606248925Snp 1607248925Snp return (0); 1608248925Snp} 1609248925Snp 1610248925Snpstatic const struct memwin t4_memwin[] = { 1611248925Snp { MEMWIN0_BASE, MEMWIN0_APERTURE }, 1612248925Snp { MEMWIN1_BASE, MEMWIN1_APERTURE }, 1613248925Snp { MEMWIN2_BASE_T4, MEMWIN2_APERTURE_T4 } 1614248925Snp}; 1615248925Snp 1616248925Snpstatic const struct memwin t5_memwin[] = { 1617248925Snp { MEMWIN0_BASE, MEMWIN0_APERTURE }, 1618248925Snp { MEMWIN1_BASE, MEMWIN1_APERTURE }, 1619248925Snp { MEMWIN2_BASE_T5, MEMWIN2_APERTURE_T5 }, 1620248925Snp}; 1621248925Snp 1622218792Snpstatic void 1623218792Snpsetup_memwin(struct adapter *sc) 1624218792Snp{ 1625248925Snp const struct memwin *mw; 1626248925Snp int i, n; 1627237587Snp uint32_t bar0; 1628218792Snp 1629248925Snp if (is_t4(sc)) { 1630248925Snp /* 1631248925Snp * Read low 32b of bar0 indirectly via the hardware backdoor 1632248925Snp * mechanism. Works from within PCI passthrough environments 1633248925Snp * too, where rman_get_start() can return a different value. We 1634248925Snp * need to program the T4 memory window decoders with the actual 1635248925Snp * addresses that will be coming across the PCIe link. 1636248925Snp */ 1637248925Snp bar0 = t4_hw_pci_read_cfg4(sc, PCIR_BAR(0)); 1638248925Snp bar0 &= (uint32_t) PCIM_BAR_MEM_BASE; 1639218792Snp 1640248925Snp mw = &t4_memwin[0]; 1641248925Snp n = nitems(t4_memwin); 1642248925Snp } else { 1643248925Snp /* T5 uses the relative offset inside the PCIe BAR */ 1644248925Snp bar0 = 0; 1645218792Snp 1646248925Snp mw = &t5_memwin[0]; 1647248925Snp n = nitems(t5_memwin); 1648248925Snp } 1649218792Snp 1650248925Snp for (i = 0; i < n; i++, mw++) { 1651248925Snp t4_write_reg(sc, 1652248925Snp PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, i), 1653248925Snp (mw->base + bar0) | V_BIR(0) | 1654248925Snp V_WINDOW(ilog2(mw->aperture) - 10)); 1655248925Snp } 1656237587Snp 1657237587Snp /* flush */ 1658237587Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2)); 1659218792Snp} 1660218792Snp 1661248925Snp/* 1662248925Snp * Verify that the memory range specified by the addr/len pair is valid and lies 1663248925Snp * entirely within a single region (EDCx or MCx). 1664248925Snp */ 1665218792Snpstatic int 1666248925Snpvalidate_mem_range(struct adapter *sc, uint32_t addr, int len) 1667248925Snp{ 1668248925Snp uint32_t em, addr_len, maddr, mlen; 1669248925Snp 1670248925Snp /* Memory can only be accessed in naturally aligned 4 byte units */ 1671248925Snp if (addr & 3 || len & 3 || len == 0) 1672248925Snp return (EINVAL); 1673248925Snp 1674248925Snp /* Enabled memories */ 1675248925Snp em = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 1676248925Snp if (em & F_EDRAM0_ENABLE) { 1677248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM0_BAR); 1678248925Snp maddr = G_EDRAM0_BASE(addr_len) << 20; 1679248925Snp mlen = G_EDRAM0_SIZE(addr_len) << 20; 1680248925Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1681248925Snp addr + len <= maddr + mlen) 1682248925Snp return (0); 1683248925Snp } 1684248925Snp if (em & F_EDRAM1_ENABLE) { 1685248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM1_BAR); 1686248925Snp maddr = G_EDRAM1_BASE(addr_len) << 20; 1687248925Snp mlen = G_EDRAM1_SIZE(addr_len) << 20; 1688248925Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1689248925Snp addr + len <= maddr + mlen) 1690248925Snp return (0); 1691248925Snp } 1692248925Snp if (em & F_EXT_MEM_ENABLE) { 1693248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 1694248925Snp maddr = G_EXT_MEM_BASE(addr_len) << 20; 1695248925Snp mlen = G_EXT_MEM_SIZE(addr_len) << 20; 1696248925Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1697248925Snp addr + len <= maddr + mlen) 1698248925Snp return (0); 1699248925Snp } 1700248925Snp if (!is_t4(sc) && em & F_EXT_MEM1_ENABLE) { 1701248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 1702248925Snp maddr = G_EXT_MEM1_BASE(addr_len) << 20; 1703248925Snp mlen = G_EXT_MEM1_SIZE(addr_len) << 20; 1704248925Snp if (mlen > 0 && addr >= maddr && addr < maddr + mlen && 1705248925Snp addr + len <= maddr + mlen) 1706248925Snp return (0); 1707248925Snp } 1708248925Snp 1709248925Snp return (EFAULT); 1710248925Snp} 1711248925Snp 1712256791Snpstatic int 1713256791Snpfwmtype_to_hwmtype(int mtype) 1714256791Snp{ 1715256791Snp 1716256791Snp switch (mtype) { 1717256791Snp case FW_MEMTYPE_EDC0: 1718256791Snp return (MEM_EDC0); 1719256791Snp case FW_MEMTYPE_EDC1: 1720256791Snp return (MEM_EDC1); 1721256791Snp case FW_MEMTYPE_EXTMEM: 1722256791Snp return (MEM_MC0); 1723256791Snp case FW_MEMTYPE_EXTMEM1: 1724256791Snp return (MEM_MC1); 1725256791Snp default: 1726256791Snp panic("%s: cannot translate fw mtype %d.", __func__, mtype); 1727256791Snp } 1728256791Snp} 1729256791Snp 1730248925Snp/* 1731248925Snp * Verify that the memory range specified by the memtype/offset/len pair is 1732248925Snp * valid and lies entirely within the memtype specified. The global address of 1733248925Snp * the start of the range is returned in addr. 1734248925Snp */ 1735248925Snpstatic int 1736248925Snpvalidate_mt_off_len(struct adapter *sc, int mtype, uint32_t off, int len, 1737248925Snp uint32_t *addr) 1738248925Snp{ 1739248925Snp uint32_t em, addr_len, maddr, mlen; 1740248925Snp 1741248925Snp /* Memory can only be accessed in naturally aligned 4 byte units */ 1742248925Snp if (off & 3 || len & 3 || len == 0) 1743248925Snp return (EINVAL); 1744248925Snp 1745248925Snp em = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 1746256791Snp switch (fwmtype_to_hwmtype(mtype)) { 1747248925Snp case MEM_EDC0: 1748248925Snp if (!(em & F_EDRAM0_ENABLE)) 1749248925Snp return (EINVAL); 1750248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM0_BAR); 1751248925Snp maddr = G_EDRAM0_BASE(addr_len) << 20; 1752248925Snp mlen = G_EDRAM0_SIZE(addr_len) << 20; 1753248925Snp break; 1754248925Snp case MEM_EDC1: 1755248925Snp if (!(em & F_EDRAM1_ENABLE)) 1756248925Snp return (EINVAL); 1757248925Snp addr_len = t4_read_reg(sc, A_MA_EDRAM1_BAR); 1758248925Snp maddr = G_EDRAM1_BASE(addr_len) << 20; 1759248925Snp mlen = G_EDRAM1_SIZE(addr_len) << 20; 1760248925Snp break; 1761248925Snp case MEM_MC: 1762248925Snp if (!(em & F_EXT_MEM_ENABLE)) 1763248925Snp return (EINVAL); 1764248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 1765248925Snp maddr = G_EXT_MEM_BASE(addr_len) << 20; 1766248925Snp mlen = G_EXT_MEM_SIZE(addr_len) << 20; 1767248925Snp break; 1768248925Snp case MEM_MC1: 1769248925Snp if (is_t4(sc) || !(em & F_EXT_MEM1_ENABLE)) 1770248925Snp return (EINVAL); 1771248925Snp addr_len = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 1772248925Snp maddr = G_EXT_MEM1_BASE(addr_len) << 20; 1773248925Snp mlen = G_EXT_MEM1_SIZE(addr_len) << 20; 1774248925Snp break; 1775248925Snp default: 1776248925Snp return (EINVAL); 1777248925Snp } 1778248925Snp 1779248925Snp if (mlen > 0 && off < mlen && off + len <= mlen) { 1780248925Snp *addr = maddr + off; /* global address */ 1781248925Snp return (0); 1782248925Snp } 1783248925Snp 1784248925Snp return (EFAULT); 1785248925Snp} 1786248925Snp 1787248925Snpstatic void 1788248925Snpmemwin_info(struct adapter *sc, int win, uint32_t *base, uint32_t *aperture) 1789248925Snp{ 1790248925Snp const struct memwin *mw; 1791248925Snp 1792248925Snp if (is_t4(sc)) { 1793248925Snp KASSERT(win >= 0 && win < nitems(t4_memwin), 1794248925Snp ("%s: incorrect memwin# (%d)", __func__, win)); 1795248925Snp mw = &t4_memwin[win]; 1796248925Snp } else { 1797248925Snp KASSERT(win >= 0 && win < nitems(t5_memwin), 1798248925Snp ("%s: incorrect memwin# (%d)", __func__, win)); 1799248925Snp mw = &t5_memwin[win]; 1800248925Snp } 1801248925Snp 1802248925Snp if (base != NULL) 1803248925Snp *base = mw->base; 1804248925Snp if (aperture != NULL) 1805248925Snp *aperture = mw->aperture; 1806248925Snp} 1807248925Snp 1808248925Snp/* 1809248925Snp * Positions the memory window such that it can be used to access the specified 1810248925Snp * address in the chip's address space. The return value is the offset of addr 1811248925Snp * from the start of the window. 1812248925Snp */ 1813248925Snpstatic uint32_t 1814248925Snpposition_memwin(struct adapter *sc, int n, uint32_t addr) 1815248925Snp{ 1816248925Snp uint32_t start, pf; 1817248925Snp uint32_t reg; 1818248925Snp 1819248925Snp KASSERT(n >= 0 && n <= 3, 1820248925Snp ("%s: invalid window %d.", __func__, n)); 1821248925Snp KASSERT((addr & 3) == 0, 1822248925Snp ("%s: addr (0x%x) is not at a 4B boundary.", __func__, addr)); 1823248925Snp 1824248925Snp if (is_t4(sc)) { 1825248925Snp pf = 0; 1826248925Snp start = addr & ~0xf; /* start must be 16B aligned */ 1827248925Snp } else { 1828248925Snp pf = V_PFNUM(sc->pf); 1829248925Snp start = addr & ~0x7f; /* start must be 128B aligned */ 1830248925Snp } 1831248925Snp reg = PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, n); 1832248925Snp 1833248925Snp t4_write_reg(sc, reg, start | pf); 1834248925Snp t4_read_reg(sc, reg); 1835248925Snp 1836248925Snp return (addr - start); 1837248925Snp} 1838248925Snp 1839248925Snpstatic int 1840218792Snpcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g, 1841218792Snp struct intrs_and_queues *iaq) 1842218792Snp{ 1843228561Snp int rc, itype, navail, nrxq10g, nrxq1g, n; 1844228561Snp int nofldrxq10g = 0, nofldrxq1g = 0; 1845270297Snp int nnmrxq10g = 0, nnmrxq1g = 0; 1846218792Snp 1847218792Snp bzero(iaq, sizeof(*iaq)); 1848218792Snp 1849228561Snp iaq->ntxq10g = t4_ntxq10g; 1850228561Snp iaq->ntxq1g = t4_ntxq1g; 1851228561Snp iaq->nrxq10g = nrxq10g = t4_nrxq10g; 1852228561Snp iaq->nrxq1g = nrxq1g = t4_nrxq1g; 1853264493Sscottl iaq->rsrv_noflowq = t4_rsrv_noflowq; 1854237263Snp#ifdef TCP_OFFLOAD 1855237463Snp if (is_offload(sc)) { 1856237463Snp iaq->nofldtxq10g = t4_nofldtxq10g; 1857237463Snp iaq->nofldtxq1g = t4_nofldtxq1g; 1858237463Snp iaq->nofldrxq10g = nofldrxq10g = t4_nofldrxq10g; 1859237463Snp iaq->nofldrxq1g = nofldrxq1g = t4_nofldrxq1g; 1860237463Snp } 1861228561Snp#endif 1862270297Snp#ifdef DEV_NETMAP 1863270297Snp iaq->nnmtxq10g = t4_nnmtxq10g; 1864270297Snp iaq->nnmtxq1g = t4_nnmtxq1g; 1865270297Snp iaq->nnmrxq10g = nnmrxq10g = t4_nnmrxq10g; 1866270297Snp iaq->nnmrxq1g = nnmrxq1g = t4_nnmrxq1g; 1867270297Snp#endif 1868228561Snp 1869219944Snp for (itype = INTR_MSIX; itype; itype >>= 1) { 1870218792Snp 1871228561Snp if ((itype & t4_intr_types) == 0) 1872218792Snp continue; /* not allowed */ 1873218792Snp 1874219944Snp if (itype == INTR_MSIX) 1875218792Snp navail = pci_msix_count(sc->dev); 1876219944Snp else if (itype == INTR_MSI) 1877218792Snp navail = pci_msi_count(sc->dev); 1878218792Snp else 1879218792Snp navail = 1; 1880228561Snprestart: 1881218792Snp if (navail == 0) 1882218792Snp continue; 1883218792Snp 1884218792Snp iaq->intr_type = itype; 1885270297Snp iaq->intr_flags_10g = 0; 1886270297Snp iaq->intr_flags_1g = 0; 1887218792Snp 1888228561Snp /* 1889228561Snp * Best option: an interrupt vector for errors, one for the 1890270297Snp * firmware event queue, and one for every rxq (NIC, TOE, and 1891270297Snp * netmap). 1892228561Snp */ 1893228561Snp iaq->nirq = T4_EXTRA_INTR; 1894270297Snp iaq->nirq += n10g * (nrxq10g + nofldrxq10g + nnmrxq10g); 1895270297Snp iaq->nirq += n1g * (nrxq1g + nofldrxq1g + nnmrxq1g); 1896228561Snp if (iaq->nirq <= navail && 1897228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) { 1898270297Snp iaq->intr_flags_10g = INTR_ALL; 1899270297Snp iaq->intr_flags_1g = INTR_ALL; 1900228561Snp goto allocate; 1901228561Snp } 1902218792Snp 1903228561Snp /* 1904270297Snp * Second best option: a vector for errors, one for the firmware 1905270297Snp * event queue, and vectors for either all the NIC rx queues or 1906270297Snp * all the TOE rx queues. The queues that don't get vectors 1907270297Snp * will forward their interrupts to those that do. 1908270297Snp * 1909270297Snp * Note: netmap rx queues cannot be created early and so they 1910270297Snp * can't be setup to receive forwarded interrupts for others. 1911228561Snp */ 1912228561Snp iaq->nirq = T4_EXTRA_INTR; 1913270297Snp if (nrxq10g >= nofldrxq10g) { 1914270297Snp iaq->intr_flags_10g = INTR_RXQ; 1915270297Snp iaq->nirq += n10g * nrxq10g; 1916270297Snp#ifdef DEV_NETMAP 1917270297Snp iaq->nnmrxq10g = min(nnmrxq10g, nrxq10g); 1918270297Snp#endif 1919270297Snp } else { 1920270297Snp iaq->intr_flags_10g = INTR_OFLD_RXQ; 1921270297Snp iaq->nirq += n10g * nofldrxq10g; 1922270297Snp#ifdef DEV_NETMAP 1923270297Snp iaq->nnmrxq10g = min(nnmrxq10g, nofldrxq10g); 1924270297Snp#endif 1925270297Snp } 1926270297Snp if (nrxq1g >= nofldrxq1g) { 1927270297Snp iaq->intr_flags_1g = INTR_RXQ; 1928270297Snp iaq->nirq += n1g * nrxq1g; 1929270297Snp#ifdef DEV_NETMAP 1930270297Snp iaq->nnmrxq1g = min(nnmrxq1g, nrxq1g); 1931270297Snp#endif 1932270297Snp } else { 1933270297Snp iaq->intr_flags_1g = INTR_OFLD_RXQ; 1934270297Snp iaq->nirq += n1g * nofldrxq1g; 1935270297Snp#ifdef DEV_NETMAP 1936270297Snp iaq->nnmrxq1g = min(nnmrxq1g, nofldrxq1g); 1937270297Snp#endif 1938270297Snp } 1939228561Snp if (iaq->nirq <= navail && 1940228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) 1941228561Snp goto allocate; 1942218792Snp 1943228561Snp /* 1944228561Snp * Next best option: an interrupt vector for errors, one for the 1945228561Snp * firmware event queue, and at least one per port. At this 1946270297Snp * point we know we'll have to downsize nrxq and/or nofldrxq 1947270297Snp * and/or nnmrxq to fit what's available to us. 1948228561Snp */ 1949228561Snp iaq->nirq = T4_EXTRA_INTR; 1950228561Snp iaq->nirq += n10g + n1g; 1951228561Snp if (iaq->nirq <= navail) { 1952228561Snp int leftover = navail - iaq->nirq; 1953218792Snp 1954228561Snp if (n10g > 0) { 1955228561Snp int target = max(nrxq10g, nofldrxq10g); 1956219944Snp 1957270297Snp iaq->intr_flags_10g = nrxq10g >= nofldrxq10g ? 1958270297Snp INTR_RXQ : INTR_OFLD_RXQ; 1959270297Snp 1960228561Snp n = 1; 1961228561Snp while (n < target && leftover >= n10g) { 1962228561Snp leftover -= n10g; 1963228561Snp iaq->nirq += n10g; 1964228561Snp n++; 1965228561Snp } 1966228561Snp iaq->nrxq10g = min(n, nrxq10g); 1967237263Snp#ifdef TCP_OFFLOAD 1968270297Snp iaq->nofldrxq10g = min(n, nofldrxq10g); 1969228561Snp#endif 1970270297Snp#ifdef DEV_NETMAP 1971270297Snp iaq->nnmrxq10g = min(n, nnmrxq10g); 1972270297Snp#endif 1973228561Snp } 1974218792Snp 1975228561Snp if (n1g > 0) { 1976228561Snp int target = max(nrxq1g, nofldrxq1g); 1977219944Snp 1978270297Snp iaq->intr_flags_1g = nrxq1g >= nofldrxq1g ? 1979270297Snp INTR_RXQ : INTR_OFLD_RXQ; 1980270297Snp 1981228561Snp n = 1; 1982228561Snp while (n < target && leftover >= n1g) { 1983228561Snp leftover -= n1g; 1984228561Snp iaq->nirq += n1g; 1985228561Snp n++; 1986219944Snp } 1987228561Snp iaq->nrxq1g = min(n, nrxq1g); 1988237263Snp#ifdef TCP_OFFLOAD 1989270297Snp iaq->nofldrxq1g = min(n, nofldrxq1g); 1990228561Snp#endif 1991270297Snp#ifdef DEV_NETMAP 1992270297Snp iaq->nnmrxq1g = min(n, nnmrxq1g); 1993270297Snp#endif 1994219944Snp } 1995219944Snp 1996228561Snp if (itype != INTR_MSI || powerof2(iaq->nirq)) 1997228561Snp goto allocate; 1998218792Snp } 1999218792Snp 2000228561Snp /* 2001228561Snp * Least desirable option: one interrupt vector for everything. 2002228561Snp */ 2003228561Snp iaq->nirq = iaq->nrxq10g = iaq->nrxq1g = 1; 2004270297Snp iaq->intr_flags_10g = iaq->intr_flags_1g = 0; 2005237263Snp#ifdef TCP_OFFLOAD 2006237463Snp if (is_offload(sc)) 2007237463Snp iaq->nofldrxq10g = iaq->nofldrxq1g = 1; 2008228561Snp#endif 2009270297Snp#ifdef DEV_NETMAP 2010270297Snp iaq->nnmrxq10g = iaq->nnmrxq1g = 1; 2011270297Snp#endif 2012228561Snp 2013228561Snpallocate: 2014218792Snp navail = iaq->nirq; 2015218792Snp rc = 0; 2016219944Snp if (itype == INTR_MSIX) 2017218792Snp rc = pci_alloc_msix(sc->dev, &navail); 2018219944Snp else if (itype == INTR_MSI) 2019218792Snp rc = pci_alloc_msi(sc->dev, &navail); 2020218792Snp 2021218792Snp if (rc == 0) { 2022218792Snp if (navail == iaq->nirq) 2023218792Snp return (0); 2024218792Snp 2025218792Snp /* 2026218792Snp * Didn't get the number requested. Use whatever number 2027218792Snp * the kernel is willing to allocate (it's in navail). 2028218792Snp */ 2029228561Snp device_printf(sc->dev, "fewer vectors than requested, " 2030228561Snp "type=%d, req=%d, rcvd=%d; will downshift req.\n", 2031228561Snp itype, iaq->nirq, navail); 2032218792Snp pci_release_msi(sc->dev); 2033228561Snp goto restart; 2034218792Snp } 2035218792Snp 2036218792Snp device_printf(sc->dev, 2037218792Snp "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n", 2038218792Snp itype, rc, iaq->nirq, navail); 2039218792Snp } 2040218792Snp 2041218792Snp device_printf(sc->dev, 2042218792Snp "failed to find a usable interrupt type. " 2043228561Snp "allowed=%d, msi-x=%d, msi=%d, intx=1", t4_intr_types, 2044218792Snp pci_msix_count(sc->dev), pci_msi_count(sc->dev)); 2045218792Snp 2046218792Snp return (ENXIO); 2047218792Snp} 2048218792Snp 2049248925Snp#define FW_VERSION(chip) ( \ 2050252661Snp V_FW_HDR_FW_VER_MAJOR(chip##FW_VERSION_MAJOR) | \ 2051252661Snp V_FW_HDR_FW_VER_MINOR(chip##FW_VERSION_MINOR) | \ 2052252661Snp V_FW_HDR_FW_VER_MICRO(chip##FW_VERSION_MICRO) | \ 2053252661Snp V_FW_HDR_FW_VER_BUILD(chip##FW_VERSION_BUILD)) 2054252661Snp#define FW_INTFVER(chip, intf) (chip##FW_HDR_INTFVER_##intf) 2055248925Snp 2056248925Snpstruct fw_info { 2057248925Snp uint8_t chip; 2058248925Snp char *kld_name; 2059248925Snp char *fw_mod_name; 2060248925Snp struct fw_hdr fw_hdr; /* XXX: waste of space, need a sparse struct */ 2061248925Snp} fw_info[] = { 2062248925Snp { 2063248925Snp .chip = CHELSIO_T4, 2064248925Snp .kld_name = "t4fw_cfg", 2065248925Snp .fw_mod_name = "t4fw", 2066248925Snp .fw_hdr = { 2067248925Snp .chip = FW_HDR_CHIP_T4, 2068248925Snp .fw_ver = htobe32_const(FW_VERSION(T4)), 2069248925Snp .intfver_nic = FW_INTFVER(T4, NIC), 2070248925Snp .intfver_vnic = FW_INTFVER(T4, VNIC), 2071248925Snp .intfver_ofld = FW_INTFVER(T4, OFLD), 2072248925Snp .intfver_ri = FW_INTFVER(T4, RI), 2073248925Snp .intfver_iscsipdu = FW_INTFVER(T4, ISCSIPDU), 2074248925Snp .intfver_iscsi = FW_INTFVER(T4, ISCSI), 2075248925Snp .intfver_fcoepdu = FW_INTFVER(T4, FCOEPDU), 2076248925Snp .intfver_fcoe = FW_INTFVER(T4, FCOE), 2077248925Snp }, 2078248925Snp }, { 2079248925Snp .chip = CHELSIO_T5, 2080248925Snp .kld_name = "t5fw_cfg", 2081248925Snp .fw_mod_name = "t5fw", 2082248925Snp .fw_hdr = { 2083248925Snp .chip = FW_HDR_CHIP_T5, 2084248925Snp .fw_ver = htobe32_const(FW_VERSION(T5)), 2085248925Snp .intfver_nic = FW_INTFVER(T5, NIC), 2086248925Snp .intfver_vnic = FW_INTFVER(T5, VNIC), 2087248925Snp .intfver_ofld = FW_INTFVER(T5, OFLD), 2088248925Snp .intfver_ri = FW_INTFVER(T5, RI), 2089248925Snp .intfver_iscsipdu = FW_INTFVER(T5, ISCSIPDU), 2090248925Snp .intfver_iscsi = FW_INTFVER(T5, ISCSI), 2091248925Snp .intfver_fcoepdu = FW_INTFVER(T5, FCOEPDU), 2092248925Snp .intfver_fcoe = FW_INTFVER(T5, FCOE), 2093248925Snp }, 2094248925Snp } 2095248925Snp}; 2096248925Snp 2097248925Snpstatic struct fw_info * 2098248925Snpfind_fw_info(int chip) 2099248925Snp{ 2100248925Snp int i; 2101248925Snp 2102248925Snp for (i = 0; i < nitems(fw_info); i++) { 2103248925Snp if (fw_info[i].chip == chip) 2104248925Snp return (&fw_info[i]); 2105248925Snp } 2106248925Snp return (NULL); 2107248925Snp} 2108248925Snp 2109218792Snp/* 2110248925Snp * Is the given firmware API compatible with the one the driver was compiled 2111248925Snp * with? 2112247347Snp */ 2113247347Snpstatic int 2114248925Snpfw_compatible(const struct fw_hdr *hdr1, const struct fw_hdr *hdr2) 2115247347Snp{ 2116247347Snp 2117248925Snp /* short circuit if it's the exact same firmware version */ 2118248925Snp if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver) 2119247347Snp return (1); 2120247347Snp 2121247347Snp /* 2122247347Snp * XXX: Is this too conservative? Perhaps I should limit this to the 2123247347Snp * features that are supported in the driver. 2124247347Snp */ 2125248925Snp#define SAME_INTF(x) (hdr1->intfver_##x == hdr2->intfver_##x) 2126248925Snp if (hdr1->chip == hdr2->chip && SAME_INTF(nic) && SAME_INTF(vnic) && 2127248925Snp SAME_INTF(ofld) && SAME_INTF(ri) && SAME_INTF(iscsipdu) && 2128248925Snp SAME_INTF(iscsi) && SAME_INTF(fcoepdu) && SAME_INTF(fcoe)) 2129247347Snp return (1); 2130248925Snp#undef SAME_INTF 2131247347Snp 2132247347Snp return (0); 2133247347Snp} 2134247347Snp 2135247347Snp/* 2136251434Snp * The firmware in the KLD is usable, but should it be installed? This routine 2137251434Snp * explains itself in detail if it indicates the KLD firmware should be 2138251434Snp * installed. 2139249376Snp */ 2140249376Snpstatic int 2141249376Snpshould_install_kld_fw(struct adapter *sc, int card_fw_usable, int k, int c) 2142249376Snp{ 2143249376Snp const char *reason; 2144249376Snp 2145249376Snp if (!card_fw_usable) { 2146249376Snp reason = "incompatible or unusable"; 2147249376Snp goto install; 2148249376Snp } 2149249376Snp 2150249376Snp if (k > c) { 2151249376Snp reason = "older than the version bundled with this driver"; 2152249376Snp goto install; 2153249376Snp } 2154249376Snp 2155249376Snp if (t4_fw_install == 2 && k != c) { 2156249376Snp reason = "different than the version bundled with this driver"; 2157249376Snp goto install; 2158249376Snp } 2159249376Snp 2160249376Snp return (0); 2161249376Snp 2162249376Snpinstall: 2163251434Snp if (t4_fw_install == 0) { 2164251434Snp device_printf(sc->dev, "firmware on card (%u.%u.%u.%u) is %s, " 2165251434Snp "but the driver is prohibited from installing a different " 2166251434Snp "firmware on the card.\n", 2167251434Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 2168251434Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), reason); 2169251434Snp 2170251434Snp return (0); 2171251434Snp } 2172251434Snp 2173249376Snp device_printf(sc->dev, "firmware on card (%u.%u.%u.%u) is %s, " 2174249376Snp "installing firmware %u.%u.%u.%u on card.\n", 2175249376Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 2176249376Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), reason, 2177249376Snp G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k), 2178249376Snp G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k)); 2179249376Snp 2180249376Snp return (1); 2181249376Snp} 2182249376Snp/* 2183248925Snp * Establish contact with the firmware and determine if we are the master driver 2184248925Snp * or not, and whether we are responsible for chip initialization. 2185218792Snp */ 2186218792Snpstatic int 2187218792Snpprep_firmware(struct adapter *sc) 2188218792Snp{ 2189248925Snp const struct firmware *fw = NULL, *default_cfg; 2190248925Snp int rc, pf, card_fw_usable, kld_fw_usable, need_fw_reset = 1; 2191218792Snp enum dev_state state; 2192248925Snp struct fw_info *fw_info; 2193248925Snp struct fw_hdr *card_fw; /* fw on the card */ 2194248925Snp const struct fw_hdr *kld_fw; /* fw in the KLD */ 2195248925Snp const struct fw_hdr *drv_fw; /* fw header the driver was compiled 2196248925Snp against */ 2197218792Snp 2198248925Snp /* Contact firmware. */ 2199248925Snp rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state); 2200248925Snp if (rc < 0 || state == DEV_STATE_ERR) { 2201248925Snp rc = -rc; 2202248925Snp device_printf(sc->dev, 2203248925Snp "failed to connect to the firmware: %d, %d.\n", rc, state); 2204248925Snp return (rc); 2205248925Snp } 2206248925Snp pf = rc; 2207248925Snp if (pf == sc->mbox) 2208248925Snp sc->flags |= MASTER_PF; 2209248925Snp else if (state == DEV_STATE_UNINIT) { 2210248925Snp /* 2211248925Snp * We didn't get to be the master so we definitely won't be 2212248925Snp * configuring the chip. It's a bug if someone else hasn't 2213248925Snp * configured it already. 2214248925Snp */ 2215248925Snp device_printf(sc->dev, "couldn't be master(%d), " 2216248925Snp "device not already initialized either(%d).\n", rc, state); 2217248925Snp return (EDOOFUS); 2218248925Snp } 2219228561Snp 2220248925Snp /* This is the firmware whose headers the driver was compiled against */ 2221248925Snp fw_info = find_fw_info(chip_id(sc)); 2222248925Snp if (fw_info == NULL) { 2223248925Snp device_printf(sc->dev, 2224248925Snp "unable to look up firmware information for chip %d.\n", 2225248925Snp chip_id(sc)); 2226248925Snp return (EINVAL); 2227248925Snp } 2228248925Snp drv_fw = &fw_info->fw_hdr; 2229248925Snp 2230248925Snp /* 2231248925Snp * The firmware KLD contains many modules. The KLD name is also the 2232248925Snp * name of the module that contains the default config file. 2233248925Snp */ 2234248925Snp default_cfg = firmware_get(fw_info->kld_name); 2235248925Snp 2236247347Snp /* Read the header of the firmware on the card */ 2237247347Snp card_fw = malloc(sizeof(*card_fw), M_CXGBE, M_ZERO | M_WAITOK); 2238247347Snp rc = -t4_read_flash(sc, FLASH_FW_START, 2239247347Snp sizeof (*card_fw) / sizeof (uint32_t), (uint32_t *)card_fw, 1); 2240247347Snp if (rc == 0) 2241248925Snp card_fw_usable = fw_compatible(drv_fw, (const void*)card_fw); 2242247347Snp else { 2243247347Snp device_printf(sc->dev, 2244247347Snp "Unable to read card's firmware header: %d\n", rc); 2245247347Snp card_fw_usable = 0; 2246247347Snp } 2247218792Snp 2248247347Snp /* This is the firmware in the KLD */ 2249248925Snp fw = firmware_get(fw_info->fw_mod_name); 2250247347Snp if (fw != NULL) { 2251247347Snp kld_fw = (const void *)fw->data; 2252248925Snp kld_fw_usable = fw_compatible(drv_fw, kld_fw); 2253247347Snp } else { 2254247347Snp kld_fw = NULL; 2255247347Snp kld_fw_usable = 0; 2256247347Snp } 2257219287Snp 2258248925Snp if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver && 2259251434Snp (!kld_fw_usable || kld_fw->fw_ver == drv_fw->fw_ver)) { 2260248925Snp /* 2261248925Snp * Common case: the firmware on the card is an exact match and 2262248925Snp * the KLD is an exact match too, or the KLD is 2263251434Snp * absent/incompatible. Note that t4_fw_install = 2 is ignored 2264251434Snp * here -- use cxgbetool loadfw if you want to reinstall the 2265251434Snp * same firmware as the one on the card. 2266248925Snp */ 2267248925Snp } else if (kld_fw_usable && state == DEV_STATE_UNINIT && 2268249376Snp should_install_kld_fw(sc, card_fw_usable, be32toh(kld_fw->fw_ver), 2269249376Snp be32toh(card_fw->fw_ver))) { 2270219287Snp 2271250221Snp rc = -t4_fw_upgrade(sc, sc->mbox, fw->data, fw->datasize, 0); 2272247347Snp if (rc != 0) { 2273247347Snp device_printf(sc->dev, 2274247347Snp "failed to install firmware: %d\n", rc); 2275228561Snp goto done; 2276219287Snp } 2277219287Snp 2278247347Snp /* Installed successfully, update the cached header too. */ 2279247347Snp memcpy(card_fw, kld_fw, sizeof(*card_fw)); 2280247347Snp card_fw_usable = 1; 2281248925Snp need_fw_reset = 0; /* already reset as part of load_fw */ 2282247347Snp } 2283219287Snp 2284247347Snp if (!card_fw_usable) { 2285248925Snp uint32_t d, c, k; 2286247347Snp 2287248925Snp d = ntohl(drv_fw->fw_ver); 2288247347Snp c = ntohl(card_fw->fw_ver); 2289247347Snp k = kld_fw ? ntohl(kld_fw->fw_ver) : 0; 2290247347Snp 2291247347Snp device_printf(sc->dev, "Cannot find a usable firmware: " 2292248925Snp "fw_install %d, chip state %d, " 2293248925Snp "driver compiled with %d.%d.%d.%d, " 2294247347Snp "card has %d.%d.%d.%d, KLD has %d.%d.%d.%d\n", 2295248925Snp t4_fw_install, state, 2296248925Snp G_FW_HDR_FW_VER_MAJOR(d), G_FW_HDR_FW_VER_MINOR(d), 2297248925Snp G_FW_HDR_FW_VER_MICRO(d), G_FW_HDR_FW_VER_BUILD(d), 2298247347Snp G_FW_HDR_FW_VER_MAJOR(c), G_FW_HDR_FW_VER_MINOR(c), 2299247347Snp G_FW_HDR_FW_VER_MICRO(c), G_FW_HDR_FW_VER_BUILD(c), 2300247347Snp G_FW_HDR_FW_VER_MAJOR(k), G_FW_HDR_FW_VER_MINOR(k), 2301247347Snp G_FW_HDR_FW_VER_MICRO(k), G_FW_HDR_FW_VER_BUILD(k)); 2302248925Snp rc = EINVAL; 2303247347Snp goto done; 2304218792Snp } 2305218792Snp 2306247347Snp /* We're using whatever's on the card and it's known to be good. */ 2307247347Snp sc->params.fw_vers = ntohl(card_fw->fw_ver); 2308247347Snp snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u", 2309247347Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 2310247347Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 2311247347Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 2312247347Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 2313252705Snp t4_get_tp_version(sc, &sc->params.tp_vers); 2314247347Snp 2315218792Snp /* Reset device */ 2316248925Snp if (need_fw_reset && 2317248925Snp (rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST)) != 0) { 2318218792Snp device_printf(sc->dev, "firmware reset failed: %d.\n", rc); 2319218792Snp if (rc != ETIMEDOUT && rc != EIO) 2320218792Snp t4_fw_bye(sc, sc->mbox); 2321228561Snp goto done; 2322218792Snp } 2323248925Snp sc->flags |= FW_OK; 2324218792Snp 2325248925Snp rc = get_params__pre_init(sc); 2326248925Snp if (rc != 0) 2327248925Snp goto done; /* error message displayed already */ 2328248925Snp 2329228561Snp /* Partition adapter resources as specified in the config file. */ 2330248925Snp if (state == DEV_STATE_UNINIT) { 2331228561Snp 2332248925Snp KASSERT(sc->flags & MASTER_PF, 2333248925Snp ("%s: trying to change chip settings when not master.", 2334248925Snp __func__)); 2335228561Snp 2336248925Snp rc = partition_resources(sc, default_cfg, fw_info->kld_name); 2337228561Snp if (rc != 0) 2338228561Snp goto done; /* error message displayed already */ 2339248925Snp 2340248925Snp t4_tweak_chip_settings(sc); 2341248925Snp 2342248925Snp /* get basic stuff going */ 2343248925Snp rc = -t4_fw_initialize(sc, sc->mbox); 2344248925Snp if (rc != 0) { 2345248925Snp device_printf(sc->dev, "fw init failed: %d.\n", rc); 2346248925Snp goto done; 2347248925Snp } 2348245936Snp } else { 2349248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "pf%d", pf); 2350248925Snp sc->cfcsum = 0; 2351228561Snp } 2352228561Snp 2353228561Snpdone: 2354247347Snp free(card_fw, M_CXGBE); 2355228561Snp if (fw != NULL) 2356228561Snp firmware_put(fw, FIRMWARE_UNLOAD); 2357228561Snp if (default_cfg != NULL) 2358228561Snp firmware_put(default_cfg, FIRMWARE_UNLOAD); 2359228561Snp 2360228561Snp return (rc); 2361218792Snp} 2362218792Snp 2363228561Snp#define FW_PARAM_DEV(param) \ 2364228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ 2365228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) 2366228561Snp#define FW_PARAM_PFVF(param) \ 2367228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ 2368228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)) 2369228561Snp 2370228561Snp/* 2371248925Snp * Partition chip resources for use between various PFs, VFs, etc. 2372228561Snp */ 2373218792Snpstatic int 2374248925Snppartition_resources(struct adapter *sc, const struct firmware *default_cfg, 2375248925Snp const char *name_prefix) 2376222551Snp{ 2377248925Snp const struct firmware *cfg = NULL; 2378248925Snp int rc = 0; 2379248925Snp struct fw_caps_config_cmd caps; 2380248925Snp uint32_t mtype, moff, finicsum, cfcsum; 2381222551Snp 2382248925Snp /* 2383248925Snp * Figure out what configuration file to use. Pick the default config 2384248925Snp * file for the card if the user hasn't specified one explicitly. 2385248925Snp */ 2386248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", t4_cfg_file); 2387248925Snp if (strncmp(t4_cfg_file, DEFAULT_CF, sizeof(t4_cfg_file)) == 0) { 2388248925Snp /* Card specific overrides go here. */ 2389248925Snp if (pci_get_device(sc->dev) == 0x440a) 2390248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), UWIRE_CF); 2391249376Snp if (is_fpga(sc)) 2392249376Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), FPGA_CF); 2393222551Snp } 2394222551Snp 2395248925Snp /* 2396248925Snp * We need to load another module if the profile is anything except 2397248925Snp * "default" or "flash". 2398248925Snp */ 2399248925Snp if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) != 0 && 2400248925Snp strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) { 2401248925Snp char s[32]; 2402248925Snp 2403248925Snp snprintf(s, sizeof(s), "%s_%s", name_prefix, sc->cfg_file); 2404248925Snp cfg = firmware_get(s); 2405248925Snp if (cfg == NULL) { 2406248925Snp if (default_cfg != NULL) { 2407249376Snp device_printf(sc->dev, 2408249376Snp "unable to load module \"%s\" for " 2409249376Snp "configuration profile \"%s\", will use " 2410249376Snp "the default config file instead.\n", 2411249376Snp s, sc->cfg_file); 2412248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), 2413248925Snp "%s", DEFAULT_CF); 2414248925Snp } else { 2415249376Snp device_printf(sc->dev, 2416249376Snp "unable to load module \"%s\" for " 2417249376Snp "configuration profile \"%s\", will use " 2418249376Snp "the config file on the card's flash " 2419249376Snp "instead.\n", s, sc->cfg_file); 2420248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), 2421248925Snp "%s", FLASH_CF); 2422248925Snp } 2423248925Snp } 2424228561Snp } 2425222551Snp 2426248925Snp if (strncmp(sc->cfg_file, DEFAULT_CF, sizeof(sc->cfg_file)) == 0 && 2427248925Snp default_cfg == NULL) { 2428228561Snp device_printf(sc->dev, 2429248925Snp "default config file not available, will use the config " 2430248925Snp "file on the card's flash instead.\n"); 2431248925Snp snprintf(sc->cfg_file, sizeof(sc->cfg_file), "%s", FLASH_CF); 2432228561Snp } 2433228561Snp 2434248925Snp if (strncmp(sc->cfg_file, FLASH_CF, sizeof(sc->cfg_file)) != 0) { 2435248925Snp u_int cflen, i, n; 2436248925Snp const uint32_t *cfdata; 2437248925Snp uint32_t param, val, addr, off, mw_base, mw_aperture; 2438228561Snp 2439248925Snp KASSERT(cfg != NULL || default_cfg != NULL, 2440248925Snp ("%s: no config to upload", __func__)); 2441228561Snp 2442248925Snp /* 2443248925Snp * Ask the firmware where it wants us to upload the config file. 2444248925Snp */ 2445248925Snp param = FW_PARAM_DEV(CF); 2446248925Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 2447248925Snp if (rc != 0) { 2448248925Snp /* No support for config file? Shouldn't happen. */ 2449248925Snp device_printf(sc->dev, 2450248925Snp "failed to query config file location: %d.\n", rc); 2451248925Snp goto done; 2452248925Snp } 2453248925Snp mtype = G_FW_PARAMS_PARAM_Y(val); 2454248925Snp moff = G_FW_PARAMS_PARAM_Z(val) << 16; 2455228561Snp 2456248925Snp /* 2457248925Snp * XXX: sheer laziness. We deliberately added 4 bytes of 2458248925Snp * useless stuffing/comments at the end of the config file so 2459248925Snp * it's ok to simply throw away the last remaining bytes when 2460248925Snp * the config file is not an exact multiple of 4. This also 2461248925Snp * helps with the validate_mt_off_len check. 2462248925Snp */ 2463248925Snp if (cfg != NULL) { 2464248925Snp cflen = cfg->datasize & ~3; 2465248925Snp cfdata = cfg->data; 2466248925Snp } else { 2467248925Snp cflen = default_cfg->datasize & ~3; 2468248925Snp cfdata = default_cfg->data; 2469248925Snp } 2470222551Snp 2471248925Snp if (cflen > FLASH_CFG_MAX_SIZE) { 2472248925Snp device_printf(sc->dev, 2473248925Snp "config file too long (%d, max allowed is %d). " 2474248925Snp "Will try to use the config on the card, if any.\n", 2475248925Snp cflen, FLASH_CFG_MAX_SIZE); 2476248925Snp goto use_config_on_flash; 2477248925Snp } 2478218792Snp 2479248925Snp rc = validate_mt_off_len(sc, mtype, moff, cflen, &addr); 2480248925Snp if (rc != 0) { 2481248925Snp device_printf(sc->dev, 2482248925Snp "%s: addr (%d/0x%x) or len %d is not valid: %d. " 2483248925Snp "Will try to use the config on the card, if any.\n", 2484248925Snp __func__, mtype, moff, cflen, rc); 2485248925Snp goto use_config_on_flash; 2486248925Snp } 2487248925Snp 2488248925Snp memwin_info(sc, 2, &mw_base, &mw_aperture); 2489248925Snp while (cflen) { 2490248925Snp off = position_memwin(sc, 2, addr); 2491248925Snp n = min(cflen, mw_aperture - off); 2492248925Snp for (i = 0; i < n; i += 4) 2493248925Snp t4_write_reg(sc, mw_base + off + i, *cfdata++); 2494248925Snp cflen -= n; 2495248925Snp addr += n; 2496248925Snp } 2497248925Snp } else { 2498248925Snpuse_config_on_flash: 2499256791Snp mtype = FW_MEMTYPE_FLASH; 2500248925Snp moff = t4_flash_cfg_addr(sc); 2501228561Snp } 2502228561Snp 2503228561Snp bzero(&caps, sizeof(caps)); 2504228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2505218792Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2506228561Snp caps.cfvalid_to_len16 = htobe32(F_FW_CAPS_CONFIG_CMD_CFVALID | 2507228561Snp V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) | 2508248925Snp V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(moff >> 16) | FW_LEN16(caps)); 2509228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 2510228561Snp if (rc != 0) { 2511228561Snp device_printf(sc->dev, 2512249376Snp "failed to pre-process config file: %d " 2513249376Snp "(mtype %d, moff 0x%x).\n", rc, mtype, moff); 2514248925Snp goto done; 2515228561Snp } 2516218792Snp 2517228561Snp finicsum = be32toh(caps.finicsum); 2518228561Snp cfcsum = be32toh(caps.cfcsum); 2519228561Snp if (finicsum != cfcsum) { 2520228561Snp device_printf(sc->dev, 2521228561Snp "WARNING: config file checksum mismatch: %08x %08x\n", 2522228561Snp finicsum, cfcsum); 2523228561Snp } 2524228561Snp sc->cfcsum = cfcsum; 2525218792Snp 2526228561Snp#define LIMIT_CAPS(x) do { \ 2527228561Snp caps.x &= htobe16(t4_##x##_allowed); \ 2528228561Snp} while (0) 2529228561Snp 2530228561Snp /* 2531228561Snp * Let the firmware know what features will (not) be used so it can tune 2532228561Snp * things accordingly. 2533228561Snp */ 2534228561Snp LIMIT_CAPS(linkcaps); 2535228561Snp LIMIT_CAPS(niccaps); 2536228561Snp LIMIT_CAPS(toecaps); 2537228561Snp LIMIT_CAPS(rdmacaps); 2538228561Snp LIMIT_CAPS(iscsicaps); 2539228561Snp LIMIT_CAPS(fcoecaps); 2540228561Snp#undef LIMIT_CAPS 2541228561Snp 2542228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2543218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE); 2544228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 2545228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), NULL); 2546228561Snp if (rc != 0) { 2547228561Snp device_printf(sc->dev, 2548228561Snp "failed to process config file: %d.\n", rc); 2549228561Snp } 2550248925Snpdone: 2551248925Snp if (cfg != NULL) 2552248925Snp firmware_put(cfg, FIRMWARE_UNLOAD); 2553248925Snp return (rc); 2554218792Snp} 2555218792Snp 2556228561Snp/* 2557248925Snp * Retrieve parameters that are needed (or nice to have) very early. 2558228561Snp */ 2559218792Snpstatic int 2560228561Snpget_params__pre_init(struct adapter *sc) 2561218792Snp{ 2562218792Snp int rc; 2563228561Snp uint32_t param[2], val[2]; 2564228561Snp struct fw_devlog_cmd cmd; 2565228561Snp struct devlog_params *dlog = &sc->params.devlog; 2566218792Snp 2567228561Snp param[0] = FW_PARAM_DEV(PORTVEC); 2568228561Snp param[1] = FW_PARAM_DEV(CCLK); 2569228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 2570218792Snp if (rc != 0) { 2571218792Snp device_printf(sc->dev, 2572228561Snp "failed to query parameters (pre_init): %d.\n", rc); 2573228561Snp return (rc); 2574218792Snp } 2575218792Snp 2576218792Snp sc->params.portvec = val[0]; 2577240452Snp sc->params.nports = bitcount32(val[0]); 2578228561Snp sc->params.vpd.cclk = val[1]; 2579218792Snp 2580228561Snp /* Read device log parameters. */ 2581228561Snp bzero(&cmd, sizeof(cmd)); 2582228561Snp cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) | 2583228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2584228561Snp cmd.retval_len16 = htobe32(FW_LEN16(cmd)); 2585228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &cmd, sizeof(cmd), &cmd); 2586228561Snp if (rc != 0) { 2587228561Snp device_printf(sc->dev, 2588228561Snp "failed to get devlog parameters: %d.\n", rc); 2589228561Snp bzero(dlog, sizeof (*dlog)); 2590228561Snp rc = 0; /* devlog isn't critical for device operation */ 2591228561Snp } else { 2592228561Snp val[0] = be32toh(cmd.memtype_devlog_memaddr16_devlog); 2593228561Snp dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(val[0]); 2594228561Snp dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(val[0]) << 4; 2595228561Snp dlog->size = be32toh(cmd.memsize_devlog); 2596228561Snp } 2597228561Snp 2598228561Snp return (rc); 2599228561Snp} 2600228561Snp 2601228561Snp/* 2602228561Snp * Retrieve various parameters that are of interest to the driver. The device 2603228561Snp * has been initialized by the firmware at this point. 2604228561Snp */ 2605228561Snpstatic int 2606228561Snpget_params__post_init(struct adapter *sc) 2607228561Snp{ 2608228561Snp int rc; 2609228561Snp uint32_t param[7], val[7]; 2610228561Snp struct fw_caps_config_cmd caps; 2611228561Snp 2612228561Snp param[0] = FW_PARAM_PFVF(IQFLINT_START); 2613228561Snp param[1] = FW_PARAM_PFVF(EQ_START); 2614228561Snp param[2] = FW_PARAM_PFVF(FILTER_START); 2615228561Snp param[3] = FW_PARAM_PFVF(FILTER_END); 2616245434Snp param[4] = FW_PARAM_PFVF(L2T_START); 2617245434Snp param[5] = FW_PARAM_PFVF(L2T_END); 2618245434Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2619228561Snp if (rc != 0) { 2620228561Snp device_printf(sc->dev, 2621228561Snp "failed to query parameters (post_init): %d.\n", rc); 2622228561Snp return (rc); 2623228561Snp } 2624228561Snp 2625228561Snp sc->sge.iq_start = val[0]; 2626228561Snp sc->sge.eq_start = val[1]; 2627228561Snp sc->tids.ftid_base = val[2]; 2628228561Snp sc->tids.nftids = val[3] - val[2] + 1; 2629265426Snp sc->params.ftid_min = val[2]; 2630265426Snp sc->params.ftid_max = val[3]; 2631245434Snp sc->vres.l2t.start = val[4]; 2632245434Snp sc->vres.l2t.size = val[5] - val[4] + 1; 2633245434Snp KASSERT(sc->vres.l2t.size <= L2T_SIZE, 2634245434Snp ("%s: L2 table size (%u) larger than expected (%u)", 2635245434Snp __func__, sc->vres.l2t.size, L2T_SIZE)); 2636228561Snp 2637228561Snp /* get capabilites */ 2638228561Snp bzero(&caps, sizeof(caps)); 2639228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 2640228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 2641228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 2642228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 2643228561Snp if (rc != 0) { 2644228561Snp device_printf(sc->dev, 2645228561Snp "failed to get card capabilities: %d.\n", rc); 2646228561Snp return (rc); 2647228561Snp } 2648228561Snp 2649265426Snp#define READ_CAPS(x) do { \ 2650265426Snp sc->x = htobe16(caps.x); \ 2651265426Snp} while (0) 2652265426Snp READ_CAPS(linkcaps); 2653265426Snp READ_CAPS(niccaps); 2654265426Snp READ_CAPS(toecaps); 2655265426Snp READ_CAPS(rdmacaps); 2656265426Snp READ_CAPS(iscsicaps); 2657265426Snp READ_CAPS(fcoecaps); 2658265426Snp 2659265426Snp if (sc->niccaps & FW_CAPS_CONFIG_NIC_ETHOFLD) { 2660265426Snp param[0] = FW_PARAM_PFVF(ETHOFLD_START); 2661265426Snp param[1] = FW_PARAM_PFVF(ETHOFLD_END); 2662265426Snp param[2] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 2663265426Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 3, param, val); 2664265426Snp if (rc != 0) { 2665265426Snp device_printf(sc->dev, 2666265426Snp "failed to query NIC parameters: %d.\n", rc); 2667265426Snp return (rc); 2668265426Snp } 2669265426Snp sc->tids.etid_base = val[0]; 2670265426Snp sc->params.etid_min = val[0]; 2671265426Snp sc->tids.netids = val[1] - val[0] + 1; 2672265426Snp sc->params.netids = sc->tids.netids; 2673265426Snp sc->params.eo_wr_cred = val[2]; 2674265426Snp sc->params.ethoffload = 1; 2675265426Snp } 2676265426Snp 2677265426Snp if (sc->toecaps) { 2678218792Snp /* query offload-related parameters */ 2679228561Snp param[0] = FW_PARAM_DEV(NTID); 2680228561Snp param[1] = FW_PARAM_PFVF(SERVER_START); 2681228561Snp param[2] = FW_PARAM_PFVF(SERVER_END); 2682228561Snp param[3] = FW_PARAM_PFVF(TDDP_START); 2683228561Snp param[4] = FW_PARAM_PFVF(TDDP_END); 2684228561Snp param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 2685228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2686218792Snp if (rc != 0) { 2687218792Snp device_printf(sc->dev, 2688218792Snp "failed to query TOE parameters: %d.\n", rc); 2689228561Snp return (rc); 2690218792Snp } 2691218792Snp sc->tids.ntids = val[0]; 2692218792Snp sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS); 2693218792Snp sc->tids.stid_base = val[1]; 2694218792Snp sc->tids.nstids = val[2] - val[1] + 1; 2695218792Snp sc->vres.ddp.start = val[3]; 2696218792Snp sc->vres.ddp.size = val[4] - val[3] + 1; 2697218792Snp sc->params.ofldq_wr_cred = val[5]; 2698218792Snp sc->params.offload = 1; 2699218792Snp } 2700265426Snp if (sc->rdmacaps) { 2701228561Snp param[0] = FW_PARAM_PFVF(STAG_START); 2702228561Snp param[1] = FW_PARAM_PFVF(STAG_END); 2703228561Snp param[2] = FW_PARAM_PFVF(RQ_START); 2704228561Snp param[3] = FW_PARAM_PFVF(RQ_END); 2705228561Snp param[4] = FW_PARAM_PFVF(PBL_START); 2706228561Snp param[5] = FW_PARAM_PFVF(PBL_END); 2707228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2708218792Snp if (rc != 0) { 2709218792Snp device_printf(sc->dev, 2710228561Snp "failed to query RDMA parameters(1): %d.\n", rc); 2711228561Snp return (rc); 2712218792Snp } 2713218792Snp sc->vres.stag.start = val[0]; 2714218792Snp sc->vres.stag.size = val[1] - val[0] + 1; 2715218792Snp sc->vres.rq.start = val[2]; 2716218792Snp sc->vres.rq.size = val[3] - val[2] + 1; 2717218792Snp sc->vres.pbl.start = val[4]; 2718218792Snp sc->vres.pbl.size = val[5] - val[4] + 1; 2719228561Snp 2720228561Snp param[0] = FW_PARAM_PFVF(SQRQ_START); 2721228561Snp param[1] = FW_PARAM_PFVF(SQRQ_END); 2722228561Snp param[2] = FW_PARAM_PFVF(CQ_START); 2723228561Snp param[3] = FW_PARAM_PFVF(CQ_END); 2724228561Snp param[4] = FW_PARAM_PFVF(OCQ_START); 2725228561Snp param[5] = FW_PARAM_PFVF(OCQ_END); 2726254933Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 2727228561Snp if (rc != 0) { 2728228561Snp device_printf(sc->dev, 2729228561Snp "failed to query RDMA parameters(2): %d.\n", rc); 2730228561Snp return (rc); 2731228561Snp } 2732228561Snp sc->vres.qp.start = val[0]; 2733228561Snp sc->vres.qp.size = val[1] - val[0] + 1; 2734228561Snp sc->vres.cq.start = val[2]; 2735228561Snp sc->vres.cq.size = val[3] - val[2] + 1; 2736228561Snp sc->vres.ocq.start = val[4]; 2737228561Snp sc->vres.ocq.size = val[5] - val[4] + 1; 2738218792Snp } 2739265426Snp if (sc->iscsicaps) { 2740228561Snp param[0] = FW_PARAM_PFVF(ISCSI_START); 2741228561Snp param[1] = FW_PARAM_PFVF(ISCSI_END); 2742228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 2743218792Snp if (rc != 0) { 2744218792Snp device_printf(sc->dev, 2745218792Snp "failed to query iSCSI parameters: %d.\n", rc); 2746228561Snp return (rc); 2747218792Snp } 2748218792Snp sc->vres.iscsi.start = val[0]; 2749218792Snp sc->vres.iscsi.size = val[1] - val[0] + 1; 2750218792Snp } 2751218792Snp 2752248925Snp /* 2753248925Snp * We've got the params we wanted to query via the firmware. Now grab 2754248925Snp * some others directly from the chip. 2755248925Snp */ 2756248925Snp rc = t4_read_chip_settings(sc); 2757228561Snp 2758218792Snp return (rc); 2759218792Snp} 2760218792Snp 2761247291Snpstatic int 2762247291Snpset_params__post_init(struct adapter *sc) 2763247291Snp{ 2764247291Snp uint32_t param, val; 2765247291Snp 2766249382Snp /* ask for encapsulated CPLs */ 2767247291Snp param = FW_PARAM_PFVF(CPLFW4MSG_ENCAP); 2768249382Snp val = 1; 2769249382Snp (void)t4_set_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 2770247291Snp 2771249382Snp return (0); 2772247291Snp} 2773247291Snp 2774228561Snp#undef FW_PARAM_PFVF 2775228561Snp#undef FW_PARAM_DEV 2776228561Snp 2777218792Snpstatic void 2778218792Snpt4_set_desc(struct adapter *sc) 2779218792Snp{ 2780218792Snp char buf[128]; 2781218792Snp struct adapter_params *p = &sc->params; 2782218792Snp 2783254577Snp snprintf(buf, sizeof(buf), "Chelsio %s %sNIC (rev %d), S/N:%s, " 2784254577Snp "P/N:%s, E/C:%s", p->vpd.id, is_offload(sc) ? "R" : "", 2785254577Snp chip_rev(sc), p->vpd.sn, p->vpd.pn, p->vpd.ec); 2786218792Snp 2787218792Snp device_set_desc_copy(sc->dev, buf); 2788218792Snp} 2789218792Snp 2790218792Snpstatic void 2791270297Snpbuild_medialist(struct port_info *pi, struct ifmedia *media) 2792218792Snp{ 2793218792Snp int data, m; 2794218792Snp 2795218792Snp PORT_LOCK(pi); 2796218792Snp 2797218792Snp ifmedia_removeall(media); 2798218792Snp 2799218792Snp m = IFM_ETHER | IFM_FDX; 2800218792Snp data = (pi->port_type << 8) | pi->mod_type; 2801218792Snp 2802218792Snp switch(pi->port_type) { 2803218792Snp case FW_PORT_TYPE_BT_XFI: 2804218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2805218792Snp break; 2806218792Snp 2807218792Snp case FW_PORT_TYPE_BT_XAUI: 2808218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2809218792Snp /* fall through */ 2810218792Snp 2811218792Snp case FW_PORT_TYPE_BT_SGMII: 2812218792Snp ifmedia_add(media, m | IFM_1000_T, data, NULL); 2813218792Snp ifmedia_add(media, m | IFM_100_TX, data, NULL); 2814218792Snp ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL); 2815218792Snp ifmedia_set(media, IFM_ETHER | IFM_AUTO); 2816218792Snp break; 2817218792Snp 2818218792Snp case FW_PORT_TYPE_CX4: 2819218792Snp ifmedia_add(media, m | IFM_10G_CX4, data, NULL); 2820218792Snp ifmedia_set(media, m | IFM_10G_CX4); 2821218792Snp break; 2822218792Snp 2823265410Snp case FW_PORT_TYPE_QSFP_10G: 2824218792Snp case FW_PORT_TYPE_SFP: 2825218792Snp case FW_PORT_TYPE_FIBER_XFI: 2826218792Snp case FW_PORT_TYPE_FIBER_XAUI: 2827218792Snp switch (pi->mod_type) { 2828218792Snp 2829218792Snp case FW_PORT_MOD_TYPE_LR: 2830218792Snp ifmedia_add(media, m | IFM_10G_LR, data, NULL); 2831218792Snp ifmedia_set(media, m | IFM_10G_LR); 2832218792Snp break; 2833218792Snp 2834218792Snp case FW_PORT_MOD_TYPE_SR: 2835218792Snp ifmedia_add(media, m | IFM_10G_SR, data, NULL); 2836218792Snp ifmedia_set(media, m | IFM_10G_SR); 2837218792Snp break; 2838218792Snp 2839218792Snp case FW_PORT_MOD_TYPE_LRM: 2840218792Snp ifmedia_add(media, m | IFM_10G_LRM, data, NULL); 2841218792Snp ifmedia_set(media, m | IFM_10G_LRM); 2842218792Snp break; 2843218792Snp 2844218792Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2845218792Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2846218792Snp ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL); 2847218792Snp ifmedia_set(media, m | IFM_10G_TWINAX); 2848218792Snp break; 2849218792Snp 2850218792Snp case FW_PORT_MOD_TYPE_NONE: 2851218792Snp m &= ~IFM_FDX; 2852218792Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2853218792Snp ifmedia_set(media, m | IFM_NONE); 2854218792Snp break; 2855218792Snp 2856218792Snp case FW_PORT_MOD_TYPE_NA: 2857218792Snp case FW_PORT_MOD_TYPE_ER: 2858218792Snp default: 2859250092Snp device_printf(pi->dev, 2860250092Snp "unknown port_type (%d), mod_type (%d)\n", 2861250092Snp pi->port_type, pi->mod_type); 2862218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2863218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2864218792Snp break; 2865218792Snp } 2866218792Snp break; 2867218792Snp 2868250092Snp case FW_PORT_TYPE_QSFP: 2869250092Snp switch (pi->mod_type) { 2870250092Snp 2871250092Snp case FW_PORT_MOD_TYPE_LR: 2872250092Snp ifmedia_add(media, m | IFM_40G_LR4, data, NULL); 2873250092Snp ifmedia_set(media, m | IFM_40G_LR4); 2874250092Snp break; 2875250092Snp 2876250092Snp case FW_PORT_MOD_TYPE_SR: 2877250092Snp ifmedia_add(media, m | IFM_40G_SR4, data, NULL); 2878250092Snp ifmedia_set(media, m | IFM_40G_SR4); 2879250092Snp break; 2880250614Snp 2881250092Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2882250092Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2883250092Snp ifmedia_add(media, m | IFM_40G_CR4, data, NULL); 2884250092Snp ifmedia_set(media, m | IFM_40G_CR4); 2885250092Snp break; 2886250092Snp 2887250614Snp case FW_PORT_MOD_TYPE_NONE: 2888250614Snp m &= ~IFM_FDX; 2889250614Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2890250614Snp ifmedia_set(media, m | IFM_NONE); 2891250614Snp break; 2892250614Snp 2893250092Snp default: 2894250092Snp device_printf(pi->dev, 2895250092Snp "unknown port_type (%d), mod_type (%d)\n", 2896250092Snp pi->port_type, pi->mod_type); 2897250092Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2898250092Snp ifmedia_set(media, m | IFM_UNKNOWN); 2899250092Snp break; 2900250092Snp } 2901250092Snp break; 2902250092Snp 2903218792Snp default: 2904250092Snp device_printf(pi->dev, 2905250092Snp "unknown port_type (%d), mod_type (%d)\n", pi->port_type, 2906250092Snp pi->mod_type); 2907218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2908218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2909218792Snp break; 2910218792Snp } 2911218792Snp 2912218792Snp PORT_UNLOCK(pi); 2913218792Snp} 2914218792Snp 2915231172Snp#define FW_MAC_EXACT_CHUNK 7 2916231172Snp 2917218792Snp/* 2918218792Snp * Program the port's XGMAC based on parameters in ifnet. The caller also 2919218792Snp * indicates which parameters should be programmed (the rest are left alone). 2920218792Snp */ 2921270297Snpint 2922270297Snpupdate_mac_settings(struct ifnet *ifp, int flags) 2923218792Snp{ 2924270297Snp int rc = 0; 2925270297Snp struct port_info *pi = ifp->if_softc; 2926218792Snp struct adapter *sc = pi->adapter; 2927218792Snp int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1; 2928270297Snp uint16_t viid = 0xffff; 2929270297Snp int16_t *xact_addr_filt = NULL; 2930218792Snp 2931245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2932218792Snp KASSERT(flags, ("%s: not told what to update.", __func__)); 2933218792Snp 2934270297Snp if (ifp == pi->ifp) { 2935270297Snp viid = pi->viid; 2936270297Snp xact_addr_filt = &pi->xact_addr_filt; 2937270297Snp } 2938270297Snp#ifdef DEV_NETMAP 2939270297Snp else if (ifp == pi->nm_ifp) { 2940270297Snp viid = pi->nm_viid; 2941270297Snp xact_addr_filt = &pi->nm_xact_addr_filt; 2942270297Snp } 2943270297Snp#endif 2944218792Snp if (flags & XGMAC_MTU) 2945218792Snp mtu = ifp->if_mtu; 2946218792Snp 2947218792Snp if (flags & XGMAC_PROMISC) 2948218792Snp promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0; 2949218792Snp 2950218792Snp if (flags & XGMAC_ALLMULTI) 2951218792Snp allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0; 2952218792Snp 2953218792Snp if (flags & XGMAC_VLANEX) 2954218792Snp vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0; 2955218792Snp 2956270297Snp if (flags & (XGMAC_MTU|XGMAC_PROMISC|XGMAC_ALLMULTI|XGMAC_VLANEX)) { 2957270297Snp rc = -t4_set_rxmode(sc, sc->mbox, viid, mtu, promisc, allmulti, 2958270297Snp 1, vlanex, false); 2959270297Snp if (rc) { 2960270297Snp if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, 2961270297Snp rc); 2962270297Snp return (rc); 2963270297Snp } 2964218792Snp } 2965218792Snp 2966218792Snp if (flags & XGMAC_UCADDR) { 2967218792Snp uint8_t ucaddr[ETHER_ADDR_LEN]; 2968218792Snp 2969218792Snp bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr)); 2970270297Snp rc = t4_change_mac(sc, sc->mbox, viid, *xact_addr_filt, ucaddr, 2971270297Snp true, true); 2972218792Snp if (rc < 0) { 2973218792Snp rc = -rc; 2974218792Snp if_printf(ifp, "change_mac failed: %d\n", rc); 2975218792Snp return (rc); 2976218792Snp } else { 2977270297Snp *xact_addr_filt = rc; 2978218792Snp rc = 0; 2979218792Snp } 2980218792Snp } 2981218792Snp 2982218792Snp if (flags & XGMAC_MCADDRS) { 2983231172Snp const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK]; 2984218792Snp int del = 1; 2985218792Snp uint64_t hash = 0; 2986218792Snp struct ifmultiaddr *ifma; 2987231172Snp int i = 0, j; 2988218792Snp 2989218792Snp if_maddr_rlock(ifp); 2990218792Snp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2991238054Snp if (ifma->ifma_addr->sa_family != AF_LINK) 2992218792Snp continue; 2993231172Snp mcaddr[i++] = 2994231172Snp LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 2995218792Snp 2996231172Snp if (i == FW_MAC_EXACT_CHUNK) { 2997270297Snp rc = t4_alloc_mac_filt(sc, sc->mbox, viid, del, 2998270297Snp i, mcaddr, NULL, &hash, 0); 2999231172Snp if (rc < 0) { 3000231172Snp rc = -rc; 3001231172Snp for (j = 0; j < i; j++) { 3002231172Snp if_printf(ifp, 3003231172Snp "failed to add mc address" 3004231172Snp " %02x:%02x:%02x:" 3005231172Snp "%02x:%02x:%02x rc=%d\n", 3006231172Snp mcaddr[j][0], mcaddr[j][1], 3007231172Snp mcaddr[j][2], mcaddr[j][3], 3008231172Snp mcaddr[j][4], mcaddr[j][5], 3009231172Snp rc); 3010231172Snp } 3011231172Snp goto mcfail; 3012231172Snp } 3013231172Snp del = 0; 3014231172Snp i = 0; 3015231172Snp } 3016231172Snp } 3017231172Snp if (i > 0) { 3018270297Snp rc = t4_alloc_mac_filt(sc, sc->mbox, viid, del, i, 3019270297Snp mcaddr, NULL, &hash, 0); 3020218792Snp if (rc < 0) { 3021218792Snp rc = -rc; 3022231172Snp for (j = 0; j < i; j++) { 3023231172Snp if_printf(ifp, 3024231172Snp "failed to add mc address" 3025231172Snp " %02x:%02x:%02x:" 3026231172Snp "%02x:%02x:%02x rc=%d\n", 3027231172Snp mcaddr[j][0], mcaddr[j][1], 3028231172Snp mcaddr[j][2], mcaddr[j][3], 3029231172Snp mcaddr[j][4], mcaddr[j][5], 3030231172Snp rc); 3031231172Snp } 3032218792Snp goto mcfail; 3033218792Snp } 3034218792Snp } 3035218792Snp 3036270297Snp rc = -t4_set_addr_hash(sc, sc->mbox, viid, 0, hash, 0); 3037218792Snp if (rc != 0) 3038218792Snp if_printf(ifp, "failed to set mc address hash: %d", rc); 3039218792Snpmcfail: 3040218792Snp if_maddr_runlock(ifp); 3041218792Snp } 3042218792Snp 3043218792Snp return (rc); 3044218792Snp} 3045218792Snp 3046245274Snpint 3047245274Snpbegin_synchronized_op(struct adapter *sc, struct port_info *pi, int flags, 3048245274Snp char *wmesg) 3049218792Snp{ 3050245274Snp int rc, pri; 3051218792Snp 3052245274Snp#ifdef WITNESS 3053245274Snp /* the caller thinks it's ok to sleep, but is it really? */ 3054245274Snp if (flags & SLEEP_OK) 3055245274Snp pause("t4slptst", 1); 3056245274Snp#endif 3057218792Snp 3058245274Snp if (INTR_OK) 3059245274Snp pri = PCATCH; 3060245274Snp else 3061245274Snp pri = 0; 3062245274Snp 3063245274Snp ADAPTER_LOCK(sc); 3064245274Snp for (;;) { 3065245274Snp 3066245274Snp if (pi && IS_DOOMED(pi)) { 3067245274Snp rc = ENXIO; 3068245274Snp goto done; 3069245274Snp } 3070245274Snp 3071245274Snp if (!IS_BUSY(sc)) { 3072245274Snp rc = 0; 3073245274Snp break; 3074245274Snp } 3075245274Snp 3076245274Snp if (!(flags & SLEEP_OK)) { 3077245274Snp rc = EBUSY; 3078245274Snp goto done; 3079245274Snp } 3080245274Snp 3081245274Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, pri, wmesg, 0)) { 3082218792Snp rc = EINTR; 3083218792Snp goto done; 3084218792Snp } 3085218792Snp } 3086245274Snp 3087218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 3088218792Snp SET_BUSY(sc); 3089245274Snp#ifdef INVARIANTS 3090245274Snp sc->last_op = wmesg; 3091245274Snp sc->last_op_thr = curthread; 3092245274Snp#endif 3093218792Snp 3094245274Snpdone: 3095245274Snp if (!(flags & HOLD_LOCK) || rc) 3096245274Snp ADAPTER_UNLOCK(sc); 3097218792Snp 3098245274Snp return (rc); 3099245274Snp} 3100245274Snp 3101245274Snpvoid 3102245274Snpend_synchronized_op(struct adapter *sc, int flags) 3103245274Snp{ 3104245274Snp 3105245274Snp if (flags & LOCK_HELD) 3106245274Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 3107245274Snp else 3108245274Snp ADAPTER_LOCK(sc); 3109245274Snp 3110218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 3111218792Snp CLR_BUSY(sc); 3112245274Snp wakeup(&sc->flags); 3113218792Snp ADAPTER_UNLOCK(sc); 3114218792Snp} 3115218792Snp 3116218792Snpstatic int 3117218792Snpcxgbe_init_synchronized(struct port_info *pi) 3118218792Snp{ 3119218792Snp struct adapter *sc = pi->adapter; 3120218792Snp struct ifnet *ifp = pi->ifp; 3121228561Snp int rc = 0; 3122218792Snp 3123245274Snp ASSERT_SYNCHRONIZED_OP(sc); 3124218792Snp 3125218792Snp if (isset(&sc->open_device_map, pi->port_id)) { 3126218792Snp KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, 3127218792Snp ("mismatch between open_device_map and if_drv_flags")); 3128218792Snp return (0); /* already running */ 3129218792Snp } 3130218792Snp 3131228561Snp if (!(sc->flags & FULL_INIT_DONE) && 3132228561Snp ((rc = adapter_full_init(sc)) != 0)) 3133218792Snp return (rc); /* error message displayed already */ 3134218792Snp 3135228561Snp if (!(pi->flags & PORT_INIT_DONE) && 3136228561Snp ((rc = port_full_init(pi)) != 0)) 3137228561Snp return (rc); /* error message displayed already */ 3138218792Snp 3139270297Snp rc = update_mac_settings(ifp, XGMAC_ALL); 3140218792Snp if (rc) 3141218792Snp goto done; /* error message displayed already */ 3142218792Snp 3143218792Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true); 3144218792Snp if (rc != 0) { 3145218792Snp if_printf(ifp, "enable_vi failed: %d\n", rc); 3146218792Snp goto done; 3147218792Snp } 3148218792Snp 3149253691Snp /* 3150253691Snp * The first iq of the first port to come up is used for tracing. 3151253691Snp */ 3152253691Snp if (sc->traceq < 0) { 3153253691Snp sc->traceq = sc->sge.rxq[pi->first_rxq].iq.abs_id; 3154253691Snp t4_write_reg(sc, is_t4(sc) ? A_MPS_TRC_RSS_CONTROL : 3155253691Snp A_MPS_T5_TRC_RSS_CONTROL, V_RSSCONTROL(pi->tx_chan) | 3156253691Snp V_QUEUENUMBER(sc->traceq)); 3157253691Snp pi->flags |= HAS_TRACEQ; 3158253691Snp } 3159253691Snp 3160218792Snp /* all ok */ 3161218792Snp setbit(&sc->open_device_map, pi->port_id); 3162245274Snp PORT_LOCK(pi); 3163218792Snp ifp->if_drv_flags |= IFF_DRV_RUNNING; 3164245274Snp PORT_UNLOCK(pi); 3165218792Snp 3166218792Snp callout_reset(&pi->tick, hz, cxgbe_tick, pi); 3167218792Snpdone: 3168218792Snp if (rc != 0) 3169218792Snp cxgbe_uninit_synchronized(pi); 3170218792Snp 3171218792Snp return (rc); 3172218792Snp} 3173218792Snp 3174218792Snp/* 3175218792Snp * Idempotent. 3176218792Snp */ 3177218792Snpstatic int 3178218792Snpcxgbe_uninit_synchronized(struct port_info *pi) 3179218792Snp{ 3180218792Snp struct adapter *sc = pi->adapter; 3181218792Snp struct ifnet *ifp = pi->ifp; 3182218792Snp int rc; 3183218792Snp 3184245274Snp ASSERT_SYNCHRONIZED_OP(sc); 3185218792Snp 3186218792Snp /* 3187228561Snp * Disable the VI so that all its data in either direction is discarded 3188228561Snp * by the MPS. Leave everything else (the queues, interrupts, and 1Hz 3189228561Snp * tick) intact as the TP can deliver negative advice or data that it's 3190228561Snp * holding in its RAM (for an offloaded connection) even after the VI is 3191228561Snp * disabled. 3192218792Snp */ 3193228561Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false); 3194228561Snp if (rc) { 3195228561Snp if_printf(ifp, "disable_vi failed: %d\n", rc); 3196228561Snp return (rc); 3197228561Snp } 3198228561Snp 3199218792Snp clrbit(&sc->open_device_map, pi->port_id); 3200245274Snp PORT_LOCK(pi); 3201228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 3202245274Snp PORT_UNLOCK(pi); 3203218792Snp 3204218792Snp pi->link_cfg.link_ok = 0; 3205218792Snp pi->link_cfg.speed = 0; 3206252747Snp pi->linkdnrc = -1; 3207252747Snp t4_os_link_changed(sc, pi->port_id, 0, -1); 3208218792Snp 3209218792Snp return (0); 3210218792Snp} 3211218792Snp 3212240453Snp/* 3213240453Snp * It is ok for this function to fail midway and return right away. t4_detach 3214240453Snp * will walk the entire sc->irq list and clean up whatever is valid. 3215240453Snp */ 3216218792Snpstatic int 3217240453Snpsetup_intr_handlers(struct adapter *sc) 3218218792Snp{ 3219240453Snp int rc, rid, p, q; 3220222510Snp char s[8]; 3221222510Snp struct irq *irq; 3222228561Snp struct port_info *pi; 3223228561Snp struct sge_rxq *rxq; 3224237263Snp#ifdef TCP_OFFLOAD 3225228561Snp struct sge_ofld_rxq *ofld_rxq; 3226228561Snp#endif 3227270297Snp#ifdef DEV_NETMAP 3228270297Snp struct sge_nm_rxq *nm_rxq; 3229270297Snp#endif 3230218792Snp 3231218792Snp /* 3232218792Snp * Setup interrupts. 3233218792Snp */ 3234222510Snp irq = &sc->irq[0]; 3235222510Snp rid = sc->intr_type == INTR_INTX ? 0 : 1; 3236270297Snp if (sc->intr_count == 1) 3237270297Snp return (t4_alloc_irq(sc, irq, rid, t4_intr_all, sc, "all")); 3238222510Snp 3239270297Snp /* Multiple interrupts. */ 3240270297Snp KASSERT(sc->intr_count >= T4_EXTRA_INTR + sc->params.nports, 3241270297Snp ("%s: too few intr.", __func__)); 3242228561Snp 3243270297Snp /* The first one is always error intr */ 3244270297Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_err, sc, "err"); 3245270297Snp if (rc != 0) 3246270297Snp return (rc); 3247270297Snp irq++; 3248270297Snp rid++; 3249218792Snp 3250270297Snp /* The second one is always the firmware event queue */ 3251270297Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_evt, &sc->sge.fwq, "evt"); 3252270297Snp if (rc != 0) 3253270297Snp return (rc); 3254270297Snp irq++; 3255270297Snp rid++; 3256222510Snp 3257270297Snp for_each_port(sc, p) { 3258270297Snp pi = sc->port[p]; 3259222510Snp 3260270297Snp if (pi->flags & INTR_RXQ) { 3261270297Snp for_each_rxq(pi, q, rxq) { 3262228561Snp snprintf(s, sizeof(s), "%d.%d", p, q); 3263240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, rxq, 3264240453Snp s); 3265240453Snp if (rc != 0) 3266240453Snp return (rc); 3267222510Snp irq++; 3268222510Snp rid++; 3269218792Snp } 3270270297Snp } 3271237263Snp#ifdef TCP_OFFLOAD 3272270297Snp if (pi->flags & INTR_OFLD_RXQ) { 3273270297Snp for_each_ofld_rxq(pi, q, ofld_rxq) { 3274228561Snp snprintf(s, sizeof(s), "%d,%d", p, q); 3275240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, 3276240453Snp ofld_rxq, s); 3277240453Snp if (rc != 0) 3278240453Snp return (rc); 3279228561Snp irq++; 3280228561Snp rid++; 3281218792Snp } 3282270297Snp } 3283228561Snp#endif 3284270297Snp#ifdef DEV_NETMAP 3285270297Snp if (pi->flags & INTR_NM_RXQ) { 3286270297Snp for_each_nm_rxq(pi, q, nm_rxq) { 3287270297Snp snprintf(s, sizeof(s), "%d-%d", p, q); 3288270297Snp rc = t4_alloc_irq(sc, irq, rid, t4_nm_intr, 3289270297Snp nm_rxq, s); 3290270297Snp if (rc != 0) 3291270297Snp return (rc); 3292270297Snp irq++; 3293270297Snp rid++; 3294270297Snp } 3295218792Snp } 3296270297Snp#endif 3297218792Snp } 3298270297Snp MPASS(irq == &sc->irq[sc->intr_count]); 3299218792Snp 3300240453Snp return (0); 3301240453Snp} 3302240453Snp 3303270297Snpint 3304240453Snpadapter_full_init(struct adapter *sc) 3305240453Snp{ 3306240453Snp int rc, i; 3307240453Snp 3308240453Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 3309240453Snp KASSERT((sc->flags & FULL_INIT_DONE) == 0, 3310240453Snp ("%s: FULL_INIT_DONE already", __func__)); 3311240453Snp 3312240453Snp /* 3313240453Snp * queues that belong to the adapter (not any particular port). 3314240453Snp */ 3315240453Snp rc = t4_setup_adapter_queues(sc); 3316240453Snp if (rc != 0) 3317240453Snp goto done; 3318240453Snp 3319240453Snp for (i = 0; i < nitems(sc->tq); i++) { 3320240453Snp sc->tq[i] = taskqueue_create("t4 taskq", M_NOWAIT, 3321240453Snp taskqueue_thread_enqueue, &sc->tq[i]); 3322240453Snp if (sc->tq[i] == NULL) { 3323240453Snp device_printf(sc->dev, 3324240453Snp "failed to allocate task queue %d\n", i); 3325240453Snp rc = ENOMEM; 3326240453Snp goto done; 3327240453Snp } 3328240453Snp taskqueue_start_threads(&sc->tq[i], 1, PI_NET, "%s tq%d", 3329240453Snp device_get_nameunit(sc->dev), i); 3330240453Snp } 3331240453Snp 3332218792Snp t4_intr_enable(sc); 3333218792Snp sc->flags |= FULL_INIT_DONE; 3334218792Snpdone: 3335218792Snp if (rc != 0) 3336228561Snp adapter_full_uninit(sc); 3337218792Snp 3338218792Snp return (rc); 3339218792Snp} 3340218792Snp 3341270297Snpint 3342228561Snpadapter_full_uninit(struct adapter *sc) 3343218792Snp{ 3344218792Snp int i; 3345218792Snp 3346218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 3347218792Snp 3348220873Snp t4_teardown_adapter_queues(sc); 3349218792Snp 3350240452Snp for (i = 0; i < nitems(sc->tq) && sc->tq[i]; i++) { 3351228561Snp taskqueue_free(sc->tq[i]); 3352228561Snp sc->tq[i] = NULL; 3353228561Snp } 3354228561Snp 3355218792Snp sc->flags &= ~FULL_INIT_DONE; 3356218792Snp 3357218792Snp return (0); 3358218792Snp} 3359218792Snp 3360270297Snpint 3361228561Snpport_full_init(struct port_info *pi) 3362228561Snp{ 3363228561Snp struct adapter *sc = pi->adapter; 3364228561Snp struct ifnet *ifp = pi->ifp; 3365228561Snp uint16_t *rss; 3366228561Snp struct sge_rxq *rxq; 3367259142Snp int rc, i, j; 3368228561Snp 3369245274Snp ASSERT_SYNCHRONIZED_OP(sc); 3370228561Snp KASSERT((pi->flags & PORT_INIT_DONE) == 0, 3371228561Snp ("%s: PORT_INIT_DONE already", __func__)); 3372228561Snp 3373228561Snp sysctl_ctx_init(&pi->ctx); 3374228561Snp pi->flags |= PORT_SYSCTL_CTX; 3375228561Snp 3376228561Snp /* 3377228561Snp * Allocate tx/rx/fl queues for this port. 3378228561Snp */ 3379228561Snp rc = t4_setup_port_queues(pi); 3380228561Snp if (rc != 0) 3381228561Snp goto done; /* error message displayed already */ 3382228561Snp 3383228561Snp /* 3384259142Snp * Setup RSS for this port. Save a copy of the RSS table for later use. 3385228561Snp */ 3386259142Snp rss = malloc(pi->rss_size * sizeof (*rss), M_CXGBE, M_ZERO | M_WAITOK); 3387259142Snp for (i = 0; i < pi->rss_size;) { 3388259142Snp for_each_rxq(pi, j, rxq) { 3389259142Snp rss[i++] = rxq->iq.abs_id; 3390259142Snp if (i == pi->rss_size) 3391259142Snp break; 3392259142Snp } 3393228561Snp } 3394259142Snp 3395259142Snp rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, pi->rss_size, rss, 3396259142Snp pi->rss_size); 3397228561Snp if (rc != 0) { 3398228561Snp if_printf(ifp, "rss_config failed: %d\n", rc); 3399228561Snp goto done; 3400228561Snp } 3401228561Snp 3402259142Snp pi->rss = rss; 3403228561Snp pi->flags |= PORT_INIT_DONE; 3404228561Snpdone: 3405228561Snp if (rc != 0) 3406228561Snp port_full_uninit(pi); 3407228561Snp 3408228561Snp return (rc); 3409228561Snp} 3410228561Snp 3411228561Snp/* 3412228561Snp * Idempotent. 3413228561Snp */ 3414270297Snpint 3415228561Snpport_full_uninit(struct port_info *pi) 3416228561Snp{ 3417228561Snp struct adapter *sc = pi->adapter; 3418228561Snp int i; 3419228561Snp struct sge_rxq *rxq; 3420228561Snp struct sge_txq *txq; 3421237263Snp#ifdef TCP_OFFLOAD 3422228561Snp struct sge_ofld_rxq *ofld_rxq; 3423228561Snp struct sge_wrq *ofld_txq; 3424228561Snp#endif 3425228561Snp 3426228561Snp if (pi->flags & PORT_INIT_DONE) { 3427228561Snp 3428228561Snp /* Need to quiesce queues. XXX: ctrl queues? */ 3429228561Snp 3430228561Snp for_each_txq(pi, i, txq) { 3431228561Snp quiesce_eq(sc, &txq->eq); 3432228561Snp } 3433228561Snp 3434237263Snp#ifdef TCP_OFFLOAD 3435228561Snp for_each_ofld_txq(pi, i, ofld_txq) { 3436228561Snp quiesce_eq(sc, &ofld_txq->eq); 3437228561Snp } 3438228561Snp#endif 3439228561Snp 3440228561Snp for_each_rxq(pi, i, rxq) { 3441228561Snp quiesce_iq(sc, &rxq->iq); 3442228561Snp quiesce_fl(sc, &rxq->fl); 3443228561Snp } 3444228561Snp 3445237263Snp#ifdef TCP_OFFLOAD 3446228561Snp for_each_ofld_rxq(pi, i, ofld_rxq) { 3447228561Snp quiesce_iq(sc, &ofld_rxq->iq); 3448228561Snp quiesce_fl(sc, &ofld_rxq->fl); 3449228561Snp } 3450228561Snp#endif 3451259142Snp free(pi->rss, M_CXGBE); 3452228561Snp } 3453228561Snp 3454228561Snp t4_teardown_port_queues(pi); 3455228561Snp pi->flags &= ~PORT_INIT_DONE; 3456228561Snp 3457228561Snp return (0); 3458228561Snp} 3459228561Snp 3460228561Snpstatic void 3461228561Snpquiesce_eq(struct adapter *sc, struct sge_eq *eq) 3462228561Snp{ 3463228561Snp EQ_LOCK(eq); 3464228561Snp eq->flags |= EQ_DOOMED; 3465228561Snp 3466228561Snp /* 3467228561Snp * Wait for the response to a credit flush if one's 3468228561Snp * pending. 3469228561Snp */ 3470228561Snp while (eq->flags & EQ_CRFLUSHED) 3471228561Snp mtx_sleep(eq, &eq->eq_lock, 0, "crflush", 0); 3472228561Snp EQ_UNLOCK(eq); 3473228561Snp 3474228561Snp callout_drain(&eq->tx_callout); /* XXX: iffy */ 3475228561Snp pause("callout", 10); /* Still iffy */ 3476228561Snp 3477228561Snp taskqueue_drain(sc->tq[eq->tx_chan], &eq->tx_task); 3478228561Snp} 3479228561Snp 3480228561Snpstatic void 3481228561Snpquiesce_iq(struct adapter *sc, struct sge_iq *iq) 3482228561Snp{ 3483228561Snp (void) sc; /* unused */ 3484228561Snp 3485228561Snp /* Synchronize with the interrupt handler */ 3486228561Snp while (!atomic_cmpset_int(&iq->state, IQS_IDLE, IQS_DISABLED)) 3487228561Snp pause("iqfree", 1); 3488228561Snp} 3489228561Snp 3490228561Snpstatic void 3491228561Snpquiesce_fl(struct adapter *sc, struct sge_fl *fl) 3492228561Snp{ 3493228561Snp mtx_lock(&sc->sfl_lock); 3494228561Snp FL_LOCK(fl); 3495228561Snp fl->flags |= FL_DOOMED; 3496228561Snp FL_UNLOCK(fl); 3497228561Snp mtx_unlock(&sc->sfl_lock); 3498228561Snp 3499228561Snp callout_drain(&sc->sfl_callout); 3500228561Snp KASSERT((fl->flags & FL_STARVING) == 0, 3501228561Snp ("%s: still starving", __func__)); 3502228561Snp} 3503228561Snp 3504228561Snpstatic int 3505218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid, 3506228561Snp driver_intr_t *handler, void *arg, char *name) 3507218792Snp{ 3508218792Snp int rc; 3509218792Snp 3510218792Snp irq->rid = rid; 3511218792Snp irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid, 3512218792Snp RF_SHAREABLE | RF_ACTIVE); 3513218792Snp if (irq->res == NULL) { 3514218792Snp device_printf(sc->dev, 3515218792Snp "failed to allocate IRQ for rid %d, name %s.\n", rid, name); 3516218792Snp return (ENOMEM); 3517218792Snp } 3518218792Snp 3519218792Snp rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET, 3520218792Snp NULL, handler, arg, &irq->tag); 3521218792Snp if (rc != 0) { 3522218792Snp device_printf(sc->dev, 3523218792Snp "failed to setup interrupt for rid %d, name %s: %d\n", 3524218792Snp rid, name, rc); 3525218792Snp } else if (name) 3526218792Snp bus_describe_intr(sc->dev, irq->res, irq->tag, name); 3527218792Snp 3528218792Snp return (rc); 3529218792Snp} 3530218792Snp 3531218792Snpstatic int 3532218792Snpt4_free_irq(struct adapter *sc, struct irq *irq) 3533218792Snp{ 3534218792Snp if (irq->tag) 3535218792Snp bus_teardown_intr(sc->dev, irq->res, irq->tag); 3536218792Snp if (irq->res) 3537218792Snp bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res); 3538218792Snp 3539218792Snp bzero(irq, sizeof(*irq)); 3540218792Snp 3541218792Snp return (0); 3542218792Snp} 3543218792Snp 3544218792Snpstatic void 3545218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start, 3546218792Snp unsigned int end) 3547218792Snp{ 3548218792Snp uint32_t *p = (uint32_t *)(buf + start); 3549218792Snp 3550218792Snp for ( ; start <= end; start += sizeof(uint32_t)) 3551218792Snp *p++ = t4_read_reg(sc, start); 3552218792Snp} 3553218792Snp 3554218792Snpstatic void 3555218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf) 3556218792Snp{ 3557248925Snp int i, n; 3558248925Snp const unsigned int *reg_ranges; 3559248925Snp static const unsigned int t4_reg_ranges[] = { 3560218792Snp 0x1008, 0x1108, 3561218792Snp 0x1180, 0x11b4, 3562218792Snp 0x11fc, 0x123c, 3563218792Snp 0x1300, 0x173c, 3564218792Snp 0x1800, 0x18fc, 3565218792Snp 0x3000, 0x30d8, 3566218792Snp 0x30e0, 0x5924, 3567218792Snp 0x5960, 0x59d4, 3568218792Snp 0x5a00, 0x5af8, 3569218792Snp 0x6000, 0x6098, 3570218792Snp 0x6100, 0x6150, 3571218792Snp 0x6200, 0x6208, 3572218792Snp 0x6240, 0x6248, 3573218792Snp 0x6280, 0x6338, 3574218792Snp 0x6370, 0x638c, 3575218792Snp 0x6400, 0x643c, 3576218792Snp 0x6500, 0x6524, 3577218792Snp 0x6a00, 0x6a38, 3578218792Snp 0x6a60, 0x6a78, 3579218792Snp 0x6b00, 0x6b84, 3580218792Snp 0x6bf0, 0x6c84, 3581218792Snp 0x6cf0, 0x6d84, 3582218792Snp 0x6df0, 0x6e84, 3583218792Snp 0x6ef0, 0x6f84, 3584218792Snp 0x6ff0, 0x7084, 3585218792Snp 0x70f0, 0x7184, 3586218792Snp 0x71f0, 0x7284, 3587218792Snp 0x72f0, 0x7384, 3588218792Snp 0x73f0, 0x7450, 3589218792Snp 0x7500, 0x7530, 3590218792Snp 0x7600, 0x761c, 3591218792Snp 0x7680, 0x76cc, 3592218792Snp 0x7700, 0x7798, 3593218792Snp 0x77c0, 0x77fc, 3594218792Snp 0x7900, 0x79fc, 3595218792Snp 0x7b00, 0x7c38, 3596218792Snp 0x7d00, 0x7efc, 3597218792Snp 0x8dc0, 0x8e1c, 3598218792Snp 0x8e30, 0x8e78, 3599218792Snp 0x8ea0, 0x8f6c, 3600218792Snp 0x8fc0, 0x9074, 3601218792Snp 0x90fc, 0x90fc, 3602218792Snp 0x9400, 0x9458, 3603218792Snp 0x9600, 0x96bc, 3604218792Snp 0x9800, 0x9808, 3605218792Snp 0x9820, 0x983c, 3606218792Snp 0x9850, 0x9864, 3607218792Snp 0x9c00, 0x9c6c, 3608218792Snp 0x9c80, 0x9cec, 3609218792Snp 0x9d00, 0x9d6c, 3610218792Snp 0x9d80, 0x9dec, 3611218792Snp 0x9e00, 0x9e6c, 3612218792Snp 0x9e80, 0x9eec, 3613218792Snp 0x9f00, 0x9f6c, 3614218792Snp 0x9f80, 0x9fec, 3615218792Snp 0xd004, 0xd03c, 3616218792Snp 0xdfc0, 0xdfe0, 3617218792Snp 0xe000, 0xea7c, 3618259142Snp 0xf000, 0x11110, 3619259142Snp 0x11118, 0x11190, 3620237439Snp 0x19040, 0x1906c, 3621237439Snp 0x19078, 0x19080, 3622237439Snp 0x1908c, 0x19124, 3623218792Snp 0x19150, 0x191b0, 3624218792Snp 0x191d0, 0x191e8, 3625218792Snp 0x19238, 0x1924c, 3626218792Snp 0x193f8, 0x19474, 3627218792Snp 0x19490, 0x194f8, 3628218792Snp 0x19800, 0x19f30, 3629218792Snp 0x1a000, 0x1a06c, 3630218792Snp 0x1a0b0, 0x1a120, 3631218792Snp 0x1a128, 0x1a138, 3632218792Snp 0x1a190, 0x1a1c4, 3633218792Snp 0x1a1fc, 0x1a1fc, 3634218792Snp 0x1e040, 0x1e04c, 3635237439Snp 0x1e284, 0x1e28c, 3636218792Snp 0x1e2c0, 0x1e2c0, 3637218792Snp 0x1e2e0, 0x1e2e0, 3638218792Snp 0x1e300, 0x1e384, 3639218792Snp 0x1e3c0, 0x1e3c8, 3640218792Snp 0x1e440, 0x1e44c, 3641237439Snp 0x1e684, 0x1e68c, 3642218792Snp 0x1e6c0, 0x1e6c0, 3643218792Snp 0x1e6e0, 0x1e6e0, 3644218792Snp 0x1e700, 0x1e784, 3645218792Snp 0x1e7c0, 0x1e7c8, 3646218792Snp 0x1e840, 0x1e84c, 3647237439Snp 0x1ea84, 0x1ea8c, 3648218792Snp 0x1eac0, 0x1eac0, 3649218792Snp 0x1eae0, 0x1eae0, 3650218792Snp 0x1eb00, 0x1eb84, 3651218792Snp 0x1ebc0, 0x1ebc8, 3652218792Snp 0x1ec40, 0x1ec4c, 3653237439Snp 0x1ee84, 0x1ee8c, 3654218792Snp 0x1eec0, 0x1eec0, 3655218792Snp 0x1eee0, 0x1eee0, 3656218792Snp 0x1ef00, 0x1ef84, 3657218792Snp 0x1efc0, 0x1efc8, 3658218792Snp 0x1f040, 0x1f04c, 3659237439Snp 0x1f284, 0x1f28c, 3660218792Snp 0x1f2c0, 0x1f2c0, 3661218792Snp 0x1f2e0, 0x1f2e0, 3662218792Snp 0x1f300, 0x1f384, 3663218792Snp 0x1f3c0, 0x1f3c8, 3664218792Snp 0x1f440, 0x1f44c, 3665237439Snp 0x1f684, 0x1f68c, 3666218792Snp 0x1f6c0, 0x1f6c0, 3667218792Snp 0x1f6e0, 0x1f6e0, 3668218792Snp 0x1f700, 0x1f784, 3669218792Snp 0x1f7c0, 0x1f7c8, 3670218792Snp 0x1f840, 0x1f84c, 3671237439Snp 0x1fa84, 0x1fa8c, 3672218792Snp 0x1fac0, 0x1fac0, 3673218792Snp 0x1fae0, 0x1fae0, 3674218792Snp 0x1fb00, 0x1fb84, 3675218792Snp 0x1fbc0, 0x1fbc8, 3676218792Snp 0x1fc40, 0x1fc4c, 3677237439Snp 0x1fe84, 0x1fe8c, 3678218792Snp 0x1fec0, 0x1fec0, 3679218792Snp 0x1fee0, 0x1fee0, 3680218792Snp 0x1ff00, 0x1ff84, 3681218792Snp 0x1ffc0, 0x1ffc8, 3682218792Snp 0x20000, 0x2002c, 3683218792Snp 0x20100, 0x2013c, 3684218792Snp 0x20190, 0x201c8, 3685218792Snp 0x20200, 0x20318, 3686218792Snp 0x20400, 0x20528, 3687218792Snp 0x20540, 0x20614, 3688218792Snp 0x21000, 0x21040, 3689218792Snp 0x2104c, 0x21060, 3690218792Snp 0x210c0, 0x210ec, 3691218792Snp 0x21200, 0x21268, 3692218792Snp 0x21270, 0x21284, 3693218792Snp 0x212fc, 0x21388, 3694218792Snp 0x21400, 0x21404, 3695218792Snp 0x21500, 0x21518, 3696218792Snp 0x2152c, 0x2153c, 3697218792Snp 0x21550, 0x21554, 3698218792Snp 0x21600, 0x21600, 3699218792Snp 0x21608, 0x21628, 3700218792Snp 0x21630, 0x2163c, 3701218792Snp 0x21700, 0x2171c, 3702218792Snp 0x21780, 0x2178c, 3703218792Snp 0x21800, 0x21c38, 3704218792Snp 0x21c80, 0x21d7c, 3705218792Snp 0x21e00, 0x21e04, 3706218792Snp 0x22000, 0x2202c, 3707218792Snp 0x22100, 0x2213c, 3708218792Snp 0x22190, 0x221c8, 3709218792Snp 0x22200, 0x22318, 3710218792Snp 0x22400, 0x22528, 3711218792Snp 0x22540, 0x22614, 3712218792Snp 0x23000, 0x23040, 3713218792Snp 0x2304c, 0x23060, 3714218792Snp 0x230c0, 0x230ec, 3715218792Snp 0x23200, 0x23268, 3716218792Snp 0x23270, 0x23284, 3717218792Snp 0x232fc, 0x23388, 3718218792Snp 0x23400, 0x23404, 3719218792Snp 0x23500, 0x23518, 3720218792Snp 0x2352c, 0x2353c, 3721218792Snp 0x23550, 0x23554, 3722218792Snp 0x23600, 0x23600, 3723218792Snp 0x23608, 0x23628, 3724218792Snp 0x23630, 0x2363c, 3725218792Snp 0x23700, 0x2371c, 3726218792Snp 0x23780, 0x2378c, 3727218792Snp 0x23800, 0x23c38, 3728218792Snp 0x23c80, 0x23d7c, 3729218792Snp 0x23e00, 0x23e04, 3730218792Snp 0x24000, 0x2402c, 3731218792Snp 0x24100, 0x2413c, 3732218792Snp 0x24190, 0x241c8, 3733218792Snp 0x24200, 0x24318, 3734218792Snp 0x24400, 0x24528, 3735218792Snp 0x24540, 0x24614, 3736218792Snp 0x25000, 0x25040, 3737218792Snp 0x2504c, 0x25060, 3738218792Snp 0x250c0, 0x250ec, 3739218792Snp 0x25200, 0x25268, 3740218792Snp 0x25270, 0x25284, 3741218792Snp 0x252fc, 0x25388, 3742218792Snp 0x25400, 0x25404, 3743218792Snp 0x25500, 0x25518, 3744218792Snp 0x2552c, 0x2553c, 3745218792Snp 0x25550, 0x25554, 3746218792Snp 0x25600, 0x25600, 3747218792Snp 0x25608, 0x25628, 3748218792Snp 0x25630, 0x2563c, 3749218792Snp 0x25700, 0x2571c, 3750218792Snp 0x25780, 0x2578c, 3751218792Snp 0x25800, 0x25c38, 3752218792Snp 0x25c80, 0x25d7c, 3753218792Snp 0x25e00, 0x25e04, 3754218792Snp 0x26000, 0x2602c, 3755218792Snp 0x26100, 0x2613c, 3756218792Snp 0x26190, 0x261c8, 3757218792Snp 0x26200, 0x26318, 3758218792Snp 0x26400, 0x26528, 3759218792Snp 0x26540, 0x26614, 3760218792Snp 0x27000, 0x27040, 3761218792Snp 0x2704c, 0x27060, 3762218792Snp 0x270c0, 0x270ec, 3763218792Snp 0x27200, 0x27268, 3764218792Snp 0x27270, 0x27284, 3765218792Snp 0x272fc, 0x27388, 3766218792Snp 0x27400, 0x27404, 3767218792Snp 0x27500, 0x27518, 3768218792Snp 0x2752c, 0x2753c, 3769218792Snp 0x27550, 0x27554, 3770218792Snp 0x27600, 0x27600, 3771218792Snp 0x27608, 0x27628, 3772218792Snp 0x27630, 0x2763c, 3773218792Snp 0x27700, 0x2771c, 3774218792Snp 0x27780, 0x2778c, 3775218792Snp 0x27800, 0x27c38, 3776218792Snp 0x27c80, 0x27d7c, 3777218792Snp 0x27e00, 0x27e04 3778218792Snp }; 3779248925Snp static const unsigned int t5_reg_ranges[] = { 3780248925Snp 0x1008, 0x1148, 3781248925Snp 0x1180, 0x11b4, 3782248925Snp 0x11fc, 0x123c, 3783248925Snp 0x1280, 0x173c, 3784248925Snp 0x1800, 0x18fc, 3785248925Snp 0x3000, 0x3028, 3786248925Snp 0x3060, 0x30d8, 3787248925Snp 0x30e0, 0x30fc, 3788248925Snp 0x3140, 0x357c, 3789248925Snp 0x35a8, 0x35cc, 3790248925Snp 0x35ec, 0x35ec, 3791248925Snp 0x3600, 0x5624, 3792248925Snp 0x56cc, 0x575c, 3793248925Snp 0x580c, 0x5814, 3794248925Snp 0x5890, 0x58bc, 3795248925Snp 0x5940, 0x59dc, 3796248925Snp 0x59fc, 0x5a18, 3797248925Snp 0x5a60, 0x5a9c, 3798248925Snp 0x5b94, 0x5bfc, 3799248925Snp 0x6000, 0x6040, 3800248925Snp 0x6058, 0x614c, 3801248925Snp 0x7700, 0x7798, 3802248925Snp 0x77c0, 0x78fc, 3803248925Snp 0x7b00, 0x7c54, 3804248925Snp 0x7d00, 0x7efc, 3805248925Snp 0x8dc0, 0x8de0, 3806248925Snp 0x8df8, 0x8e84, 3807248925Snp 0x8ea0, 0x8f84, 3808248925Snp 0x8fc0, 0x90f8, 3809248925Snp 0x9400, 0x9470, 3810248925Snp 0x9600, 0x96f4, 3811248925Snp 0x9800, 0x9808, 3812248925Snp 0x9820, 0x983c, 3813248925Snp 0x9850, 0x9864, 3814248925Snp 0x9c00, 0x9c6c, 3815248925Snp 0x9c80, 0x9cec, 3816248925Snp 0x9d00, 0x9d6c, 3817248925Snp 0x9d80, 0x9dec, 3818248925Snp 0x9e00, 0x9e6c, 3819248925Snp 0x9e80, 0x9eec, 3820248925Snp 0x9f00, 0x9f6c, 3821248925Snp 0x9f80, 0xa020, 3822248925Snp 0xd004, 0xd03c, 3823248925Snp 0xdfc0, 0xdfe0, 3824248925Snp 0xe000, 0x11088, 3825259142Snp 0x1109c, 0x11110, 3826259142Snp 0x11118, 0x1117c, 3827248925Snp 0x11190, 0x11204, 3828248925Snp 0x19040, 0x1906c, 3829248925Snp 0x19078, 0x19080, 3830248925Snp 0x1908c, 0x19124, 3831248925Snp 0x19150, 0x191b0, 3832248925Snp 0x191d0, 0x191e8, 3833248925Snp 0x19238, 0x19290, 3834248925Snp 0x193f8, 0x19474, 3835248925Snp 0x19490, 0x194cc, 3836248925Snp 0x194f0, 0x194f8, 3837248925Snp 0x19c00, 0x19c60, 3838248925Snp 0x19c94, 0x19e10, 3839248925Snp 0x19e50, 0x19f34, 3840248925Snp 0x19f40, 0x19f50, 3841248925Snp 0x19f90, 0x19fe4, 3842248925Snp 0x1a000, 0x1a06c, 3843248925Snp 0x1a0b0, 0x1a120, 3844248925Snp 0x1a128, 0x1a138, 3845248925Snp 0x1a190, 0x1a1c4, 3846248925Snp 0x1a1fc, 0x1a1fc, 3847248925Snp 0x1e008, 0x1e00c, 3848248925Snp 0x1e040, 0x1e04c, 3849248925Snp 0x1e284, 0x1e290, 3850248925Snp 0x1e2c0, 0x1e2c0, 3851248925Snp 0x1e2e0, 0x1e2e0, 3852248925Snp 0x1e300, 0x1e384, 3853248925Snp 0x1e3c0, 0x1e3c8, 3854248925Snp 0x1e408, 0x1e40c, 3855248925Snp 0x1e440, 0x1e44c, 3856248925Snp 0x1e684, 0x1e690, 3857248925Snp 0x1e6c0, 0x1e6c0, 3858248925Snp 0x1e6e0, 0x1e6e0, 3859248925Snp 0x1e700, 0x1e784, 3860248925Snp 0x1e7c0, 0x1e7c8, 3861248925Snp 0x1e808, 0x1e80c, 3862248925Snp 0x1e840, 0x1e84c, 3863248925Snp 0x1ea84, 0x1ea90, 3864248925Snp 0x1eac0, 0x1eac0, 3865248925Snp 0x1eae0, 0x1eae0, 3866248925Snp 0x1eb00, 0x1eb84, 3867248925Snp 0x1ebc0, 0x1ebc8, 3868248925Snp 0x1ec08, 0x1ec0c, 3869248925Snp 0x1ec40, 0x1ec4c, 3870248925Snp 0x1ee84, 0x1ee90, 3871248925Snp 0x1eec0, 0x1eec0, 3872248925Snp 0x1eee0, 0x1eee0, 3873248925Snp 0x1ef00, 0x1ef84, 3874248925Snp 0x1efc0, 0x1efc8, 3875248925Snp 0x1f008, 0x1f00c, 3876248925Snp 0x1f040, 0x1f04c, 3877248925Snp 0x1f284, 0x1f290, 3878248925Snp 0x1f2c0, 0x1f2c0, 3879248925Snp 0x1f2e0, 0x1f2e0, 3880248925Snp 0x1f300, 0x1f384, 3881248925Snp 0x1f3c0, 0x1f3c8, 3882248925Snp 0x1f408, 0x1f40c, 3883248925Snp 0x1f440, 0x1f44c, 3884248925Snp 0x1f684, 0x1f690, 3885248925Snp 0x1f6c0, 0x1f6c0, 3886248925Snp 0x1f6e0, 0x1f6e0, 3887248925Snp 0x1f700, 0x1f784, 3888248925Snp 0x1f7c0, 0x1f7c8, 3889248925Snp 0x1f808, 0x1f80c, 3890248925Snp 0x1f840, 0x1f84c, 3891248925Snp 0x1fa84, 0x1fa90, 3892248925Snp 0x1fac0, 0x1fac0, 3893248925Snp 0x1fae0, 0x1fae0, 3894248925Snp 0x1fb00, 0x1fb84, 3895248925Snp 0x1fbc0, 0x1fbc8, 3896248925Snp 0x1fc08, 0x1fc0c, 3897248925Snp 0x1fc40, 0x1fc4c, 3898248925Snp 0x1fe84, 0x1fe90, 3899248925Snp 0x1fec0, 0x1fec0, 3900248925Snp 0x1fee0, 0x1fee0, 3901248925Snp 0x1ff00, 0x1ff84, 3902248925Snp 0x1ffc0, 0x1ffc8, 3903252312Snp 0x30000, 0x30030, 3904248925Snp 0x30100, 0x30144, 3905248925Snp 0x30190, 0x301d0, 3906248925Snp 0x30200, 0x30318, 3907248925Snp 0x30400, 0x3052c, 3908248925Snp 0x30540, 0x3061c, 3909248925Snp 0x30800, 0x30834, 3910248925Snp 0x308c0, 0x30908, 3911248925Snp 0x30910, 0x309ac, 3912252312Snp 0x30a00, 0x30a2c, 3913248925Snp 0x30a44, 0x30a50, 3914248925Snp 0x30a74, 0x30c24, 3915252312Snp 0x30d00, 0x30d00, 3916248925Snp 0x30d08, 0x30d14, 3917248925Snp 0x30d1c, 0x30d20, 3918248925Snp 0x30d3c, 0x30d50, 3919248925Snp 0x31200, 0x3120c, 3920248925Snp 0x31220, 0x31220, 3921248925Snp 0x31240, 0x31240, 3922252312Snp 0x31600, 0x3160c, 3923248925Snp 0x31a00, 0x31a1c, 3924252312Snp 0x31e00, 0x31e20, 3925248925Snp 0x31e38, 0x31e3c, 3926248925Snp 0x31e80, 0x31e80, 3927248925Snp 0x31e88, 0x31ea8, 3928248925Snp 0x31eb0, 0x31eb4, 3929248925Snp 0x31ec8, 0x31ed4, 3930248925Snp 0x31fb8, 0x32004, 3931252312Snp 0x32200, 0x32200, 3932252312Snp 0x32208, 0x32240, 3933252312Snp 0x32248, 0x32280, 3934252312Snp 0x32288, 0x322c0, 3935248925Snp 0x322c8, 0x322fc, 3936248925Snp 0x32600, 0x32630, 3937248925Snp 0x32a00, 0x32abc, 3938248925Snp 0x32b00, 0x32b70, 3939248925Snp 0x33000, 0x33048, 3940248925Snp 0x33060, 0x3309c, 3941248925Snp 0x330f0, 0x33148, 3942248925Snp 0x33160, 0x3319c, 3943248925Snp 0x331f0, 0x332e4, 3944248925Snp 0x332f8, 0x333e4, 3945248925Snp 0x333f8, 0x33448, 3946248925Snp 0x33460, 0x3349c, 3947248925Snp 0x334f0, 0x33548, 3948248925Snp 0x33560, 0x3359c, 3949248925Snp 0x335f0, 0x336e4, 3950248925Snp 0x336f8, 0x337e4, 3951248925Snp 0x337f8, 0x337fc, 3952248925Snp 0x33814, 0x33814, 3953248925Snp 0x3382c, 0x3382c, 3954248925Snp 0x33880, 0x3388c, 3955248925Snp 0x338e8, 0x338ec, 3956248925Snp 0x33900, 0x33948, 3957248925Snp 0x33960, 0x3399c, 3958248925Snp 0x339f0, 0x33ae4, 3959248925Snp 0x33af8, 0x33b10, 3960248925Snp 0x33b28, 0x33b28, 3961248925Snp 0x33b3c, 0x33b50, 3962248925Snp 0x33bf0, 0x33c10, 3963248925Snp 0x33c28, 0x33c28, 3964248925Snp 0x33c3c, 0x33c50, 3965248925Snp 0x33cf0, 0x33cfc, 3966252312Snp 0x34000, 0x34030, 3967248925Snp 0x34100, 0x34144, 3968248925Snp 0x34190, 0x341d0, 3969248925Snp 0x34200, 0x34318, 3970248925Snp 0x34400, 0x3452c, 3971248925Snp 0x34540, 0x3461c, 3972248925Snp 0x34800, 0x34834, 3973248925Snp 0x348c0, 0x34908, 3974248925Snp 0x34910, 0x349ac, 3975252312Snp 0x34a00, 0x34a2c, 3976248925Snp 0x34a44, 0x34a50, 3977248925Snp 0x34a74, 0x34c24, 3978252312Snp 0x34d00, 0x34d00, 3979248925Snp 0x34d08, 0x34d14, 3980248925Snp 0x34d1c, 0x34d20, 3981248925Snp 0x34d3c, 0x34d50, 3982248925Snp 0x35200, 0x3520c, 3983248925Snp 0x35220, 0x35220, 3984248925Snp 0x35240, 0x35240, 3985252312Snp 0x35600, 0x3560c, 3986248925Snp 0x35a00, 0x35a1c, 3987252312Snp 0x35e00, 0x35e20, 3988248925Snp 0x35e38, 0x35e3c, 3989248925Snp 0x35e80, 0x35e80, 3990248925Snp 0x35e88, 0x35ea8, 3991248925Snp 0x35eb0, 0x35eb4, 3992248925Snp 0x35ec8, 0x35ed4, 3993248925Snp 0x35fb8, 0x36004, 3994252312Snp 0x36200, 0x36200, 3995252312Snp 0x36208, 0x36240, 3996252312Snp 0x36248, 0x36280, 3997252312Snp 0x36288, 0x362c0, 3998248925Snp 0x362c8, 0x362fc, 3999248925Snp 0x36600, 0x36630, 4000248925Snp 0x36a00, 0x36abc, 4001248925Snp 0x36b00, 0x36b70, 4002248925Snp 0x37000, 0x37048, 4003248925Snp 0x37060, 0x3709c, 4004248925Snp 0x370f0, 0x37148, 4005248925Snp 0x37160, 0x3719c, 4006248925Snp 0x371f0, 0x372e4, 4007248925Snp 0x372f8, 0x373e4, 4008248925Snp 0x373f8, 0x37448, 4009248925Snp 0x37460, 0x3749c, 4010248925Snp 0x374f0, 0x37548, 4011248925Snp 0x37560, 0x3759c, 4012248925Snp 0x375f0, 0x376e4, 4013248925Snp 0x376f8, 0x377e4, 4014248925Snp 0x377f8, 0x377fc, 4015248925Snp 0x37814, 0x37814, 4016248925Snp 0x3782c, 0x3782c, 4017248925Snp 0x37880, 0x3788c, 4018248925Snp 0x378e8, 0x378ec, 4019248925Snp 0x37900, 0x37948, 4020248925Snp 0x37960, 0x3799c, 4021248925Snp 0x379f0, 0x37ae4, 4022248925Snp 0x37af8, 0x37b10, 4023248925Snp 0x37b28, 0x37b28, 4024248925Snp 0x37b3c, 0x37b50, 4025248925Snp 0x37bf0, 0x37c10, 4026248925Snp 0x37c28, 0x37c28, 4027248925Snp 0x37c3c, 0x37c50, 4028248925Snp 0x37cf0, 0x37cfc, 4029252312Snp 0x38000, 0x38030, 4030248925Snp 0x38100, 0x38144, 4031248925Snp 0x38190, 0x381d0, 4032248925Snp 0x38200, 0x38318, 4033248925Snp 0x38400, 0x3852c, 4034248925Snp 0x38540, 0x3861c, 4035248925Snp 0x38800, 0x38834, 4036248925Snp 0x388c0, 0x38908, 4037248925Snp 0x38910, 0x389ac, 4038252312Snp 0x38a00, 0x38a2c, 4039248925Snp 0x38a44, 0x38a50, 4040248925Snp 0x38a74, 0x38c24, 4041252312Snp 0x38d00, 0x38d00, 4042248925Snp 0x38d08, 0x38d14, 4043248925Snp 0x38d1c, 0x38d20, 4044248925Snp 0x38d3c, 0x38d50, 4045248925Snp 0x39200, 0x3920c, 4046248925Snp 0x39220, 0x39220, 4047248925Snp 0x39240, 0x39240, 4048252312Snp 0x39600, 0x3960c, 4049248925Snp 0x39a00, 0x39a1c, 4050252312Snp 0x39e00, 0x39e20, 4051248925Snp 0x39e38, 0x39e3c, 4052248925Snp 0x39e80, 0x39e80, 4053248925Snp 0x39e88, 0x39ea8, 4054248925Snp 0x39eb0, 0x39eb4, 4055248925Snp 0x39ec8, 0x39ed4, 4056248925Snp 0x39fb8, 0x3a004, 4057252312Snp 0x3a200, 0x3a200, 4058252312Snp 0x3a208, 0x3a240, 4059252312Snp 0x3a248, 0x3a280, 4060252312Snp 0x3a288, 0x3a2c0, 4061248925Snp 0x3a2c8, 0x3a2fc, 4062248925Snp 0x3a600, 0x3a630, 4063248925Snp 0x3aa00, 0x3aabc, 4064248925Snp 0x3ab00, 0x3ab70, 4065248925Snp 0x3b000, 0x3b048, 4066248925Snp 0x3b060, 0x3b09c, 4067248925Snp 0x3b0f0, 0x3b148, 4068248925Snp 0x3b160, 0x3b19c, 4069248925Snp 0x3b1f0, 0x3b2e4, 4070248925Snp 0x3b2f8, 0x3b3e4, 4071248925Snp 0x3b3f8, 0x3b448, 4072248925Snp 0x3b460, 0x3b49c, 4073248925Snp 0x3b4f0, 0x3b548, 4074248925Snp 0x3b560, 0x3b59c, 4075248925Snp 0x3b5f0, 0x3b6e4, 4076248925Snp 0x3b6f8, 0x3b7e4, 4077248925Snp 0x3b7f8, 0x3b7fc, 4078248925Snp 0x3b814, 0x3b814, 4079248925Snp 0x3b82c, 0x3b82c, 4080248925Snp 0x3b880, 0x3b88c, 4081248925Snp 0x3b8e8, 0x3b8ec, 4082248925Snp 0x3b900, 0x3b948, 4083248925Snp 0x3b960, 0x3b99c, 4084248925Snp 0x3b9f0, 0x3bae4, 4085248925Snp 0x3baf8, 0x3bb10, 4086248925Snp 0x3bb28, 0x3bb28, 4087248925Snp 0x3bb3c, 0x3bb50, 4088248925Snp 0x3bbf0, 0x3bc10, 4089248925Snp 0x3bc28, 0x3bc28, 4090248925Snp 0x3bc3c, 0x3bc50, 4091248925Snp 0x3bcf0, 0x3bcfc, 4092252312Snp 0x3c000, 0x3c030, 4093248925Snp 0x3c100, 0x3c144, 4094248925Snp 0x3c190, 0x3c1d0, 4095248925Snp 0x3c200, 0x3c318, 4096248925Snp 0x3c400, 0x3c52c, 4097248925Snp 0x3c540, 0x3c61c, 4098248925Snp 0x3c800, 0x3c834, 4099248925Snp 0x3c8c0, 0x3c908, 4100248925Snp 0x3c910, 0x3c9ac, 4101252312Snp 0x3ca00, 0x3ca2c, 4102248925Snp 0x3ca44, 0x3ca50, 4103248925Snp 0x3ca74, 0x3cc24, 4104252312Snp 0x3cd00, 0x3cd00, 4105248925Snp 0x3cd08, 0x3cd14, 4106248925Snp 0x3cd1c, 0x3cd20, 4107248925Snp 0x3cd3c, 0x3cd50, 4108248925Snp 0x3d200, 0x3d20c, 4109248925Snp 0x3d220, 0x3d220, 4110248925Snp 0x3d240, 0x3d240, 4111252312Snp 0x3d600, 0x3d60c, 4112248925Snp 0x3da00, 0x3da1c, 4113252312Snp 0x3de00, 0x3de20, 4114248925Snp 0x3de38, 0x3de3c, 4115248925Snp 0x3de80, 0x3de80, 4116248925Snp 0x3de88, 0x3dea8, 4117248925Snp 0x3deb0, 0x3deb4, 4118248925Snp 0x3dec8, 0x3ded4, 4119248925Snp 0x3dfb8, 0x3e004, 4120252312Snp 0x3e200, 0x3e200, 4121252312Snp 0x3e208, 0x3e240, 4122252312Snp 0x3e248, 0x3e280, 4123252312Snp 0x3e288, 0x3e2c0, 4124248925Snp 0x3e2c8, 0x3e2fc, 4125248925Snp 0x3e600, 0x3e630, 4126248925Snp 0x3ea00, 0x3eabc, 4127248925Snp 0x3eb00, 0x3eb70, 4128248925Snp 0x3f000, 0x3f048, 4129248925Snp 0x3f060, 0x3f09c, 4130248925Snp 0x3f0f0, 0x3f148, 4131248925Snp 0x3f160, 0x3f19c, 4132248925Snp 0x3f1f0, 0x3f2e4, 4133248925Snp 0x3f2f8, 0x3f3e4, 4134248925Snp 0x3f3f8, 0x3f448, 4135248925Snp 0x3f460, 0x3f49c, 4136248925Snp 0x3f4f0, 0x3f548, 4137248925Snp 0x3f560, 0x3f59c, 4138248925Snp 0x3f5f0, 0x3f6e4, 4139248925Snp 0x3f6f8, 0x3f7e4, 4140248925Snp 0x3f7f8, 0x3f7fc, 4141248925Snp 0x3f814, 0x3f814, 4142248925Snp 0x3f82c, 0x3f82c, 4143248925Snp 0x3f880, 0x3f88c, 4144248925Snp 0x3f8e8, 0x3f8ec, 4145248925Snp 0x3f900, 0x3f948, 4146248925Snp 0x3f960, 0x3f99c, 4147248925Snp 0x3f9f0, 0x3fae4, 4148248925Snp 0x3faf8, 0x3fb10, 4149248925Snp 0x3fb28, 0x3fb28, 4150248925Snp 0x3fb3c, 0x3fb50, 4151248925Snp 0x3fbf0, 0x3fc10, 4152248925Snp 0x3fc28, 0x3fc28, 4153248925Snp 0x3fc3c, 0x3fc50, 4154248925Snp 0x3fcf0, 0x3fcfc, 4155248925Snp 0x40000, 0x4000c, 4156248925Snp 0x40040, 0x40068, 4157248925Snp 0x4007c, 0x40144, 4158248925Snp 0x40180, 0x4018c, 4159248925Snp 0x40200, 0x40298, 4160248925Snp 0x402ac, 0x4033c, 4161248925Snp 0x403f8, 0x403fc, 4162252312Snp 0x41304, 0x413c4, 4163248925Snp 0x41400, 0x4141c, 4164248925Snp 0x41480, 0x414d0, 4165248925Snp 0x44000, 0x44078, 4166248925Snp 0x440c0, 0x44278, 4167248925Snp 0x442c0, 0x44478, 4168248925Snp 0x444c0, 0x44678, 4169248925Snp 0x446c0, 0x44878, 4170248925Snp 0x448c0, 0x449fc, 4171248925Snp 0x45000, 0x45068, 4172248925Snp 0x45080, 0x45084, 4173248925Snp 0x450a0, 0x450b0, 4174248925Snp 0x45200, 0x45268, 4175248925Snp 0x45280, 0x45284, 4176248925Snp 0x452a0, 0x452b0, 4177248925Snp 0x460c0, 0x460e4, 4178248925Snp 0x47000, 0x4708c, 4179248925Snp 0x47200, 0x47250, 4180248925Snp 0x47400, 0x47420, 4181248925Snp 0x47600, 0x47618, 4182248925Snp 0x47800, 0x47814, 4183248925Snp 0x48000, 0x4800c, 4184248925Snp 0x48040, 0x48068, 4185248925Snp 0x4807c, 0x48144, 4186248925Snp 0x48180, 0x4818c, 4187248925Snp 0x48200, 0x48298, 4188248925Snp 0x482ac, 0x4833c, 4189248925Snp 0x483f8, 0x483fc, 4190252312Snp 0x49304, 0x493c4, 4191248925Snp 0x49400, 0x4941c, 4192248925Snp 0x49480, 0x494d0, 4193248925Snp 0x4c000, 0x4c078, 4194248925Snp 0x4c0c0, 0x4c278, 4195248925Snp 0x4c2c0, 0x4c478, 4196248925Snp 0x4c4c0, 0x4c678, 4197248925Snp 0x4c6c0, 0x4c878, 4198248925Snp 0x4c8c0, 0x4c9fc, 4199248925Snp 0x4d000, 0x4d068, 4200248925Snp 0x4d080, 0x4d084, 4201248925Snp 0x4d0a0, 0x4d0b0, 4202248925Snp 0x4d200, 0x4d268, 4203248925Snp 0x4d280, 0x4d284, 4204248925Snp 0x4d2a0, 0x4d2b0, 4205248925Snp 0x4e0c0, 0x4e0e4, 4206248925Snp 0x4f000, 0x4f08c, 4207248925Snp 0x4f200, 0x4f250, 4208248925Snp 0x4f400, 0x4f420, 4209248925Snp 0x4f600, 0x4f618, 4210248925Snp 0x4f800, 0x4f814, 4211248925Snp 0x50000, 0x500cc, 4212248925Snp 0x50400, 0x50400, 4213248925Snp 0x50800, 0x508cc, 4214248925Snp 0x50c00, 0x50c00, 4215248925Snp 0x51000, 0x5101c, 4216248925Snp 0x51300, 0x51308, 4217248925Snp }; 4218218792Snp 4219248925Snp if (is_t4(sc)) { 4220248925Snp reg_ranges = &t4_reg_ranges[0]; 4221248925Snp n = nitems(t4_reg_ranges); 4222248925Snp } else { 4223248925Snp reg_ranges = &t5_reg_ranges[0]; 4224248925Snp n = nitems(t5_reg_ranges); 4225248925Snp } 4226248925Snp 4227248925Snp regs->version = chip_id(sc) | chip_rev(sc) << 10; 4228248925Snp for (i = 0; i < n; i += 2) 4229218792Snp reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]); 4230218792Snp} 4231218792Snp 4232218792Snpstatic void 4233218792Snpcxgbe_tick(void *arg) 4234218792Snp{ 4235218792Snp struct port_info *pi = arg; 4236265425Snp struct adapter *sc = pi->adapter; 4237218792Snp struct ifnet *ifp = pi->ifp; 4238218792Snp struct sge_txq *txq; 4239218792Snp int i, drops; 4240218792Snp struct port_stats *s = &pi->stats; 4241218792Snp 4242218792Snp PORT_LOCK(pi); 4243218792Snp if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 4244218792Snp PORT_UNLOCK(pi); 4245218792Snp return; /* without scheduling another callout */ 4246218792Snp } 4247218792Snp 4248265425Snp t4_get_port_stats(sc, pi->tx_chan, s); 4249218792Snp 4250228561Snp ifp->if_opackets = s->tx_frames - s->tx_pause; 4251228561Snp ifp->if_ipackets = s->rx_frames - s->rx_pause; 4252228561Snp ifp->if_obytes = s->tx_octets - s->tx_pause * 64; 4253228561Snp ifp->if_ibytes = s->rx_octets - s->rx_pause * 64; 4254228561Snp ifp->if_omcasts = s->tx_mcast_frames - s->tx_pause; 4255228561Snp ifp->if_imcasts = s->rx_mcast_frames - s->rx_pause; 4256218792Snp ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 + 4257239259Snp s->rx_ovflow3 + s->rx_trunc0 + s->rx_trunc1 + s->rx_trunc2 + 4258239259Snp s->rx_trunc3; 4259265425Snp for (i = 0; i < 4; i++) { 4260265425Snp if (pi->rx_chan_map & (1 << i)) { 4261265425Snp uint32_t v; 4262218792Snp 4263265425Snp /* 4264265425Snp * XXX: indirect reads from the same ADDR/DATA pair can 4265265425Snp * race with each other. 4266265425Snp */ 4267265425Snp t4_read_indirect(sc, A_TP_MIB_INDEX, A_TP_MIB_DATA, &v, 4268265425Snp 1, A_TP_MIB_TNL_CNG_DROP_0 + i); 4269265425Snp ifp->if_iqdrops += v; 4270265425Snp } 4271265425Snp } 4272265425Snp 4273218792Snp drops = s->tx_drop; 4274218792Snp for_each_txq(pi, i, txq) 4275220873Snp drops += txq->br->br_drops; 4276218792Snp ifp->if_snd.ifq_drops = drops; 4277218792Snp 4278218792Snp ifp->if_oerrors = s->tx_error_frames; 4279218792Snp ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long + 4280218792Snp s->rx_fcs_err + s->rx_len_err; 4281218792Snp 4282218792Snp callout_schedule(&pi->tick, hz); 4283218792Snp PORT_UNLOCK(pi); 4284218792Snp} 4285218792Snp 4286237263Snpstatic void 4287237263Snpcxgbe_vlan_config(void *arg, struct ifnet *ifp, uint16_t vid) 4288237263Snp{ 4289237263Snp struct ifnet *vlan; 4290237263Snp 4291241494Snp if (arg != ifp || ifp->if_type != IFT_ETHER) 4292237263Snp return; 4293237263Snp 4294237263Snp vlan = VLAN_DEVAT(ifp, vid); 4295237263Snp VLAN_SETCOOKIE(vlan, ifp); 4296237263Snp} 4297237263Snp 4298218792Snpstatic int 4299228561Snpcpl_not_handled(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 4300228561Snp{ 4301237263Snp 4302228561Snp#ifdef INVARIANTS 4303237263Snp panic("%s: opcode 0x%02x on iq %p with payload %p", 4304228561Snp __func__, rss->opcode, iq, m); 4305228561Snp#else 4306239336Snp log(LOG_ERR, "%s: opcode 0x%02x on iq %p with payload %p\n", 4307228561Snp __func__, rss->opcode, iq, m); 4308228561Snp m_freem(m); 4309228561Snp#endif 4310228561Snp return (EDOOFUS); 4311228561Snp} 4312228561Snp 4313228561Snpint 4314228561Snpt4_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h) 4315228561Snp{ 4316228561Snp uintptr_t *loc, new; 4317228561Snp 4318240452Snp if (opcode >= nitems(sc->cpl_handler)) 4319228561Snp return (EINVAL); 4320228561Snp 4321228561Snp new = h ? (uintptr_t)h : (uintptr_t)cpl_not_handled; 4322228561Snp loc = (uintptr_t *) &sc->cpl_handler[opcode]; 4323228561Snp atomic_store_rel_ptr(loc, new); 4324228561Snp 4325228561Snp return (0); 4326228561Snp} 4327228561Snp 4328228561Snpstatic int 4329237263Snpan_not_handled(struct sge_iq *iq, const struct rsp_ctrl *ctrl) 4330237263Snp{ 4331237263Snp 4332237263Snp#ifdef INVARIANTS 4333237263Snp panic("%s: async notification on iq %p (ctrl %p)", __func__, iq, ctrl); 4334237263Snp#else 4335239336Snp log(LOG_ERR, "%s: async notification on iq %p (ctrl %p)\n", 4336237263Snp __func__, iq, ctrl); 4337237263Snp#endif 4338237263Snp return (EDOOFUS); 4339237263Snp} 4340237263Snp 4341237263Snpint 4342237263Snpt4_register_an_handler(struct adapter *sc, an_handler_t h) 4343237263Snp{ 4344237263Snp uintptr_t *loc, new; 4345237263Snp 4346237263Snp new = h ? (uintptr_t)h : (uintptr_t)an_not_handled; 4347237263Snp loc = (uintptr_t *) &sc->an_handler; 4348237263Snp atomic_store_rel_ptr(loc, new); 4349237263Snp 4350237263Snp return (0); 4351237263Snp} 4352237263Snp 4353237263Snpstatic int 4354239336Snpfw_msg_not_handled(struct adapter *sc, const __be64 *rpl) 4355239336Snp{ 4356241733Sed const struct cpl_fw6_msg *cpl = 4357241733Sed __containerof(rpl, struct cpl_fw6_msg, data[0]); 4358239336Snp 4359239336Snp#ifdef INVARIANTS 4360239336Snp panic("%s: fw_msg type %d", __func__, cpl->type); 4361239336Snp#else 4362239336Snp log(LOG_ERR, "%s: fw_msg type %d\n", __func__, cpl->type); 4363239336Snp#endif 4364239336Snp return (EDOOFUS); 4365239336Snp} 4366239336Snp 4367239336Snpint 4368239336Snpt4_register_fw_msg_handler(struct adapter *sc, int type, fw_msg_handler_t h) 4369239336Snp{ 4370239336Snp uintptr_t *loc, new; 4371239336Snp 4372240452Snp if (type >= nitems(sc->fw_msg_handler)) 4373239336Snp return (EINVAL); 4374239336Snp 4375247291Snp /* 4376247291Snp * These are dispatched by the handler for FW{4|6}_CPL_MSG using the CPL 4377247291Snp * handler dispatch table. Reject any attempt to install a handler for 4378247291Snp * this subtype. 4379247291Snp */ 4380247291Snp if (type == FW_TYPE_RSSCPL || type == FW6_TYPE_RSSCPL) 4381247291Snp return (EINVAL); 4382247291Snp 4383239336Snp new = h ? (uintptr_t)h : (uintptr_t)fw_msg_not_handled; 4384239336Snp loc = (uintptr_t *) &sc->fw_msg_handler[type]; 4385239336Snp atomic_store_rel_ptr(loc, new); 4386239336Snp 4387239336Snp return (0); 4388239336Snp} 4389239336Snp 4390239336Snpstatic int 4391218792Snpt4_sysctls(struct adapter *sc) 4392218792Snp{ 4393218792Snp struct sysctl_ctx_list *ctx; 4394218792Snp struct sysctl_oid *oid; 4395228561Snp struct sysctl_oid_list *children, *c0; 4396228561Snp static char *caps[] = { 4397228561Snp "\20\1PPP\2QFC\3DCBX", /* caps[0] linkcaps */ 4398259142Snp "\20\1NIC\2VM\3IDS\4UM\5UM_ISGL" /* caps[1] niccaps */ 4399259142Snp "\6HASHFILTER\7ETHOFLD", 4400228561Snp "\20\1TOE", /* caps[2] toecaps */ 4401228561Snp "\20\1RDDP\2RDMAC", /* caps[3] rdmacaps */ 4402228561Snp "\20\1INITIATOR_PDU\2TARGET_PDU" /* caps[4] iscsicaps */ 4403228561Snp "\3INITIATOR_CNXOFLD\4TARGET_CNXOFLD" 4404228561Snp "\5INITIATOR_SSNOFLD\6TARGET_SSNOFLD", 4405228561Snp "\20\1INITIATOR\2TARGET\3CTRL_OFLD" /* caps[5] fcoecaps */ 4406259142Snp "\4PO_INITIAOR\5PO_TARGET" 4407228561Snp }; 4408249392Snp static char *doorbells = {"\20\1UDB\2WCWR\3UDBWC\4KDB"}; 4409218792Snp 4410218792Snp ctx = device_get_sysctl_ctx(sc->dev); 4411228561Snp 4412228561Snp /* 4413228561Snp * dev.t4nex.X. 4414228561Snp */ 4415218792Snp oid = device_get_sysctl_tree(sc->dev); 4416228561Snp c0 = children = SYSCTL_CHILDREN(oid); 4417218792Snp 4418265421Snp sc->sc_do_rxcopy = 1; 4419265421Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "do_rx_copy", CTLFLAG_RW, 4420265421Snp &sc->sc_do_rxcopy, 1, "Do RX copy of small frames"); 4421265421Snp 4422248925Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, NULL, 4423248925Snp sc->params.nports, "# of ports"); 4424218792Snp 4425218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD, 4426248925Snp NULL, chip_rev(sc), "chip hardware revision"); 4427218792Snp 4428218792Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 4429218792Snp CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 4430218792Snp 4431228561Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "cf", 4432245936Snp CTLFLAG_RD, &sc->cfg_file, 0, "configuration file"); 4433218792Snp 4434248925Snp SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cfcsum", CTLFLAG_RD, NULL, 4435248925Snp sc->cfcsum, "config file checksum"); 4436228561Snp 4437248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "doorbells", 4438248925Snp CTLTYPE_STRING | CTLFLAG_RD, doorbells, sc->doorbells, 4439248925Snp sysctl_bitfield, "A", "available doorbells"); 4440248925Snp 4441228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkcaps", 4442228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[0], sc->linkcaps, 4443228561Snp sysctl_bitfield, "A", "available link capabilities"); 4444228561Snp 4445228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "niccaps", 4446228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[1], sc->niccaps, 4447228561Snp sysctl_bitfield, "A", "available NIC capabilities"); 4448228561Snp 4449228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "toecaps", 4450228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[2], sc->toecaps, 4451228561Snp sysctl_bitfield, "A", "available TCP offload capabilities"); 4452228561Snp 4453228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdmacaps", 4454228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[3], sc->rdmacaps, 4455228561Snp sysctl_bitfield, "A", "available RDMA capabilities"); 4456228561Snp 4457228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "iscsicaps", 4458228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[4], sc->iscsicaps, 4459228561Snp sysctl_bitfield, "A", "available iSCSI capabilities"); 4460228561Snp 4461228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoecaps", 4462228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[5], sc->fcoecaps, 4463228561Snp sysctl_bitfield, "A", "available FCoE capabilities"); 4464228561Snp 4465248925Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, NULL, 4466248925Snp sc->params.vpd.cclk, "core clock frequency (in KHz)"); 4467218792Snp 4468219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers", 4469228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.timer_val, 4470228561Snp sizeof(sc->sge.timer_val), sysctl_int_array, "A", 4471228561Snp "interrupt holdoff timer values (us)"); 4472218792Snp 4473219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts", 4474228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.counter_val, 4475228561Snp sizeof(sc->sge.counter_val), sysctl_int_array, "A", 4476228561Snp "interrupt holdoff packet counter values"); 4477218792Snp 4478252469Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nfilters", CTLFLAG_RD, 4479252469Snp NULL, sc->tids.nftids, "number of filters"); 4480252469Snp 4481253890Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "temperature", CTLTYPE_INT | 4482264736Semax CTLFLAG_RD, sc, 0, sysctl_temperature, "I", 4483253890Snp "chip temperature (in Celsius)"); 4484253890Snp 4485253829Snp t4_sge_sysctls(sc, ctx, children); 4486253829Snp 4487255015Snp sc->lro_timeout = 100; 4488255015Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "lro_timeout", CTLFLAG_RW, 4489255015Snp &sc->lro_timeout, 0, "lro inactive-flush timeout (in us)"); 4490255015Snp 4491231115Snp#ifdef SBUF_DRAIN 4492228561Snp /* 4493228561Snp * dev.t4nex.X.misc. Marked CTLFLAG_SKIP to avoid information overload. 4494228561Snp */ 4495228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "misc", 4496228561Snp CTLFLAG_RD | CTLFLAG_SKIP, NULL, 4497228561Snp "logs and miscellaneous information"); 4498228561Snp children = SYSCTL_CHILDREN(oid); 4499228561Snp 4500228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cctrl", 4501228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4502228561Snp sysctl_cctrl, "A", "congestion control"); 4503228561Snp 4504247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp0", 4505247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4506247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 0 (TP0)"); 4507247122Snp 4508247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_tp1", 4509247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 1, 4510247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 1 (TP1)"); 4511247122Snp 4512247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ulp", 4513247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 2, 4514247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 2 (ULP)"); 4515247122Snp 4516247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge0", 4517247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 3, 4518247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 3 (SGE0)"); 4519247122Snp 4520247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_sge1", 4521247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 4, 4522247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 4 (SGE1)"); 4523247122Snp 4524247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ibq_ncsi", 4525247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 5, 4526247122Snp sysctl_cim_ibq_obq, "A", "CIM IBQ 5 (NCSI)"); 4527247122Snp 4528247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_la", 4529247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4530247122Snp sysctl_cim_la, "A", "CIM logic analyzer"); 4531247122Snp 4532251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_ma_la", 4533251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4534251213Snp sysctl_cim_ma_la, "A", "CIM MA logic analyzer"); 4535251213Snp 4536247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp0", 4537247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0 + CIM_NUM_IBQ, 4538247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 0 (ULP0)"); 4539247122Snp 4540247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp1", 4541247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 1 + CIM_NUM_IBQ, 4542247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 1 (ULP1)"); 4543247122Snp 4544247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp2", 4545247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 2 + CIM_NUM_IBQ, 4546247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 2 (ULP2)"); 4547247122Snp 4548247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ulp3", 4549247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 3 + CIM_NUM_IBQ, 4550247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 3 (ULP3)"); 4551247122Snp 4552247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge", 4553247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 4 + CIM_NUM_IBQ, 4554247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 4 (SGE)"); 4555247122Snp 4556247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_ncsi", 4557247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 5 + CIM_NUM_IBQ, 4558247122Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 5 (NCSI)"); 4559247122Snp 4560248925Snp if (is_t5(sc)) { 4561248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge0_rx", 4562248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 6 + CIM_NUM_IBQ, 4563248925Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 6 (SGE0-RX)"); 4564248925Snp 4565248925Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_obq_sge1_rx", 4566248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 7 + CIM_NUM_IBQ, 4567248925Snp sysctl_cim_ibq_obq, "A", "CIM OBQ 7 (SGE1-RX)"); 4568248925Snp } 4569248925Snp 4570251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_pif_la", 4571251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4572251213Snp sysctl_cim_pif_la, "A", "CIM PIF logic analyzer"); 4573251213Snp 4574247122Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cim_qcfg", 4575247122Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4576247122Snp sysctl_cim_qcfg, "A", "CIM queue configuration"); 4577247122Snp 4578228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats", 4579228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4580228561Snp sysctl_cpl_stats, "A", "CPL statistics"); 4581228561Snp 4582228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ddp_stats", 4583228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4584228561Snp sysctl_ddp_stats, "A", "DDP statistics"); 4585228561Snp 4586222551Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog", 4587222551Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4588228561Snp sysctl_devlog, "A", "firmware's device log"); 4589222551Snp 4590228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoe_stats", 4591228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4592228561Snp sysctl_fcoe_stats, "A", "FCoE statistics"); 4593228561Snp 4594228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hw_sched", 4595228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4596228561Snp sysctl_hw_sched, "A", "hardware scheduler "); 4597228561Snp 4598228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "l2t", 4599228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4600228561Snp sysctl_l2t, "A", "hardware L2 table"); 4601228561Snp 4602228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats", 4603228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4604228561Snp sysctl_lb_stats, "A", "loopback statistics"); 4605228561Snp 4606228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "meminfo", 4607228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4608228561Snp sysctl_meminfo, "A", "memory regions"); 4609228561Snp 4610251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "mps_tcam", 4611251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4612251213Snp sysctl_mps_tcam, "A", "MPS TCAM entries"); 4613251213Snp 4614228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "path_mtus", 4615228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4616228561Snp sysctl_path_mtus, "A", "path MTUs"); 4617228561Snp 4618228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pm_stats", 4619228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4620228561Snp sysctl_pm_stats, "A", "PM statistics"); 4621228561Snp 4622228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_stats", 4623228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4624228561Snp sysctl_rdma_stats, "A", "RDMA statistics"); 4625228561Snp 4626228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tcp_stats", 4627228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4628228561Snp sysctl_tcp_stats, "A", "TCP statistics"); 4629228561Snp 4630228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tids", 4631228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4632228561Snp sysctl_tids, "A", "TID information"); 4633228561Snp 4634228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_err_stats", 4635228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4636228561Snp sysctl_tp_err_stats, "A", "TP error statistics"); 4637228561Snp 4638251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_la", 4639251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4640251213Snp sysctl_tp_la, "A", "TP logic analyzer"); 4641251213Snp 4642228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_rate", 4643228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4644228561Snp sysctl_tx_rate, "A", "Tx rate"); 4645248925Snp 4646251213Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ulprx_la", 4647251213Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4648251213Snp sysctl_ulprx_la, "A", "ULPRX logic analyzer"); 4649251213Snp 4650248925Snp if (is_t5(sc)) { 4651249392Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "wcwr_stats", 4652248925Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 4653249392Snp sysctl_wcwr_stats, "A", "write combined work requests"); 4654248925Snp } 4655231115Snp#endif 4656228561Snp 4657237263Snp#ifdef TCP_OFFLOAD 4658228561Snp if (is_offload(sc)) { 4659228561Snp /* 4660228561Snp * dev.t4nex.X.toe. 4661228561Snp */ 4662228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "toe", CTLFLAG_RD, 4663228561Snp NULL, "TOE parameters"); 4664228561Snp children = SYSCTL_CHILDREN(oid); 4665228561Snp 4666228561Snp sc->tt.sndbuf = 256 * 1024; 4667228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "sndbuf", CTLFLAG_RW, 4668228561Snp &sc->tt.sndbuf, 0, "max hardware send buffer size"); 4669228561Snp 4670228561Snp sc->tt.ddp = 0; 4671228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp", CTLFLAG_RW, 4672228561Snp &sc->tt.ddp, 0, "DDP allowed"); 4673239341Snp 4674239341Snp sc->tt.indsz = G_INDICATESIZE(t4_read_reg(sc, A_TP_PARA_REG5)); 4675228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "indsz", CTLFLAG_RW, 4676228561Snp &sc->tt.indsz, 0, "DDP max indicate size allowed"); 4677239341Snp 4678239341Snp sc->tt.ddp_thres = 4679239341Snp G_RXCOALESCESIZE(t4_read_reg(sc, A_TP_PARA_REG2)); 4680228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp_thres", CTLFLAG_RW, 4681228561Snp &sc->tt.ddp_thres, 0, "DDP threshold"); 4682252728Snp 4683252728Snp sc->tt.rx_coalesce = 1; 4684252728Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "rx_coalesce", 4685252728Snp CTLFLAG_RW, &sc->tt.rx_coalesce, 0, "receive coalescing"); 4686228561Snp } 4687228561Snp#endif 4688228561Snp 4689228561Snp 4690218792Snp return (0); 4691218792Snp} 4692218792Snp 4693218792Snpstatic int 4694218792Snpcxgbe_sysctls(struct port_info *pi) 4695218792Snp{ 4696218792Snp struct sysctl_ctx_list *ctx; 4697218792Snp struct sysctl_oid *oid; 4698218792Snp struct sysctl_oid_list *children; 4699265426Snp struct adapter *sc = pi->adapter; 4700218792Snp 4701218792Snp ctx = device_get_sysctl_ctx(pi->dev); 4702218792Snp 4703218792Snp /* 4704218792Snp * dev.cxgbe.X. 4705218792Snp */ 4706218792Snp oid = device_get_sysctl_tree(pi->dev); 4707218792Snp children = SYSCTL_CHILDREN(oid); 4708218792Snp 4709253701Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkdnrc", CTLTYPE_STRING | 4710253701Snp CTLFLAG_RD, pi, 0, sysctl_linkdnrc, "A", "reason why link is down"); 4711252747Snp if (pi->port_type == FW_PORT_TYPE_BT_XAUI) { 4712252747Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "temperature", 4713252747Snp CTLTYPE_INT | CTLFLAG_RD, pi, 0, sysctl_btphy, "I", 4714252747Snp "PHY temperature (in Celsius)"); 4715252747Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fw_version", 4716252747Snp CTLTYPE_INT | CTLFLAG_RD, pi, 1, sysctl_btphy, "I", 4717252747Snp "PHY firmware version"); 4718252747Snp } 4719218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD, 4720218792Snp &pi->nrxq, 0, "# of rx queues"); 4721218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD, 4722218792Snp &pi->ntxq, 0, "# of tx queues"); 4723218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD, 4724218792Snp &pi->first_rxq, 0, "index of first rx queue"); 4725218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD, 4726218792Snp &pi->first_txq, 0, "index of first tx queue"); 4727264493Sscottl SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rsrv_noflowq", CTLTYPE_INT | 4728264493Sscottl CTLFLAG_RW, pi, 0, sysctl_noflowq, "IU", 4729264493Sscottl "Reserve queue 0 for non-flowid packets"); 4730218792Snp 4731237263Snp#ifdef TCP_OFFLOAD 4732265426Snp if (is_offload(sc)) { 4733228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldrxq", CTLFLAG_RD, 4734228561Snp &pi->nofldrxq, 0, 4735228561Snp "# of rx queues for offloaded TCP connections"); 4736228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldtxq", CTLFLAG_RD, 4737228561Snp &pi->nofldtxq, 0, 4738228561Snp "# of tx queues for offloaded TCP connections"); 4739228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_rxq", 4740228561Snp CTLFLAG_RD, &pi->first_ofld_rxq, 0, 4741228561Snp "index of first TOE rx queue"); 4742228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_txq", 4743228561Snp CTLFLAG_RD, &pi->first_ofld_txq, 0, 4744228561Snp "index of first TOE tx queue"); 4745228561Snp } 4746228561Snp#endif 4747270297Snp#ifdef DEV_NETMAP 4748270297Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nnmrxq", CTLFLAG_RD, 4749270297Snp &pi->nnmrxq, 0, "# of rx queues for netmap"); 4750270297Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nnmtxq", CTLFLAG_RD, 4751270297Snp &pi->nnmtxq, 0, "# of tx queues for netmap"); 4752270297Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_nm_rxq", 4753270297Snp CTLFLAG_RD, &pi->first_nm_rxq, 0, 4754270297Snp "index of first netmap rx queue"); 4755270297Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_nm_txq", 4756270297Snp CTLFLAG_RD, &pi->first_nm_txq, 0, 4757270297Snp "index of first netmap tx queue"); 4758270297Snp#endif 4759228561Snp 4760218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx", 4761218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I", 4762218792Snp "holdoff timer index"); 4763218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx", 4764218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I", 4765218792Snp "holdoff packet counter index"); 4766218792Snp 4767218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq", 4768218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I", 4769218792Snp "rx queue size"); 4770218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq", 4771218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I", 4772218792Snp "tx queue size"); 4773218792Snp 4774271961Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pause_settings", 4775271961Snp CTLTYPE_STRING | CTLFLAG_RW, pi, PAUSE_TX, sysctl_pause_settings, 4776271961Snp "A", "PAUSE settings (bit 0 = rx_pause, bit 1 = tx_pause)"); 4777271961Snp 4778218792Snp /* 4779218792Snp * dev.cxgbe.X.stats. 4780218792Snp */ 4781218792Snp oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, 4782218792Snp NULL, "port statistics"); 4783218792Snp children = SYSCTL_CHILDREN(oid); 4784218792Snp 4785218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \ 4786218792Snp SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \ 4787265426Snp CTLTYPE_U64 | CTLFLAG_RD, sc, reg, \ 4788218792Snp sysctl_handle_t4_reg64, "QU", desc) 4789218792Snp 4790218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames", 4791218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L)); 4792218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames", 4793218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L)); 4794218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames", 4795218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L)); 4796218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames", 4797218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L)); 4798218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames", 4799218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L)); 4800218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames", 4801218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L)); 4802218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_64", 4803218792Snp "# of tx frames in this range", 4804218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L)); 4805218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127", 4806218792Snp "# of tx frames in this range", 4807218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L)); 4808218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255", 4809218792Snp "# of tx frames in this range", 4810218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L)); 4811218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511", 4812218792Snp "# of tx frames in this range", 4813218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L)); 4814218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023", 4815218792Snp "# of tx frames in this range", 4816218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L)); 4817218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518", 4818218792Snp "# of tx frames in this range", 4819218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L)); 4820218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max", 4821218792Snp "# of tx frames in this range", 4822218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L)); 4823218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames", 4824218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L)); 4825218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted", 4826218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L)); 4827218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted", 4828218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L)); 4829218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted", 4830218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L)); 4831218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted", 4832218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L)); 4833218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted", 4834218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L)); 4835218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted", 4836218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L)); 4837218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted", 4838218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L)); 4839218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted", 4840218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L)); 4841218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted", 4842218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L)); 4843218792Snp 4844218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames", 4845218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L)); 4846218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames", 4847218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L)); 4848218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames", 4849218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L)); 4850218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames", 4851218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L)); 4852218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames", 4853218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L)); 4854218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU", 4855218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L)); 4856218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames", 4857218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L)); 4858218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err", 4859218792Snp "# of frames received with bad FCS", 4860218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L)); 4861218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_len_err", 4862218792Snp "# of frames received with length error", 4863218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L)); 4864218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors", 4865218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L)); 4866218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received", 4867218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L)); 4868218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_64", 4869218792Snp "# of rx frames in this range", 4870218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L)); 4871218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127", 4872218792Snp "# of rx frames in this range", 4873218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L)); 4874218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255", 4875218792Snp "# of rx frames in this range", 4876218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L)); 4877218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511", 4878218792Snp "# of rx frames in this range", 4879218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L)); 4880218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023", 4881218792Snp "# of rx frames in this range", 4882218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L)); 4883218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518", 4884218792Snp "# of rx frames in this range", 4885218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L)); 4886218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max", 4887218792Snp "# of rx frames in this range", 4888218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L)); 4889218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received", 4890218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L)); 4891218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received", 4892218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L)); 4893218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received", 4894218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L)); 4895218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received", 4896218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L)); 4897218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received", 4898218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L)); 4899218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received", 4900218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L)); 4901218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received", 4902218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L)); 4903218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received", 4904218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L)); 4905218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received", 4906218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L)); 4907218792Snp 4908218792Snp#undef SYSCTL_ADD_T4_REG64 4909218792Snp 4910218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \ 4911218792Snp SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \ 4912218792Snp &pi->stats.name, desc) 4913218792Snp 4914218792Snp /* We get these from port_stats and they may be stale by upto 1s */ 4915218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0, 4916218792Snp "# drops due to buffer-group 0 overflows"); 4917218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1, 4918218792Snp "# drops due to buffer-group 1 overflows"); 4919218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2, 4920218792Snp "# drops due to buffer-group 2 overflows"); 4921218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3, 4922218792Snp "# drops due to buffer-group 3 overflows"); 4923218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc0, 4924218792Snp "# of buffer-group 0 truncated packets"); 4925218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc1, 4926218792Snp "# of buffer-group 1 truncated packets"); 4927218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc2, 4928218792Snp "# of buffer-group 2 truncated packets"); 4929218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc3, 4930218792Snp "# of buffer-group 3 truncated packets"); 4931218792Snp 4932218792Snp#undef SYSCTL_ADD_T4_PORTSTAT 4933218792Snp 4934218792Snp return (0); 4935218792Snp} 4936218792Snp 4937218792Snpstatic int 4938219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS) 4939219436Snp{ 4940219436Snp int rc, *i; 4941219436Snp struct sbuf sb; 4942219436Snp 4943219436Snp sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); 4944219436Snp for (i = arg1; arg2; arg2 -= sizeof(int), i++) 4945219436Snp sbuf_printf(&sb, "%d ", *i); 4946219436Snp sbuf_trim(&sb); 4947219436Snp sbuf_finish(&sb); 4948219436Snp rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 4949219436Snp sbuf_delete(&sb); 4950219436Snp return (rc); 4951219436Snp} 4952219436Snp 4953219436Snpstatic int 4954228561Snpsysctl_bitfield(SYSCTL_HANDLER_ARGS) 4955228561Snp{ 4956228561Snp int rc; 4957228561Snp struct sbuf *sb; 4958228561Snp 4959228561Snp rc = sysctl_wire_old_buffer(req, 0); 4960228561Snp if (rc != 0) 4961228561Snp return(rc); 4962228561Snp 4963228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 4964228561Snp if (sb == NULL) 4965228561Snp return (ENOMEM); 4966228561Snp 4967228561Snp sbuf_printf(sb, "%b", (int)arg2, (char *)arg1); 4968228561Snp rc = sbuf_finish(sb); 4969228561Snp sbuf_delete(sb); 4970228561Snp 4971228561Snp return (rc); 4972228561Snp} 4973228561Snp 4974228561Snpstatic int 4975252747Snpsysctl_btphy(SYSCTL_HANDLER_ARGS) 4976252747Snp{ 4977252747Snp struct port_info *pi = arg1; 4978252747Snp int op = arg2; 4979252747Snp struct adapter *sc = pi->adapter; 4980252747Snp u_int v; 4981252747Snp int rc; 4982252747Snp 4983252747Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4btt"); 4984252747Snp if (rc) 4985252747Snp return (rc); 4986252747Snp /* XXX: magic numbers */ 4987252747Snp rc = -t4_mdio_rd(sc, sc->mbox, pi->mdio_addr, 0x1e, op ? 0x20 : 0xc820, 4988252747Snp &v); 4989252747Snp end_synchronized_op(sc, 0); 4990252747Snp if (rc) 4991252747Snp return (rc); 4992252747Snp if (op == 0) 4993252747Snp v /= 256; 4994252747Snp 4995252747Snp rc = sysctl_handle_int(oidp, &v, 0, req); 4996252747Snp return (rc); 4997252747Snp} 4998252747Snp 4999252747Snpstatic int 5000264493Sscottlsysctl_noflowq(SYSCTL_HANDLER_ARGS) 5001264493Sscottl{ 5002264493Sscottl struct port_info *pi = arg1; 5003264493Sscottl int rc, val; 5004264493Sscottl 5005264493Sscottl val = pi->rsrv_noflowq; 5006264493Sscottl rc = sysctl_handle_int(oidp, &val, 0, req); 5007264493Sscottl if (rc != 0 || req->newptr == NULL) 5008264493Sscottl return (rc); 5009264493Sscottl 5010264493Sscottl if ((val >= 1) && (pi->ntxq > 1)) 5011264493Sscottl pi->rsrv_noflowq = 1; 5012264493Sscottl else 5013264493Sscottl pi->rsrv_noflowq = 0; 5014264493Sscottl 5015264493Sscottl return (rc); 5016264493Sscottl} 5017264493Sscottl 5018264493Sscottlstatic int 5019218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS) 5020218792Snp{ 5021218792Snp struct port_info *pi = arg1; 5022218792Snp struct adapter *sc = pi->adapter; 5023218792Snp int idx, rc, i; 5024245274Snp struct sge_rxq *rxq; 5025252724Snp#ifdef TCP_OFFLOAD 5026252724Snp struct sge_ofld_rxq *ofld_rxq; 5027252724Snp#endif 5028245274Snp uint8_t v; 5029218792Snp 5030218792Snp idx = pi->tmr_idx; 5031218792Snp 5032218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 5033218792Snp if (rc != 0 || req->newptr == NULL) 5034218792Snp return (rc); 5035218792Snp 5036218792Snp if (idx < 0 || idx >= SGE_NTIMERS) 5037218792Snp return (EINVAL); 5038218792Snp 5039245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 5040245274Snp "t4tmr"); 5041245274Snp if (rc) 5042245274Snp return (rc); 5043228561Snp 5044245274Snp v = V_QINTR_TIMER_IDX(idx) | V_QINTR_CNT_EN(pi->pktc_idx != -1); 5045245274Snp for_each_rxq(pi, i, rxq) { 5046228561Snp#ifdef atomic_store_rel_8 5047245274Snp atomic_store_rel_8(&rxq->iq.intr_params, v); 5048228561Snp#else 5049245274Snp rxq->iq.intr_params = v; 5050228561Snp#endif 5051218792Snp } 5052252724Snp#ifdef TCP_OFFLOAD 5053252724Snp for_each_ofld_rxq(pi, i, ofld_rxq) { 5054252724Snp#ifdef atomic_store_rel_8 5055252724Snp atomic_store_rel_8(&ofld_rxq->iq.intr_params, v); 5056252724Snp#else 5057252724Snp ofld_rxq->iq.intr_params = v; 5058252724Snp#endif 5059252724Snp } 5060252724Snp#endif 5061245274Snp pi->tmr_idx = idx; 5062218792Snp 5063245274Snp end_synchronized_op(sc, LOCK_HELD); 5064245274Snp return (0); 5065218792Snp} 5066218792Snp 5067218792Snpstatic int 5068218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS) 5069218792Snp{ 5070218792Snp struct port_info *pi = arg1; 5071218792Snp struct adapter *sc = pi->adapter; 5072218792Snp int idx, rc; 5073218792Snp 5074218792Snp idx = pi->pktc_idx; 5075218792Snp 5076218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 5077218792Snp if (rc != 0 || req->newptr == NULL) 5078218792Snp return (rc); 5079218792Snp 5080218792Snp if (idx < -1 || idx >= SGE_NCOUNTERS) 5081218792Snp return (EINVAL); 5082218792Snp 5083245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 5084245274Snp "t4pktc"); 5085245274Snp if (rc) 5086245274Snp return (rc); 5087245274Snp 5088245274Snp if (pi->flags & PORT_INIT_DONE) 5089228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 5090245274Snp else 5091218792Snp pi->pktc_idx = idx; 5092218792Snp 5093245274Snp end_synchronized_op(sc, LOCK_HELD); 5094218792Snp return (rc); 5095218792Snp} 5096218792Snp 5097218792Snpstatic int 5098218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS) 5099218792Snp{ 5100218792Snp struct port_info *pi = arg1; 5101218792Snp struct adapter *sc = pi->adapter; 5102218792Snp int qsize, rc; 5103218792Snp 5104218792Snp qsize = pi->qsize_rxq; 5105218792Snp 5106218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 5107218792Snp if (rc != 0 || req->newptr == NULL) 5108218792Snp return (rc); 5109218792Snp 5110218792Snp if (qsize < 128 || (qsize & 7)) 5111218792Snp return (EINVAL); 5112218792Snp 5113245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 5114245274Snp "t4rxqs"); 5115245274Snp if (rc) 5116245274Snp return (rc); 5117245274Snp 5118245274Snp if (pi->flags & PORT_INIT_DONE) 5119228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 5120245274Snp else 5121218792Snp pi->qsize_rxq = qsize; 5122218792Snp 5123245274Snp end_synchronized_op(sc, LOCK_HELD); 5124218792Snp return (rc); 5125218792Snp} 5126218792Snp 5127218792Snpstatic int 5128218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS) 5129218792Snp{ 5130218792Snp struct port_info *pi = arg1; 5131218792Snp struct adapter *sc = pi->adapter; 5132218792Snp int qsize, rc; 5133218792Snp 5134218792Snp qsize = pi->qsize_txq; 5135218792Snp 5136218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 5137218792Snp if (rc != 0 || req->newptr == NULL) 5138218792Snp return (rc); 5139218792Snp 5140245274Snp /* bufring size must be powerof2 */ 5141245274Snp if (qsize < 128 || !powerof2(qsize)) 5142218792Snp return (EINVAL); 5143218792Snp 5144245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 5145245274Snp "t4txqs"); 5146245274Snp if (rc) 5147245274Snp return (rc); 5148245274Snp 5149245274Snp if (pi->flags & PORT_INIT_DONE) 5150228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 5151245274Snp else 5152218792Snp pi->qsize_txq = qsize; 5153218792Snp 5154245274Snp end_synchronized_op(sc, LOCK_HELD); 5155218792Snp return (rc); 5156218792Snp} 5157218792Snp 5158218792Snpstatic int 5159271961Snpsysctl_pause_settings(SYSCTL_HANDLER_ARGS) 5160271961Snp{ 5161271961Snp struct port_info *pi = arg1; 5162271961Snp struct adapter *sc = pi->adapter; 5163271961Snp struct link_config *lc = &pi->link_cfg; 5164271961Snp int rc; 5165271961Snp 5166271961Snp if (req->newptr == NULL) { 5167271961Snp struct sbuf *sb; 5168271961Snp static char *bits = "\20\1PAUSE_RX\2PAUSE_TX"; 5169271961Snp 5170271961Snp rc = sysctl_wire_old_buffer(req, 0); 5171271961Snp if (rc != 0) 5172271961Snp return(rc); 5173271961Snp 5174271961Snp sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 5175271961Snp if (sb == NULL) 5176271961Snp return (ENOMEM); 5177271961Snp 5178271961Snp sbuf_printf(sb, "%b", lc->fc & (PAUSE_TX | PAUSE_RX), bits); 5179271961Snp rc = sbuf_finish(sb); 5180271961Snp sbuf_delete(sb); 5181271961Snp } else { 5182271961Snp char s[2]; 5183271961Snp int n; 5184271961Snp 5185271961Snp s[0] = '0' + (lc->requested_fc & (PAUSE_TX | PAUSE_RX)); 5186271961Snp s[1] = 0; 5187271961Snp 5188271961Snp rc = sysctl_handle_string(oidp, s, sizeof(s), req); 5189271961Snp if (rc != 0) 5190271961Snp return(rc); 5191271961Snp 5192271961Snp if (s[1] != 0) 5193271961Snp return (EINVAL); 5194271961Snp if (s[0] < '0' || s[0] > '9') 5195271961Snp return (EINVAL); /* not a number */ 5196271961Snp n = s[0] - '0'; 5197271961Snp if (n & ~(PAUSE_TX | PAUSE_RX)) 5198271961Snp return (EINVAL); /* some other bit is set too */ 5199271961Snp 5200271961Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4PAUSE"); 5201271961Snp if (rc) 5202271961Snp return (rc); 5203271961Snp if ((lc->requested_fc & (PAUSE_TX | PAUSE_RX)) != n) { 5204271961Snp int link_ok = lc->link_ok; 5205271961Snp 5206271961Snp lc->requested_fc &= ~(PAUSE_TX | PAUSE_RX); 5207271961Snp lc->requested_fc |= n; 5208271961Snp rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, lc); 5209271961Snp lc->link_ok = link_ok; /* restore */ 5210271961Snp } 5211271961Snp end_synchronized_op(sc, 0); 5212271961Snp } 5213271961Snp 5214271961Snp return (rc); 5215271961Snp} 5216271961Snp 5217271961Snpstatic int 5218218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS) 5219218792Snp{ 5220218792Snp struct adapter *sc = arg1; 5221218792Snp int reg = arg2; 5222218792Snp uint64_t val; 5223218792Snp 5224218792Snp val = t4_read_reg64(sc, reg); 5225218792Snp 5226218792Snp return (sysctl_handle_64(oidp, &val, 0, req)); 5227218792Snp} 5228218792Snp 5229253890Snpstatic int 5230253890Snpsysctl_temperature(SYSCTL_HANDLER_ARGS) 5231253890Snp{ 5232253890Snp struct adapter *sc = arg1; 5233253890Snp int rc, t; 5234253890Snp uint32_t param, val; 5235253890Snp 5236253890Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4temp"); 5237253890Snp if (rc) 5238253890Snp return (rc); 5239253890Snp param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | 5240253890Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_DIAG) | 5241253890Snp V_FW_PARAMS_PARAM_Y(FW_PARAM_DEV_DIAG_TMP); 5242253890Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 5243253890Snp end_synchronized_op(sc, 0); 5244253890Snp if (rc) 5245253890Snp return (rc); 5246253890Snp 5247253890Snp /* unknown is returned as 0 but we display -1 in that case */ 5248253890Snp t = val == 0 ? -1 : val; 5249253890Snp 5250253890Snp rc = sysctl_handle_int(oidp, &t, 0, req); 5251253890Snp return (rc); 5252253890Snp} 5253253890Snp 5254231115Snp#ifdef SBUF_DRAIN 5255228561Snpstatic int 5256228561Snpsysctl_cctrl(SYSCTL_HANDLER_ARGS) 5257228561Snp{ 5258228561Snp struct adapter *sc = arg1; 5259228561Snp struct sbuf *sb; 5260228561Snp int rc, i; 5261228561Snp uint16_t incr[NMTUS][NCCTRL_WIN]; 5262228561Snp static const char *dec_fac[] = { 5263228561Snp "0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875", 5264228561Snp "0.9375" 5265228561Snp }; 5266228561Snp 5267228561Snp rc = sysctl_wire_old_buffer(req, 0); 5268228561Snp if (rc != 0) 5269228561Snp return (rc); 5270228561Snp 5271228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5272228561Snp if (sb == NULL) 5273228561Snp return (ENOMEM); 5274228561Snp 5275228561Snp t4_read_cong_tbl(sc, incr); 5276228561Snp 5277228561Snp for (i = 0; i < NCCTRL_WIN; ++i) { 5278228561Snp sbuf_printf(sb, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i, 5279228561Snp incr[0][i], incr[1][i], incr[2][i], incr[3][i], incr[4][i], 5280228561Snp incr[5][i], incr[6][i], incr[7][i]); 5281228561Snp sbuf_printf(sb, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n", 5282228561Snp incr[8][i], incr[9][i], incr[10][i], incr[11][i], 5283228561Snp incr[12][i], incr[13][i], incr[14][i], incr[15][i], 5284228561Snp sc->params.a_wnd[i], dec_fac[sc->params.b_wnd[i]]); 5285228561Snp } 5286228561Snp 5287228561Snp rc = sbuf_finish(sb); 5288228561Snp sbuf_delete(sb); 5289228561Snp 5290228561Snp return (rc); 5291228561Snp} 5292228561Snp 5293248925Snpstatic const char *qname[CIM_NUM_IBQ + CIM_NUM_OBQ_T5] = { 5294247122Snp "TP0", "TP1", "ULP", "SGE0", "SGE1", "NC-SI", /* ibq's */ 5295248925Snp "ULP0", "ULP1", "ULP2", "ULP3", "SGE", "NC-SI", /* obq's */ 5296248925Snp "SGE0-RX", "SGE1-RX" /* additional obq's (T5 onwards) */ 5297247122Snp}; 5298247122Snp 5299228561Snpstatic int 5300247122Snpsysctl_cim_ibq_obq(SYSCTL_HANDLER_ARGS) 5301247122Snp{ 5302247122Snp struct adapter *sc = arg1; 5303247122Snp struct sbuf *sb; 5304247122Snp int rc, i, n, qid = arg2; 5305247122Snp uint32_t *buf, *p; 5306247122Snp char *qtype; 5307248925Snp u_int cim_num_obq = is_t4(sc) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5; 5308247122Snp 5309248925Snp KASSERT(qid >= 0 && qid < CIM_NUM_IBQ + cim_num_obq, 5310247122Snp ("%s: bad qid %d\n", __func__, qid)); 5311247122Snp 5312247122Snp if (qid < CIM_NUM_IBQ) { 5313247122Snp /* inbound queue */ 5314247122Snp qtype = "IBQ"; 5315247122Snp n = 4 * CIM_IBQ_SIZE; 5316247122Snp buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); 5317247122Snp rc = t4_read_cim_ibq(sc, qid, buf, n); 5318247122Snp } else { 5319247122Snp /* outbound queue */ 5320247122Snp qtype = "OBQ"; 5321247122Snp qid -= CIM_NUM_IBQ; 5322248925Snp n = 4 * cim_num_obq * CIM_OBQ_SIZE; 5323247122Snp buf = malloc(n * sizeof(uint32_t), M_CXGBE, M_ZERO | M_WAITOK); 5324247122Snp rc = t4_read_cim_obq(sc, qid, buf, n); 5325247122Snp } 5326247122Snp 5327247122Snp if (rc < 0) { 5328247122Snp rc = -rc; 5329247122Snp goto done; 5330247122Snp } 5331247122Snp n = rc * sizeof(uint32_t); /* rc has # of words actually read */ 5332247122Snp 5333247122Snp rc = sysctl_wire_old_buffer(req, 0); 5334247122Snp if (rc != 0) 5335247122Snp goto done; 5336247122Snp 5337248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req); 5338247122Snp if (sb == NULL) { 5339247122Snp rc = ENOMEM; 5340247122Snp goto done; 5341247122Snp } 5342247122Snp 5343247122Snp sbuf_printf(sb, "%s%d %s", qtype , qid, qname[arg2]); 5344247122Snp for (i = 0, p = buf; i < n; i += 16, p += 4) 5345247122Snp sbuf_printf(sb, "\n%#06x: %08x %08x %08x %08x", i, p[0], p[1], 5346247122Snp p[2], p[3]); 5347247122Snp 5348247122Snp rc = sbuf_finish(sb); 5349247122Snp sbuf_delete(sb); 5350247122Snpdone: 5351247122Snp free(buf, M_CXGBE); 5352247122Snp return (rc); 5353247122Snp} 5354247122Snp 5355247122Snpstatic int 5356247122Snpsysctl_cim_la(SYSCTL_HANDLER_ARGS) 5357247122Snp{ 5358247122Snp struct adapter *sc = arg1; 5359247122Snp u_int cfg; 5360247122Snp struct sbuf *sb; 5361247122Snp uint32_t *buf, *p; 5362247122Snp int rc; 5363247122Snp 5364247122Snp rc = -t4_cim_read(sc, A_UP_UP_DBG_LA_CFG, 1, &cfg); 5365247122Snp if (rc != 0) 5366247122Snp return (rc); 5367247122Snp 5368247122Snp rc = sysctl_wire_old_buffer(req, 0); 5369247122Snp if (rc != 0) 5370247122Snp return (rc); 5371247122Snp 5372247122Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5373247122Snp if (sb == NULL) 5374247122Snp return (ENOMEM); 5375247122Snp 5376247122Snp buf = malloc(sc->params.cim_la_size * sizeof(uint32_t), M_CXGBE, 5377247122Snp M_ZERO | M_WAITOK); 5378247122Snp 5379247122Snp rc = -t4_cim_read_la(sc, buf, NULL); 5380247122Snp if (rc != 0) 5381247122Snp goto done; 5382247122Snp 5383247122Snp sbuf_printf(sb, "Status Data PC%s", 5384247122Snp cfg & F_UPDBGLACAPTPCONLY ? "" : 5385247122Snp " LS0Stat LS0Addr LS0Data"); 5386247122Snp 5387247122Snp KASSERT((sc->params.cim_la_size & 7) == 0, 5388247122Snp ("%s: p will walk off the end of buf", __func__)); 5389247122Snp 5390247122Snp for (p = buf; p < &buf[sc->params.cim_la_size]; p += 8) { 5391247122Snp if (cfg & F_UPDBGLACAPTPCONLY) { 5392247122Snp sbuf_printf(sb, "\n %02x %08x %08x", p[5] & 0xff, 5393247122Snp p[6], p[7]); 5394247122Snp sbuf_printf(sb, "\n %02x %02x%06x %02x%06x", 5395247122Snp (p[3] >> 8) & 0xff, p[3] & 0xff, p[4] >> 8, 5396247122Snp p[4] & 0xff, p[5] >> 8); 5397247122Snp sbuf_printf(sb, "\n %02x %x%07x %x%07x", 5398247122Snp (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, 5399247122Snp p[1] & 0xf, p[2] >> 4); 5400247122Snp } else { 5401247122Snp sbuf_printf(sb, 5402247122Snp "\n %02x %x%07x %x%07x %08x %08x " 5403247122Snp "%08x%08x%08x%08x", 5404247122Snp (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4, 5405247122Snp p[1] & 0xf, p[2] >> 4, p[2] & 0xf, p[3], p[4], p[5], 5406247122Snp p[6], p[7]); 5407247122Snp } 5408247122Snp } 5409247122Snp 5410247122Snp rc = sbuf_finish(sb); 5411247122Snp sbuf_delete(sb); 5412247122Snpdone: 5413247122Snp free(buf, M_CXGBE); 5414247122Snp return (rc); 5415247122Snp} 5416247122Snp 5417247122Snpstatic int 5418251213Snpsysctl_cim_ma_la(SYSCTL_HANDLER_ARGS) 5419251213Snp{ 5420251213Snp struct adapter *sc = arg1; 5421251213Snp u_int i; 5422251213Snp struct sbuf *sb; 5423251213Snp uint32_t *buf, *p; 5424251213Snp int rc; 5425251213Snp 5426251213Snp rc = sysctl_wire_old_buffer(req, 0); 5427251213Snp if (rc != 0) 5428251213Snp return (rc); 5429251213Snp 5430251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5431251213Snp if (sb == NULL) 5432251213Snp return (ENOMEM); 5433251213Snp 5434251213Snp buf = malloc(2 * CIM_MALA_SIZE * 5 * sizeof(uint32_t), M_CXGBE, 5435251213Snp M_ZERO | M_WAITOK); 5436251213Snp 5437251213Snp t4_cim_read_ma_la(sc, buf, buf + 5 * CIM_MALA_SIZE); 5438251213Snp p = buf; 5439251213Snp 5440251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) { 5441251213Snp sbuf_printf(sb, "\n%02x%08x%08x%08x%08x", p[4], p[3], p[2], 5442251213Snp p[1], p[0]); 5443251213Snp } 5444251213Snp 5445251213Snp sbuf_printf(sb, "\n\nCnt ID Tag UE Data RDY VLD"); 5446251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 5) { 5447251213Snp sbuf_printf(sb, "\n%3u %2u %x %u %08x%08x %u %u", 5448251213Snp (p[2] >> 10) & 0xff, (p[2] >> 7) & 7, 5449251213Snp (p[2] >> 3) & 0xf, (p[2] >> 2) & 1, 5450251213Snp (p[1] >> 2) | ((p[2] & 3) << 30), 5451251213Snp (p[0] >> 2) | ((p[1] & 3) << 30), (p[0] >> 1) & 1, 5452251213Snp p[0] & 1); 5453251213Snp } 5454251213Snp 5455251213Snp rc = sbuf_finish(sb); 5456251213Snp sbuf_delete(sb); 5457251213Snp free(buf, M_CXGBE); 5458251213Snp return (rc); 5459251213Snp} 5460251213Snp 5461251213Snpstatic int 5462251213Snpsysctl_cim_pif_la(SYSCTL_HANDLER_ARGS) 5463251213Snp{ 5464251213Snp struct adapter *sc = arg1; 5465251213Snp u_int i; 5466251213Snp struct sbuf *sb; 5467251213Snp uint32_t *buf, *p; 5468251213Snp int rc; 5469251213Snp 5470251213Snp rc = sysctl_wire_old_buffer(req, 0); 5471251213Snp if (rc != 0) 5472251213Snp return (rc); 5473251213Snp 5474251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5475251213Snp if (sb == NULL) 5476251213Snp return (ENOMEM); 5477251213Snp 5478251213Snp buf = malloc(2 * CIM_PIFLA_SIZE * 6 * sizeof(uint32_t), M_CXGBE, 5479251213Snp M_ZERO | M_WAITOK); 5480251213Snp 5481251213Snp t4_cim_read_pif_la(sc, buf, buf + 6 * CIM_PIFLA_SIZE, NULL, NULL); 5482251213Snp p = buf; 5483251213Snp 5484251213Snp sbuf_printf(sb, "Cntl ID DataBE Addr Data"); 5485251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 6) { 5486251213Snp sbuf_printf(sb, "\n %02x %02x %04x %08x %08x%08x%08x%08x", 5487251213Snp (p[5] >> 22) & 0xff, (p[5] >> 16) & 0x3f, p[5] & 0xffff, 5488251213Snp p[4], p[3], p[2], p[1], p[0]); 5489251213Snp } 5490251213Snp 5491251213Snp sbuf_printf(sb, "\n\nCntl ID Data"); 5492251213Snp for (i = 0; i < CIM_MALA_SIZE; i++, p += 6) { 5493251213Snp sbuf_printf(sb, "\n %02x %02x %08x%08x%08x%08x", 5494251213Snp (p[4] >> 6) & 0xff, p[4] & 0x3f, p[3], p[2], p[1], p[0]); 5495251213Snp } 5496251213Snp 5497251213Snp rc = sbuf_finish(sb); 5498251213Snp sbuf_delete(sb); 5499251213Snp free(buf, M_CXGBE); 5500251213Snp return (rc); 5501251213Snp} 5502251213Snp 5503251213Snpstatic int 5504247122Snpsysctl_cim_qcfg(SYSCTL_HANDLER_ARGS) 5505247122Snp{ 5506247122Snp struct adapter *sc = arg1; 5507247122Snp struct sbuf *sb; 5508247122Snp int rc, i; 5509248925Snp uint16_t base[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; 5510248925Snp uint16_t size[CIM_NUM_IBQ + CIM_NUM_OBQ_T5]; 5511247122Snp uint16_t thres[CIM_NUM_IBQ]; 5512248925Snp uint32_t obq_wr[2 * CIM_NUM_OBQ_T5], *wr = obq_wr; 5513248925Snp uint32_t stat[4 * (CIM_NUM_IBQ + CIM_NUM_OBQ_T5)], *p = stat; 5514248925Snp u_int cim_num_obq, ibq_rdaddr, obq_rdaddr, nq; 5515247122Snp 5516248925Snp if (is_t4(sc)) { 5517248925Snp cim_num_obq = CIM_NUM_OBQ; 5518248925Snp ibq_rdaddr = A_UP_IBQ_0_RDADDR; 5519248925Snp obq_rdaddr = A_UP_OBQ_0_REALADDR; 5520248925Snp } else { 5521248925Snp cim_num_obq = CIM_NUM_OBQ_T5; 5522248925Snp ibq_rdaddr = A_UP_IBQ_0_SHADOW_RDADDR; 5523248925Snp obq_rdaddr = A_UP_OBQ_0_SHADOW_REALADDR; 5524248925Snp } 5525248925Snp nq = CIM_NUM_IBQ + cim_num_obq; 5526248925Snp 5527248925Snp rc = -t4_cim_read(sc, ibq_rdaddr, 4 * nq, stat); 5528247122Snp if (rc == 0) 5529248925Snp rc = -t4_cim_read(sc, obq_rdaddr, 2 * cim_num_obq, obq_wr); 5530247122Snp if (rc != 0) 5531247122Snp return (rc); 5532247122Snp 5533247122Snp t4_read_cimq_cfg(sc, base, size, thres); 5534247122Snp 5535247122Snp rc = sysctl_wire_old_buffer(req, 0); 5536247122Snp if (rc != 0) 5537247122Snp return (rc); 5538247122Snp 5539248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, PAGE_SIZE, req); 5540247122Snp if (sb == NULL) 5541247122Snp return (ENOMEM); 5542247122Snp 5543247122Snp sbuf_printf(sb, "Queue Base Size Thres RdPtr WrPtr SOP EOP Avail"); 5544247122Snp 5545247122Snp for (i = 0; i < CIM_NUM_IBQ; i++, p += 4) 5546248925Snp sbuf_printf(sb, "\n%7s %5x %5u %5u %6x %4x %4u %4u %5u", 5547247122Snp qname[i], base[i], size[i], thres[i], G_IBQRDADDR(p[0]), 5548247122Snp G_IBQWRADDR(p[1]), G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), 5549247122Snp G_QUEREMFLITS(p[2]) * 16); 5550248925Snp for ( ; i < nq; i++, p += 4, wr += 2) 5551248925Snp sbuf_printf(sb, "\n%7s %5x %5u %12x %4x %4u %4u %5u", qname[i], 5552247122Snp base[i], size[i], G_QUERDADDR(p[0]) & 0x3fff, 5553247122Snp wr[0] - base[i], G_QUESOPCNT(p[3]), G_QUEEOPCNT(p[3]), 5554247122Snp G_QUEREMFLITS(p[2]) * 16); 5555247122Snp 5556247122Snp rc = sbuf_finish(sb); 5557247122Snp sbuf_delete(sb); 5558247122Snp 5559247122Snp return (rc); 5560247122Snp} 5561247122Snp 5562247122Snpstatic int 5563228561Snpsysctl_cpl_stats(SYSCTL_HANDLER_ARGS) 5564228561Snp{ 5565228561Snp struct adapter *sc = arg1; 5566228561Snp struct sbuf *sb; 5567228561Snp int rc; 5568228561Snp struct tp_cpl_stats stats; 5569228561Snp 5570228561Snp rc = sysctl_wire_old_buffer(req, 0); 5571228561Snp if (rc != 0) 5572228561Snp return (rc); 5573228561Snp 5574228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5575228561Snp if (sb == NULL) 5576228561Snp return (ENOMEM); 5577228561Snp 5578228561Snp t4_tp_get_cpl_stats(sc, &stats); 5579228561Snp 5580228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 5581228561Snp "channel 3\n"); 5582228561Snp sbuf_printf(sb, "CPL requests: %10u %10u %10u %10u\n", 5583228561Snp stats.req[0], stats.req[1], stats.req[2], stats.req[3]); 5584228561Snp sbuf_printf(sb, "CPL responses: %10u %10u %10u %10u", 5585228561Snp stats.rsp[0], stats.rsp[1], stats.rsp[2], stats.rsp[3]); 5586228561Snp 5587228561Snp rc = sbuf_finish(sb); 5588228561Snp sbuf_delete(sb); 5589228561Snp 5590228561Snp return (rc); 5591228561Snp} 5592228561Snp 5593228561Snpstatic int 5594228561Snpsysctl_ddp_stats(SYSCTL_HANDLER_ARGS) 5595228561Snp{ 5596228561Snp struct adapter *sc = arg1; 5597228561Snp struct sbuf *sb; 5598228561Snp int rc; 5599228561Snp struct tp_usm_stats stats; 5600228561Snp 5601228561Snp rc = sysctl_wire_old_buffer(req, 0); 5602228561Snp if (rc != 0) 5603228561Snp return(rc); 5604228561Snp 5605228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5606228561Snp if (sb == NULL) 5607228561Snp return (ENOMEM); 5608228561Snp 5609228561Snp t4_get_usm_stats(sc, &stats); 5610228561Snp 5611228561Snp sbuf_printf(sb, "Frames: %u\n", stats.frames); 5612228561Snp sbuf_printf(sb, "Octets: %ju\n", stats.octets); 5613228561Snp sbuf_printf(sb, "Drops: %u", stats.drops); 5614228561Snp 5615228561Snp rc = sbuf_finish(sb); 5616228561Snp sbuf_delete(sb); 5617228561Snp 5618228561Snp return (rc); 5619228561Snp} 5620228561Snp 5621222551Snpconst char *devlog_level_strings[] = { 5622222551Snp [FW_DEVLOG_LEVEL_EMERG] = "EMERG", 5623222551Snp [FW_DEVLOG_LEVEL_CRIT] = "CRIT", 5624222551Snp [FW_DEVLOG_LEVEL_ERR] = "ERR", 5625222551Snp [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", 5626222551Snp [FW_DEVLOG_LEVEL_INFO] = "INFO", 5627222551Snp [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" 5628222551Snp}; 5629222551Snp 5630222551Snpconst char *devlog_facility_strings[] = { 5631222551Snp [FW_DEVLOG_FACILITY_CORE] = "CORE", 5632268823Snp [FW_DEVLOG_FACILITY_CF] = "CF", 5633222551Snp [FW_DEVLOG_FACILITY_SCHED] = "SCHED", 5634222551Snp [FW_DEVLOG_FACILITY_TIMER] = "TIMER", 5635222551Snp [FW_DEVLOG_FACILITY_RES] = "RES", 5636222551Snp [FW_DEVLOG_FACILITY_HW] = "HW", 5637222551Snp [FW_DEVLOG_FACILITY_FLR] = "FLR", 5638222551Snp [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", 5639222551Snp [FW_DEVLOG_FACILITY_PHY] = "PHY", 5640222551Snp [FW_DEVLOG_FACILITY_MAC] = "MAC", 5641222551Snp [FW_DEVLOG_FACILITY_PORT] = "PORT", 5642222551Snp [FW_DEVLOG_FACILITY_VI] = "VI", 5643222551Snp [FW_DEVLOG_FACILITY_FILTER] = "FILTER", 5644222551Snp [FW_DEVLOG_FACILITY_ACL] = "ACL", 5645222551Snp [FW_DEVLOG_FACILITY_TM] = "TM", 5646222551Snp [FW_DEVLOG_FACILITY_QFC] = "QFC", 5647222551Snp [FW_DEVLOG_FACILITY_DCB] = "DCB", 5648222551Snp [FW_DEVLOG_FACILITY_ETH] = "ETH", 5649222551Snp [FW_DEVLOG_FACILITY_OFLD] = "OFLD", 5650222551Snp [FW_DEVLOG_FACILITY_RI] = "RI", 5651222551Snp [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", 5652222551Snp [FW_DEVLOG_FACILITY_FCOE] = "FCOE", 5653222551Snp [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", 5654222551Snp [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE" 5655222551Snp}; 5656222551Snp 5657222551Snpstatic int 5658222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS) 5659222551Snp{ 5660222551Snp struct adapter *sc = arg1; 5661222551Snp struct devlog_params *dparams = &sc->params.devlog; 5662222551Snp struct fw_devlog_e *buf, *e; 5663256791Snp int i, j, rc, nentries, first = 0, m; 5664222551Snp struct sbuf *sb; 5665222551Snp uint64_t ftstamp = UINT64_MAX; 5666222551Snp 5667248925Snp if (dparams->start == 0) { 5668256791Snp dparams->memtype = FW_MEMTYPE_EDC0; 5669248925Snp dparams->start = 0x84000; 5670248925Snp dparams->size = 32768; 5671248925Snp } 5672222551Snp 5673222551Snp nentries = dparams->size / sizeof(struct fw_devlog_e); 5674222551Snp 5675222551Snp buf = malloc(dparams->size, M_CXGBE, M_NOWAIT); 5676222551Snp if (buf == NULL) 5677222551Snp return (ENOMEM); 5678222551Snp 5679256791Snp m = fwmtype_to_hwmtype(dparams->memtype); 5680256791Snp rc = -t4_mem_read(sc, m, dparams->start, dparams->size, (void *)buf); 5681222551Snp if (rc != 0) 5682222551Snp goto done; 5683222551Snp 5684222551Snp for (i = 0; i < nentries; i++) { 5685222551Snp e = &buf[i]; 5686222551Snp 5687222551Snp if (e->timestamp == 0) 5688222551Snp break; /* end */ 5689222551Snp 5690222551Snp e->timestamp = be64toh(e->timestamp); 5691222551Snp e->seqno = be32toh(e->seqno); 5692222551Snp for (j = 0; j < 8; j++) 5693222551Snp e->params[j] = be32toh(e->params[j]); 5694222551Snp 5695222551Snp if (e->timestamp < ftstamp) { 5696222551Snp ftstamp = e->timestamp; 5697222551Snp first = i; 5698222551Snp } 5699222551Snp } 5700222551Snp 5701222551Snp if (buf[first].timestamp == 0) 5702222551Snp goto done; /* nothing in the log */ 5703222551Snp 5704222551Snp rc = sysctl_wire_old_buffer(req, 0); 5705222551Snp if (rc != 0) 5706222551Snp goto done; 5707222551Snp 5708222551Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5709228561Snp if (sb == NULL) { 5710228561Snp rc = ENOMEM; 5711228561Snp goto done; 5712228561Snp } 5713228561Snp sbuf_printf(sb, "%10s %15s %8s %8s %s\n", 5714222551Snp "Seq#", "Tstamp", "Level", "Facility", "Message"); 5715222551Snp 5716222551Snp i = first; 5717222551Snp do { 5718222551Snp e = &buf[i]; 5719222551Snp if (e->timestamp == 0) 5720222551Snp break; /* end */ 5721222551Snp 5722222551Snp sbuf_printf(sb, "%10d %15ju %8s %8s ", 5723222551Snp e->seqno, e->timestamp, 5724240452Snp (e->level < nitems(devlog_level_strings) ? 5725222551Snp devlog_level_strings[e->level] : "UNKNOWN"), 5726240452Snp (e->facility < nitems(devlog_facility_strings) ? 5727222551Snp devlog_facility_strings[e->facility] : "UNKNOWN")); 5728222551Snp sbuf_printf(sb, e->fmt, e->params[0], e->params[1], 5729222551Snp e->params[2], e->params[3], e->params[4], 5730222551Snp e->params[5], e->params[6], e->params[7]); 5731222551Snp 5732222551Snp if (++i == nentries) 5733222551Snp i = 0; 5734222551Snp } while (i != first); 5735222551Snp 5736222551Snp rc = sbuf_finish(sb); 5737222551Snp sbuf_delete(sb); 5738222551Snpdone: 5739222551Snp free(buf, M_CXGBE); 5740222551Snp return (rc); 5741222551Snp} 5742222551Snp 5743228561Snpstatic int 5744228561Snpsysctl_fcoe_stats(SYSCTL_HANDLER_ARGS) 5745228561Snp{ 5746228561Snp struct adapter *sc = arg1; 5747228561Snp struct sbuf *sb; 5748228561Snp int rc; 5749228561Snp struct tp_fcoe_stats stats[4]; 5750228561Snp 5751228561Snp rc = sysctl_wire_old_buffer(req, 0); 5752228561Snp if (rc != 0) 5753228561Snp return (rc); 5754228561Snp 5755228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5756228561Snp if (sb == NULL) 5757228561Snp return (ENOMEM); 5758228561Snp 5759228561Snp t4_get_fcoe_stats(sc, 0, &stats[0]); 5760228561Snp t4_get_fcoe_stats(sc, 1, &stats[1]); 5761228561Snp t4_get_fcoe_stats(sc, 2, &stats[2]); 5762228561Snp t4_get_fcoe_stats(sc, 3, &stats[3]); 5763228561Snp 5764228561Snp sbuf_printf(sb, " channel 0 channel 1 " 5765228561Snp "channel 2 channel 3\n"); 5766228561Snp sbuf_printf(sb, "octetsDDP: %16ju %16ju %16ju %16ju\n", 5767228561Snp stats[0].octetsDDP, stats[1].octetsDDP, stats[2].octetsDDP, 5768228561Snp stats[3].octetsDDP); 5769228561Snp sbuf_printf(sb, "framesDDP: %16u %16u %16u %16u\n", stats[0].framesDDP, 5770228561Snp stats[1].framesDDP, stats[2].framesDDP, stats[3].framesDDP); 5771228561Snp sbuf_printf(sb, "framesDrop: %16u %16u %16u %16u", 5772228561Snp stats[0].framesDrop, stats[1].framesDrop, stats[2].framesDrop, 5773228561Snp stats[3].framesDrop); 5774228561Snp 5775228561Snp rc = sbuf_finish(sb); 5776228561Snp sbuf_delete(sb); 5777228561Snp 5778228561Snp return (rc); 5779228561Snp} 5780228561Snp 5781228561Snpstatic int 5782228561Snpsysctl_hw_sched(SYSCTL_HANDLER_ARGS) 5783228561Snp{ 5784228561Snp struct adapter *sc = arg1; 5785228561Snp struct sbuf *sb; 5786228561Snp int rc, i; 5787228561Snp unsigned int map, kbps, ipg, mode; 5788228561Snp unsigned int pace_tab[NTX_SCHED]; 5789228561Snp 5790228561Snp rc = sysctl_wire_old_buffer(req, 0); 5791228561Snp if (rc != 0) 5792228561Snp return (rc); 5793228561Snp 5794228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 5795228561Snp if (sb == NULL) 5796228561Snp return (ENOMEM); 5797228561Snp 5798228561Snp map = t4_read_reg(sc, A_TP_TX_MOD_QUEUE_REQ_MAP); 5799228561Snp mode = G_TIMERMODE(t4_read_reg(sc, A_TP_MOD_CONFIG)); 5800228561Snp t4_read_pace_tbl(sc, pace_tab); 5801228561Snp 5802228561Snp sbuf_printf(sb, "Scheduler Mode Channel Rate (Kbps) " 5803228561Snp "Class IPG (0.1 ns) Flow IPG (us)"); 5804228561Snp 5805228561Snp for (i = 0; i < NTX_SCHED; ++i, map >>= 2) { 5806228561Snp t4_get_tx_sched(sc, i, &kbps, &ipg); 5807228561Snp sbuf_printf(sb, "\n %u %-5s %u ", i, 5808228561Snp (mode & (1 << i)) ? "flow" : "class", map & 3); 5809228561Snp if (kbps) 5810228561Snp sbuf_printf(sb, "%9u ", kbps); 5811228561Snp else 5812228561Snp sbuf_printf(sb, " disabled "); 5813228561Snp 5814228561Snp if (ipg) 5815228561Snp sbuf_printf(sb, "%13u ", ipg); 5816228561Snp else 5817228561Snp sbuf_printf(sb, " disabled "); 5818228561Snp 5819228561Snp if (pace_tab[i]) 5820228561Snp sbuf_printf(sb, "%10u", pace_tab[i]); 5821228561Snp else 5822228561Snp sbuf_printf(sb, " disabled"); 5823228561Snp } 5824228561Snp 5825228561Snp rc = sbuf_finish(sb); 5826228561Snp sbuf_delete(sb); 5827228561Snp 5828228561Snp return (rc); 5829228561Snp} 5830228561Snp 5831228561Snpstatic int 5832228561Snpsysctl_lb_stats(SYSCTL_HANDLER_ARGS) 5833228561Snp{ 5834228561Snp struct adapter *sc = arg1; 5835228561Snp struct sbuf *sb; 5836228561Snp int rc, i, j; 5837228561Snp uint64_t *p0, *p1; 5838228561Snp struct lb_port_stats s[2]; 5839228561Snp static const char *stat_name[] = { 5840228561Snp "OctetsOK:", "FramesOK:", "BcastFrames:", "McastFrames:", 5841228561Snp "UcastFrames:", "ErrorFrames:", "Frames64:", "Frames65To127:", 5842228561Snp "Frames128To255:", "Frames256To511:", "Frames512To1023:", 5843228561Snp "Frames1024To1518:", "Frames1519ToMax:", "FramesDropped:", 5844228561Snp "BG0FramesDropped:", "BG1FramesDropped:", "BG2FramesDropped:", 5845228561Snp "BG3FramesDropped:", "BG0FramesTrunc:", "BG1FramesTrunc:", 5846228561Snp "BG2FramesTrunc:", "BG3FramesTrunc:" 5847228561Snp }; 5848228561Snp 5849228561Snp rc = sysctl_wire_old_buffer(req, 0); 5850228561Snp if (rc != 0) 5851228561Snp return (rc); 5852228561Snp 5853228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5854228561Snp if (sb == NULL) 5855228561Snp return (ENOMEM); 5856228561Snp 5857228561Snp memset(s, 0, sizeof(s)); 5858228561Snp 5859228561Snp for (i = 0; i < 4; i += 2) { 5860228561Snp t4_get_lb_stats(sc, i, &s[0]); 5861228561Snp t4_get_lb_stats(sc, i + 1, &s[1]); 5862228561Snp 5863228561Snp p0 = &s[0].octets; 5864228561Snp p1 = &s[1].octets; 5865228561Snp sbuf_printf(sb, "%s Loopback %u" 5866228561Snp " Loopback %u", i == 0 ? "" : "\n", i, i + 1); 5867228561Snp 5868240452Snp for (j = 0; j < nitems(stat_name); j++) 5869228561Snp sbuf_printf(sb, "\n%-17s %20ju %20ju", stat_name[j], 5870228561Snp *p0++, *p1++); 5871228561Snp } 5872228561Snp 5873228561Snp rc = sbuf_finish(sb); 5874228561Snp sbuf_delete(sb); 5875228561Snp 5876228561Snp return (rc); 5877228561Snp} 5878228561Snp 5879253701Snpstatic int 5880253701Snpsysctl_linkdnrc(SYSCTL_HANDLER_ARGS) 5881253701Snp{ 5882253701Snp int rc = 0; 5883253701Snp struct port_info *pi = arg1; 5884253701Snp struct sbuf *sb; 5885253701Snp static const char *linkdnreasons[] = { 5886253701Snp "non-specific", "remote fault", "autoneg failed", "reserved3", 5887253701Snp "PHY overheated", "unknown", "rx los", "reserved7" 5888253701Snp }; 5889253701Snp 5890253701Snp rc = sysctl_wire_old_buffer(req, 0); 5891253701Snp if (rc != 0) 5892253701Snp return(rc); 5893253701Snp sb = sbuf_new_for_sysctl(NULL, NULL, 64, req); 5894253701Snp if (sb == NULL) 5895253701Snp return (ENOMEM); 5896253701Snp 5897253701Snp if (pi->linkdnrc < 0) 5898253701Snp sbuf_printf(sb, "n/a"); 5899253701Snp else if (pi->linkdnrc < nitems(linkdnreasons)) 5900253701Snp sbuf_printf(sb, "%s", linkdnreasons[pi->linkdnrc]); 5901253701Snp else 5902253701Snp sbuf_printf(sb, "%d", pi->linkdnrc); 5903253701Snp 5904253701Snp rc = sbuf_finish(sb); 5905253701Snp sbuf_delete(sb); 5906253701Snp 5907253701Snp return (rc); 5908253701Snp} 5909253701Snp 5910228561Snpstruct mem_desc { 5911228561Snp unsigned int base; 5912228561Snp unsigned int limit; 5913228561Snp unsigned int idx; 5914228561Snp}; 5915228561Snp 5916228561Snpstatic int 5917228561Snpmem_desc_cmp(const void *a, const void *b) 5918228561Snp{ 5919228561Snp return ((const struct mem_desc *)a)->base - 5920228561Snp ((const struct mem_desc *)b)->base; 5921228561Snp} 5922228561Snp 5923228561Snpstatic void 5924228561Snpmem_region_show(struct sbuf *sb, const char *name, unsigned int from, 5925228561Snp unsigned int to) 5926228561Snp{ 5927228561Snp unsigned int size; 5928228561Snp 5929228561Snp size = to - from + 1; 5930228561Snp if (size == 0) 5931228561Snp return; 5932228561Snp 5933228561Snp /* XXX: need humanize_number(3) in libkern for a more readable 'size' */ 5934228561Snp sbuf_printf(sb, "%-15s %#x-%#x [%u]\n", name, from, to, size); 5935228561Snp} 5936228561Snp 5937228561Snpstatic int 5938228561Snpsysctl_meminfo(SYSCTL_HANDLER_ARGS) 5939228561Snp{ 5940228561Snp struct adapter *sc = arg1; 5941228561Snp struct sbuf *sb; 5942228561Snp int rc, i, n; 5943248925Snp uint32_t lo, hi, used, alloc; 5944248925Snp static const char *memory[] = {"EDC0:", "EDC1:", "MC:", "MC0:", "MC1:"}; 5945228561Snp static const char *region[] = { 5946228561Snp "DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:", 5947228561Snp "Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:", 5948228561Snp "Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:", 5949228561Snp "TDDP region:", "TPT region:", "STAG region:", "RQ region:", 5950248925Snp "RQUDP region:", "PBL region:", "TXPBL region:", 5951248925Snp "DBVFIFO region:", "ULPRX state:", "ULPTX state:", 5952248925Snp "On-chip queues:" 5953228561Snp }; 5954248925Snp struct mem_desc avail[4]; 5955240452Snp struct mem_desc mem[nitems(region) + 3]; /* up to 3 holes */ 5956228561Snp struct mem_desc *md = mem; 5957228561Snp 5958228561Snp rc = sysctl_wire_old_buffer(req, 0); 5959228561Snp if (rc != 0) 5960228561Snp return (rc); 5961228561Snp 5962228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 5963228561Snp if (sb == NULL) 5964228561Snp return (ENOMEM); 5965228561Snp 5966240452Snp for (i = 0; i < nitems(mem); i++) { 5967228561Snp mem[i].limit = 0; 5968228561Snp mem[i].idx = i; 5969228561Snp } 5970228561Snp 5971228561Snp /* Find and sort the populated memory ranges */ 5972228561Snp i = 0; 5973228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 5974228561Snp if (lo & F_EDRAM0_ENABLE) { 5975228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 5976228561Snp avail[i].base = G_EDRAM0_BASE(hi) << 20; 5977228561Snp avail[i].limit = avail[i].base + (G_EDRAM0_SIZE(hi) << 20); 5978228561Snp avail[i].idx = 0; 5979228561Snp i++; 5980228561Snp } 5981228561Snp if (lo & F_EDRAM1_ENABLE) { 5982228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 5983228561Snp avail[i].base = G_EDRAM1_BASE(hi) << 20; 5984228561Snp avail[i].limit = avail[i].base + (G_EDRAM1_SIZE(hi) << 20); 5985228561Snp avail[i].idx = 1; 5986228561Snp i++; 5987228561Snp } 5988228561Snp if (lo & F_EXT_MEM_ENABLE) { 5989228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 5990228561Snp avail[i].base = G_EXT_MEM_BASE(hi) << 20; 5991248925Snp avail[i].limit = avail[i].base + 5992248925Snp (G_EXT_MEM_SIZE(hi) << 20); 5993248925Snp avail[i].idx = is_t4(sc) ? 2 : 3; /* Call it MC for T4 */ 5994228561Snp i++; 5995228561Snp } 5996248925Snp if (!is_t4(sc) && lo & F_EXT_MEM1_ENABLE) { 5997248925Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY1_BAR); 5998248925Snp avail[i].base = G_EXT_MEM1_BASE(hi) << 20; 5999248925Snp avail[i].limit = avail[i].base + 6000248925Snp (G_EXT_MEM1_SIZE(hi) << 20); 6001248925Snp avail[i].idx = 4; 6002248925Snp i++; 6003248925Snp } 6004228561Snp if (!i) /* no memory available */ 6005228561Snp return 0; 6006228561Snp qsort(avail, i, sizeof(struct mem_desc), mem_desc_cmp); 6007228561Snp 6008228561Snp (md++)->base = t4_read_reg(sc, A_SGE_DBQ_CTXT_BADDR); 6009228561Snp (md++)->base = t4_read_reg(sc, A_SGE_IMSG_CTXT_BADDR); 6010228561Snp (md++)->base = t4_read_reg(sc, A_SGE_FLM_CACHE_BADDR); 6011228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 6012228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_BASE); 6013228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TIMER_BASE); 6014228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_RX_FLST_BASE); 6015228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_TX_FLST_BASE); 6016228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_PS_FLST_BASE); 6017228561Snp 6018228561Snp /* the next few have explicit upper bounds */ 6019228561Snp md->base = t4_read_reg(sc, A_TP_PMM_TX_BASE); 6020228561Snp md->limit = md->base - 1 + 6021228561Snp t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE) * 6022228561Snp G_PMTXMAXPAGE(t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE)); 6023228561Snp md++; 6024228561Snp 6025228561Snp md->base = t4_read_reg(sc, A_TP_PMM_RX_BASE); 6026228561Snp md->limit = md->base - 1 + 6027228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) * 6028228561Snp G_PMRXMAXPAGE(t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE)); 6029228561Snp md++; 6030228561Snp 6031228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 6032228561Snp hi = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4; 6033228561Snp md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE); 6034228561Snp md->limit = (sc->tids.ntids - hi) * 16 + md->base - 1; 6035228561Snp } else { 6036228561Snp md->base = 0; 6037240452Snp md->idx = nitems(region); /* hide it */ 6038228561Snp } 6039228561Snp md++; 6040228561Snp 6041228561Snp#define ulp_region(reg) \ 6042228561Snp md->base = t4_read_reg(sc, A_ULP_ ## reg ## _LLIMIT);\ 6043228561Snp (md++)->limit = t4_read_reg(sc, A_ULP_ ## reg ## _ULIMIT) 6044228561Snp 6045228561Snp ulp_region(RX_ISCSI); 6046228561Snp ulp_region(RX_TDDP); 6047228561Snp ulp_region(TX_TPT); 6048228561Snp ulp_region(RX_STAG); 6049228561Snp ulp_region(RX_RQ); 6050228561Snp ulp_region(RX_RQUDP); 6051228561Snp ulp_region(RX_PBL); 6052228561Snp ulp_region(TX_PBL); 6053228561Snp#undef ulp_region 6054228561Snp 6055248925Snp md->base = 0; 6056248925Snp md->idx = nitems(region); 6057248925Snp if (!is_t4(sc) && t4_read_reg(sc, A_SGE_CONTROL2) & F_VFIFO_ENABLE) { 6058248925Snp md->base = G_BASEADDR(t4_read_reg(sc, A_SGE_DBVFIFO_BADDR)); 6059248925Snp md->limit = md->base + (G_DBVFIFO_SIZE((t4_read_reg(sc, 6060248925Snp A_SGE_DBVFIFO_SIZE))) << 2) - 1; 6061248925Snp } 6062248925Snp md++; 6063248925Snp 6064228561Snp md->base = t4_read_reg(sc, A_ULP_RX_CTX_BASE); 6065228561Snp md->limit = md->base + sc->tids.ntids - 1; 6066228561Snp md++; 6067228561Snp md->base = t4_read_reg(sc, A_ULP_TX_ERR_TABLE_BASE); 6068228561Snp md->limit = md->base + sc->tids.ntids - 1; 6069228561Snp md++; 6070228561Snp 6071228561Snp md->base = sc->vres.ocq.start; 6072228561Snp if (sc->vres.ocq.size) 6073228561Snp md->limit = md->base + sc->vres.ocq.size - 1; 6074228561Snp else 6075240452Snp md->idx = nitems(region); /* hide it */ 6076228561Snp md++; 6077228561Snp 6078228561Snp /* add any address-space holes, there can be up to 3 */ 6079228561Snp for (n = 0; n < i - 1; n++) 6080228561Snp if (avail[n].limit < avail[n + 1].base) 6081228561Snp (md++)->base = avail[n].limit; 6082228561Snp if (avail[n].limit) 6083228561Snp (md++)->base = avail[n].limit; 6084228561Snp 6085228561Snp n = md - mem; 6086228561Snp qsort(mem, n, sizeof(struct mem_desc), mem_desc_cmp); 6087228561Snp 6088228561Snp for (lo = 0; lo < i; lo++) 6089228561Snp mem_region_show(sb, memory[avail[lo].idx], avail[lo].base, 6090228561Snp avail[lo].limit - 1); 6091228561Snp 6092228561Snp sbuf_printf(sb, "\n"); 6093228561Snp for (i = 0; i < n; i++) { 6094240452Snp if (mem[i].idx >= nitems(region)) 6095228561Snp continue; /* skip holes */ 6096228561Snp if (!mem[i].limit) 6097228561Snp mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0; 6098228561Snp mem_region_show(sb, region[mem[i].idx], mem[i].base, 6099228561Snp mem[i].limit); 6100228561Snp } 6101228561Snp 6102228561Snp sbuf_printf(sb, "\n"); 6103228561Snp lo = t4_read_reg(sc, A_CIM_SDRAM_BASE_ADDR); 6104228561Snp hi = t4_read_reg(sc, A_CIM_SDRAM_ADDR_SIZE) + lo - 1; 6105228561Snp mem_region_show(sb, "uP RAM:", lo, hi); 6106228561Snp 6107228561Snp lo = t4_read_reg(sc, A_CIM_EXTMEM2_BASE_ADDR); 6108228561Snp hi = t4_read_reg(sc, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1; 6109228561Snp mem_region_show(sb, "uP Extmem2:", lo, hi); 6110228561Snp 6111228561Snp lo = t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE); 6112228561Snp sbuf_printf(sb, "\n%u Rx pages of size %uKiB for %u channels\n", 6113228561Snp G_PMRXMAXPAGE(lo), 6114228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) >> 10, 6115228561Snp (lo & F_PMRXNUMCHN) ? 2 : 1); 6116228561Snp 6117228561Snp lo = t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE); 6118228561Snp hi = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE); 6119228561Snp sbuf_printf(sb, "%u Tx pages of size %u%ciB for %u channels\n", 6120228561Snp G_PMTXMAXPAGE(lo), 6121228561Snp hi >= (1 << 20) ? (hi >> 20) : (hi >> 10), 6122228561Snp hi >= (1 << 20) ? 'M' : 'K', 1 << G_PMTXNUMCHN(lo)); 6123228561Snp sbuf_printf(sb, "%u p-structs\n", 6124228561Snp t4_read_reg(sc, A_TP_CMM_MM_MAX_PSTRUCT)); 6125228561Snp 6126228561Snp for (i = 0; i < 4; i++) { 6127228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV0 + i * 4); 6128248925Snp if (is_t4(sc)) { 6129248925Snp used = G_USED(lo); 6130248925Snp alloc = G_ALLOC(lo); 6131248925Snp } else { 6132248925Snp used = G_T5_USED(lo); 6133248925Snp alloc = G_T5_ALLOC(lo); 6134248925Snp } 6135228561Snp sbuf_printf(sb, "\nPort %d using %u pages out of %u allocated", 6136248925Snp i, used, alloc); 6137228561Snp } 6138228561Snp for (i = 0; i < 4; i++) { 6139228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV4 + i * 4); 6140248925Snp if (is_t4(sc)) { 6141248925Snp used = G_USED(lo); 6142248925Snp alloc = G_ALLOC(lo); 6143248925Snp } else { 6144248925Snp used = G_T5_USED(lo); 6145248925Snp alloc = G_T5_ALLOC(lo); 6146248925Snp } 6147228561Snp sbuf_printf(sb, 6148228561Snp "\nLoopback %d using %u pages out of %u allocated", 6149248925Snp i, used, alloc); 6150228561Snp } 6151228561Snp 6152228561Snp rc = sbuf_finish(sb); 6153228561Snp sbuf_delete(sb); 6154228561Snp 6155228561Snp return (rc); 6156228561Snp} 6157228561Snp 6158251213Snpstatic inline void 6159251213Snptcamxy2valmask(uint64_t x, uint64_t y, uint8_t *addr, uint64_t *mask) 6160251213Snp{ 6161251213Snp *mask = x | y; 6162251213Snp y = htobe64(y); 6163251213Snp memcpy(addr, (char *)&y + 2, ETHER_ADDR_LEN); 6164251213Snp} 6165251213Snp 6166228561Snpstatic int 6167251213Snpsysctl_mps_tcam(SYSCTL_HANDLER_ARGS) 6168251213Snp{ 6169251213Snp struct adapter *sc = arg1; 6170251213Snp struct sbuf *sb; 6171251213Snp int rc, i, n; 6172251213Snp 6173251213Snp rc = sysctl_wire_old_buffer(req, 0); 6174251213Snp if (rc != 0) 6175251213Snp return (rc); 6176251213Snp 6177251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6178251213Snp if (sb == NULL) 6179251213Snp return (ENOMEM); 6180251213Snp 6181251213Snp sbuf_printf(sb, 6182251213Snp "Idx Ethernet address Mask Vld Ports PF" 6183251213Snp " VF Replication P0 P1 P2 P3 ML"); 6184251213Snp n = is_t4(sc) ? NUM_MPS_CLS_SRAM_L_INSTANCES : 6185251213Snp NUM_MPS_T5_CLS_SRAM_L_INSTANCES; 6186251213Snp for (i = 0; i < n; i++) { 6187251213Snp uint64_t tcamx, tcamy, mask; 6188251213Snp uint32_t cls_lo, cls_hi; 6189251213Snp uint8_t addr[ETHER_ADDR_LEN]; 6190251213Snp 6191251213Snp tcamy = t4_read_reg64(sc, MPS_CLS_TCAM_Y_L(i)); 6192251213Snp tcamx = t4_read_reg64(sc, MPS_CLS_TCAM_X_L(i)); 6193251213Snp cls_lo = t4_read_reg(sc, MPS_CLS_SRAM_L(i)); 6194251213Snp cls_hi = t4_read_reg(sc, MPS_CLS_SRAM_H(i)); 6195251213Snp 6196251213Snp if (tcamx & tcamy) 6197251213Snp continue; 6198251213Snp 6199251213Snp tcamxy2valmask(tcamx, tcamy, addr, &mask); 6200251213Snp sbuf_printf(sb, "\n%3u %02x:%02x:%02x:%02x:%02x:%02x %012jx" 6201251213Snp " %c %#x%4u%4d", i, addr[0], addr[1], addr[2], 6202251213Snp addr[3], addr[4], addr[5], (uintmax_t)mask, 6203251213Snp (cls_lo & F_SRAM_VLD) ? 'Y' : 'N', 6204251213Snp G_PORTMAP(cls_hi), G_PF(cls_lo), 6205251213Snp (cls_lo & F_VF_VALID) ? G_VF(cls_lo) : -1); 6206251213Snp 6207251213Snp if (cls_lo & F_REPLICATE) { 6208251213Snp struct fw_ldst_cmd ldst_cmd; 6209251213Snp 6210251213Snp memset(&ldst_cmd, 0, sizeof(ldst_cmd)); 6211251213Snp ldst_cmd.op_to_addrspace = 6212251213Snp htobe32(V_FW_CMD_OP(FW_LDST_CMD) | 6213251213Snp F_FW_CMD_REQUEST | F_FW_CMD_READ | 6214251213Snp V_FW_LDST_CMD_ADDRSPACE(FW_LDST_ADDRSPC_MPS)); 6215251213Snp ldst_cmd.cycles_to_len16 = htobe32(FW_LEN16(ldst_cmd)); 6216251213Snp ldst_cmd.u.mps.fid_ctl = 6217251213Snp htobe16(V_FW_LDST_CMD_FID(FW_LDST_MPS_RPLC) | 6218251213Snp V_FW_LDST_CMD_CTL(i)); 6219251213Snp 6220251213Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, 6221251213Snp "t4mps"); 6222251213Snp if (rc) 6223251213Snp break; 6224251213Snp rc = -t4_wr_mbox(sc, sc->mbox, &ldst_cmd, 6225251213Snp sizeof(ldst_cmd), &ldst_cmd); 6226251213Snp end_synchronized_op(sc, 0); 6227251213Snp 6228251213Snp if (rc != 0) { 6229251213Snp sbuf_printf(sb, 6230251213Snp " ------------ error %3u ------------", rc); 6231251213Snp rc = 0; 6232251213Snp } else { 6233251213Snp sbuf_printf(sb, " %08x %08x %08x %08x", 6234251213Snp be32toh(ldst_cmd.u.mps.rplc127_96), 6235251213Snp be32toh(ldst_cmd.u.mps.rplc95_64), 6236251213Snp be32toh(ldst_cmd.u.mps.rplc63_32), 6237251213Snp be32toh(ldst_cmd.u.mps.rplc31_0)); 6238251213Snp } 6239251213Snp } else 6240251213Snp sbuf_printf(sb, "%36s", ""); 6241251213Snp 6242251213Snp sbuf_printf(sb, "%4u%3u%3u%3u %#3x", G_SRAM_PRIO0(cls_lo), 6243251213Snp G_SRAM_PRIO1(cls_lo), G_SRAM_PRIO2(cls_lo), 6244251213Snp G_SRAM_PRIO3(cls_lo), (cls_lo >> S_MULTILISTEN0) & 0xf); 6245251213Snp } 6246251213Snp 6247251213Snp if (rc) 6248251213Snp (void) sbuf_finish(sb); 6249251213Snp else 6250251213Snp rc = sbuf_finish(sb); 6251251213Snp sbuf_delete(sb); 6252251213Snp 6253251213Snp return (rc); 6254251213Snp} 6255251213Snp 6256251213Snpstatic int 6257228561Snpsysctl_path_mtus(SYSCTL_HANDLER_ARGS) 6258228561Snp{ 6259228561Snp struct adapter *sc = arg1; 6260228561Snp struct sbuf *sb; 6261228561Snp int rc; 6262228561Snp uint16_t mtus[NMTUS]; 6263228561Snp 6264228561Snp rc = sysctl_wire_old_buffer(req, 0); 6265228561Snp if (rc != 0) 6266228561Snp return (rc); 6267228561Snp 6268228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6269228561Snp if (sb == NULL) 6270228561Snp return (ENOMEM); 6271228561Snp 6272228561Snp t4_read_mtu_tbl(sc, mtus, NULL); 6273228561Snp 6274228561Snp sbuf_printf(sb, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", 6275228561Snp mtus[0], mtus[1], mtus[2], mtus[3], mtus[4], mtus[5], mtus[6], 6276228561Snp mtus[7], mtus[8], mtus[9], mtus[10], mtus[11], mtus[12], mtus[13], 6277228561Snp mtus[14], mtus[15]); 6278228561Snp 6279228561Snp rc = sbuf_finish(sb); 6280228561Snp sbuf_delete(sb); 6281228561Snp 6282228561Snp return (rc); 6283228561Snp} 6284228561Snp 6285228561Snpstatic int 6286228561Snpsysctl_pm_stats(SYSCTL_HANDLER_ARGS) 6287228561Snp{ 6288228561Snp struct adapter *sc = arg1; 6289228561Snp struct sbuf *sb; 6290228561Snp int rc, i; 6291259142Snp uint32_t cnt[PM_NSTATS]; 6292259142Snp uint64_t cyc[PM_NSTATS]; 6293259142Snp static const char *rx_stats[] = { 6294259142Snp "Read:", "Write bypass:", "Write mem:", "Flush:" 6295228561Snp }; 6296259142Snp static const char *tx_stats[] = { 6297259142Snp "Read:", "Write bypass:", "Write mem:", "Bypass + mem:" 6298259142Snp }; 6299228561Snp 6300228561Snp rc = sysctl_wire_old_buffer(req, 0); 6301228561Snp if (rc != 0) 6302228561Snp return (rc); 6303228561Snp 6304228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6305228561Snp if (sb == NULL) 6306228561Snp return (ENOMEM); 6307228561Snp 6308259142Snp t4_pmtx_get_stats(sc, cnt, cyc); 6309259142Snp sbuf_printf(sb, " Tx pcmds Tx bytes"); 6310259142Snp for (i = 0; i < ARRAY_SIZE(tx_stats); i++) 6311259142Snp sbuf_printf(sb, "\n%-13s %10u %20ju", tx_stats[i], cnt[i], 6312259142Snp cyc[i]); 6313228561Snp 6314259142Snp t4_pmrx_get_stats(sc, cnt, cyc); 6315259142Snp sbuf_printf(sb, "\n Rx pcmds Rx bytes"); 6316259142Snp for (i = 0; i < ARRAY_SIZE(rx_stats); i++) 6317259142Snp sbuf_printf(sb, "\n%-13s %10u %20ju", rx_stats[i], cnt[i], 6318259142Snp cyc[i]); 6319228561Snp 6320228561Snp rc = sbuf_finish(sb); 6321228561Snp sbuf_delete(sb); 6322228561Snp 6323228561Snp return (rc); 6324228561Snp} 6325228561Snp 6326228561Snpstatic int 6327228561Snpsysctl_rdma_stats(SYSCTL_HANDLER_ARGS) 6328228561Snp{ 6329228561Snp struct adapter *sc = arg1; 6330228561Snp struct sbuf *sb; 6331228561Snp int rc; 6332228561Snp struct tp_rdma_stats stats; 6333228561Snp 6334228561Snp rc = sysctl_wire_old_buffer(req, 0); 6335228561Snp if (rc != 0) 6336228561Snp return (rc); 6337228561Snp 6338228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6339228561Snp if (sb == NULL) 6340228561Snp return (ENOMEM); 6341228561Snp 6342228561Snp t4_tp_get_rdma_stats(sc, &stats); 6343228561Snp sbuf_printf(sb, "NoRQEModDefferals: %u\n", stats.rqe_dfr_mod); 6344228561Snp sbuf_printf(sb, "NoRQEPktDefferals: %u", stats.rqe_dfr_pkt); 6345228561Snp 6346228561Snp rc = sbuf_finish(sb); 6347228561Snp sbuf_delete(sb); 6348228561Snp 6349228561Snp return (rc); 6350228561Snp} 6351228561Snp 6352228561Snpstatic int 6353228561Snpsysctl_tcp_stats(SYSCTL_HANDLER_ARGS) 6354228561Snp{ 6355228561Snp struct adapter *sc = arg1; 6356228561Snp struct sbuf *sb; 6357228561Snp int rc; 6358228561Snp struct tp_tcp_stats v4, v6; 6359228561Snp 6360228561Snp rc = sysctl_wire_old_buffer(req, 0); 6361228561Snp if (rc != 0) 6362228561Snp return (rc); 6363228561Snp 6364228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6365228561Snp if (sb == NULL) 6366228561Snp return (ENOMEM); 6367228561Snp 6368228561Snp t4_tp_get_tcp_stats(sc, &v4, &v6); 6369228561Snp sbuf_printf(sb, 6370228561Snp " IP IPv6\n"); 6371228561Snp sbuf_printf(sb, "OutRsts: %20u %20u\n", 6372228561Snp v4.tcpOutRsts, v6.tcpOutRsts); 6373228561Snp sbuf_printf(sb, "InSegs: %20ju %20ju\n", 6374228561Snp v4.tcpInSegs, v6.tcpInSegs); 6375228561Snp sbuf_printf(sb, "OutSegs: %20ju %20ju\n", 6376228561Snp v4.tcpOutSegs, v6.tcpOutSegs); 6377228561Snp sbuf_printf(sb, "RetransSegs: %20ju %20ju", 6378228561Snp v4.tcpRetransSegs, v6.tcpRetransSegs); 6379228561Snp 6380228561Snp rc = sbuf_finish(sb); 6381228561Snp sbuf_delete(sb); 6382228561Snp 6383228561Snp return (rc); 6384228561Snp} 6385228561Snp 6386228561Snpstatic int 6387228561Snpsysctl_tids(SYSCTL_HANDLER_ARGS) 6388228561Snp{ 6389228561Snp struct adapter *sc = arg1; 6390228561Snp struct sbuf *sb; 6391228561Snp int rc; 6392228561Snp struct tid_info *t = &sc->tids; 6393228561Snp 6394228561Snp rc = sysctl_wire_old_buffer(req, 0); 6395228561Snp if (rc != 0) 6396228561Snp return (rc); 6397228561Snp 6398228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6399228561Snp if (sb == NULL) 6400228561Snp return (ENOMEM); 6401228561Snp 6402228561Snp if (t->natids) { 6403228561Snp sbuf_printf(sb, "ATID range: 0-%u, in use: %u\n", t->natids - 1, 6404228561Snp t->atids_in_use); 6405228561Snp } 6406228561Snp 6407228561Snp if (t->ntids) { 6408228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 6409228561Snp uint32_t b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4; 6410228561Snp 6411228561Snp if (b) { 6412228561Snp sbuf_printf(sb, "TID range: 0-%u, %u-%u", b - 1, 6413228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 6414228561Snp t->ntids - 1); 6415228561Snp } else { 6416228561Snp sbuf_printf(sb, "TID range: %u-%u", 6417228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 6418228561Snp t->ntids - 1); 6419228561Snp } 6420228561Snp } else 6421228561Snp sbuf_printf(sb, "TID range: 0-%u", t->ntids - 1); 6422228561Snp sbuf_printf(sb, ", in use: %u\n", 6423228561Snp atomic_load_acq_int(&t->tids_in_use)); 6424228561Snp } 6425228561Snp 6426228561Snp if (t->nstids) { 6427228561Snp sbuf_printf(sb, "STID range: %u-%u, in use: %u\n", t->stid_base, 6428228561Snp t->stid_base + t->nstids - 1, t->stids_in_use); 6429228561Snp } 6430228561Snp 6431228561Snp if (t->nftids) { 6432228561Snp sbuf_printf(sb, "FTID range: %u-%u\n", t->ftid_base, 6433228561Snp t->ftid_base + t->nftids - 1); 6434228561Snp } 6435228561Snp 6436265426Snp if (t->netids) { 6437265426Snp sbuf_printf(sb, "ETID range: %u-%u\n", t->etid_base, 6438265426Snp t->etid_base + t->netids - 1); 6439265426Snp } 6440265426Snp 6441228561Snp sbuf_printf(sb, "HW TID usage: %u IP users, %u IPv6 users", 6442228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV4), 6443228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV6)); 6444228561Snp 6445228561Snp rc = sbuf_finish(sb); 6446228561Snp sbuf_delete(sb); 6447228561Snp 6448228561Snp return (rc); 6449228561Snp} 6450228561Snp 6451228561Snpstatic int 6452228561Snpsysctl_tp_err_stats(SYSCTL_HANDLER_ARGS) 6453228561Snp{ 6454228561Snp struct adapter *sc = arg1; 6455228561Snp struct sbuf *sb; 6456228561Snp int rc; 6457228561Snp struct tp_err_stats stats; 6458228561Snp 6459228561Snp rc = sysctl_wire_old_buffer(req, 0); 6460228561Snp if (rc != 0) 6461228561Snp return (rc); 6462228561Snp 6463228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6464228561Snp if (sb == NULL) 6465228561Snp return (ENOMEM); 6466228561Snp 6467228561Snp t4_tp_get_err_stats(sc, &stats); 6468228561Snp 6469228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 6470228561Snp "channel 3\n"); 6471228561Snp sbuf_printf(sb, "macInErrs: %10u %10u %10u %10u\n", 6472228561Snp stats.macInErrs[0], stats.macInErrs[1], stats.macInErrs[2], 6473228561Snp stats.macInErrs[3]); 6474228561Snp sbuf_printf(sb, "hdrInErrs: %10u %10u %10u %10u\n", 6475228561Snp stats.hdrInErrs[0], stats.hdrInErrs[1], stats.hdrInErrs[2], 6476228561Snp stats.hdrInErrs[3]); 6477228561Snp sbuf_printf(sb, "tcpInErrs: %10u %10u %10u %10u\n", 6478228561Snp stats.tcpInErrs[0], stats.tcpInErrs[1], stats.tcpInErrs[2], 6479228561Snp stats.tcpInErrs[3]); 6480228561Snp sbuf_printf(sb, "tcp6InErrs: %10u %10u %10u %10u\n", 6481228561Snp stats.tcp6InErrs[0], stats.tcp6InErrs[1], stats.tcp6InErrs[2], 6482228561Snp stats.tcp6InErrs[3]); 6483228561Snp sbuf_printf(sb, "tnlCongDrops: %10u %10u %10u %10u\n", 6484228561Snp stats.tnlCongDrops[0], stats.tnlCongDrops[1], stats.tnlCongDrops[2], 6485228561Snp stats.tnlCongDrops[3]); 6486228561Snp sbuf_printf(sb, "tnlTxDrops: %10u %10u %10u %10u\n", 6487228561Snp stats.tnlTxDrops[0], stats.tnlTxDrops[1], stats.tnlTxDrops[2], 6488228561Snp stats.tnlTxDrops[3]); 6489228561Snp sbuf_printf(sb, "ofldVlanDrops: %10u %10u %10u %10u\n", 6490228561Snp stats.ofldVlanDrops[0], stats.ofldVlanDrops[1], 6491228561Snp stats.ofldVlanDrops[2], stats.ofldVlanDrops[3]); 6492228561Snp sbuf_printf(sb, "ofldChanDrops: %10u %10u %10u %10u\n\n", 6493228561Snp stats.ofldChanDrops[0], stats.ofldChanDrops[1], 6494228561Snp stats.ofldChanDrops[2], stats.ofldChanDrops[3]); 6495228561Snp sbuf_printf(sb, "ofldNoNeigh: %u\nofldCongDefer: %u", 6496228561Snp stats.ofldNoNeigh, stats.ofldCongDefer); 6497228561Snp 6498228561Snp rc = sbuf_finish(sb); 6499228561Snp sbuf_delete(sb); 6500228561Snp 6501228561Snp return (rc); 6502228561Snp} 6503228561Snp 6504251213Snpstruct field_desc { 6505251213Snp const char *name; 6506251213Snp u_int start; 6507251213Snp u_int width; 6508251213Snp}; 6509251213Snp 6510251213Snpstatic void 6511251213Snpfield_desc_show(struct sbuf *sb, uint64_t v, const struct field_desc *f) 6512251213Snp{ 6513251213Snp char buf[32]; 6514251213Snp int line_size = 0; 6515251213Snp 6516251213Snp while (f->name) { 6517251213Snp uint64_t mask = (1ULL << f->width) - 1; 6518251213Snp int len = snprintf(buf, sizeof(buf), "%s: %ju", f->name, 6519251213Snp ((uintmax_t)v >> f->start) & mask); 6520251213Snp 6521251213Snp if (line_size + len >= 79) { 6522251213Snp line_size = 8; 6523251213Snp sbuf_printf(sb, "\n "); 6524251213Snp } 6525251213Snp sbuf_printf(sb, "%s ", buf); 6526251213Snp line_size += len + 1; 6527251213Snp f++; 6528251213Snp } 6529251213Snp sbuf_printf(sb, "\n"); 6530251213Snp} 6531251213Snp 6532251213Snpstatic struct field_desc tp_la0[] = { 6533251213Snp { "RcfOpCodeOut", 60, 4 }, 6534251213Snp { "State", 56, 4 }, 6535251213Snp { "WcfState", 52, 4 }, 6536251213Snp { "RcfOpcSrcOut", 50, 2 }, 6537251213Snp { "CRxError", 49, 1 }, 6538251213Snp { "ERxError", 48, 1 }, 6539251213Snp { "SanityFailed", 47, 1 }, 6540251213Snp { "SpuriousMsg", 46, 1 }, 6541251213Snp { "FlushInputMsg", 45, 1 }, 6542251213Snp { "FlushInputCpl", 44, 1 }, 6543251213Snp { "RssUpBit", 43, 1 }, 6544251213Snp { "RssFilterHit", 42, 1 }, 6545251213Snp { "Tid", 32, 10 }, 6546251213Snp { "InitTcb", 31, 1 }, 6547251213Snp { "LineNumber", 24, 7 }, 6548251213Snp { "Emsg", 23, 1 }, 6549251213Snp { "EdataOut", 22, 1 }, 6550251213Snp { "Cmsg", 21, 1 }, 6551251213Snp { "CdataOut", 20, 1 }, 6552251213Snp { "EreadPdu", 19, 1 }, 6553251213Snp { "CreadPdu", 18, 1 }, 6554251213Snp { "TunnelPkt", 17, 1 }, 6555251213Snp { "RcfPeerFin", 16, 1 }, 6556251213Snp { "RcfReasonOut", 12, 4 }, 6557251213Snp { "TxCchannel", 10, 2 }, 6558251213Snp { "RcfTxChannel", 8, 2 }, 6559251213Snp { "RxEchannel", 6, 2 }, 6560251213Snp { "RcfRxChannel", 5, 1 }, 6561251213Snp { "RcfDataOutSrdy", 4, 1 }, 6562251213Snp { "RxDvld", 3, 1 }, 6563251213Snp { "RxOoDvld", 2, 1 }, 6564251213Snp { "RxCongestion", 1, 1 }, 6565251213Snp { "TxCongestion", 0, 1 }, 6566251213Snp { NULL } 6567251213Snp}; 6568251213Snp 6569251213Snpstatic struct field_desc tp_la1[] = { 6570251213Snp { "CplCmdIn", 56, 8 }, 6571251213Snp { "CplCmdOut", 48, 8 }, 6572251213Snp { "ESynOut", 47, 1 }, 6573251213Snp { "EAckOut", 46, 1 }, 6574251213Snp { "EFinOut", 45, 1 }, 6575251213Snp { "ERstOut", 44, 1 }, 6576251213Snp { "SynIn", 43, 1 }, 6577251213Snp { "AckIn", 42, 1 }, 6578251213Snp { "FinIn", 41, 1 }, 6579251213Snp { "RstIn", 40, 1 }, 6580251213Snp { "DataIn", 39, 1 }, 6581251213Snp { "DataInVld", 38, 1 }, 6582251213Snp { "PadIn", 37, 1 }, 6583251213Snp { "RxBufEmpty", 36, 1 }, 6584251213Snp { "RxDdp", 35, 1 }, 6585251213Snp { "RxFbCongestion", 34, 1 }, 6586251213Snp { "TxFbCongestion", 33, 1 }, 6587251213Snp { "TxPktSumSrdy", 32, 1 }, 6588251213Snp { "RcfUlpType", 28, 4 }, 6589251213Snp { "Eread", 27, 1 }, 6590251213Snp { "Ebypass", 26, 1 }, 6591251213Snp { "Esave", 25, 1 }, 6592251213Snp { "Static0", 24, 1 }, 6593251213Snp { "Cread", 23, 1 }, 6594251213Snp { "Cbypass", 22, 1 }, 6595251213Snp { "Csave", 21, 1 }, 6596251213Snp { "CPktOut", 20, 1 }, 6597251213Snp { "RxPagePoolFull", 18, 2 }, 6598251213Snp { "RxLpbkPkt", 17, 1 }, 6599251213Snp { "TxLpbkPkt", 16, 1 }, 6600251213Snp { "RxVfValid", 15, 1 }, 6601251213Snp { "SynLearned", 14, 1 }, 6602251213Snp { "SetDelEntry", 13, 1 }, 6603251213Snp { "SetInvEntry", 12, 1 }, 6604251213Snp { "CpcmdDvld", 11, 1 }, 6605251213Snp { "CpcmdSave", 10, 1 }, 6606251213Snp { "RxPstructsFull", 8, 2 }, 6607251213Snp { "EpcmdDvld", 7, 1 }, 6608251213Snp { "EpcmdFlush", 6, 1 }, 6609251213Snp { "EpcmdTrimPrefix", 5, 1 }, 6610251213Snp { "EpcmdTrimPostfix", 4, 1 }, 6611251213Snp { "ERssIp4Pkt", 3, 1 }, 6612251213Snp { "ERssIp6Pkt", 2, 1 }, 6613251213Snp { "ERssTcpUdpPkt", 1, 1 }, 6614251213Snp { "ERssFceFipPkt", 0, 1 }, 6615251213Snp { NULL } 6616251213Snp}; 6617251213Snp 6618251213Snpstatic struct field_desc tp_la2[] = { 6619251213Snp { "CplCmdIn", 56, 8 }, 6620251213Snp { "MpsVfVld", 55, 1 }, 6621251213Snp { "MpsPf", 52, 3 }, 6622251213Snp { "MpsVf", 44, 8 }, 6623251213Snp { "SynIn", 43, 1 }, 6624251213Snp { "AckIn", 42, 1 }, 6625251213Snp { "FinIn", 41, 1 }, 6626251213Snp { "RstIn", 40, 1 }, 6627251213Snp { "DataIn", 39, 1 }, 6628251213Snp { "DataInVld", 38, 1 }, 6629251213Snp { "PadIn", 37, 1 }, 6630251213Snp { "RxBufEmpty", 36, 1 }, 6631251213Snp { "RxDdp", 35, 1 }, 6632251213Snp { "RxFbCongestion", 34, 1 }, 6633251213Snp { "TxFbCongestion", 33, 1 }, 6634251213Snp { "TxPktSumSrdy", 32, 1 }, 6635251213Snp { "RcfUlpType", 28, 4 }, 6636251213Snp { "Eread", 27, 1 }, 6637251213Snp { "Ebypass", 26, 1 }, 6638251213Snp { "Esave", 25, 1 }, 6639251213Snp { "Static0", 24, 1 }, 6640251213Snp { "Cread", 23, 1 }, 6641251213Snp { "Cbypass", 22, 1 }, 6642251213Snp { "Csave", 21, 1 }, 6643251213Snp { "CPktOut", 20, 1 }, 6644251213Snp { "RxPagePoolFull", 18, 2 }, 6645251213Snp { "RxLpbkPkt", 17, 1 }, 6646251213Snp { "TxLpbkPkt", 16, 1 }, 6647251213Snp { "RxVfValid", 15, 1 }, 6648251213Snp { "SynLearned", 14, 1 }, 6649251213Snp { "SetDelEntry", 13, 1 }, 6650251213Snp { "SetInvEntry", 12, 1 }, 6651251213Snp { "CpcmdDvld", 11, 1 }, 6652251213Snp { "CpcmdSave", 10, 1 }, 6653251213Snp { "RxPstructsFull", 8, 2 }, 6654251213Snp { "EpcmdDvld", 7, 1 }, 6655251213Snp { "EpcmdFlush", 6, 1 }, 6656251213Snp { "EpcmdTrimPrefix", 5, 1 }, 6657251213Snp { "EpcmdTrimPostfix", 4, 1 }, 6658251213Snp { "ERssIp4Pkt", 3, 1 }, 6659251213Snp { "ERssIp6Pkt", 2, 1 }, 6660251213Snp { "ERssTcpUdpPkt", 1, 1 }, 6661251213Snp { "ERssFceFipPkt", 0, 1 }, 6662251213Snp { NULL } 6663251213Snp}; 6664251213Snp 6665251213Snpstatic void 6666251213Snptp_la_show(struct sbuf *sb, uint64_t *p, int idx) 6667251213Snp{ 6668251213Snp 6669251213Snp field_desc_show(sb, *p, tp_la0); 6670251213Snp} 6671251213Snp 6672251213Snpstatic void 6673251213Snptp_la_show2(struct sbuf *sb, uint64_t *p, int idx) 6674251213Snp{ 6675251213Snp 6676251213Snp if (idx) 6677251213Snp sbuf_printf(sb, "\n"); 6678251213Snp field_desc_show(sb, p[0], tp_la0); 6679251213Snp if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) 6680251213Snp field_desc_show(sb, p[1], tp_la0); 6681251213Snp} 6682251213Snp 6683251213Snpstatic void 6684251213Snptp_la_show3(struct sbuf *sb, uint64_t *p, int idx) 6685251213Snp{ 6686251213Snp 6687251213Snp if (idx) 6688251213Snp sbuf_printf(sb, "\n"); 6689251213Snp field_desc_show(sb, p[0], tp_la0); 6690251213Snp if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL) 6691251213Snp field_desc_show(sb, p[1], (p[0] & (1 << 17)) ? tp_la2 : tp_la1); 6692251213Snp} 6693251213Snp 6694228561Snpstatic int 6695251213Snpsysctl_tp_la(SYSCTL_HANDLER_ARGS) 6696251213Snp{ 6697251213Snp struct adapter *sc = arg1; 6698251213Snp struct sbuf *sb; 6699251213Snp uint64_t *buf, *p; 6700251213Snp int rc; 6701251213Snp u_int i, inc; 6702251213Snp void (*show_func)(struct sbuf *, uint64_t *, int); 6703251213Snp 6704251213Snp rc = sysctl_wire_old_buffer(req, 0); 6705251213Snp if (rc != 0) 6706251213Snp return (rc); 6707251213Snp 6708251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6709251213Snp if (sb == NULL) 6710251213Snp return (ENOMEM); 6711251213Snp 6712251213Snp buf = malloc(TPLA_SIZE * sizeof(uint64_t), M_CXGBE, M_ZERO | M_WAITOK); 6713251213Snp 6714251213Snp t4_tp_read_la(sc, buf, NULL); 6715251213Snp p = buf; 6716251213Snp 6717251213Snp switch (G_DBGLAMODE(t4_read_reg(sc, A_TP_DBG_LA_CONFIG))) { 6718251213Snp case 2: 6719251213Snp inc = 2; 6720251213Snp show_func = tp_la_show2; 6721251213Snp break; 6722251213Snp case 3: 6723251213Snp inc = 2; 6724251213Snp show_func = tp_la_show3; 6725251213Snp break; 6726251213Snp default: 6727251213Snp inc = 1; 6728251213Snp show_func = tp_la_show; 6729251213Snp } 6730251213Snp 6731251213Snp for (i = 0; i < TPLA_SIZE / inc; i++, p += inc) 6732251213Snp (*show_func)(sb, p, i); 6733251213Snp 6734251213Snp rc = sbuf_finish(sb); 6735251213Snp sbuf_delete(sb); 6736251213Snp free(buf, M_CXGBE); 6737251213Snp return (rc); 6738251213Snp} 6739251213Snp 6740251213Snpstatic int 6741228561Snpsysctl_tx_rate(SYSCTL_HANDLER_ARGS) 6742228561Snp{ 6743228561Snp struct adapter *sc = arg1; 6744228561Snp struct sbuf *sb; 6745228561Snp int rc; 6746228561Snp u64 nrate[NCHAN], orate[NCHAN]; 6747228561Snp 6748228561Snp rc = sysctl_wire_old_buffer(req, 0); 6749228561Snp if (rc != 0) 6750228561Snp return (rc); 6751228561Snp 6752228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 6753228561Snp if (sb == NULL) 6754228561Snp return (ENOMEM); 6755228561Snp 6756228561Snp t4_get_chan_txrate(sc, nrate, orate); 6757228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 6758228561Snp "channel 3\n"); 6759228561Snp sbuf_printf(sb, "NIC B/s: %10ju %10ju %10ju %10ju\n", 6760228561Snp nrate[0], nrate[1], nrate[2], nrate[3]); 6761228561Snp sbuf_printf(sb, "Offload B/s: %10ju %10ju %10ju %10ju", 6762228561Snp orate[0], orate[1], orate[2], orate[3]); 6763228561Snp 6764228561Snp rc = sbuf_finish(sb); 6765228561Snp sbuf_delete(sb); 6766228561Snp 6767228561Snp return (rc); 6768228561Snp} 6769248925Snp 6770248925Snpstatic int 6771251213Snpsysctl_ulprx_la(SYSCTL_HANDLER_ARGS) 6772251213Snp{ 6773251213Snp struct adapter *sc = arg1; 6774251213Snp struct sbuf *sb; 6775251213Snp uint32_t *buf, *p; 6776251213Snp int rc, i; 6777251213Snp 6778251213Snp rc = sysctl_wire_old_buffer(req, 0); 6779251213Snp if (rc != 0) 6780251213Snp return (rc); 6781251213Snp 6782251213Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6783251213Snp if (sb == NULL) 6784251213Snp return (ENOMEM); 6785251213Snp 6786251213Snp buf = malloc(ULPRX_LA_SIZE * 8 * sizeof(uint32_t), M_CXGBE, 6787251213Snp M_ZERO | M_WAITOK); 6788251213Snp 6789251213Snp t4_ulprx_read_la(sc, buf); 6790251213Snp p = buf; 6791251213Snp 6792251213Snp sbuf_printf(sb, " Pcmd Type Message" 6793251213Snp " Data"); 6794251213Snp for (i = 0; i < ULPRX_LA_SIZE; i++, p += 8) { 6795251213Snp sbuf_printf(sb, "\n%08x%08x %4x %08x %08x%08x%08x%08x", 6796251213Snp p[1], p[0], p[2], p[3], p[7], p[6], p[5], p[4]); 6797251213Snp } 6798251213Snp 6799251213Snp rc = sbuf_finish(sb); 6800251213Snp sbuf_delete(sb); 6801251213Snp free(buf, M_CXGBE); 6802251213Snp return (rc); 6803251213Snp} 6804251213Snp 6805251213Snpstatic int 6806249392Snpsysctl_wcwr_stats(SYSCTL_HANDLER_ARGS) 6807248925Snp{ 6808248925Snp struct adapter *sc = arg1; 6809248925Snp struct sbuf *sb; 6810248925Snp int rc, v; 6811248925Snp 6812248925Snp rc = sysctl_wire_old_buffer(req, 0); 6813248925Snp if (rc != 0) 6814248925Snp return (rc); 6815248925Snp 6816248925Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6817248925Snp if (sb == NULL) 6818248925Snp return (ENOMEM); 6819248925Snp 6820248925Snp v = t4_read_reg(sc, A_SGE_STAT_CFG); 6821248925Snp if (G_STATSOURCE_T5(v) == 7) { 6822248925Snp if (G_STATMODE(v) == 0) { 6823249383Snp sbuf_printf(sb, "total %d, incomplete %d", 6824248925Snp t4_read_reg(sc, A_SGE_STAT_TOTAL), 6825248925Snp t4_read_reg(sc, A_SGE_STAT_MATCH)); 6826248925Snp } else if (G_STATMODE(v) == 1) { 6827249383Snp sbuf_printf(sb, "total %d, data overflow %d", 6828248925Snp t4_read_reg(sc, A_SGE_STAT_TOTAL), 6829248925Snp t4_read_reg(sc, A_SGE_STAT_MATCH)); 6830248925Snp } 6831248925Snp } 6832248925Snp rc = sbuf_finish(sb); 6833248925Snp sbuf_delete(sb); 6834248925Snp 6835248925Snp return (rc); 6836248925Snp} 6837231115Snp#endif 6838228561Snp 6839219286Snpstatic inline void 6840219286Snptxq_start(struct ifnet *ifp, struct sge_txq *txq) 6841219286Snp{ 6842219286Snp struct buf_ring *br; 6843219286Snp struct mbuf *m; 6844219286Snp 6845219286Snp TXQ_LOCK_ASSERT_OWNED(txq); 6846219286Snp 6847220873Snp br = txq->br; 6848219286Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 6849219286Snp if (m) 6850219286Snp t4_eth_tx(ifp, txq, m); 6851219286Snp} 6852219286Snp 6853219286Snpvoid 6854228561Snpt4_tx_callout(void *arg) 6855219286Snp{ 6856228561Snp struct sge_eq *eq = arg; 6857228561Snp struct adapter *sc; 6858219286Snp 6859228561Snp if (EQ_TRYLOCK(eq) == 0) 6860228561Snp goto reschedule; 6861228561Snp 6862228561Snp if (eq->flags & EQ_STALLED && !can_resume_tx(eq)) { 6863228561Snp EQ_UNLOCK(eq); 6864228561Snpreschedule: 6865228561Snp if (__predict_true(!(eq->flags && EQ_DOOMED))) 6866228561Snp callout_schedule(&eq->tx_callout, 1); 6867228561Snp return; 6868228561Snp } 6869228561Snp 6870228561Snp EQ_LOCK_ASSERT_OWNED(eq); 6871228561Snp 6872228561Snp if (__predict_true((eq->flags & EQ_DOOMED) == 0)) { 6873228561Snp 6874228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 6875228561Snp struct sge_txq *txq = arg; 6876228561Snp struct port_info *pi = txq->ifp->if_softc; 6877228561Snp 6878228561Snp sc = pi->adapter; 6879228561Snp } else { 6880228561Snp struct sge_wrq *wrq = arg; 6881228561Snp 6882228561Snp sc = wrq->adapter; 6883228561Snp } 6884228561Snp 6885228561Snp taskqueue_enqueue(sc->tq[eq->tx_chan], &eq->tx_task); 6886228561Snp } 6887228561Snp 6888228561Snp EQ_UNLOCK(eq); 6889228561Snp} 6890228561Snp 6891228561Snpvoid 6892228561Snpt4_tx_task(void *arg, int count) 6893228561Snp{ 6894228561Snp struct sge_eq *eq = arg; 6895228561Snp 6896228561Snp EQ_LOCK(eq); 6897228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 6898228561Snp struct sge_txq *txq = arg; 6899220649Snp txq_start(txq->ifp, txq); 6900228561Snp } else { 6901228561Snp struct sge_wrq *wrq = arg; 6902228561Snp t4_wrq_tx_locked(wrq->adapter, wrq, NULL); 6903228561Snp } 6904228561Snp EQ_UNLOCK(eq); 6905219286Snp} 6906219286Snp 6907221474Snpstatic uint32_t 6908221474Snpfconf_to_mode(uint32_t fconf) 6909221474Snp{ 6910221474Snp uint32_t mode; 6911221474Snp 6912221474Snp mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR | 6913221474Snp T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT; 6914221474Snp 6915221474Snp if (fconf & F_FRAGMENTATION) 6916221474Snp mode |= T4_FILTER_IP_FRAGMENT; 6917221474Snp 6918221474Snp if (fconf & F_MPSHITTYPE) 6919221474Snp mode |= T4_FILTER_MPS_HIT_TYPE; 6920221474Snp 6921221474Snp if (fconf & F_MACMATCH) 6922221474Snp mode |= T4_FILTER_MAC_IDX; 6923221474Snp 6924221474Snp if (fconf & F_ETHERTYPE) 6925221474Snp mode |= T4_FILTER_ETH_TYPE; 6926221474Snp 6927221474Snp if (fconf & F_PROTOCOL) 6928221474Snp mode |= T4_FILTER_IP_PROTO; 6929221474Snp 6930221474Snp if (fconf & F_TOS) 6931221474Snp mode |= T4_FILTER_IP_TOS; 6932221474Snp 6933221474Snp if (fconf & F_VLAN) 6934228561Snp mode |= T4_FILTER_VLAN; 6935221474Snp 6936221474Snp if (fconf & F_VNIC_ID) 6937228561Snp mode |= T4_FILTER_VNIC; 6938221474Snp 6939221474Snp if (fconf & F_PORT) 6940221474Snp mode |= T4_FILTER_PORT; 6941221474Snp 6942221474Snp if (fconf & F_FCOE) 6943221474Snp mode |= T4_FILTER_FCoE; 6944221474Snp 6945221474Snp return (mode); 6946221474Snp} 6947221474Snp 6948221474Snpstatic uint32_t 6949221474Snpmode_to_fconf(uint32_t mode) 6950221474Snp{ 6951221474Snp uint32_t fconf = 0; 6952221474Snp 6953221474Snp if (mode & T4_FILTER_IP_FRAGMENT) 6954221474Snp fconf |= F_FRAGMENTATION; 6955221474Snp 6956221474Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 6957221474Snp fconf |= F_MPSHITTYPE; 6958221474Snp 6959221474Snp if (mode & T4_FILTER_MAC_IDX) 6960221474Snp fconf |= F_MACMATCH; 6961221474Snp 6962221474Snp if (mode & T4_FILTER_ETH_TYPE) 6963221474Snp fconf |= F_ETHERTYPE; 6964221474Snp 6965221474Snp if (mode & T4_FILTER_IP_PROTO) 6966221474Snp fconf |= F_PROTOCOL; 6967221474Snp 6968221474Snp if (mode & T4_FILTER_IP_TOS) 6969221474Snp fconf |= F_TOS; 6970221474Snp 6971228561Snp if (mode & T4_FILTER_VLAN) 6972221474Snp fconf |= F_VLAN; 6973221474Snp 6974228561Snp if (mode & T4_FILTER_VNIC) 6975221474Snp fconf |= F_VNIC_ID; 6976221474Snp 6977221474Snp if (mode & T4_FILTER_PORT) 6978221474Snp fconf |= F_PORT; 6979221474Snp 6980221474Snp if (mode & T4_FILTER_FCoE) 6981221474Snp fconf |= F_FCOE; 6982221474Snp 6983221474Snp return (fconf); 6984221474Snp} 6985221474Snp 6986221474Snpstatic uint32_t 6987221474Snpfspec_to_fconf(struct t4_filter_specification *fs) 6988221474Snp{ 6989221474Snp uint32_t fconf = 0; 6990221474Snp 6991221474Snp if (fs->val.frag || fs->mask.frag) 6992221474Snp fconf |= F_FRAGMENTATION; 6993221474Snp 6994221474Snp if (fs->val.matchtype || fs->mask.matchtype) 6995221474Snp fconf |= F_MPSHITTYPE; 6996221474Snp 6997221474Snp if (fs->val.macidx || fs->mask.macidx) 6998221474Snp fconf |= F_MACMATCH; 6999221474Snp 7000221474Snp if (fs->val.ethtype || fs->mask.ethtype) 7001221474Snp fconf |= F_ETHERTYPE; 7002221474Snp 7003221474Snp if (fs->val.proto || fs->mask.proto) 7004221474Snp fconf |= F_PROTOCOL; 7005221474Snp 7006221474Snp if (fs->val.tos || fs->mask.tos) 7007221474Snp fconf |= F_TOS; 7008221474Snp 7009228561Snp if (fs->val.vlan_vld || fs->mask.vlan_vld) 7010221474Snp fconf |= F_VLAN; 7011221474Snp 7012228561Snp if (fs->val.vnic_vld || fs->mask.vnic_vld) 7013221474Snp fconf |= F_VNIC_ID; 7014221474Snp 7015221474Snp if (fs->val.iport || fs->mask.iport) 7016221474Snp fconf |= F_PORT; 7017221474Snp 7018221474Snp if (fs->val.fcoe || fs->mask.fcoe) 7019221474Snp fconf |= F_FCOE; 7020221474Snp 7021221474Snp return (fconf); 7022221474Snp} 7023221474Snp 7024221474Snpstatic int 7025221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode) 7026221474Snp{ 7027245274Snp int rc; 7028221474Snp uint32_t fconf; 7029221474Snp 7030245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 7031245274Snp "t4getfm"); 7032245274Snp if (rc) 7033245274Snp return (rc); 7034245274Snp 7035221474Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1, 7036221474Snp A_TP_VLAN_PRI_MAP); 7037221474Snp 7038252705Snp if (sc->params.tp.vlan_pri_map != fconf) { 7039228561Snp log(LOG_WARNING, "%s: cached filter mode out of sync %x %x.\n", 7040252705Snp device_get_nameunit(sc->dev), sc->params.tp.vlan_pri_map, 7041252705Snp fconf); 7042252705Snp sc->params.tp.vlan_pri_map = fconf; 7043228561Snp } 7044221474Snp 7045252705Snp *mode = fconf_to_mode(sc->params.tp.vlan_pri_map); 7046228561Snp 7047245274Snp end_synchronized_op(sc, LOCK_HELD); 7048221474Snp return (0); 7049221474Snp} 7050221474Snp 7051221474Snpstatic int 7052221474Snpset_filter_mode(struct adapter *sc, uint32_t mode) 7053221474Snp{ 7054221474Snp uint32_t fconf; 7055221474Snp int rc; 7056221474Snp 7057221474Snp fconf = mode_to_fconf(mode); 7058221474Snp 7059245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 7060245274Snp "t4setfm"); 7061245274Snp if (rc) 7062245274Snp return (rc); 7063221474Snp 7064221474Snp if (sc->tids.ftids_in_use > 0) { 7065221474Snp rc = EBUSY; 7066221474Snp goto done; 7067221474Snp } 7068221474Snp 7069237263Snp#ifdef TCP_OFFLOAD 7070228561Snp if (sc->offload_map) { 7071228561Snp rc = EBUSY; 7072228561Snp goto done; 7073228561Snp } 7074228561Snp#endif 7075228561Snp 7076228561Snp#ifdef notyet 7077221474Snp rc = -t4_set_filter_mode(sc, fconf); 7078228561Snp if (rc == 0) 7079228561Snp sc->filter_mode = fconf; 7080228561Snp#else 7081228561Snp rc = ENOTSUP; 7082228561Snp#endif 7083228561Snp 7084221474Snpdone: 7085245274Snp end_synchronized_op(sc, LOCK_HELD); 7086221474Snp return (rc); 7087221474Snp} 7088221474Snp 7089222552Snpstatic inline uint64_t 7090222552Snpget_filter_hits(struct adapter *sc, uint32_t fid) 7091222552Snp{ 7092248925Snp uint32_t mw_base, off, tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 7093222552Snp uint64_t hits; 7094222552Snp 7095248925Snp memwin_info(sc, 0, &mw_base, NULL); 7096248925Snp off = position_memwin(sc, 0, 7097222552Snp tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE); 7098251358Snp if (is_t4(sc)) { 7099251358Snp hits = t4_read_reg64(sc, mw_base + off + 16); 7100251358Snp hits = be64toh(hits); 7101251358Snp } else { 7102251358Snp hits = t4_read_reg(sc, mw_base + off + 24); 7103251358Snp hits = be32toh(hits); 7104251358Snp } 7105222552Snp 7106251358Snp return (hits); 7107222552Snp} 7108222552Snp 7109221474Snpstatic int 7110221474Snpget_filter(struct adapter *sc, struct t4_filter *t) 7111221474Snp{ 7112245274Snp int i, rc, nfilters = sc->tids.nftids; 7113221474Snp struct filter_entry *f; 7114221474Snp 7115245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 7116245274Snp "t4getf"); 7117245274Snp if (rc) 7118245274Snp return (rc); 7119221474Snp 7120221474Snp if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL || 7121221474Snp t->idx >= nfilters) { 7122221474Snp t->idx = 0xffffffff; 7123245274Snp goto done; 7124221474Snp } 7125221474Snp 7126221474Snp f = &sc->tids.ftid_tab[t->idx]; 7127221474Snp for (i = t->idx; i < nfilters; i++, f++) { 7128221474Snp if (f->valid) { 7129221474Snp t->idx = i; 7130222509Snp t->l2tidx = f->l2t ? f->l2t->idx : 0; 7131222509Snp t->smtidx = f->smtidx; 7132222552Snp if (f->fs.hitcnts) 7133222552Snp t->hits = get_filter_hits(sc, t->idx); 7134222552Snp else 7135222552Snp t->hits = UINT64_MAX; 7136221474Snp t->fs = f->fs; 7137221474Snp 7138245274Snp goto done; 7139221474Snp } 7140221474Snp } 7141221474Snp 7142221474Snp t->idx = 0xffffffff; 7143245274Snpdone: 7144245274Snp end_synchronized_op(sc, LOCK_HELD); 7145221474Snp return (0); 7146221474Snp} 7147221474Snp 7148221474Snpstatic int 7149221474Snpset_filter(struct adapter *sc, struct t4_filter *t) 7150221474Snp{ 7151221474Snp unsigned int nfilters, nports; 7152221474Snp struct filter_entry *f; 7153245274Snp int i, rc; 7154221474Snp 7155245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setf"); 7156245274Snp if (rc) 7157245274Snp return (rc); 7158221474Snp 7159221474Snp nfilters = sc->tids.nftids; 7160221474Snp nports = sc->params.nports; 7161221474Snp 7162245274Snp if (nfilters == 0) { 7163245274Snp rc = ENOTSUP; 7164245274Snp goto done; 7165245274Snp } 7166221474Snp 7167245274Snp if (!(sc->flags & FULL_INIT_DONE)) { 7168245274Snp rc = EAGAIN; 7169245274Snp goto done; 7170245274Snp } 7171221474Snp 7172245274Snp if (t->idx >= nfilters) { 7173245274Snp rc = EINVAL; 7174245274Snp goto done; 7175245274Snp } 7176221474Snp 7177221474Snp /* Validate against the global filter mode */ 7178252705Snp if ((sc->params.tp.vlan_pri_map | fspec_to_fconf(&t->fs)) != 7179252705Snp sc->params.tp.vlan_pri_map) { 7180245274Snp rc = E2BIG; 7181245274Snp goto done; 7182245274Snp } 7183221474Snp 7184245274Snp if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) { 7185245274Snp rc = EINVAL; 7186245274Snp goto done; 7187245274Snp } 7188221474Snp 7189245274Snp if (t->fs.val.iport >= nports) { 7190245274Snp rc = EINVAL; 7191245274Snp goto done; 7192245274Snp } 7193221474Snp 7194221474Snp /* Can't specify an iq if not steering to it */ 7195245274Snp if (!t->fs.dirsteer && t->fs.iq) { 7196245274Snp rc = EINVAL; 7197245274Snp goto done; 7198245274Snp } 7199221474Snp 7200221474Snp /* IPv6 filter idx must be 4 aligned */ 7201221474Snp if (t->fs.type == 1 && 7202245274Snp ((t->idx & 0x3) || t->idx + 4 >= nfilters)) { 7203245274Snp rc = EINVAL; 7204245274Snp goto done; 7205245274Snp } 7206221474Snp 7207221474Snp if (sc->tids.ftid_tab == NULL) { 7208221474Snp KASSERT(sc->tids.ftids_in_use == 0, 7209221474Snp ("%s: no memory allocated but filters_in_use > 0", 7210221474Snp __func__)); 7211221474Snp 7212221474Snp sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) * 7213221474Snp nfilters, M_CXGBE, M_NOWAIT | M_ZERO); 7214245274Snp if (sc->tids.ftid_tab == NULL) { 7215245274Snp rc = ENOMEM; 7216245274Snp goto done; 7217245274Snp } 7218245274Snp mtx_init(&sc->tids.ftid_lock, "T4 filters", 0, MTX_DEF); 7219221474Snp } 7220221474Snp 7221221474Snp for (i = 0; i < 4; i++) { 7222221474Snp f = &sc->tids.ftid_tab[t->idx + i]; 7223221474Snp 7224245274Snp if (f->pending || f->valid) { 7225245274Snp rc = EBUSY; 7226245274Snp goto done; 7227245274Snp } 7228245274Snp if (f->locked) { 7229245274Snp rc = EPERM; 7230245274Snp goto done; 7231245274Snp } 7232221474Snp 7233221474Snp if (t->fs.type == 0) 7234221474Snp break; 7235221474Snp } 7236221474Snp 7237221474Snp f = &sc->tids.ftid_tab[t->idx]; 7238221474Snp f->fs = t->fs; 7239221474Snp 7240245274Snp rc = set_filter_wr(sc, t->idx); 7241245274Snpdone: 7242245274Snp end_synchronized_op(sc, 0); 7243245274Snp 7244245274Snp if (rc == 0) { 7245245274Snp mtx_lock(&sc->tids.ftid_lock); 7246245274Snp for (;;) { 7247245274Snp if (f->pending == 0) { 7248245274Snp rc = f->valid ? 0 : EIO; 7249245274Snp break; 7250245274Snp } 7251245274Snp 7252245274Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 7253245274Snp PCATCH, "t4setfw", 0)) { 7254245274Snp rc = EINPROGRESS; 7255245274Snp break; 7256245274Snp } 7257245274Snp } 7258245274Snp mtx_unlock(&sc->tids.ftid_lock); 7259245274Snp } 7260245274Snp return (rc); 7261221474Snp} 7262221474Snp 7263221474Snpstatic int 7264221474Snpdel_filter(struct adapter *sc, struct t4_filter *t) 7265221474Snp{ 7266221474Snp unsigned int nfilters; 7267221474Snp struct filter_entry *f; 7268245274Snp int rc; 7269221474Snp 7270245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4delf"); 7271245274Snp if (rc) 7272245274Snp return (rc); 7273221474Snp 7274221474Snp nfilters = sc->tids.nftids; 7275221474Snp 7276245274Snp if (nfilters == 0) { 7277245274Snp rc = ENOTSUP; 7278245274Snp goto done; 7279245274Snp } 7280221474Snp 7281221474Snp if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 || 7282245274Snp t->idx >= nfilters) { 7283245274Snp rc = EINVAL; 7284245274Snp goto done; 7285245274Snp } 7286221474Snp 7287245274Snp if (!(sc->flags & FULL_INIT_DONE)) { 7288245274Snp rc = EAGAIN; 7289245274Snp goto done; 7290245274Snp } 7291221474Snp 7292221474Snp f = &sc->tids.ftid_tab[t->idx]; 7293221474Snp 7294245274Snp if (f->pending) { 7295245274Snp rc = EBUSY; 7296245274Snp goto done; 7297245274Snp } 7298245274Snp if (f->locked) { 7299245274Snp rc = EPERM; 7300245274Snp goto done; 7301245274Snp } 7302221474Snp 7303221474Snp if (f->valid) { 7304221474Snp t->fs = f->fs; /* extra info for the caller */ 7305245274Snp rc = del_filter_wr(sc, t->idx); 7306221474Snp } 7307221474Snp 7308245274Snpdone: 7309245274Snp end_synchronized_op(sc, 0); 7310245274Snp 7311245274Snp if (rc == 0) { 7312245274Snp mtx_lock(&sc->tids.ftid_lock); 7313245274Snp for (;;) { 7314245274Snp if (f->pending == 0) { 7315245274Snp rc = f->valid ? EIO : 0; 7316245274Snp break; 7317245274Snp } 7318245274Snp 7319245274Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 7320245274Snp PCATCH, "t4delfw", 0)) { 7321245274Snp rc = EINPROGRESS; 7322245274Snp break; 7323245274Snp } 7324245274Snp } 7325245274Snp mtx_unlock(&sc->tids.ftid_lock); 7326245274Snp } 7327245274Snp 7328245274Snp return (rc); 7329221474Snp} 7330221474Snp 7331221474Snpstatic void 7332222509Snpclear_filter(struct filter_entry *f) 7333221474Snp{ 7334222509Snp if (f->l2t) 7335222509Snp t4_l2t_release(f->l2t); 7336222509Snp 7337221474Snp bzero(f, sizeof (*f)); 7338221474Snp} 7339221474Snp 7340221474Snpstatic int 7341221474Snpset_filter_wr(struct adapter *sc, int fidx) 7342221474Snp{ 7343221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 7344237263Snp struct wrqe *wr; 7345221474Snp struct fw_filter_wr *fwr; 7346221474Snp unsigned int ftid; 7347221474Snp 7348245274Snp ASSERT_SYNCHRONIZED_OP(sc); 7349221474Snp 7350222509Snp if (f->fs.newdmac || f->fs.newvlan) { 7351222509Snp /* This filter needs an L2T entry; allocate one. */ 7352222509Snp f->l2t = t4_l2t_alloc_switching(sc->l2t); 7353222509Snp if (f->l2t == NULL) 7354222509Snp return (EAGAIN); 7355222509Snp if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport, 7356222509Snp f->fs.dmac)) { 7357222509Snp t4_l2t_release(f->l2t); 7358222509Snp f->l2t = NULL; 7359222509Snp return (ENOMEM); 7360222509Snp } 7361222509Snp } 7362221474Snp 7363221474Snp ftid = sc->tids.ftid_base + fidx; 7364221474Snp 7365237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 7366237263Snp if (wr == NULL) 7367221474Snp return (ENOMEM); 7368221474Snp 7369237263Snp fwr = wrtod(wr); 7370221474Snp bzero(fwr, sizeof (*fwr)); 7371221474Snp 7372221474Snp fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR)); 7373221474Snp fwr->len16_pkd = htobe32(FW_LEN16(*fwr)); 7374221474Snp fwr->tid_to_iq = 7375221474Snp htobe32(V_FW_FILTER_WR_TID(ftid) | 7376221474Snp V_FW_FILTER_WR_RQTYPE(f->fs.type) | 7377221474Snp V_FW_FILTER_WR_NOREPLY(0) | 7378221474Snp V_FW_FILTER_WR_IQ(f->fs.iq)); 7379221474Snp fwr->del_filter_to_l2tix = 7380221474Snp htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) | 7381221474Snp V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) | 7382221474Snp V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) | 7383221474Snp V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) | 7384221474Snp V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) | 7385221474Snp V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) | 7386221474Snp V_FW_FILTER_WR_DMAC(f->fs.newdmac) | 7387221474Snp V_FW_FILTER_WR_SMAC(f->fs.newsmac) | 7388221474Snp V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT || 7389221474Snp f->fs.newvlan == VLAN_REWRITE) | 7390221474Snp V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE || 7391221474Snp f->fs.newvlan == VLAN_REWRITE) | 7392221474Snp V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) | 7393221474Snp V_FW_FILTER_WR_TXCHAN(f->fs.eport) | 7394221474Snp V_FW_FILTER_WR_PRIO(f->fs.prio) | 7395222509Snp V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0)); 7396221474Snp fwr->ethtype = htobe16(f->fs.val.ethtype); 7397221474Snp fwr->ethtypem = htobe16(f->fs.mask.ethtype); 7398221474Snp fwr->frag_to_ovlan_vldm = 7399221474Snp (V_FW_FILTER_WR_FRAG(f->fs.val.frag) | 7400221474Snp V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) | 7401228561Snp V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) | 7402228561Snp V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.vnic_vld) | 7403228561Snp V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) | 7404228561Snp V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.vnic_vld)); 7405221474Snp fwr->smac_sel = 0; 7406221474Snp fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) | 7407228561Snp V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id)); 7408221474Snp fwr->maci_to_matchtypem = 7409221474Snp htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) | 7410221474Snp V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) | 7411221474Snp V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) | 7412221474Snp V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) | 7413221474Snp V_FW_FILTER_WR_PORT(f->fs.val.iport) | 7414221474Snp V_FW_FILTER_WR_PORTM(f->fs.mask.iport) | 7415221474Snp V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) | 7416221474Snp V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype)); 7417221474Snp fwr->ptcl = f->fs.val.proto; 7418221474Snp fwr->ptclm = f->fs.mask.proto; 7419221474Snp fwr->ttyp = f->fs.val.tos; 7420221474Snp fwr->ttypm = f->fs.mask.tos; 7421228561Snp fwr->ivlan = htobe16(f->fs.val.vlan); 7422228561Snp fwr->ivlanm = htobe16(f->fs.mask.vlan); 7423228561Snp fwr->ovlan = htobe16(f->fs.val.vnic); 7424228561Snp fwr->ovlanm = htobe16(f->fs.mask.vnic); 7425221474Snp bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip)); 7426221474Snp bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm)); 7427221474Snp bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip)); 7428221474Snp bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm)); 7429221474Snp fwr->lp = htobe16(f->fs.val.dport); 7430221474Snp fwr->lpm = htobe16(f->fs.mask.dport); 7431221474Snp fwr->fp = htobe16(f->fs.val.sport); 7432221474Snp fwr->fpm = htobe16(f->fs.mask.sport); 7433221474Snp if (f->fs.newsmac) 7434221474Snp bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma)); 7435221474Snp 7436221474Snp f->pending = 1; 7437221474Snp sc->tids.ftids_in_use++; 7438228561Snp 7439237263Snp t4_wrq_tx(sc, wr); 7440228561Snp return (0); 7441221474Snp} 7442221474Snp 7443221474Snpstatic int 7444221474Snpdel_filter_wr(struct adapter *sc, int fidx) 7445221474Snp{ 7446221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 7447237263Snp struct wrqe *wr; 7448221474Snp struct fw_filter_wr *fwr; 7449228561Snp unsigned int ftid; 7450221474Snp 7451221474Snp ftid = sc->tids.ftid_base + fidx; 7452221474Snp 7453237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 7454237263Snp if (wr == NULL) 7455221474Snp return (ENOMEM); 7456237263Snp fwr = wrtod(wr); 7457221474Snp bzero(fwr, sizeof (*fwr)); 7458221474Snp 7459228561Snp t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id); 7460221474Snp 7461221474Snp f->pending = 1; 7462237263Snp t4_wrq_tx(sc, wr); 7463228561Snp return (0); 7464221474Snp} 7465221474Snp 7466239338Snpint 7467239338Snpt4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 7468221474Snp{ 7469228561Snp struct adapter *sc = iq->adapter; 7470228561Snp const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1); 7471221474Snp unsigned int idx = GET_TID(rpl); 7472265426Snp unsigned int rc; 7473265426Snp struct filter_entry *f; 7474221474Snp 7475228561Snp KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__, 7476228561Snp rss->opcode)); 7477228561Snp 7478265426Snp if (is_ftid(sc, idx)) { 7479221474Snp 7480265426Snp idx -= sc->tids.ftid_base; 7481265426Snp f = &sc->tids.ftid_tab[idx]; 7482265426Snp rc = G_COOKIE(rpl->cookie); 7483265426Snp 7484245274Snp mtx_lock(&sc->tids.ftid_lock); 7485228561Snp if (rc == FW_FILTER_WR_FLT_ADDED) { 7486245274Snp KASSERT(f->pending, ("%s: filter[%u] isn't pending.", 7487245274Snp __func__, idx)); 7488221474Snp f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff; 7489221474Snp f->pending = 0; /* asynchronous setup completed */ 7490221474Snp f->valid = 1; 7491231120Snp } else { 7492231120Snp if (rc != FW_FILTER_WR_FLT_DELETED) { 7493231120Snp /* Add or delete failed, display an error */ 7494231120Snp log(LOG_ERR, 7495231120Snp "filter %u setup failed with error %u\n", 7496231120Snp idx, rc); 7497231120Snp } 7498228561Snp 7499231120Snp clear_filter(f); 7500231120Snp sc->tids.ftids_in_use--; 7501221474Snp } 7502245274Snp wakeup(&sc->tids.ftid_tab); 7503245274Snp mtx_unlock(&sc->tids.ftid_lock); 7504221474Snp } 7505228561Snp 7506228561Snp return (0); 7507221474Snp} 7508221474Snp 7509222973Snpstatic int 7510222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt) 7511222973Snp{ 7512245274Snp int rc; 7513222973Snp 7514222973Snp if (cntxt->cid > M_CTXTQID) 7515245274Snp return (EINVAL); 7516222973Snp 7517222973Snp if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS && 7518222973Snp cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM) 7519245274Snp return (EINVAL); 7520222973Snp 7521246575Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ctxt"); 7522246575Snp if (rc) 7523246575Snp return (rc); 7524246575Snp 7525222973Snp if (sc->flags & FW_OK) { 7526246575Snp rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id, 7527246575Snp &cntxt->data[0]); 7528246575Snp if (rc == 0) 7529246575Snp goto done; 7530222973Snp } 7531222973Snp 7532245274Snp /* 7533245274Snp * Read via firmware failed or wasn't even attempted. Read directly via 7534245274Snp * the backdoor. 7535245274Snp */ 7536246575Snp rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id, &cntxt->data[0]); 7537246575Snpdone: 7538246575Snp end_synchronized_op(sc, 0); 7539245274Snp return (rc); 7540245274Snp} 7541222973Snp 7542245274Snpstatic int 7543245274Snpload_fw(struct adapter *sc, struct t4_data *fw) 7544245274Snp{ 7545245274Snp int rc; 7546245274Snp uint8_t *fw_data; 7547245274Snp 7548245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ldfw"); 7549245274Snp if (rc) 7550245274Snp return (rc); 7551245274Snp 7552245274Snp if (sc->flags & FULL_INIT_DONE) { 7553245274Snp rc = EBUSY; 7554245274Snp goto done; 7555222973Snp } 7556222973Snp 7557245274Snp fw_data = malloc(fw->len, M_CXGBE, M_WAITOK); 7558245274Snp if (fw_data == NULL) { 7559245274Snp rc = ENOMEM; 7560245274Snp goto done; 7561245274Snp } 7562245274Snp 7563245274Snp rc = copyin(fw->data, fw_data, fw->len); 7564245274Snp if (rc == 0) 7565245274Snp rc = -t4_load_fw(sc, fw_data, fw->len); 7566245274Snp 7567245274Snp free(fw_data, M_CXGBE); 7568245274Snpdone: 7569245274Snp end_synchronized_op(sc, 0); 7570222973Snp return (rc); 7571222973Snp} 7572222973Snp 7573228561Snpstatic int 7574248925Snpread_card_mem(struct adapter *sc, int win, struct t4_mem_range *mr) 7575228561Snp{ 7576248925Snp uint32_t addr, off, remaining, i, n; 7577228561Snp uint32_t *buf, *b; 7578248925Snp uint32_t mw_base, mw_aperture; 7579228561Snp int rc; 7580248925Snp uint8_t *dst; 7581228561Snp 7582248925Snp rc = validate_mem_range(sc, mr->addr, mr->len); 7583248925Snp if (rc != 0) 7584248925Snp return (rc); 7585228561Snp 7586248925Snp memwin_info(sc, win, &mw_base, &mw_aperture); 7587248925Snp buf = b = malloc(min(mr->len, mw_aperture), M_CXGBE, M_WAITOK); 7588248925Snp addr = mr->addr; 7589228561Snp remaining = mr->len; 7590248925Snp dst = (void *)mr->data; 7591228561Snp 7592228561Snp while (remaining) { 7593248925Snp off = position_memwin(sc, win, addr); 7594228561Snp 7595228561Snp /* number of bytes that we'll copy in the inner loop */ 7596248925Snp n = min(remaining, mw_aperture - off); 7597248925Snp for (i = 0; i < n; i += 4) 7598248925Snp *b++ = t4_read_reg(sc, mw_base + off + i); 7599228561Snp 7600248925Snp rc = copyout(buf, dst, n); 7601248925Snp if (rc != 0) 7602248925Snp break; 7603228561Snp 7604248925Snp b = buf; 7605248925Snp dst += n; 7606248925Snp remaining -= n; 7607248925Snp addr += n; 7608228561Snp } 7609228561Snp 7610228561Snp free(buf, M_CXGBE); 7611228561Snp return (rc); 7612228561Snp} 7613228561Snp 7614241399Snpstatic int 7615241399Snpread_i2c(struct adapter *sc, struct t4_i2c_data *i2cd) 7616241399Snp{ 7617241399Snp int rc; 7618241399Snp 7619241399Snp if (i2cd->len == 0 || i2cd->port_id >= sc->params.nports) 7620241399Snp return (EINVAL); 7621241399Snp 7622269082Snp if (i2cd->len > sizeof(i2cd->data)) 7623269082Snp return (EFBIG); 7624241399Snp 7625245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4i2crd"); 7626245274Snp if (rc) 7627245274Snp return (rc); 7628241399Snp rc = -t4_i2c_rd(sc, sc->mbox, i2cd->port_id, i2cd->dev_addr, 7629269082Snp i2cd->offset, i2cd->len, &i2cd->data[0]); 7630245274Snp end_synchronized_op(sc, 0); 7631241399Snp 7632241399Snp return (rc); 7633241399Snp} 7634241399Snp 7635259142Snpstatic int 7636259142Snpin_range(int val, int lo, int hi) 7637259142Snp{ 7638259142Snp 7639259142Snp return (val < 0 || (val <= hi && val >= lo)); 7640259142Snp} 7641259142Snp 7642259142Snpstatic int 7643259142Snpset_sched_class(struct adapter *sc, struct t4_sched_params *p) 7644259142Snp{ 7645259142Snp int fw_subcmd, fw_type, rc; 7646259142Snp 7647259142Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setsc"); 7648259142Snp if (rc) 7649259142Snp return (rc); 7650259142Snp 7651259142Snp if (!(sc->flags & FULL_INIT_DONE)) { 7652259142Snp rc = EAGAIN; 7653259142Snp goto done; 7654259142Snp } 7655259142Snp 7656259142Snp /* 7657259142Snp * Translate the cxgbetool parameters into T4 firmware parameters. (The 7658259142Snp * sub-command and type are in common locations.) 7659259142Snp */ 7660259142Snp if (p->subcmd == SCHED_CLASS_SUBCMD_CONFIG) 7661259142Snp fw_subcmd = FW_SCHED_SC_CONFIG; 7662259142Snp else if (p->subcmd == SCHED_CLASS_SUBCMD_PARAMS) 7663259142Snp fw_subcmd = FW_SCHED_SC_PARAMS; 7664259142Snp else { 7665259142Snp rc = EINVAL; 7666259142Snp goto done; 7667259142Snp } 7668259142Snp if (p->type == SCHED_CLASS_TYPE_PACKET) 7669259142Snp fw_type = FW_SCHED_TYPE_PKTSCHED; 7670259142Snp else { 7671259142Snp rc = EINVAL; 7672259142Snp goto done; 7673259142Snp } 7674259142Snp 7675259142Snp if (fw_subcmd == FW_SCHED_SC_CONFIG) { 7676259142Snp /* Vet our parameters ..*/ 7677259142Snp if (p->u.config.minmax < 0) { 7678259142Snp rc = EINVAL; 7679259142Snp goto done; 7680259142Snp } 7681259142Snp 7682259142Snp /* And pass the request to the firmware ...*/ 7683270297Snp rc = -t4_sched_config(sc, fw_type, p->u.config.minmax, 1); 7684259142Snp goto done; 7685259142Snp } 7686259142Snp 7687259142Snp if (fw_subcmd == FW_SCHED_SC_PARAMS) { 7688259142Snp int fw_level; 7689259142Snp int fw_mode; 7690259142Snp int fw_rateunit; 7691259142Snp int fw_ratemode; 7692259142Snp 7693259142Snp if (p->u.params.level == SCHED_CLASS_LEVEL_CL_RL) 7694259142Snp fw_level = FW_SCHED_PARAMS_LEVEL_CL_RL; 7695259142Snp else if (p->u.params.level == SCHED_CLASS_LEVEL_CL_WRR) 7696259142Snp fw_level = FW_SCHED_PARAMS_LEVEL_CL_WRR; 7697259142Snp else if (p->u.params.level == SCHED_CLASS_LEVEL_CH_RL) 7698259142Snp fw_level = FW_SCHED_PARAMS_LEVEL_CH_RL; 7699259142Snp else { 7700259142Snp rc = EINVAL; 7701259142Snp goto done; 7702259142Snp } 7703259142Snp 7704259142Snp if (p->u.params.mode == SCHED_CLASS_MODE_CLASS) 7705259142Snp fw_mode = FW_SCHED_PARAMS_MODE_CLASS; 7706259142Snp else if (p->u.params.mode == SCHED_CLASS_MODE_FLOW) 7707259142Snp fw_mode = FW_SCHED_PARAMS_MODE_FLOW; 7708259142Snp else { 7709259142Snp rc = EINVAL; 7710259142Snp goto done; 7711259142Snp } 7712259142Snp 7713259142Snp if (p->u.params.rateunit == SCHED_CLASS_RATEUNIT_BITS) 7714259142Snp fw_rateunit = FW_SCHED_PARAMS_UNIT_BITRATE; 7715259142Snp else if (p->u.params.rateunit == SCHED_CLASS_RATEUNIT_PKTS) 7716259142Snp fw_rateunit = FW_SCHED_PARAMS_UNIT_PKTRATE; 7717259142Snp else { 7718259142Snp rc = EINVAL; 7719259142Snp goto done; 7720259142Snp } 7721259142Snp 7722259142Snp if (p->u.params.ratemode == SCHED_CLASS_RATEMODE_REL) 7723259142Snp fw_ratemode = FW_SCHED_PARAMS_RATE_REL; 7724259142Snp else if (p->u.params.ratemode == SCHED_CLASS_RATEMODE_ABS) 7725259142Snp fw_ratemode = FW_SCHED_PARAMS_RATE_ABS; 7726259142Snp else { 7727259142Snp rc = EINVAL; 7728259142Snp goto done; 7729259142Snp } 7730259142Snp 7731259142Snp /* Vet our parameters ... */ 7732259142Snp if (!in_range(p->u.params.channel, 0, 3) || 7733259142Snp !in_range(p->u.params.cl, 0, is_t4(sc) ? 15 : 16) || 7734259142Snp !in_range(p->u.params.minrate, 0, 10000000) || 7735259142Snp !in_range(p->u.params.maxrate, 0, 10000000) || 7736259142Snp !in_range(p->u.params.weight, 0, 100)) { 7737259142Snp rc = ERANGE; 7738259142Snp goto done; 7739259142Snp } 7740259142Snp 7741259142Snp /* 7742259142Snp * Translate any unset parameters into the firmware's 7743259142Snp * nomenclature and/or fail the call if the parameters 7744259142Snp * are required ... 7745259142Snp */ 7746259142Snp if (p->u.params.rateunit < 0 || p->u.params.ratemode < 0 || 7747259142Snp p->u.params.channel < 0 || p->u.params.cl < 0) { 7748259142Snp rc = EINVAL; 7749259142Snp goto done; 7750259142Snp } 7751259142Snp if (p->u.params.minrate < 0) 7752259142Snp p->u.params.minrate = 0; 7753259142Snp if (p->u.params.maxrate < 0) { 7754259142Snp if (p->u.params.level == SCHED_CLASS_LEVEL_CL_RL || 7755259142Snp p->u.params.level == SCHED_CLASS_LEVEL_CH_RL) { 7756259142Snp rc = EINVAL; 7757259142Snp goto done; 7758259142Snp } else 7759259142Snp p->u.params.maxrate = 0; 7760259142Snp } 7761259142Snp if (p->u.params.weight < 0) { 7762259142Snp if (p->u.params.level == SCHED_CLASS_LEVEL_CL_WRR) { 7763259142Snp rc = EINVAL; 7764259142Snp goto done; 7765259142Snp } else 7766259142Snp p->u.params.weight = 0; 7767259142Snp } 7768259142Snp if (p->u.params.pktsize < 0) { 7769259142Snp if (p->u.params.level == SCHED_CLASS_LEVEL_CL_RL || 7770259142Snp p->u.params.level == SCHED_CLASS_LEVEL_CH_RL) { 7771259142Snp rc = EINVAL; 7772259142Snp goto done; 7773259142Snp } else 7774259142Snp p->u.params.pktsize = 0; 7775259142Snp } 7776259142Snp 7777259142Snp /* See what the firmware thinks of the request ... */ 7778259142Snp rc = -t4_sched_params(sc, fw_type, fw_level, fw_mode, 7779259142Snp fw_rateunit, fw_ratemode, p->u.params.channel, 7780259142Snp p->u.params.cl, p->u.params.minrate, p->u.params.maxrate, 7781270297Snp p->u.params.weight, p->u.params.pktsize, 1); 7782259142Snp goto done; 7783259142Snp } 7784259142Snp 7785259142Snp rc = EINVAL; 7786259142Snpdone: 7787259142Snp end_synchronized_op(sc, 0); 7788259142Snp return (rc); 7789259142Snp} 7790259142Snp 7791259142Snpstatic int 7792259142Snpset_sched_queue(struct adapter *sc, struct t4_sched_queue *p) 7793259142Snp{ 7794259142Snp struct port_info *pi = NULL; 7795259142Snp struct sge_txq *txq; 7796259142Snp uint32_t fw_mnem, fw_queue, fw_class; 7797259142Snp int i, rc; 7798259142Snp 7799259142Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setsq"); 7800259142Snp if (rc) 7801259142Snp return (rc); 7802259142Snp 7803259142Snp if (!(sc->flags & FULL_INIT_DONE)) { 7804259142Snp rc = EAGAIN; 7805259142Snp goto done; 7806259142Snp } 7807259142Snp 7808259142Snp if (p->port >= sc->params.nports) { 7809259142Snp rc = EINVAL; 7810259142Snp goto done; 7811259142Snp } 7812259142Snp 7813259142Snp pi = sc->port[p->port]; 7814259142Snp if (!in_range(p->queue, 0, pi->ntxq - 1) || !in_range(p->cl, 0, 7)) { 7815259142Snp rc = EINVAL; 7816259142Snp goto done; 7817259142Snp } 7818259142Snp 7819259142Snp /* 7820259142Snp * Create a template for the FW_PARAMS_CMD mnemonic and value (TX 7821259142Snp * Scheduling Class in this case). 7822259142Snp */ 7823259142Snp fw_mnem = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) | 7824259142Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH)); 7825259142Snp fw_class = p->cl < 0 ? 0xffffffff : p->cl; 7826259142Snp 7827259142Snp /* 7828259142Snp * If op.queue is non-negative, then we're only changing the scheduling 7829259142Snp * on a single specified TX queue. 7830259142Snp */ 7831259142Snp if (p->queue >= 0) { 7832259142Snp txq = &sc->sge.txq[pi->first_txq + p->queue]; 7833259142Snp fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id)); 7834259142Snp rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue, 7835259142Snp &fw_class); 7836259142Snp goto done; 7837259142Snp } 7838259142Snp 7839259142Snp /* 7840259142Snp * Change the scheduling on all the TX queues for the 7841259142Snp * interface. 7842259142Snp */ 7843259142Snp for_each_txq(pi, i, txq) { 7844259142Snp fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id)); 7845259142Snp rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue, 7846259142Snp &fw_class); 7847259142Snp if (rc) 7848259142Snp goto done; 7849259142Snp } 7850259142Snp 7851259142Snp rc = 0; 7852259142Snpdone: 7853259142Snp end_synchronized_op(sc, 0); 7854259142Snp return (rc); 7855259142Snp} 7856259142Snp 7857218792Snpint 7858218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap) 7859218792Snp{ 7860222102Snp int i; 7861218792Snp 7862222102Snp return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0); 7863218792Snp} 7864218792Snp 7865218792Snpint 7866218792Snpt4_os_pci_save_state(struct adapter *sc) 7867218792Snp{ 7868218792Snp device_t dev; 7869218792Snp struct pci_devinfo *dinfo; 7870218792Snp 7871218792Snp dev = sc->dev; 7872218792Snp dinfo = device_get_ivars(dev); 7873218792Snp 7874218792Snp pci_cfg_save(dev, dinfo, 0); 7875218792Snp return (0); 7876218792Snp} 7877218792Snp 7878218792Snpint 7879218792Snpt4_os_pci_restore_state(struct adapter *sc) 7880218792Snp{ 7881218792Snp device_t dev; 7882218792Snp struct pci_devinfo *dinfo; 7883218792Snp 7884218792Snp dev = sc->dev; 7885218792Snp dinfo = device_get_ivars(dev); 7886218792Snp 7887218792Snp pci_cfg_restore(dev, dinfo); 7888218792Snp return (0); 7889218792Snp} 7890219299Snp 7891218792Snpvoid 7892218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx) 7893218792Snp{ 7894218792Snp struct port_info *pi = sc->port[idx]; 7895218792Snp static const char *mod_str[] = { 7896220232Snp NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM" 7897218792Snp }; 7898218792Snp 7899218792Snp if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 7900218792Snp if_printf(pi->ifp, "transceiver unplugged.\n"); 7901220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) 7902220232Snp if_printf(pi->ifp, "unknown transceiver inserted.\n"); 7903220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) 7904220232Snp if_printf(pi->ifp, "unsupported transceiver inserted.\n"); 7905240452Snp else if (pi->mod_type > 0 && pi->mod_type < nitems(mod_str)) { 7906218792Snp if_printf(pi->ifp, "%s transceiver inserted.\n", 7907218792Snp mod_str[pi->mod_type]); 7908219299Snp } else { 7909219299Snp if_printf(pi->ifp, "transceiver (type %d) inserted.\n", 7910219299Snp pi->mod_type); 7911219299Snp } 7912218792Snp} 7913218792Snp 7914218792Snpvoid 7915252747Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat, int reason) 7916218792Snp{ 7917218792Snp struct port_info *pi = sc->port[idx]; 7918218792Snp struct ifnet *ifp = pi->ifp; 7919218792Snp 7920218792Snp if (link_stat) { 7921252747Snp pi->linkdnrc = -1; 7922218792Snp ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed); 7923218792Snp if_link_state_change(ifp, LINK_STATE_UP); 7924252747Snp } else { 7925252747Snp if (reason >= 0) 7926252747Snp pi->linkdnrc = reason; 7927218792Snp if_link_state_change(ifp, LINK_STATE_DOWN); 7928252747Snp } 7929218792Snp} 7930218792Snp 7931228561Snpvoid 7932228561Snpt4_iterate(void (*func)(struct adapter *, void *), void *arg) 7933228561Snp{ 7934228561Snp struct adapter *sc; 7935228561Snp 7936255006Snp sx_slock(&t4_list_lock); 7937228561Snp SLIST_FOREACH(sc, &t4_list, link) { 7938228561Snp /* 7939228561Snp * func should not make any assumptions about what state sc is 7940228561Snp * in - the only guarantee is that sc->sc_lock is a valid lock. 7941228561Snp */ 7942228561Snp func(sc, arg); 7943228561Snp } 7944255006Snp sx_sunlock(&t4_list_lock); 7945228561Snp} 7946228561Snp 7947218792Snpstatic int 7948218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td) 7949218792Snp{ 7950218792Snp return (0); 7951218792Snp} 7952218792Snp 7953218792Snpstatic int 7954218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td) 7955218792Snp{ 7956218792Snp return (0); 7957218792Snp} 7958218792Snp 7959218792Snpstatic int 7960218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag, 7961218792Snp struct thread *td) 7962218792Snp{ 7963218792Snp int rc; 7964218792Snp struct adapter *sc = dev->si_drv1; 7965218792Snp 7966218792Snp rc = priv_check(td, PRIV_DRIVER); 7967218792Snp if (rc != 0) 7968218792Snp return (rc); 7969218792Snp 7970218792Snp switch (cmd) { 7971220410Snp case CHELSIO_T4_GETREG: { 7972220410Snp struct t4_reg *edata = (struct t4_reg *)data; 7973220410Snp 7974218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 7975218792Snp return (EFAULT); 7976220410Snp 7977220410Snp if (edata->size == 4) 7978220410Snp edata->val = t4_read_reg(sc, edata->addr); 7979220410Snp else if (edata->size == 8) 7980220410Snp edata->val = t4_read_reg64(sc, edata->addr); 7981220410Snp else 7982220410Snp return (EINVAL); 7983220410Snp 7984218792Snp break; 7985218792Snp } 7986220410Snp case CHELSIO_T4_SETREG: { 7987220410Snp struct t4_reg *edata = (struct t4_reg *)data; 7988220410Snp 7989218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 7990218792Snp return (EFAULT); 7991220410Snp 7992220410Snp if (edata->size == 4) { 7993220410Snp if (edata->val & 0xffffffff00000000) 7994220410Snp return (EINVAL); 7995220410Snp t4_write_reg(sc, edata->addr, (uint32_t) edata->val); 7996220410Snp } else if (edata->size == 8) 7997220410Snp t4_write_reg64(sc, edata->addr, edata->val); 7998220410Snp else 7999220410Snp return (EINVAL); 8000218792Snp break; 8001218792Snp } 8002218792Snp case CHELSIO_T4_REGDUMP: { 8003218792Snp struct t4_regdump *regs = (struct t4_regdump *)data; 8004248925Snp int reglen = is_t4(sc) ? T4_REGDUMP_SIZE : T5_REGDUMP_SIZE; 8005218792Snp uint8_t *buf; 8006218792Snp 8007218792Snp if (regs->len < reglen) { 8008218792Snp regs->len = reglen; /* hint to the caller */ 8009218792Snp return (ENOBUFS); 8010218792Snp } 8011218792Snp 8012218792Snp regs->len = reglen; 8013218792Snp buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO); 8014218792Snp t4_get_regs(sc, regs, buf); 8015218792Snp rc = copyout(buf, regs->data, reglen); 8016218792Snp free(buf, M_CXGBE); 8017218792Snp break; 8018218792Snp } 8019221474Snp case CHELSIO_T4_GET_FILTER_MODE: 8020221474Snp rc = get_filter_mode(sc, (uint32_t *)data); 8021221474Snp break; 8022221474Snp case CHELSIO_T4_SET_FILTER_MODE: 8023221474Snp rc = set_filter_mode(sc, *(uint32_t *)data); 8024221474Snp break; 8025221474Snp case CHELSIO_T4_GET_FILTER: 8026221474Snp rc = get_filter(sc, (struct t4_filter *)data); 8027221474Snp break; 8028221474Snp case CHELSIO_T4_SET_FILTER: 8029221474Snp rc = set_filter(sc, (struct t4_filter *)data); 8030221474Snp break; 8031221474Snp case CHELSIO_T4_DEL_FILTER: 8032221474Snp rc = del_filter(sc, (struct t4_filter *)data); 8033221474Snp break; 8034222973Snp case CHELSIO_T4_GET_SGE_CONTEXT: 8035222973Snp rc = get_sge_context(sc, (struct t4_sge_context *)data); 8036222973Snp break; 8037245274Snp case CHELSIO_T4_LOAD_FW: 8038245274Snp rc = load_fw(sc, (struct t4_data *)data); 8039228561Snp break; 8040228561Snp case CHELSIO_T4_GET_MEM: 8041248925Snp rc = read_card_mem(sc, 2, (struct t4_mem_range *)data); 8042228561Snp break; 8043241399Snp case CHELSIO_T4_GET_I2C: 8044241399Snp rc = read_i2c(sc, (struct t4_i2c_data *)data); 8045241399Snp break; 8046241409Snp case CHELSIO_T4_CLEAR_STATS: { 8047245518Snp int i; 8048241409Snp u_int port_id = *(uint32_t *)data; 8049245518Snp struct port_info *pi; 8050241409Snp 8051241409Snp if (port_id >= sc->params.nports) 8052241409Snp return (EINVAL); 8053265410Snp pi = sc->port[port_id]; 8054241409Snp 8055245518Snp /* MAC stats */ 8056265410Snp t4_clr_port_stats(sc, pi->tx_chan); 8057245518Snp 8058245518Snp if (pi->flags & PORT_INIT_DONE) { 8059245518Snp struct sge_rxq *rxq; 8060245518Snp struct sge_txq *txq; 8061245518Snp struct sge_wrq *wrq; 8062245518Snp 8063245518Snp for_each_rxq(pi, i, rxq) { 8064245518Snp#if defined(INET) || defined(INET6) 8065245518Snp rxq->lro.lro_queued = 0; 8066245518Snp rxq->lro.lro_flushed = 0; 8067245518Snp#endif 8068245518Snp rxq->rxcsum = 0; 8069245518Snp rxq->vlan_extraction = 0; 8070245518Snp } 8071245518Snp 8072245518Snp for_each_txq(pi, i, txq) { 8073245518Snp txq->txcsum = 0; 8074245518Snp txq->tso_wrs = 0; 8075245518Snp txq->vlan_insertion = 0; 8076245518Snp txq->imm_wrs = 0; 8077245518Snp txq->sgl_wrs = 0; 8078245518Snp txq->txpkt_wrs = 0; 8079245518Snp txq->txpkts_wrs = 0; 8080245518Snp txq->txpkts_pkts = 0; 8081246093Snp txq->br->br_drops = 0; 8082245518Snp txq->no_dmamap = 0; 8083245518Snp txq->no_desc = 0; 8084245518Snp } 8085245518Snp 8086245518Snp#ifdef TCP_OFFLOAD 8087245518Snp /* nothing to clear for each ofld_rxq */ 8088245518Snp 8089245518Snp for_each_ofld_txq(pi, i, wrq) { 8090245518Snp wrq->tx_wrs = 0; 8091245518Snp wrq->no_desc = 0; 8092245518Snp } 8093245518Snp#endif 8094245518Snp wrq = &sc->sge.ctrlq[pi->port_id]; 8095245518Snp wrq->tx_wrs = 0; 8096245518Snp wrq->no_desc = 0; 8097245518Snp } 8098241409Snp break; 8099241409Snp } 8100259142Snp case CHELSIO_T4_SCHED_CLASS: 8101259142Snp rc = set_sched_class(sc, (struct t4_sched_params *)data); 8102259142Snp break; 8103259142Snp case CHELSIO_T4_SCHED_QUEUE: 8104259142Snp rc = set_sched_queue(sc, (struct t4_sched_queue *)data); 8105259142Snp break; 8106253691Snp case CHELSIO_T4_GET_TRACER: 8107253691Snp rc = t4_get_tracer(sc, (struct t4_tracer *)data); 8108253691Snp break; 8109253691Snp case CHELSIO_T4_SET_TRACER: 8110253691Snp rc = t4_set_tracer(sc, (struct t4_tracer *)data); 8111253691Snp break; 8112218792Snp default: 8113218792Snp rc = EINVAL; 8114218792Snp } 8115218792Snp 8116218792Snp return (rc); 8117218792Snp} 8118218792Snp 8119237263Snp#ifdef TCP_OFFLOAD 8120270297Snpvoid 8121270297Snpt4_iscsi_init(struct ifnet *ifp, unsigned int tag_mask, 8122270297Snp const unsigned int *pgsz_order) 8123270297Snp{ 8124270297Snp struct port_info *pi = ifp->if_softc; 8125270297Snp struct adapter *sc = pi->adapter; 8126270297Snp 8127270297Snp t4_write_reg(sc, A_ULP_RX_ISCSI_TAGMASK, tag_mask); 8128270297Snp t4_write_reg(sc, A_ULP_RX_ISCSI_PSZ, V_HPZ0(pgsz_order[0]) | 8129270297Snp V_HPZ1(pgsz_order[1]) | V_HPZ2(pgsz_order[2]) | 8130270297Snp V_HPZ3(pgsz_order[3])); 8131270297Snp} 8132270297Snp 8133219392Snpstatic int 8134228561Snptoe_capability(struct port_info *pi, int enable) 8135228561Snp{ 8136228561Snp int rc; 8137228561Snp struct adapter *sc = pi->adapter; 8138228561Snp 8139245274Snp ASSERT_SYNCHRONIZED_OP(sc); 8140228561Snp 8141228561Snp if (!is_offload(sc)) 8142228561Snp return (ENODEV); 8143228561Snp 8144228561Snp if (enable) { 8145237263Snp if (!(sc->flags & FULL_INIT_DONE)) { 8146245274Snp rc = cxgbe_init_synchronized(pi); 8147245274Snp if (rc) 8148245274Snp return (rc); 8149237263Snp } 8150237263Snp 8151228561Snp if (isset(&sc->offload_map, pi->port_id)) 8152228561Snp return (0); 8153228561Snp 8154237263Snp if (!(sc->flags & TOM_INIT_DONE)) { 8155237263Snp rc = t4_activate_uld(sc, ULD_TOM); 8156237263Snp if (rc == EAGAIN) { 8157237263Snp log(LOG_WARNING, 8158237263Snp "You must kldload t4_tom.ko before trying " 8159237263Snp "to enable TOE on a cxgbe interface.\n"); 8160237263Snp } 8161228561Snp if (rc != 0) 8162228561Snp return (rc); 8163237263Snp KASSERT(sc->tom_softc != NULL, 8164237263Snp ("%s: TOM activated but softc NULL", __func__)); 8165237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 8166237263Snp ("%s: TOM activated but flag not set", __func__)); 8167228561Snp } 8168228561Snp 8169228561Snp setbit(&sc->offload_map, pi->port_id); 8170228561Snp } else { 8171228561Snp if (!isset(&sc->offload_map, pi->port_id)) 8172228561Snp return (0); 8173228561Snp 8174237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 8175237263Snp ("%s: TOM never initialized?", __func__)); 8176228561Snp clrbit(&sc->offload_map, pi->port_id); 8177228561Snp } 8178228561Snp 8179228561Snp return (0); 8180228561Snp} 8181228561Snp 8182228561Snp/* 8183228561Snp * Add an upper layer driver to the global list. 8184228561Snp */ 8185228561Snpint 8186228561Snpt4_register_uld(struct uld_info *ui) 8187228561Snp{ 8188228561Snp int rc = 0; 8189228561Snp struct uld_info *u; 8190228561Snp 8191255006Snp sx_xlock(&t4_uld_list_lock); 8192228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 8193228561Snp if (u->uld_id == ui->uld_id) { 8194228561Snp rc = EEXIST; 8195228561Snp goto done; 8196228561Snp } 8197228561Snp } 8198228561Snp 8199228561Snp SLIST_INSERT_HEAD(&t4_uld_list, ui, link); 8200228561Snp ui->refcount = 0; 8201228561Snpdone: 8202255006Snp sx_xunlock(&t4_uld_list_lock); 8203228561Snp return (rc); 8204228561Snp} 8205228561Snp 8206228561Snpint 8207228561Snpt4_unregister_uld(struct uld_info *ui) 8208228561Snp{ 8209228561Snp int rc = EINVAL; 8210228561Snp struct uld_info *u; 8211228561Snp 8212255006Snp sx_xlock(&t4_uld_list_lock); 8213228561Snp 8214228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 8215228561Snp if (u == ui) { 8216228561Snp if (ui->refcount > 0) { 8217228561Snp rc = EBUSY; 8218228561Snp goto done; 8219228561Snp } 8220228561Snp 8221228561Snp SLIST_REMOVE(&t4_uld_list, ui, uld_info, link); 8222228561Snp rc = 0; 8223228561Snp goto done; 8224228561Snp } 8225228561Snp } 8226228561Snpdone: 8227255006Snp sx_xunlock(&t4_uld_list_lock); 8228228561Snp return (rc); 8229228561Snp} 8230228561Snp 8231237263Snpint 8232237263Snpt4_activate_uld(struct adapter *sc, int id) 8233228561Snp{ 8234228561Snp int rc = EAGAIN; 8235228561Snp struct uld_info *ui; 8236228561Snp 8237245274Snp ASSERT_SYNCHRONIZED_OP(sc); 8238245274Snp 8239255006Snp sx_slock(&t4_uld_list_lock); 8240228561Snp 8241228561Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 8242228561Snp if (ui->uld_id == id) { 8243237263Snp rc = ui->activate(sc); 8244237263Snp if (rc == 0) 8245228561Snp ui->refcount++; 8246228561Snp goto done; 8247228561Snp } 8248228561Snp } 8249228561Snpdone: 8250255006Snp sx_sunlock(&t4_uld_list_lock); 8251228561Snp 8252228561Snp return (rc); 8253228561Snp} 8254228561Snp 8255237263Snpint 8256237263Snpt4_deactivate_uld(struct adapter *sc, int id) 8257228561Snp{ 8258237263Snp int rc = EINVAL; 8259237263Snp struct uld_info *ui; 8260228561Snp 8261245274Snp ASSERT_SYNCHRONIZED_OP(sc); 8262245274Snp 8263255006Snp sx_slock(&t4_uld_list_lock); 8264228561Snp 8265237263Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 8266237263Snp if (ui->uld_id == id) { 8267237263Snp rc = ui->deactivate(sc); 8268237263Snp if (rc == 0) 8269237263Snp ui->refcount--; 8270237263Snp goto done; 8271237263Snp } 8272228561Snp } 8273228561Snpdone: 8274255006Snp sx_sunlock(&t4_uld_list_lock); 8275228561Snp 8276228561Snp return (rc); 8277228561Snp} 8278228561Snp#endif 8279228561Snp 8280228561Snp/* 8281228561Snp * Come up with reasonable defaults for some of the tunables, provided they're 8282228561Snp * not set by the user (in which case we'll use the values as is). 8283228561Snp */ 8284228561Snpstatic void 8285228561Snptweak_tunables(void) 8286228561Snp{ 8287228561Snp int nc = mp_ncpus; /* our snapshot of the number of CPUs */ 8288228561Snp 8289228561Snp if (t4_ntxq10g < 1) 8290228561Snp t4_ntxq10g = min(nc, NTXQ_10G); 8291228561Snp 8292228561Snp if (t4_ntxq1g < 1) 8293228561Snp t4_ntxq1g = min(nc, NTXQ_1G); 8294228561Snp 8295228561Snp if (t4_nrxq10g < 1) 8296228561Snp t4_nrxq10g = min(nc, NRXQ_10G); 8297228561Snp 8298228561Snp if (t4_nrxq1g < 1) 8299228561Snp t4_nrxq1g = min(nc, NRXQ_1G); 8300228561Snp 8301237263Snp#ifdef TCP_OFFLOAD 8302228561Snp if (t4_nofldtxq10g < 1) 8303228561Snp t4_nofldtxq10g = min(nc, NOFLDTXQ_10G); 8304228561Snp 8305228561Snp if (t4_nofldtxq1g < 1) 8306228561Snp t4_nofldtxq1g = min(nc, NOFLDTXQ_1G); 8307228561Snp 8308228561Snp if (t4_nofldrxq10g < 1) 8309228561Snp t4_nofldrxq10g = min(nc, NOFLDRXQ_10G); 8310228561Snp 8311228561Snp if (t4_nofldrxq1g < 1) 8312228561Snp t4_nofldrxq1g = min(nc, NOFLDRXQ_1G); 8313238028Snp 8314238028Snp if (t4_toecaps_allowed == -1) 8315238028Snp t4_toecaps_allowed = FW_CAPS_CONFIG_TOE; 8316238028Snp#else 8317238028Snp if (t4_toecaps_allowed == -1) 8318238028Snp t4_toecaps_allowed = 0; 8319228561Snp#endif 8320228561Snp 8321270297Snp#ifdef DEV_NETMAP 8322270297Snp if (t4_nnmtxq10g < 1) 8323270297Snp t4_nnmtxq10g = min(nc, NNMTXQ_10G); 8324270297Snp 8325270297Snp if (t4_nnmtxq1g < 1) 8326270297Snp t4_nnmtxq1g = min(nc, NNMTXQ_1G); 8327270297Snp 8328270297Snp if (t4_nnmrxq10g < 1) 8329270297Snp t4_nnmrxq10g = min(nc, NNMRXQ_10G); 8330270297Snp 8331270297Snp if (t4_nnmrxq1g < 1) 8332270297Snp t4_nnmrxq1g = min(nc, NNMRXQ_1G); 8333270297Snp#endif 8334270297Snp 8335228561Snp if (t4_tmr_idx_10g < 0 || t4_tmr_idx_10g >= SGE_NTIMERS) 8336228561Snp t4_tmr_idx_10g = TMR_IDX_10G; 8337228561Snp 8338228561Snp if (t4_pktc_idx_10g < -1 || t4_pktc_idx_10g >= SGE_NCOUNTERS) 8339228561Snp t4_pktc_idx_10g = PKTC_IDX_10G; 8340228561Snp 8341228561Snp if (t4_tmr_idx_1g < 0 || t4_tmr_idx_1g >= SGE_NTIMERS) 8342228561Snp t4_tmr_idx_1g = TMR_IDX_1G; 8343228561Snp 8344228561Snp if (t4_pktc_idx_1g < -1 || t4_pktc_idx_1g >= SGE_NCOUNTERS) 8345228561Snp t4_pktc_idx_1g = PKTC_IDX_1G; 8346228561Snp 8347228561Snp if (t4_qsize_txq < 128) 8348228561Snp t4_qsize_txq = 128; 8349228561Snp 8350228561Snp if (t4_qsize_rxq < 128) 8351228561Snp t4_qsize_rxq = 128; 8352228561Snp while (t4_qsize_rxq & 7) 8353228561Snp t4_qsize_rxq++; 8354228561Snp 8355228561Snp t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX; 8356228561Snp} 8357228561Snp 8358269356Snpstatic struct sx mlu; /* mod load unload */ 8359269356SnpSX_SYSINIT(cxgbe_mlu, &mlu, "cxgbe mod load/unload"); 8360269356Snp 8361228561Snpstatic int 8362249370Snpmod_event(module_t mod, int cmd, void *arg) 8363219392Snp{ 8364228561Snp int rc = 0; 8365249370Snp static int loaded = 0; 8366219392Snp 8367228561Snp switch (cmd) { 8368228561Snp case MOD_LOAD: 8369269356Snp sx_xlock(&mlu); 8370269356Snp if (loaded++ == 0) { 8371269356Snp t4_sge_modload(); 8372269356Snp sx_init(&t4_list_lock, "T4/T5 adapters"); 8373269356Snp SLIST_INIT(&t4_list); 8374237263Snp#ifdef TCP_OFFLOAD 8375269356Snp sx_init(&t4_uld_list_lock, "T4/T5 ULDs"); 8376269356Snp SLIST_INIT(&t4_uld_list); 8377228561Snp#endif 8378269356Snp t4_tracer_modload(); 8379269356Snp tweak_tunables(); 8380269356Snp } 8381269356Snp sx_xunlock(&mlu); 8382228561Snp break; 8383219392Snp 8384228561Snp case MOD_UNLOAD: 8385269356Snp sx_xlock(&mlu); 8386269356Snp if (--loaded == 0) { 8387269356Snp int tries; 8388269356Snp 8389269356Snp sx_slock(&t4_list_lock); 8390269356Snp if (!SLIST_EMPTY(&t4_list)) { 8391269356Snp rc = EBUSY; 8392269356Snp sx_sunlock(&t4_list_lock); 8393269356Snp goto done_unload; 8394269356Snp } 8395237263Snp#ifdef TCP_OFFLOAD 8396269356Snp sx_slock(&t4_uld_list_lock); 8397269356Snp if (!SLIST_EMPTY(&t4_uld_list)) { 8398269356Snp rc = EBUSY; 8399269356Snp sx_sunlock(&t4_uld_list_lock); 8400269356Snp sx_sunlock(&t4_list_lock); 8401269356Snp goto done_unload; 8402269356Snp } 8403269356Snp#endif 8404269356Snp tries = 0; 8405269356Snp while (tries++ < 5 && t4_sge_extfree_refs() != 0) { 8406269356Snp uprintf("%ju clusters with custom free routine " 8407269356Snp "still is use.\n", t4_sge_extfree_refs()); 8408269356Snp pause("t4unload", 2 * hz); 8409269356Snp } 8410269356Snp#ifdef TCP_OFFLOAD 8411255006Snp sx_sunlock(&t4_uld_list_lock); 8412228561Snp#endif 8413255006Snp sx_sunlock(&t4_list_lock); 8414269356Snp 8415269356Snp if (t4_sge_extfree_refs() == 0) { 8416269356Snp t4_tracer_modunload(); 8417269356Snp#ifdef TCP_OFFLOAD 8418269356Snp sx_destroy(&t4_uld_list_lock); 8419269356Snp#endif 8420269356Snp sx_destroy(&t4_list_lock); 8421269356Snp t4_sge_modunload(); 8422269356Snp loaded = 0; 8423269356Snp } else { 8424269356Snp rc = EBUSY; 8425269356Snp loaded++; /* undo earlier decrement */ 8426269356Snp } 8427228561Snp } 8428269356Snpdone_unload: 8429269356Snp sx_xunlock(&mlu); 8430228561Snp break; 8431228561Snp } 8432228561Snp 8433228561Snp return (rc); 8434219392Snp} 8435219392Snp 8436248925Snpstatic devclass_t t4_devclass, t5_devclass; 8437248925Snpstatic devclass_t cxgbe_devclass, cxl_devclass; 8438218792Snp 8439249370SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, mod_event, 0); 8440218792SnpMODULE_VERSION(t4nex, 1); 8441250697SkibMODULE_DEPEND(t4nex, firmware, 1, 1, 1); 8442218792Snp 8443249370SnpDRIVER_MODULE(t5nex, pci, t5_driver, t5_devclass, mod_event, 0); 8444248925SnpMODULE_VERSION(t5nex, 1); 8445250697SkibMODULE_DEPEND(t5nex, firmware, 1, 1, 1); 8446248925Snp 8447218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0); 8448218792SnpMODULE_VERSION(cxgbe, 1); 8449248925Snp 8450248925SnpDRIVER_MODULE(cxl, t5nex, cxl_driver, cxl_devclass, 0, 0); 8451248925SnpMODULE_VERSION(cxl, 1); 8452