t4_main.c revision 241733
1218792Snp/*- 2218792Snp * Copyright (c) 2011 Chelsio Communications, Inc. 3218792Snp * All rights reserved. 4218792Snp * Written by: Navdeep Parhar <np@FreeBSD.org> 5218792Snp * 6218792Snp * Redistribution and use in source and binary forms, with or without 7218792Snp * modification, are permitted provided that the following conditions 8218792Snp * are met: 9218792Snp * 1. Redistributions of source code must retain the above copyright 10218792Snp * notice, this list of conditions and the following disclaimer. 11218792Snp * 2. Redistributions in binary form must reproduce the above copyright 12218792Snp * notice, this list of conditions and the following disclaimer in the 13218792Snp * documentation and/or other materials provided with the distribution. 14218792Snp * 15218792Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16218792Snp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17218792Snp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18218792Snp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19218792Snp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20218792Snp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21218792Snp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22218792Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23218792Snp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24218792Snp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25218792Snp * SUCH DAMAGE. 26218792Snp */ 27218792Snp 28218792Snp#include <sys/cdefs.h> 29218792Snp__FBSDID("$FreeBSD: head/sys/dev/cxgbe/t4_main.c 241733 2012-10-19 13:26:40Z ed $"); 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> 58218792Snp 59218792Snp#include "common/common.h" 60221474Snp#include "common/t4_msg.h" 61218792Snp#include "common/t4_regs.h" 62218792Snp#include "common/t4_regs_values.h" 63218792Snp#include "t4_ioctl.h" 64222509Snp#include "t4_l2t.h" 65218792Snp 66218792Snp/* T4 bus driver interface */ 67218792Snpstatic int t4_probe(device_t); 68218792Snpstatic int t4_attach(device_t); 69218792Snpstatic int t4_detach(device_t); 70218792Snpstatic device_method_t t4_methods[] = { 71218792Snp DEVMETHOD(device_probe, t4_probe), 72218792Snp DEVMETHOD(device_attach, t4_attach), 73218792Snp DEVMETHOD(device_detach, t4_detach), 74218792Snp 75227843Smarius DEVMETHOD_END 76218792Snp}; 77218792Snpstatic driver_t t4_driver = { 78218792Snp "t4nex", 79218792Snp t4_methods, 80218792Snp sizeof(struct adapter) 81218792Snp}; 82218792Snp 83218792Snp 84218792Snp/* T4 port (cxgbe) interface */ 85218792Snpstatic int cxgbe_probe(device_t); 86218792Snpstatic int cxgbe_attach(device_t); 87218792Snpstatic int cxgbe_detach(device_t); 88218792Snpstatic device_method_t cxgbe_methods[] = { 89218792Snp DEVMETHOD(device_probe, cxgbe_probe), 90218792Snp DEVMETHOD(device_attach, cxgbe_attach), 91218792Snp DEVMETHOD(device_detach, cxgbe_detach), 92218792Snp { 0, 0 } 93218792Snp}; 94218792Snpstatic driver_t cxgbe_driver = { 95218792Snp "cxgbe", 96218792Snp cxgbe_methods, 97218792Snp sizeof(struct port_info) 98218792Snp}; 99218792Snp 100218792Snpstatic d_ioctl_t t4_ioctl; 101218792Snpstatic d_open_t t4_open; 102218792Snpstatic d_close_t t4_close; 103218792Snp 104218792Snpstatic struct cdevsw t4_cdevsw = { 105218792Snp .d_version = D_VERSION, 106218792Snp .d_flags = 0, 107218792Snp .d_open = t4_open, 108218792Snp .d_close = t4_close, 109218792Snp .d_ioctl = t4_ioctl, 110218792Snp .d_name = "t4nex", 111218792Snp}; 112218792Snp 113218792Snp/* ifnet + media interface */ 114218792Snpstatic void cxgbe_init(void *); 115218792Snpstatic int cxgbe_ioctl(struct ifnet *, unsigned long, caddr_t); 116218792Snpstatic int cxgbe_transmit(struct ifnet *, struct mbuf *); 117218792Snpstatic void cxgbe_qflush(struct ifnet *); 118218792Snpstatic int cxgbe_media_change(struct ifnet *); 119218792Snpstatic void cxgbe_media_status(struct ifnet *, struct ifmediareq *); 120218792Snp 121218792SnpMALLOC_DEFINE(M_CXGBE, "cxgbe", "Chelsio T4 Ethernet driver and services"); 122218792Snp 123237263Snp/* 124237263Snp * Correct lock order when you need to acquire multiple locks is t4_list_lock, 125237263Snp * then ADAPTER_LOCK, then t4_uld_list_lock. 126237263Snp */ 127228561Snpstatic struct mtx t4_list_lock; 128228561Snpstatic SLIST_HEAD(, adapter) t4_list; 129237263Snp#ifdef TCP_OFFLOAD 130228561Snpstatic struct mtx t4_uld_list_lock; 131228561Snpstatic SLIST_HEAD(, uld_info) t4_uld_list; 132228561Snp#endif 133218792Snp 134218792Snp/* 135228561Snp * Tunables. See tweak_tunables() too. 136218792Snp */ 137218792Snp 138218792Snp/* 139228561Snp * Number of queues for tx and rx, 10G and 1G, NIC and offload. 140218792Snp */ 141228561Snp#define NTXQ_10G 16 142228561Snpstatic int t4_ntxq10g = -1; 143228561SnpTUNABLE_INT("hw.cxgbe.ntxq10g", &t4_ntxq10g); 144218792Snp 145228561Snp#define NRXQ_10G 8 146228561Snpstatic int t4_nrxq10g = -1; 147228561SnpTUNABLE_INT("hw.cxgbe.nrxq10g", &t4_nrxq10g); 148218792Snp 149228561Snp#define NTXQ_1G 4 150228561Snpstatic int t4_ntxq1g = -1; 151228561SnpTUNABLE_INT("hw.cxgbe.ntxq1g", &t4_ntxq1g); 152218792Snp 153228561Snp#define NRXQ_1G 2 154228561Snpstatic int t4_nrxq1g = -1; 155228561SnpTUNABLE_INT("hw.cxgbe.nrxq1g", &t4_nrxq1g); 156218792Snp 157237263Snp#ifdef TCP_OFFLOAD 158228561Snp#define NOFLDTXQ_10G 8 159228561Snpstatic int t4_nofldtxq10g = -1; 160228561SnpTUNABLE_INT("hw.cxgbe.nofldtxq10g", &t4_nofldtxq10g); 161228561Snp 162228561Snp#define NOFLDRXQ_10G 2 163228561Snpstatic int t4_nofldrxq10g = -1; 164228561SnpTUNABLE_INT("hw.cxgbe.nofldrxq10g", &t4_nofldrxq10g); 165228561Snp 166228561Snp#define NOFLDTXQ_1G 2 167228561Snpstatic int t4_nofldtxq1g = -1; 168228561SnpTUNABLE_INT("hw.cxgbe.nofldtxq1g", &t4_nofldtxq1g); 169228561Snp 170228561Snp#define NOFLDRXQ_1G 1 171228561Snpstatic int t4_nofldrxq1g = -1; 172228561SnpTUNABLE_INT("hw.cxgbe.nofldrxq1g", &t4_nofldrxq1g); 173228561Snp#endif 174228561Snp 175218792Snp/* 176218792Snp * Holdoff parameters for 10G and 1G ports. 177218792Snp */ 178228561Snp#define TMR_IDX_10G 1 179228561Snpstatic int t4_tmr_idx_10g = TMR_IDX_10G; 180228561SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_10G", &t4_tmr_idx_10g); 181218792Snp 182234833Snp#define PKTC_IDX_10G (-1) 183228561Snpstatic int t4_pktc_idx_10g = PKTC_IDX_10G; 184228561SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_10G", &t4_pktc_idx_10g); 185218792Snp 186228561Snp#define TMR_IDX_1G 1 187228561Snpstatic int t4_tmr_idx_1g = TMR_IDX_1G; 188228561SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_1G", &t4_tmr_idx_1g); 189218792Snp 190234833Snp#define PKTC_IDX_1G (-1) 191228561Snpstatic int t4_pktc_idx_1g = PKTC_IDX_1G; 192228561SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_1G", &t4_pktc_idx_1g); 193218792Snp 194218792Snp/* 195218792Snp * Size (# of entries) of each tx and rx queue. 196218792Snp */ 197228561Snpstatic unsigned int t4_qsize_txq = TX_EQ_QSIZE; 198228561SnpTUNABLE_INT("hw.cxgbe.qsize_txq", &t4_qsize_txq); 199218792Snp 200228561Snpstatic unsigned int t4_qsize_rxq = RX_IQ_QSIZE; 201228561SnpTUNABLE_INT("hw.cxgbe.qsize_rxq", &t4_qsize_rxq); 202218792Snp 203218792Snp/* 204228561Snp * Interrupt types allowed (bits 0, 1, 2 = INTx, MSI, MSI-X respectively). 205218792Snp */ 206228561Snpstatic int t4_intr_types = INTR_MSIX | INTR_MSI | INTR_INTX; 207228561SnpTUNABLE_INT("hw.cxgbe.interrupt_types", &t4_intr_types); 208218792Snp 209218792Snp/* 210228561Snp * Configuration file. 211218792Snp */ 212228561Snpstatic char t4_cfg_file[32] = "default"; 213228561SnpTUNABLE_STR("hw.cxgbe.config_file", t4_cfg_file, sizeof(t4_cfg_file)); 214218792Snp 215228561Snp/* 216228561Snp * ASIC features that will be used. Disable the ones you don't want so that the 217228561Snp * chip resources aren't wasted on features that will not be used. 218228561Snp */ 219228561Snpstatic int t4_linkcaps_allowed = 0; /* No DCBX, PPP, etc. by default */ 220228561SnpTUNABLE_INT("hw.cxgbe.linkcaps_allowed", &t4_linkcaps_allowed); 221221474Snp 222228561Snpstatic int t4_niccaps_allowed = FW_CAPS_CONFIG_NIC; 223228561SnpTUNABLE_INT("hw.cxgbe.niccaps_allowed", &t4_niccaps_allowed); 224228561Snp 225238028Snpstatic int t4_toecaps_allowed = -1; 226228561SnpTUNABLE_INT("hw.cxgbe.toecaps_allowed", &t4_toecaps_allowed); 227228561Snp 228228561Snpstatic int t4_rdmacaps_allowed = 0; 229228561SnpTUNABLE_INT("hw.cxgbe.rdmacaps_allowed", &t4_rdmacaps_allowed); 230228561Snp 231228561Snpstatic int t4_iscsicaps_allowed = 0; 232228561SnpTUNABLE_INT("hw.cxgbe.iscsicaps_allowed", &t4_iscsicaps_allowed); 233228561Snp 234228561Snpstatic int t4_fcoecaps_allowed = 0; 235228561SnpTUNABLE_INT("hw.cxgbe.fcoecaps_allowed", &t4_fcoecaps_allowed); 236228561Snp 237218792Snpstruct intrs_and_queues { 238219944Snp int intr_type; /* INTx, MSI, or MSI-X */ 239218792Snp int nirq; /* Number of vectors */ 240228561Snp int intr_flags; 241218792Snp int ntxq10g; /* # of NIC txq's for each 10G port */ 242218792Snp int nrxq10g; /* # of NIC rxq's for each 10G port */ 243218792Snp int ntxq1g; /* # of NIC txq's for each 1G port */ 244218792Snp int nrxq1g; /* # of NIC rxq's for each 1G port */ 245237263Snp#ifdef TCP_OFFLOAD 246228561Snp int nofldtxq10g; /* # of TOE txq's for each 10G port */ 247228561Snp int nofldrxq10g; /* # of TOE rxq's for each 10G port */ 248228561Snp int nofldtxq1g; /* # of TOE txq's for each 1G port */ 249228561Snp int nofldrxq1g; /* # of TOE rxq's for each 1G port */ 250228561Snp#endif 251218792Snp}; 252218792Snp 253221474Snpstruct filter_entry { 254221474Snp uint32_t valid:1; /* filter allocated and valid */ 255221474Snp uint32_t locked:1; /* filter is administratively locked */ 256221474Snp uint32_t pending:1; /* filter action is pending firmware reply */ 257221474Snp uint32_t smtidx:8; /* Source MAC Table index for smac */ 258222509Snp struct l2t_entry *l2t; /* Layer Two Table entry for dmac */ 259221474Snp 260221474Snp struct t4_filter_specification fs; 261221474Snp}; 262221474Snp 263218792Snpenum { 264218792Snp XGMAC_MTU = (1 << 0), 265218792Snp XGMAC_PROMISC = (1 << 1), 266218792Snp XGMAC_ALLMULTI = (1 << 2), 267218792Snp XGMAC_VLANEX = (1 << 3), 268218792Snp XGMAC_UCADDR = (1 << 4), 269218792Snp XGMAC_MCADDRS = (1 << 5), 270218792Snp 271218792Snp XGMAC_ALL = 0xffff 272218792Snp}; 273218792Snp 274218792Snpstatic int map_bars(struct adapter *); 275218792Snpstatic void setup_memwin(struct adapter *); 276218792Snpstatic int cfg_itype_and_nqueues(struct adapter *, int, int, 277218792Snp struct intrs_and_queues *); 278218792Snpstatic int prep_firmware(struct adapter *); 279228561Snpstatic int upload_config_file(struct adapter *, const struct firmware *, 280228561Snp uint32_t *, uint32_t *); 281228561Snpstatic int partition_resources(struct adapter *, const struct firmware *); 282228561Snpstatic int get_params__pre_init(struct adapter *); 283228561Snpstatic int get_params__post_init(struct adapter *); 284218792Snpstatic void t4_set_desc(struct adapter *); 285218792Snpstatic void build_medialist(struct port_info *); 286218792Snpstatic int update_mac_settings(struct port_info *, int); 287218792Snpstatic int cxgbe_init_locked(struct port_info *); 288218792Snpstatic int cxgbe_init_synchronized(struct port_info *); 289218792Snpstatic int cxgbe_uninit_locked(struct port_info *); 290218792Snpstatic int cxgbe_uninit_synchronized(struct port_info *); 291240453Snpstatic int setup_intr_handlers(struct adapter *); 292228561Snpstatic int adapter_full_init(struct adapter *); 293228561Snpstatic int adapter_full_uninit(struct adapter *); 294228561Snpstatic int port_full_init(struct port_info *); 295228561Snpstatic int port_full_uninit(struct port_info *); 296228561Snpstatic void quiesce_eq(struct adapter *, struct sge_eq *); 297228561Snpstatic void quiesce_iq(struct adapter *, struct sge_iq *); 298228561Snpstatic void quiesce_fl(struct adapter *, struct sge_fl *); 299218792Snpstatic int t4_alloc_irq(struct adapter *, struct irq *, int rid, 300228561Snp driver_intr_t *, void *, char *); 301218792Snpstatic int t4_free_irq(struct adapter *, struct irq *); 302218792Snpstatic void reg_block_dump(struct adapter *, uint8_t *, unsigned int, 303218792Snp unsigned int); 304218792Snpstatic void t4_get_regs(struct adapter *, struct t4_regdump *, uint8_t *); 305218792Snpstatic void cxgbe_tick(void *); 306237263Snpstatic void cxgbe_vlan_config(void *, struct ifnet *, uint16_t); 307228561Snpstatic int cpl_not_handled(struct sge_iq *, const struct rss_header *, 308228561Snp struct mbuf *); 309237263Snpstatic int an_not_handled(struct sge_iq *, const struct rsp_ctrl *); 310239336Snpstatic int fw_msg_not_handled(struct adapter *, const __be64 *); 311218792Snpstatic int t4_sysctls(struct adapter *); 312218792Snpstatic int cxgbe_sysctls(struct port_info *); 313219436Snpstatic int sysctl_int_array(SYSCTL_HANDLER_ARGS); 314228561Snpstatic int sysctl_bitfield(SYSCTL_HANDLER_ARGS); 315218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS); 316218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS); 317218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS); 318218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS); 319218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS); 320231115Snp#ifdef SBUF_DRAIN 321228561Snpstatic int sysctl_cctrl(SYSCTL_HANDLER_ARGS); 322228561Snpstatic int sysctl_cpl_stats(SYSCTL_HANDLER_ARGS); 323228561Snpstatic int sysctl_ddp_stats(SYSCTL_HANDLER_ARGS); 324222551Snpstatic int sysctl_devlog(SYSCTL_HANDLER_ARGS); 325228561Snpstatic int sysctl_fcoe_stats(SYSCTL_HANDLER_ARGS); 326228561Snpstatic int sysctl_hw_sched(SYSCTL_HANDLER_ARGS); 327228561Snpstatic int sysctl_lb_stats(SYSCTL_HANDLER_ARGS); 328228561Snpstatic int sysctl_meminfo(SYSCTL_HANDLER_ARGS); 329228561Snpstatic int sysctl_path_mtus(SYSCTL_HANDLER_ARGS); 330228561Snpstatic int sysctl_pm_stats(SYSCTL_HANDLER_ARGS); 331228561Snpstatic int sysctl_rdma_stats(SYSCTL_HANDLER_ARGS); 332228561Snpstatic int sysctl_tcp_stats(SYSCTL_HANDLER_ARGS); 333228561Snpstatic int sysctl_tids(SYSCTL_HANDLER_ARGS); 334228561Snpstatic int sysctl_tp_err_stats(SYSCTL_HANDLER_ARGS); 335228561Snpstatic int sysctl_tx_rate(SYSCTL_HANDLER_ARGS); 336231115Snp#endif 337219286Snpstatic inline void txq_start(struct ifnet *, struct sge_txq *); 338221474Snpstatic uint32_t fconf_to_mode(uint32_t); 339221474Snpstatic uint32_t mode_to_fconf(uint32_t); 340221474Snpstatic uint32_t fspec_to_fconf(struct t4_filter_specification *); 341221474Snpstatic int get_filter_mode(struct adapter *, uint32_t *); 342221474Snpstatic int set_filter_mode(struct adapter *, uint32_t); 343222552Snpstatic inline uint64_t get_filter_hits(struct adapter *, uint32_t); 344221474Snpstatic int get_filter(struct adapter *, struct t4_filter *); 345221474Snpstatic int set_filter(struct adapter *, struct t4_filter *); 346221474Snpstatic int del_filter(struct adapter *, struct t4_filter *); 347222509Snpstatic void clear_filter(struct filter_entry *); 348221474Snpstatic int set_filter_wr(struct adapter *, int); 349221474Snpstatic int del_filter_wr(struct adapter *, int); 350222973Snpstatic int get_sge_context(struct adapter *, struct t4_sge_context *); 351228561Snpstatic int read_card_mem(struct adapter *, struct t4_mem_range *); 352241399Snpstatic int read_i2c(struct adapter *, struct t4_i2c_data *); 353237263Snp#ifdef TCP_OFFLOAD 354228561Snpstatic int toe_capability(struct port_info *, int); 355228561Snp#endif 356219392Snpstatic int t4_mod_event(module_t, int, void *); 357218792Snp 358218792Snpstruct t4_pciids { 359218792Snp uint16_t device; 360218792Snp char *desc; 361218792Snp} t4_pciids[] = { 362237587Snp {0xa000, "Chelsio Terminator 4 FPGA"}, 363237587Snp {0x4400, "Chelsio T440-dbg"}, 364237587Snp {0x4401, "Chelsio T420-CR"}, 365237587Snp {0x4402, "Chelsio T422-CR"}, 366237587Snp {0x4403, "Chelsio T440-CR"}, 367237587Snp {0x4404, "Chelsio T420-BCH"}, 368237587Snp {0x4405, "Chelsio T440-BCH"}, 369237587Snp {0x4406, "Chelsio T440-CH"}, 370237587Snp {0x4407, "Chelsio T420-SO"}, 371237587Snp {0x4408, "Chelsio T420-CX"}, 372237587Snp {0x4409, "Chelsio T420-BT"}, 373237587Snp {0x440a, "Chelsio T404-BT"}, 374218792Snp}; 375218792Snp 376237263Snp#ifdef TCP_OFFLOAD 377237263Snp/* 378237263Snp * service_iq() has an iq and needs the fl. Offset of fl from the iq should be 379237263Snp * exactly the same for both rxq and ofld_rxq. 380237263Snp */ 381237263SnpCTASSERT(offsetof(struct sge_ofld_rxq, iq) == offsetof(struct sge_rxq, iq)); 382228561SnpCTASSERT(offsetof(struct sge_ofld_rxq, fl) == offsetof(struct sge_rxq, fl)); 383228561Snp#endif 384228561Snp 385239336Snp/* No easy way to include t4_msg.h before adapter.h so we check this way */ 386240452SnpCTASSERT(nitems(((struct adapter *)0)->cpl_handler) == NUM_CPL_CMDS); 387240452SnpCTASSERT(nitems(((struct adapter *)0)->fw_msg_handler) == NUM_FW6_TYPES); 388239336Snp 389218792Snpstatic int 390218792Snpt4_probe(device_t dev) 391218792Snp{ 392218792Snp int i; 393218792Snp uint16_t v = pci_get_vendor(dev); 394218792Snp uint16_t d = pci_get_device(dev); 395237587Snp uint8_t f = pci_get_function(dev); 396218792Snp 397218792Snp if (v != PCI_VENDOR_ID_CHELSIO) 398218792Snp return (ENXIO); 399218792Snp 400237587Snp /* Attach only to PF0 of the FPGA */ 401237587Snp if (d == 0xa000 && f != 0) 402237587Snp return (ENXIO); 403237587Snp 404240452Snp for (i = 0; i < nitems(t4_pciids); i++) { 405237587Snp if (d == t4_pciids[i].device) { 406218792Snp device_set_desc(dev, t4_pciids[i].desc); 407218792Snp return (BUS_PROBE_DEFAULT); 408218792Snp } 409218792Snp } 410218792Snp 411218792Snp return (ENXIO); 412218792Snp} 413218792Snp 414218792Snpstatic int 415218792Snpt4_attach(device_t dev) 416218792Snp{ 417218792Snp struct adapter *sc; 418218792Snp int rc = 0, i, n10g, n1g, rqidx, tqidx; 419218792Snp struct intrs_and_queues iaq; 420218792Snp struct sge *s; 421237263Snp#ifdef TCP_OFFLOAD 422228561Snp int ofld_rqidx, ofld_tqidx; 423228561Snp#endif 424218792Snp 425218792Snp sc = device_get_softc(dev); 426218792Snp sc->dev = dev; 427218792Snp 428218792Snp pci_enable_busmaster(dev); 429222085Snp if (pci_find_cap(dev, PCIY_EXPRESS, &i) == 0) { 430228561Snp uint32_t v; 431228561Snp 432222085Snp pci_set_max_read_req(dev, 4096); 433240680Sgavin v = pci_read_config(dev, i + PCIER_DEVICE_CTL, 2); 434240680Sgavin v |= PCIEM_CTL_RELAXED_ORD_ENABLE; 435240680Sgavin pci_write_config(dev, i + PCIER_DEVICE_CTL, v, 2); 436222085Snp } 437222085Snp 438218792Snp snprintf(sc->lockname, sizeof(sc->lockname), "%s", 439218792Snp device_get_nameunit(dev)); 440218792Snp mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF); 441228561Snp mtx_lock(&t4_list_lock); 442228561Snp SLIST_INSERT_HEAD(&t4_list, sc, link); 443228561Snp mtx_unlock(&t4_list_lock); 444218792Snp 445228561Snp mtx_init(&sc->sfl_lock, "starving freelists", 0, MTX_DEF); 446228561Snp TAILQ_INIT(&sc->sfl); 447228561Snp callout_init(&sc->sfl_callout, CALLOUT_MPSAFE); 448228561Snp 449218792Snp rc = map_bars(sc); 450218792Snp if (rc != 0) 451218792Snp goto done; /* error message displayed already */ 452218792Snp 453237587Snp /* 454237587Snp * This is the real PF# to which we're attaching. Works from within PCI 455237587Snp * passthrough environments too, where pci_get_function() could return a 456237587Snp * different PF# depending on the passthrough configuration. We need to 457237587Snp * use the real PF# in all our communication with the firmware. 458237587Snp */ 459237587Snp sc->pf = G_SOURCEPF(t4_read_reg(sc, A_PL_WHOAMI)); 460237587Snp sc->mbox = sc->pf; 461237587Snp 462218792Snp memset(sc->chan_map, 0xff, sizeof(sc->chan_map)); 463237263Snp sc->an_handler = an_not_handled; 464240452Snp for (i = 0; i < nitems(sc->cpl_handler); i++) 465228561Snp sc->cpl_handler[i] = cpl_not_handled; 466240452Snp for (i = 0; i < nitems(sc->fw_msg_handler); i++) 467239336Snp sc->fw_msg_handler[i] = fw_msg_not_handled; 468239338Snp t4_register_cpl_handler(sc, CPL_SET_TCB_RPL, t4_filter_rpl); 469218792Snp 470218792Snp /* Prepare the adapter for operation */ 471218792Snp rc = -t4_prep_adapter(sc); 472218792Snp if (rc != 0) { 473218792Snp device_printf(dev, "failed to prepare adapter: %d.\n", rc); 474218792Snp goto done; 475218792Snp } 476218792Snp 477228561Snp /* 478228561Snp * Do this really early, with the memory windows set up even before the 479228561Snp * character device. The userland tool's register i/o and mem read 480228561Snp * will work even in "recovery mode". 481228561Snp */ 482228561Snp setup_memwin(sc); 483218792Snp sc->cdev = make_dev(&t4_cdevsw, device_get_unit(dev), UID_ROOT, 484218792Snp GID_WHEEL, 0600, "%s", device_get_nameunit(dev)); 485218792Snp sc->cdev->si_drv1 = sc; 486218792Snp 487228561Snp /* Go no further if recovery mode has been requested. */ 488228561Snp if (TUNABLE_INT_FETCH("hw.cxgbe.sos", &i) && i != 0) { 489228561Snp device_printf(dev, "recovery mode.\n"); 490228561Snp goto done; 491228561Snp } 492228561Snp 493218792Snp /* Prepare the firmware for operation */ 494218792Snp rc = prep_firmware(sc); 495218792Snp if (rc != 0) 496218792Snp goto done; /* error message displayed already */ 497218792Snp 498228561Snp rc = get_params__pre_init(sc); 499228561Snp if (rc != 0) 500228561Snp goto done; /* error message displayed already */ 501222551Snp 502228561Snp rc = t4_sge_init(sc); 503228561Snp if (rc != 0) 504228561Snp goto done; /* error message displayed already */ 505218792Snp 506228561Snp if (sc->flags & MASTER_PF) { 507228561Snp /* get basic stuff going */ 508228561Snp rc = -t4_fw_initialize(sc, sc->mbox); 509228561Snp if (rc != 0) { 510228561Snp device_printf(dev, "early init failed: %d.\n", rc); 511228561Snp goto done; 512228561Snp } 513218792Snp } 514218792Snp 515228561Snp rc = get_params__post_init(sc); 516228561Snp if (rc != 0) 517228561Snp goto done; /* error message displayed already */ 518218792Snp 519228561Snp if (sc->flags & MASTER_PF) { 520239341Snp uint16_t indsz = min(RX_COPY_THRESHOLD - 1, M_INDICATESIZE); 521218792Snp 522228561Snp /* final tweaks to some settings */ 523218792Snp 524228561Snp t4_load_mtus(sc, sc->params.mtus, sc->params.a_wnd, 525228561Snp sc->params.b_wnd); 526239341Snp /* 4K, 16K, 64K, 256K DDP "page sizes" */ 527239341Snp t4_write_reg(sc, A_ULP_RX_TDDP_PSZ, V_HPZ0(0) | V_HPZ1(2) | 528239341Snp V_HPZ2(4) | V_HPZ3(6)); 529239341Snp t4_set_reg_field(sc, A_ULP_RX_CTL, F_TDDPTAGTCB, F_TDDPTAGTCB); 530228561Snp t4_set_reg_field(sc, A_TP_PARA_REG5, 531228561Snp V_INDICATESIZE(M_INDICATESIZE) | 532228561Snp F_REARMDDPOFFSET | F_RESETDDPOFFSET, 533239341Snp V_INDICATESIZE(indsz) | 534228561Snp F_REARMDDPOFFSET | F_RESETDDPOFFSET); 535228561Snp } else { 536228561Snp /* 537228561Snp * XXX: Verify that we can live with whatever the master driver 538228561Snp * has done so far, and hope that it doesn't change any global 539228561Snp * setting from underneath us in the future. 540228561Snp */ 541218792Snp } 542218792Snp 543228561Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &sc->filter_mode, 1, 544228561Snp A_TP_VLAN_PRI_MAP); 545218792Snp 546228561Snp for (i = 0; i < NCHAN; i++) 547228561Snp sc->params.tp.tx_modq[i] = i; 548218792Snp 549218792Snp rc = t4_create_dma_tag(sc); 550218792Snp if (rc != 0) 551218792Snp goto done; /* error message displayed already */ 552218792Snp 553218792Snp /* 554218792Snp * First pass over all the ports - allocate VIs and initialize some 555218792Snp * basic parameters like mac address, port type, etc. We also figure 556218792Snp * out whether a port is 10G or 1G and use that information when 557218792Snp * calculating how many interrupts to attempt to allocate. 558218792Snp */ 559218792Snp n10g = n1g = 0; 560218792Snp for_each_port(sc, i) { 561218792Snp struct port_info *pi; 562218792Snp 563218792Snp pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK); 564218792Snp sc->port[i] = pi; 565218792Snp 566218792Snp /* These must be set before t4_port_init */ 567218792Snp pi->adapter = sc; 568218792Snp pi->port_id = i; 569218792Snp 570218792Snp /* Allocate the vi and initialize parameters like mac addr */ 571218792Snp rc = -t4_port_init(pi, sc->mbox, sc->pf, 0); 572218792Snp if (rc != 0) { 573218792Snp device_printf(dev, "unable to initialize port %d: %d\n", 574218792Snp i, rc); 575218792Snp free(pi, M_CXGBE); 576222510Snp sc->port[i] = NULL; 577222510Snp goto done; 578218792Snp } 579218792Snp 580218792Snp snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d", 581218792Snp device_get_nameunit(dev), i); 582218792Snp mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF); 583218792Snp 584218792Snp if (is_10G_port(pi)) { 585218792Snp n10g++; 586228561Snp pi->tmr_idx = t4_tmr_idx_10g; 587228561Snp pi->pktc_idx = t4_pktc_idx_10g; 588218792Snp } else { 589218792Snp n1g++; 590228561Snp pi->tmr_idx = t4_tmr_idx_1g; 591228561Snp pi->pktc_idx = t4_pktc_idx_1g; 592218792Snp } 593218792Snp 594218792Snp pi->xact_addr_filt = -1; 595218792Snp 596228561Snp pi->qsize_rxq = t4_qsize_rxq; 597228561Snp pi->qsize_txq = t4_qsize_txq; 598218792Snp 599218792Snp pi->dev = device_add_child(dev, "cxgbe", -1); 600218792Snp if (pi->dev == NULL) { 601218792Snp device_printf(dev, 602218792Snp "failed to add device for port %d.\n", i); 603218792Snp rc = ENXIO; 604218792Snp goto done; 605218792Snp } 606218792Snp device_set_softc(pi->dev, pi); 607218792Snp } 608218792Snp 609218792Snp /* 610218792Snp * Interrupt type, # of interrupts, # of rx/tx queues, etc. 611218792Snp */ 612218792Snp rc = cfg_itype_and_nqueues(sc, n10g, n1g, &iaq); 613218792Snp if (rc != 0) 614218792Snp goto done; /* error message displayed already */ 615218792Snp 616218792Snp sc->intr_type = iaq.intr_type; 617218792Snp sc->intr_count = iaq.nirq; 618228561Snp sc->flags |= iaq.intr_flags; 619218792Snp 620218792Snp s = &sc->sge; 621218792Snp s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g; 622218792Snp s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g; 623220873Snp s->neq = s->ntxq + s->nrxq; /* the free list in an rxq is an eq */ 624228561Snp s->neq += sc->params.nports + 1;/* ctrl queues: 1 per port + 1 mgmt */ 625218792Snp s->niq = s->nrxq + 1; /* 1 extra for firmware event queue */ 626222510Snp 627237263Snp#ifdef TCP_OFFLOAD 628228561Snp if (is_offload(sc)) { 629228561Snp 630228561Snp s->nofldrxq = n10g * iaq.nofldrxq10g + n1g * iaq.nofldrxq1g; 631228561Snp s->nofldtxq = n10g * iaq.nofldtxq10g + n1g * iaq.nofldtxq1g; 632228561Snp s->neq += s->nofldtxq + s->nofldrxq; 633228561Snp s->niq += s->nofldrxq; 634228561Snp 635228561Snp s->ofld_rxq = malloc(s->nofldrxq * sizeof(struct sge_ofld_rxq), 636228561Snp M_CXGBE, M_ZERO | M_WAITOK); 637228561Snp s->ofld_txq = malloc(s->nofldtxq * sizeof(struct sge_wrq), 638228561Snp M_CXGBE, M_ZERO | M_WAITOK); 639228561Snp } 640228561Snp#endif 641228561Snp 642228561Snp s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_wrq), M_CXGBE, 643220873Snp M_ZERO | M_WAITOK); 644218792Snp s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE, 645218792Snp M_ZERO | M_WAITOK); 646218792Snp s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE, 647218792Snp M_ZERO | M_WAITOK); 648218792Snp s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE, 649218792Snp M_ZERO | M_WAITOK); 650218792Snp s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE, 651218792Snp M_ZERO | M_WAITOK); 652218792Snp 653218792Snp sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE, 654218792Snp M_ZERO | M_WAITOK); 655218792Snp 656228561Snp t4_init_l2t(sc, M_WAITOK); 657222509Snp 658218792Snp /* 659218792Snp * Second pass over the ports. This time we know the number of rx and 660218792Snp * tx queues that each port should get. 661218792Snp */ 662218792Snp rqidx = tqidx = 0; 663237263Snp#ifdef TCP_OFFLOAD 664228561Snp ofld_rqidx = ofld_tqidx = 0; 665228561Snp#endif 666218792Snp for_each_port(sc, i) { 667218792Snp struct port_info *pi = sc->port[i]; 668218792Snp 669218792Snp if (pi == NULL) 670218792Snp continue; 671218792Snp 672218792Snp pi->first_rxq = rqidx; 673218792Snp pi->first_txq = tqidx; 674228561Snp if (is_10G_port(pi)) { 675228561Snp pi->nrxq = iaq.nrxq10g; 676228561Snp pi->ntxq = iaq.ntxq10g; 677228561Snp } else { 678228561Snp pi->nrxq = iaq.nrxq1g; 679228561Snp pi->ntxq = iaq.ntxq1g; 680228561Snp } 681218792Snp 682218792Snp rqidx += pi->nrxq; 683218792Snp tqidx += pi->ntxq; 684228561Snp 685237263Snp#ifdef TCP_OFFLOAD 686228561Snp if (is_offload(sc)) { 687228561Snp pi->first_ofld_rxq = ofld_rqidx; 688228561Snp pi->first_ofld_txq = ofld_tqidx; 689228561Snp if (is_10G_port(pi)) { 690228561Snp pi->nofldrxq = iaq.nofldrxq10g; 691228561Snp pi->nofldtxq = iaq.nofldtxq10g; 692228561Snp } else { 693228561Snp pi->nofldrxq = iaq.nofldrxq1g; 694228561Snp pi->nofldtxq = iaq.nofldtxq1g; 695228561Snp } 696228561Snp ofld_rqidx += pi->nofldrxq; 697228561Snp ofld_tqidx += pi->nofldtxq; 698228561Snp } 699228561Snp#endif 700218792Snp } 701218792Snp 702240453Snp rc = setup_intr_handlers(sc); 703240453Snp if (rc != 0) { 704240453Snp device_printf(dev, 705240453Snp "failed to setup interrupt handlers: %d\n", rc); 706240453Snp goto done; 707240453Snp } 708240453Snp 709218792Snp rc = bus_generic_attach(dev); 710218792Snp if (rc != 0) { 711218792Snp device_printf(dev, 712218792Snp "failed to attach all child ports: %d\n", rc); 713218792Snp goto done; 714218792Snp } 715218792Snp 716218792Snp device_printf(dev, 717228561Snp "PCIe x%d, %d ports, %d %s interrupt%s, %d eq, %d iq\n", 718228561Snp sc->params.pci.width, sc->params.nports, sc->intr_count, 719228561Snp sc->intr_type == INTR_MSIX ? "MSI-X" : 720228561Snp (sc->intr_type == INTR_MSI ? "MSI" : "INTx"), 721228561Snp sc->intr_count > 1 ? "s" : "", sc->sge.neq, sc->sge.niq); 722228561Snp 723218792Snp t4_set_desc(sc); 724218792Snp 725218792Snpdone: 726228561Snp if (rc != 0 && sc->cdev) { 727228561Snp /* cdev was created and so cxgbetool works; recover that way. */ 728228561Snp device_printf(dev, 729228561Snp "error during attach, adapter is now in recovery mode.\n"); 730228561Snp rc = 0; 731228561Snp } 732228561Snp 733218792Snp if (rc != 0) 734218792Snp t4_detach(dev); 735228561Snp else 736228561Snp t4_sysctls(sc); 737218792Snp 738218792Snp return (rc); 739218792Snp} 740218792Snp 741218792Snp/* 742218792Snp * Idempotent 743218792Snp */ 744218792Snpstatic int 745218792Snpt4_detach(device_t dev) 746218792Snp{ 747218792Snp struct adapter *sc; 748218792Snp struct port_info *pi; 749228561Snp int i, rc; 750218792Snp 751218792Snp sc = device_get_softc(dev); 752218792Snp 753228561Snp if (sc->flags & FULL_INIT_DONE) 754228561Snp t4_intr_disable(sc); 755228561Snp 756228561Snp if (sc->cdev) { 757218792Snp destroy_dev(sc->cdev); 758228561Snp sc->cdev = NULL; 759228561Snp } 760218792Snp 761228561Snp rc = bus_generic_detach(dev); 762228561Snp if (rc) { 763228561Snp device_printf(dev, 764228561Snp "failed to detach child devices: %d\n", rc); 765228561Snp return (rc); 766228561Snp } 767228561Snp 768240453Snp for (i = 0; i < sc->intr_count; i++) 769240453Snp t4_free_irq(sc, &sc->irq[i]); 770240453Snp 771218792Snp for (i = 0; i < MAX_NPORTS; i++) { 772218792Snp pi = sc->port[i]; 773218792Snp if (pi) { 774218792Snp t4_free_vi(pi->adapter, sc->mbox, sc->pf, 0, pi->viid); 775218792Snp if (pi->dev) 776218792Snp device_delete_child(dev, pi->dev); 777218792Snp 778218792Snp mtx_destroy(&pi->pi_lock); 779218792Snp free(pi, M_CXGBE); 780218792Snp } 781218792Snp } 782218792Snp 783228561Snp if (sc->flags & FULL_INIT_DONE) 784228561Snp adapter_full_uninit(sc); 785228561Snp 786218792Snp if (sc->flags & FW_OK) 787218792Snp t4_fw_bye(sc, sc->mbox); 788218792Snp 789219944Snp if (sc->intr_type == INTR_MSI || sc->intr_type == INTR_MSIX) 790218792Snp pci_release_msi(dev); 791218792Snp 792218792Snp if (sc->regs_res) 793218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid, 794218792Snp sc->regs_res); 795218792Snp 796218792Snp if (sc->msix_res) 797218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid, 798218792Snp sc->msix_res); 799218792Snp 800222509Snp if (sc->l2t) 801222509Snp t4_free_l2t(sc->l2t); 802222509Snp 803237263Snp#ifdef TCP_OFFLOAD 804228561Snp free(sc->sge.ofld_rxq, M_CXGBE); 805228561Snp free(sc->sge.ofld_txq, M_CXGBE); 806228561Snp#endif 807218792Snp free(sc->irq, M_CXGBE); 808218792Snp free(sc->sge.rxq, M_CXGBE); 809218792Snp free(sc->sge.txq, M_CXGBE); 810220873Snp free(sc->sge.ctrlq, M_CXGBE); 811218792Snp free(sc->sge.iqmap, M_CXGBE); 812218792Snp free(sc->sge.eqmap, M_CXGBE); 813221474Snp free(sc->tids.ftid_tab, M_CXGBE); 814218792Snp t4_destroy_dma_tag(sc); 815228561Snp if (mtx_initialized(&sc->sc_lock)) { 816228561Snp mtx_lock(&t4_list_lock); 817228561Snp SLIST_REMOVE(&t4_list, sc, adapter, link); 818228561Snp mtx_unlock(&t4_list_lock); 819228561Snp mtx_destroy(&sc->sc_lock); 820228561Snp } 821218792Snp 822228561Snp if (mtx_initialized(&sc->sfl_lock)) 823228561Snp mtx_destroy(&sc->sfl_lock); 824228561Snp 825218792Snp bzero(sc, sizeof(*sc)); 826218792Snp 827218792Snp return (0); 828218792Snp} 829218792Snp 830218792Snp 831218792Snpstatic int 832218792Snpcxgbe_probe(device_t dev) 833218792Snp{ 834218792Snp char buf[128]; 835218792Snp struct port_info *pi = device_get_softc(dev); 836218792Snp 837228561Snp snprintf(buf, sizeof(buf), "port %d", pi->port_id); 838218792Snp device_set_desc_copy(dev, buf); 839218792Snp 840218792Snp return (BUS_PROBE_DEFAULT); 841218792Snp} 842218792Snp 843218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \ 844218792Snp IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \ 845237831Snp IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6) 846237819Snp#define T4_CAP_ENABLE (T4_CAP) 847218792Snp 848218792Snpstatic int 849218792Snpcxgbe_attach(device_t dev) 850218792Snp{ 851218792Snp struct port_info *pi = device_get_softc(dev); 852218792Snp struct ifnet *ifp; 853218792Snp 854218792Snp /* Allocate an ifnet and set it up */ 855218792Snp ifp = if_alloc(IFT_ETHER); 856218792Snp if (ifp == NULL) { 857218792Snp device_printf(dev, "Cannot allocate ifnet\n"); 858218792Snp return (ENOMEM); 859218792Snp } 860218792Snp pi->ifp = ifp; 861218792Snp ifp->if_softc = pi; 862218792Snp 863218792Snp callout_init(&pi->tick, CALLOUT_MPSAFE); 864218792Snp 865218792Snp if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 866218792Snp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 867218792Snp 868218792Snp ifp->if_init = cxgbe_init; 869218792Snp ifp->if_ioctl = cxgbe_ioctl; 870218792Snp ifp->if_transmit = cxgbe_transmit; 871218792Snp ifp->if_qflush = cxgbe_qflush; 872218792Snp 873218792Snp ifp->if_capabilities = T4_CAP; 874237263Snp#ifdef TCP_OFFLOAD 875228561Snp if (is_offload(pi->adapter)) 876228561Snp ifp->if_capabilities |= IFCAP_TOE4; 877228561Snp#endif 878218792Snp ifp->if_capenable = T4_CAP_ENABLE; 879237799Snp ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO | 880237799Snp CSUM_UDP_IPV6 | CSUM_TCP_IPV6; 881218792Snp 882218792Snp /* Initialize ifmedia for this port */ 883218792Snp ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change, 884218792Snp cxgbe_media_status); 885218792Snp build_medialist(pi); 886218792Snp 887237263Snp pi->vlan_c = EVENTHANDLER_REGISTER(vlan_config, cxgbe_vlan_config, ifp, 888237263Snp EVENTHANDLER_PRI_ANY); 889237263Snp 890218792Snp ether_ifattach(ifp, pi->hw_addr); 891218792Snp 892237263Snp#ifdef TCP_OFFLOAD 893228561Snp if (is_offload(pi->adapter)) { 894228561Snp device_printf(dev, 895228561Snp "%d txq, %d rxq (NIC); %d txq, %d rxq (TOE)\n", 896228561Snp pi->ntxq, pi->nrxq, pi->nofldtxq, pi->nofldrxq); 897228561Snp } else 898218792Snp#endif 899228561Snp device_printf(dev, "%d txq, %d rxq\n", pi->ntxq, pi->nrxq); 900218792Snp 901218792Snp cxgbe_sysctls(pi); 902218792Snp 903218792Snp return (0); 904218792Snp} 905218792Snp 906218792Snpstatic int 907218792Snpcxgbe_detach(device_t dev) 908218792Snp{ 909218792Snp struct port_info *pi = device_get_softc(dev); 910218792Snp struct adapter *sc = pi->adapter; 911228561Snp struct ifnet *ifp = pi->ifp; 912218792Snp 913218792Snp /* Tell if_ioctl and if_init that the port is going away */ 914218792Snp ADAPTER_LOCK(sc); 915218792Snp SET_DOOMED(pi); 916218792Snp wakeup(&sc->flags); 917218792Snp while (IS_BUSY(sc)) 918218792Snp mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0); 919218792Snp SET_BUSY(sc); 920218792Snp ADAPTER_UNLOCK(sc); 921218792Snp 922237263Snp if (pi->vlan_c) 923237263Snp EVENTHANDLER_DEREGISTER(vlan_config, pi->vlan_c); 924237263Snp 925228561Snp PORT_LOCK(pi); 926228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 927228561Snp callout_stop(&pi->tick); 928228561Snp PORT_UNLOCK(pi); 929228561Snp callout_drain(&pi->tick); 930218792Snp 931228561Snp /* Let detach proceed even if these fail. */ 932228561Snp cxgbe_uninit_synchronized(pi); 933228561Snp port_full_uninit(pi); 934219286Snp 935218792Snp ifmedia_removeall(&pi->media); 936218792Snp ether_ifdetach(pi->ifp); 937218792Snp if_free(pi->ifp); 938218792Snp 939218792Snp ADAPTER_LOCK(sc); 940218792Snp CLR_BUSY(sc); 941218792Snp wakeup_one(&sc->flags); 942218792Snp ADAPTER_UNLOCK(sc); 943218792Snp 944218792Snp return (0); 945218792Snp} 946218792Snp 947218792Snpstatic void 948218792Snpcxgbe_init(void *arg) 949218792Snp{ 950218792Snp struct port_info *pi = arg; 951218792Snp struct adapter *sc = pi->adapter; 952218792Snp 953218792Snp ADAPTER_LOCK(sc); 954218792Snp cxgbe_init_locked(pi); /* releases adapter lock */ 955218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 956218792Snp} 957218792Snp 958218792Snpstatic int 959218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) 960218792Snp{ 961218792Snp int rc = 0, mtu, flags; 962218792Snp struct port_info *pi = ifp->if_softc; 963218792Snp struct adapter *sc = pi->adapter; 964218792Snp struct ifreq *ifr = (struct ifreq *)data; 965218792Snp uint32_t mask; 966218792Snp 967218792Snp switch (cmd) { 968218792Snp case SIOCSIFMTU: 969218792Snp ADAPTER_LOCK(sc); 970218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 971218792Snp if (rc) { 972218792Snpfail: 973218792Snp ADAPTER_UNLOCK(sc); 974218792Snp return (rc); 975218792Snp } 976218792Snp 977218792Snp mtu = ifr->ifr_mtu; 978218792Snp if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) { 979218792Snp rc = EINVAL; 980218792Snp } else { 981218792Snp ifp->if_mtu = mtu; 982218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 983218792Snp t4_update_fl_bufsize(ifp); 984218792Snp PORT_LOCK(pi); 985218792Snp rc = update_mac_settings(pi, XGMAC_MTU); 986218792Snp PORT_UNLOCK(pi); 987218792Snp } 988218792Snp } 989218792Snp ADAPTER_UNLOCK(sc); 990218792Snp break; 991218792Snp 992218792Snp case SIOCSIFFLAGS: 993218792Snp ADAPTER_LOCK(sc); 994218792Snp if (IS_DOOMED(pi)) { 995218792Snp rc = ENXIO; 996218792Snp goto fail; 997218792Snp } 998218792Snp if (ifp->if_flags & IFF_UP) { 999218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1000218792Snp flags = pi->if_flags; 1001218792Snp if ((ifp->if_flags ^ flags) & 1002218792Snp (IFF_PROMISC | IFF_ALLMULTI)) { 1003218792Snp if (IS_BUSY(sc)) { 1004218792Snp rc = EBUSY; 1005218792Snp goto fail; 1006218792Snp } 1007218792Snp PORT_LOCK(pi); 1008218792Snp rc = update_mac_settings(pi, 1009218792Snp XGMAC_PROMISC | XGMAC_ALLMULTI); 1010218792Snp PORT_UNLOCK(pi); 1011218792Snp } 1012218792Snp ADAPTER_UNLOCK(sc); 1013218792Snp } else 1014218792Snp rc = cxgbe_init_locked(pi); 1015218792Snp pi->if_flags = ifp->if_flags; 1016218792Snp } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1017218792Snp rc = cxgbe_uninit_locked(pi); 1018218792Snp else 1019218792Snp ADAPTER_UNLOCK(sc); 1020218792Snp 1021218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 1022218792Snp break; 1023218792Snp 1024218792Snp case SIOCADDMULTI: 1025218792Snp case SIOCDELMULTI: /* these two can be called with a mutex held :-( */ 1026218792Snp ADAPTER_LOCK(sc); 1027218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 1028218792Snp if (rc) 1029218792Snp goto fail; 1030218792Snp 1031218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1032218792Snp PORT_LOCK(pi); 1033218792Snp rc = update_mac_settings(pi, XGMAC_MCADDRS); 1034218792Snp PORT_UNLOCK(pi); 1035218792Snp } 1036218792Snp ADAPTER_UNLOCK(sc); 1037218792Snp break; 1038218792Snp 1039218792Snp case SIOCSIFCAP: 1040218792Snp ADAPTER_LOCK(sc); 1041218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 1042218792Snp if (rc) 1043218792Snp goto fail; 1044218792Snp 1045218792Snp mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1046218792Snp if (mask & IFCAP_TXCSUM) { 1047218792Snp ifp->if_capenable ^= IFCAP_TXCSUM; 1048218792Snp ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 1049218792Snp 1050237831Snp if (IFCAP_TSO4 & ifp->if_capenable && 1051218792Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1052237799Snp ifp->if_capenable &= ~IFCAP_TSO4; 1053218792Snp if_printf(ifp, 1054237831Snp "tso4 disabled due to -txcsum.\n"); 1055218792Snp } 1056218792Snp } 1057237799Snp if (mask & IFCAP_TXCSUM_IPV6) { 1058237799Snp ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 1059237799Snp ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); 1060237799Snp 1061237799Snp if (IFCAP_TSO6 & ifp->if_capenable && 1062237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1063237799Snp ifp->if_capenable &= ~IFCAP_TSO6; 1064237799Snp if_printf(ifp, 1065237799Snp "tso6 disabled due to -txcsum6.\n"); 1066237799Snp } 1067237799Snp } 1068218792Snp if (mask & IFCAP_RXCSUM) 1069218792Snp ifp->if_capenable ^= IFCAP_RXCSUM; 1070237799Snp if (mask & IFCAP_RXCSUM_IPV6) 1071237799Snp ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 1072237799Snp 1073237799Snp /* 1074237799Snp * Note that we leave CSUM_TSO alone (it is always set). The 1075237799Snp * kernel takes both IFCAP_TSOx and CSUM_TSO into account before 1076237799Snp * sending a TSO request our way, so it's sufficient to toggle 1077237799Snp * IFCAP_TSOx only. 1078237799Snp */ 1079218792Snp if (mask & IFCAP_TSO4) { 1080237799Snp if (!(IFCAP_TSO4 & ifp->if_capenable) && 1081237799Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1082237799Snp if_printf(ifp, "enable txcsum first.\n"); 1083237799Snp rc = EAGAIN; 1084237799Snp goto fail; 1085237799Snp } 1086218792Snp ifp->if_capenable ^= IFCAP_TSO4; 1087218792Snp } 1088237799Snp if (mask & IFCAP_TSO6) { 1089237799Snp if (!(IFCAP_TSO6 & ifp->if_capenable) && 1090237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1091237799Snp if_printf(ifp, "enable txcsum6 first.\n"); 1092237799Snp rc = EAGAIN; 1093237799Snp goto fail; 1094237799Snp } 1095237799Snp ifp->if_capenable ^= IFCAP_TSO6; 1096237799Snp } 1097218792Snp if (mask & IFCAP_LRO) { 1098237819Snp#if defined(INET) || defined(INET6) 1099218792Snp int i; 1100218792Snp struct sge_rxq *rxq; 1101218792Snp 1102218792Snp ifp->if_capenable ^= IFCAP_LRO; 1103218792Snp for_each_rxq(pi, i, rxq) { 1104218792Snp if (ifp->if_capenable & IFCAP_LRO) 1105228561Snp rxq->iq.flags |= IQ_LRO_ENABLED; 1106218792Snp else 1107228561Snp rxq->iq.flags &= ~IQ_LRO_ENABLED; 1108218792Snp } 1109218792Snp#endif 1110218792Snp } 1111237263Snp#ifdef TCP_OFFLOAD 1112228561Snp if (mask & IFCAP_TOE) { 1113228561Snp int enable = (ifp->if_capenable ^ mask) & IFCAP_TOE; 1114228561Snp 1115228561Snp rc = toe_capability(pi, enable); 1116228561Snp if (rc != 0) 1117228561Snp goto fail; 1118228561Snp 1119228561Snp ifp->if_capenable ^= mask; 1120218792Snp } 1121218792Snp#endif 1122218792Snp if (mask & IFCAP_VLAN_HWTAGGING) { 1123218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1124218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1125218792Snp PORT_LOCK(pi); 1126218792Snp rc = update_mac_settings(pi, XGMAC_VLANEX); 1127218792Snp PORT_UNLOCK(pi); 1128218792Snp } 1129218792Snp } 1130218792Snp if (mask & IFCAP_VLAN_MTU) { 1131218792Snp ifp->if_capenable ^= IFCAP_VLAN_MTU; 1132218792Snp 1133218792Snp /* Need to find out how to disable auto-mtu-inflation */ 1134218792Snp } 1135218792Snp if (mask & IFCAP_VLAN_HWTSO) 1136218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1137218792Snp if (mask & IFCAP_VLAN_HWCSUM) 1138218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 1139218792Snp 1140218792Snp#ifdef VLAN_CAPABILITIES 1141218792Snp VLAN_CAPABILITIES(ifp); 1142218792Snp#endif 1143218792Snp ADAPTER_UNLOCK(sc); 1144218792Snp break; 1145218792Snp 1146218792Snp case SIOCSIFMEDIA: 1147218792Snp case SIOCGIFMEDIA: 1148218792Snp ifmedia_ioctl(ifp, ifr, &pi->media, cmd); 1149218792Snp break; 1150218792Snp 1151218792Snp default: 1152218792Snp rc = ether_ioctl(ifp, cmd, data); 1153218792Snp } 1154218792Snp 1155218792Snp return (rc); 1156218792Snp} 1157218792Snp 1158218792Snpstatic int 1159218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m) 1160218792Snp{ 1161218792Snp struct port_info *pi = ifp->if_softc; 1162218792Snp struct adapter *sc = pi->adapter; 1163218792Snp struct sge_txq *txq = &sc->sge.txq[pi->first_txq]; 1164218792Snp struct buf_ring *br; 1165218792Snp int rc; 1166218792Snp 1167218792Snp M_ASSERTPKTHDR(m); 1168218792Snp 1169228561Snp if (__predict_false(pi->link_cfg.link_ok == 0)) { 1170218792Snp m_freem(m); 1171228561Snp return (ENETDOWN); 1172218792Snp } 1173218792Snp 1174218792Snp if (m->m_flags & M_FLOWID) 1175218792Snp txq += (m->m_pkthdr.flowid % pi->ntxq); 1176220873Snp br = txq->br; 1177218792Snp 1178218792Snp if (TXQ_TRYLOCK(txq) == 0) { 1179228561Snp struct sge_eq *eq = &txq->eq; 1180228561Snp 1181218792Snp /* 1182228561Snp * It is possible that t4_eth_tx finishes up and releases the 1183228561Snp * lock between the TRYLOCK above and the drbr_enqueue here. We 1184228561Snp * need to make sure that this mbuf doesn't just sit there in 1185228561Snp * the drbr. 1186218792Snp */ 1187218792Snp 1188228561Snp rc = drbr_enqueue(ifp, br, m); 1189228561Snp if (rc == 0 && callout_pending(&eq->tx_callout) == 0 && 1190228561Snp !(eq->flags & EQ_DOOMED)) 1191228561Snp callout_reset(&eq->tx_callout, 1, t4_tx_callout, eq); 1192228561Snp return (rc); 1193218792Snp } 1194218792Snp 1195218792Snp /* 1196218792Snp * txq->m is the mbuf that is held up due to a temporary shortage of 1197218792Snp * resources and it should be put on the wire first. Then what's in 1198218792Snp * drbr and finally the mbuf that was just passed in to us. 1199218792Snp * 1200218792Snp * Return code should indicate the fate of the mbuf that was passed in 1201218792Snp * this time. 1202218792Snp */ 1203218792Snp 1204218792Snp TXQ_LOCK_ASSERT_OWNED(txq); 1205218792Snp if (drbr_needs_enqueue(ifp, br) || txq->m) { 1206218792Snp 1207218792Snp /* Queued for transmission. */ 1208218792Snp 1209218792Snp rc = drbr_enqueue(ifp, br, m); 1210218792Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 1211218792Snp (void) t4_eth_tx(ifp, txq, m); 1212218792Snp TXQ_UNLOCK(txq); 1213218792Snp return (rc); 1214218792Snp } 1215218792Snp 1216218792Snp /* Direct transmission. */ 1217218792Snp rc = t4_eth_tx(ifp, txq, m); 1218218792Snp if (rc != 0 && txq->m) 1219218792Snp rc = 0; /* held, will be transmitted soon (hopefully) */ 1220218792Snp 1221218792Snp TXQ_UNLOCK(txq); 1222218792Snp return (rc); 1223218792Snp} 1224218792Snp 1225218792Snpstatic void 1226218792Snpcxgbe_qflush(struct ifnet *ifp) 1227218792Snp{ 1228218792Snp struct port_info *pi = ifp->if_softc; 1229220649Snp struct sge_txq *txq; 1230220649Snp int i; 1231220649Snp struct mbuf *m; 1232218792Snp 1233228561Snp /* queues do not exist if !PORT_INIT_DONE. */ 1234228561Snp if (pi->flags & PORT_INIT_DONE) { 1235220649Snp for_each_txq(pi, i, txq) { 1236220649Snp TXQ_LOCK(txq); 1237220649Snp m_freem(txq->m); 1238228561Snp txq->m = NULL; 1239220873Snp while ((m = buf_ring_dequeue_sc(txq->br)) != NULL) 1240220649Snp m_freem(m); 1241220649Snp TXQ_UNLOCK(txq); 1242220649Snp } 1243220649Snp } 1244220649Snp if_qflush(ifp); 1245218792Snp} 1246218792Snp 1247218792Snpstatic int 1248218792Snpcxgbe_media_change(struct ifnet *ifp) 1249218792Snp{ 1250218792Snp struct port_info *pi = ifp->if_softc; 1251218792Snp 1252218792Snp device_printf(pi->dev, "%s unimplemented.\n", __func__); 1253218792Snp 1254218792Snp return (EOPNOTSUPP); 1255218792Snp} 1256218792Snp 1257218792Snpstatic void 1258218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1259218792Snp{ 1260218792Snp struct port_info *pi = ifp->if_softc; 1261218792Snp struct ifmedia_entry *cur = pi->media.ifm_cur; 1262218792Snp int speed = pi->link_cfg.speed; 1263218792Snp int data = (pi->port_type << 8) | pi->mod_type; 1264218792Snp 1265218792Snp if (cur->ifm_data != data) { 1266218792Snp build_medialist(pi); 1267218792Snp cur = pi->media.ifm_cur; 1268218792Snp } 1269218792Snp 1270218792Snp ifmr->ifm_status = IFM_AVALID; 1271218792Snp if (!pi->link_cfg.link_ok) 1272218792Snp return; 1273218792Snp 1274218792Snp ifmr->ifm_status |= IFM_ACTIVE; 1275218792Snp 1276218792Snp /* active and current will differ iff current media is autoselect. */ 1277218792Snp if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO) 1278218792Snp return; 1279218792Snp 1280218792Snp ifmr->ifm_active = IFM_ETHER | IFM_FDX; 1281218792Snp if (speed == SPEED_10000) 1282218792Snp ifmr->ifm_active |= IFM_10G_T; 1283218792Snp else if (speed == SPEED_1000) 1284218792Snp ifmr->ifm_active |= IFM_1000_T; 1285218792Snp else if (speed == SPEED_100) 1286218792Snp ifmr->ifm_active |= IFM_100_TX; 1287218792Snp else if (speed == SPEED_10) 1288218792Snp ifmr->ifm_active |= IFM_10_T; 1289218792Snp else 1290218792Snp KASSERT(0, ("%s: link up but speed unknown (%u)", __func__, 1291218792Snp speed)); 1292218792Snp} 1293218792Snp 1294218792Snpvoid 1295218792Snpt4_fatal_err(struct adapter *sc) 1296218792Snp{ 1297218792Snp t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0); 1298218792Snp t4_intr_disable(sc); 1299218792Snp log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n", 1300218792Snp device_get_nameunit(sc->dev)); 1301218792Snp} 1302218792Snp 1303218792Snpstatic int 1304218792Snpmap_bars(struct adapter *sc) 1305218792Snp{ 1306218792Snp sc->regs_rid = PCIR_BAR(0); 1307218792Snp sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1308218792Snp &sc->regs_rid, RF_ACTIVE); 1309218792Snp if (sc->regs_res == NULL) { 1310218792Snp device_printf(sc->dev, "cannot map registers.\n"); 1311218792Snp return (ENXIO); 1312218792Snp } 1313218792Snp sc->bt = rman_get_bustag(sc->regs_res); 1314218792Snp sc->bh = rman_get_bushandle(sc->regs_res); 1315218792Snp sc->mmio_len = rman_get_size(sc->regs_res); 1316218792Snp 1317218792Snp sc->msix_rid = PCIR_BAR(4); 1318218792Snp sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1319218792Snp &sc->msix_rid, RF_ACTIVE); 1320218792Snp if (sc->msix_res == NULL) { 1321218792Snp device_printf(sc->dev, "cannot map MSI-X BAR.\n"); 1322218792Snp return (ENXIO); 1323218792Snp } 1324218792Snp 1325218792Snp return (0); 1326218792Snp} 1327218792Snp 1328218792Snpstatic void 1329218792Snpsetup_memwin(struct adapter *sc) 1330218792Snp{ 1331237587Snp uint32_t bar0; 1332218792Snp 1333237587Snp /* 1334237587Snp * Read low 32b of bar0 indirectly via the hardware backdoor mechanism. 1335237587Snp * Works from within PCI passthrough environments too, where 1336237587Snp * rman_get_start() can return a different value. We need to program 1337237587Snp * the memory window decoders with the actual addresses that will be 1338237587Snp * coming across the PCIe link. 1339237587Snp */ 1340237587Snp bar0 = t4_hw_pci_read_cfg4(sc, PCIR_BAR(0)); 1341237587Snp bar0 &= (uint32_t) PCIM_BAR_MEM_BASE; 1342218792Snp 1343218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 0), 1344218792Snp (bar0 + MEMWIN0_BASE) | V_BIR(0) | 1345218792Snp V_WINDOW(ilog2(MEMWIN0_APERTURE) - 10)); 1346218792Snp 1347218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 1), 1348218792Snp (bar0 + MEMWIN1_BASE) | V_BIR(0) | 1349218792Snp V_WINDOW(ilog2(MEMWIN1_APERTURE) - 10)); 1350218792Snp 1351218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2), 1352218792Snp (bar0 + MEMWIN2_BASE) | V_BIR(0) | 1353218792Snp V_WINDOW(ilog2(MEMWIN2_APERTURE) - 10)); 1354237587Snp 1355237587Snp /* flush */ 1356237587Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2)); 1357218792Snp} 1358218792Snp 1359218792Snpstatic int 1360218792Snpcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g, 1361218792Snp struct intrs_and_queues *iaq) 1362218792Snp{ 1363228561Snp int rc, itype, navail, nrxq10g, nrxq1g, n; 1364228561Snp int nofldrxq10g = 0, nofldrxq1g = 0; 1365218792Snp 1366218792Snp bzero(iaq, sizeof(*iaq)); 1367218792Snp 1368228561Snp iaq->ntxq10g = t4_ntxq10g; 1369228561Snp iaq->ntxq1g = t4_ntxq1g; 1370228561Snp iaq->nrxq10g = nrxq10g = t4_nrxq10g; 1371228561Snp iaq->nrxq1g = nrxq1g = t4_nrxq1g; 1372237263Snp#ifdef TCP_OFFLOAD 1373237463Snp if (is_offload(sc)) { 1374237463Snp iaq->nofldtxq10g = t4_nofldtxq10g; 1375237463Snp iaq->nofldtxq1g = t4_nofldtxq1g; 1376237463Snp iaq->nofldrxq10g = nofldrxq10g = t4_nofldrxq10g; 1377237463Snp iaq->nofldrxq1g = nofldrxq1g = t4_nofldrxq1g; 1378237463Snp } 1379228561Snp#endif 1380228561Snp 1381219944Snp for (itype = INTR_MSIX; itype; itype >>= 1) { 1382218792Snp 1383228561Snp if ((itype & t4_intr_types) == 0) 1384218792Snp continue; /* not allowed */ 1385218792Snp 1386219944Snp if (itype == INTR_MSIX) 1387218792Snp navail = pci_msix_count(sc->dev); 1388219944Snp else if (itype == INTR_MSI) 1389218792Snp navail = pci_msi_count(sc->dev); 1390218792Snp else 1391218792Snp navail = 1; 1392228561Snprestart: 1393218792Snp if (navail == 0) 1394218792Snp continue; 1395218792Snp 1396218792Snp iaq->intr_type = itype; 1397228561Snp iaq->intr_flags = 0; 1398218792Snp 1399228561Snp /* 1400228561Snp * Best option: an interrupt vector for errors, one for the 1401228561Snp * firmware event queue, and one each for each rxq (NIC as well 1402228561Snp * as offload). 1403228561Snp */ 1404228561Snp iaq->nirq = T4_EXTRA_INTR; 1405228561Snp iaq->nirq += n10g * (nrxq10g + nofldrxq10g); 1406228561Snp iaq->nirq += n1g * (nrxq1g + nofldrxq1g); 1407228561Snp if (iaq->nirq <= navail && 1408228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) { 1409228561Snp iaq->intr_flags |= INTR_DIRECT; 1410228561Snp goto allocate; 1411228561Snp } 1412218792Snp 1413228561Snp /* 1414228561Snp * Second best option: an interrupt vector for errors, one for 1415228561Snp * the firmware event queue, and one each for either NIC or 1416228561Snp * offload rxq's. 1417228561Snp */ 1418228561Snp iaq->nirq = T4_EXTRA_INTR; 1419228561Snp iaq->nirq += n10g * max(nrxq10g, nofldrxq10g); 1420228561Snp iaq->nirq += n1g * max(nrxq1g, nofldrxq1g); 1421228561Snp if (iaq->nirq <= navail && 1422228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) 1423228561Snp goto allocate; 1424218792Snp 1425228561Snp /* 1426228561Snp * Next best option: an interrupt vector for errors, one for the 1427228561Snp * firmware event queue, and at least one per port. At this 1428228561Snp * point we know we'll have to downsize nrxq or nofldrxq to fit 1429228561Snp * what's available to us. 1430228561Snp */ 1431228561Snp iaq->nirq = T4_EXTRA_INTR; 1432228561Snp iaq->nirq += n10g + n1g; 1433228561Snp if (iaq->nirq <= navail) { 1434228561Snp int leftover = navail - iaq->nirq; 1435218792Snp 1436228561Snp if (n10g > 0) { 1437228561Snp int target = max(nrxq10g, nofldrxq10g); 1438219944Snp 1439228561Snp n = 1; 1440228561Snp while (n < target && leftover >= n10g) { 1441228561Snp leftover -= n10g; 1442228561Snp iaq->nirq += n10g; 1443228561Snp n++; 1444228561Snp } 1445228561Snp iaq->nrxq10g = min(n, nrxq10g); 1446237263Snp#ifdef TCP_OFFLOAD 1447237463Snp if (is_offload(sc)) 1448237463Snp iaq->nofldrxq10g = min(n, nofldrxq10g); 1449228561Snp#endif 1450228561Snp } 1451218792Snp 1452228561Snp if (n1g > 0) { 1453228561Snp int target = max(nrxq1g, nofldrxq1g); 1454219944Snp 1455228561Snp n = 1; 1456228561Snp while (n < target && leftover >= n1g) { 1457228561Snp leftover -= n1g; 1458228561Snp iaq->nirq += n1g; 1459228561Snp n++; 1460219944Snp } 1461228561Snp iaq->nrxq1g = min(n, nrxq1g); 1462237263Snp#ifdef TCP_OFFLOAD 1463237463Snp if (is_offload(sc)) 1464237463Snp iaq->nofldrxq1g = min(n, nofldrxq1g); 1465228561Snp#endif 1466219944Snp } 1467219944Snp 1468228561Snp if (itype != INTR_MSI || powerof2(iaq->nirq)) 1469228561Snp goto allocate; 1470218792Snp } 1471218792Snp 1472228561Snp /* 1473228561Snp * Least desirable option: one interrupt vector for everything. 1474228561Snp */ 1475228561Snp iaq->nirq = iaq->nrxq10g = iaq->nrxq1g = 1; 1476237263Snp#ifdef TCP_OFFLOAD 1477237463Snp if (is_offload(sc)) 1478237463Snp iaq->nofldrxq10g = iaq->nofldrxq1g = 1; 1479228561Snp#endif 1480228561Snp 1481228561Snpallocate: 1482218792Snp navail = iaq->nirq; 1483218792Snp rc = 0; 1484219944Snp if (itype == INTR_MSIX) 1485218792Snp rc = pci_alloc_msix(sc->dev, &navail); 1486219944Snp else if (itype == INTR_MSI) 1487218792Snp rc = pci_alloc_msi(sc->dev, &navail); 1488218792Snp 1489218792Snp if (rc == 0) { 1490218792Snp if (navail == iaq->nirq) 1491218792Snp return (0); 1492218792Snp 1493218792Snp /* 1494218792Snp * Didn't get the number requested. Use whatever number 1495218792Snp * the kernel is willing to allocate (it's in navail). 1496218792Snp */ 1497228561Snp device_printf(sc->dev, "fewer vectors than requested, " 1498228561Snp "type=%d, req=%d, rcvd=%d; will downshift req.\n", 1499228561Snp itype, iaq->nirq, navail); 1500218792Snp pci_release_msi(sc->dev); 1501228561Snp goto restart; 1502218792Snp } 1503218792Snp 1504218792Snp device_printf(sc->dev, 1505218792Snp "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n", 1506218792Snp itype, rc, iaq->nirq, navail); 1507218792Snp } 1508218792Snp 1509218792Snp device_printf(sc->dev, 1510218792Snp "failed to find a usable interrupt type. " 1511228561Snp "allowed=%d, msi-x=%d, msi=%d, intx=1", t4_intr_types, 1512218792Snp pci_msix_count(sc->dev), pci_msi_count(sc->dev)); 1513218792Snp 1514218792Snp return (ENXIO); 1515218792Snp} 1516218792Snp 1517218792Snp/* 1518228561Snp * Install a compatible firmware (if required), establish contact with it (by 1519228561Snp * saying hello), and reset the device. If we end up as the master driver, 1520228561Snp * partition adapter resources by providing a configuration file to the 1521228561Snp * firmware. 1522218792Snp */ 1523218792Snpstatic int 1524218792Snpprep_firmware(struct adapter *sc) 1525218792Snp{ 1526228561Snp const struct firmware *fw = NULL, *cfg = NULL, *default_cfg; 1527218792Snp int rc; 1528218792Snp enum dev_state state; 1529218792Snp 1530228561Snp default_cfg = firmware_get(T4_CFGNAME); 1531228561Snp 1532218792Snp /* Check firmware version and install a different one if necessary */ 1533218792Snp rc = t4_check_fw_version(sc); 1534234831Snp snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u", 1535234831Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1536234831Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1537234831Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1538234831Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 1539228561Snp if (rc != 0) { 1540219287Snp uint32_t v = 0; 1541218792Snp 1542218792Snp fw = firmware_get(T4_FWNAME); 1543219287Snp if (fw != NULL) { 1544219287Snp const struct fw_hdr *hdr = (const void *)fw->data; 1545219287Snp 1546219287Snp v = ntohl(hdr->fw_ver); 1547219287Snp 1548219287Snp /* 1549219287Snp * The firmware module will not be used if it isn't the 1550219287Snp * same major version as what the driver was compiled 1551228561Snp * with. 1552219287Snp */ 1553219287Snp if (G_FW_HDR_FW_VER_MAJOR(v) != FW_VERSION_MAJOR) { 1554219287Snp device_printf(sc->dev, 1555219287Snp "Found firmware image but version %d " 1556219287Snp "can not be used with this driver (%d)\n", 1557219287Snp G_FW_HDR_FW_VER_MAJOR(v), FW_VERSION_MAJOR); 1558219287Snp 1559219287Snp firmware_put(fw, FIRMWARE_UNLOAD); 1560219287Snp fw = NULL; 1561219287Snp } 1562218792Snp } 1563218792Snp 1564228561Snp if (fw == NULL && rc < 0) { 1565219287Snp device_printf(sc->dev, "No usable firmware. " 1566228561Snp "card has %d.%d.%d, driver compiled with %d.%d.%d", 1567219287Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1568219287Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1569219287Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1570219287Snp FW_VERSION_MAJOR, FW_VERSION_MINOR, 1571228561Snp FW_VERSION_MICRO); 1572228561Snp rc = EAGAIN; 1573228561Snp goto done; 1574219287Snp } 1575219287Snp 1576219287Snp /* 1577219287Snp * Always upgrade, even for minor/micro/build mismatches. 1578219287Snp * Downgrade only for a major version mismatch or if 1579219287Snp * force_firmware_install was specified. 1580219287Snp */ 1581228561Snp if (fw != NULL && (rc < 0 || v > sc->params.fw_vers)) { 1582218792Snp device_printf(sc->dev, 1583219287Snp "installing firmware %d.%d.%d.%d on card.\n", 1584219287Snp G_FW_HDR_FW_VER_MAJOR(v), G_FW_HDR_FW_VER_MINOR(v), 1585219287Snp G_FW_HDR_FW_VER_MICRO(v), G_FW_HDR_FW_VER_BUILD(v)); 1586219287Snp 1587219287Snp rc = -t4_load_fw(sc, fw->data, fw->datasize); 1588219287Snp if (rc != 0) { 1589219287Snp device_printf(sc->dev, 1590219287Snp "failed to install firmware: %d\n", rc); 1591228561Snp goto done; 1592219287Snp } else { 1593219287Snp /* refresh */ 1594219287Snp (void) t4_check_fw_version(sc); 1595234831Snp snprintf(sc->fw_version, 1596234831Snp sizeof(sc->fw_version), "%u.%u.%u.%u", 1597234831Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1598234831Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1599234831Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1600234831Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 1601219287Snp } 1602218792Snp } 1603218792Snp } 1604218792Snp 1605228561Snp /* Contact firmware. */ 1606228561Snp rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state); 1607218792Snp if (rc < 0) { 1608218792Snp rc = -rc; 1609218792Snp device_printf(sc->dev, 1610218792Snp "failed to connect to the firmware: %d.\n", rc); 1611228561Snp goto done; 1612218792Snp } 1613228561Snp if (rc == sc->mbox) 1614228561Snp sc->flags |= MASTER_PF; 1615218792Snp 1616218792Snp /* Reset device */ 1617218792Snp rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST); 1618218792Snp if (rc != 0) { 1619218792Snp device_printf(sc->dev, "firmware reset failed: %d.\n", rc); 1620218792Snp if (rc != ETIMEDOUT && rc != EIO) 1621218792Snp t4_fw_bye(sc, sc->mbox); 1622228561Snp goto done; 1623218792Snp } 1624218792Snp 1625228561Snp /* Partition adapter resources as specified in the config file. */ 1626228561Snp if (sc->flags & MASTER_PF) { 1627228561Snp if (strncmp(t4_cfg_file, "default", sizeof(t4_cfg_file))) { 1628228561Snp char s[32]; 1629228561Snp 1630228561Snp snprintf(s, sizeof(s), "t4fw_cfg_%s", t4_cfg_file); 1631228561Snp cfg = firmware_get(s); 1632228561Snp if (cfg == NULL) { 1633228561Snp device_printf(sc->dev, 1634228561Snp "unable to locate %s module, " 1635228561Snp "will use default config file.\n", s); 1636228561Snp } 1637228561Snp } 1638228561Snp 1639228561Snp rc = partition_resources(sc, cfg ? cfg : default_cfg); 1640228561Snp if (rc != 0) 1641228561Snp goto done; /* error message displayed already */ 1642228561Snp } 1643228561Snp 1644218792Snp sc->flags |= FW_OK; 1645218792Snp 1646228561Snpdone: 1647228561Snp if (fw != NULL) 1648228561Snp firmware_put(fw, FIRMWARE_UNLOAD); 1649228561Snp if (cfg != NULL) 1650228561Snp firmware_put(cfg, FIRMWARE_UNLOAD); 1651228561Snp if (default_cfg != NULL) 1652228561Snp firmware_put(default_cfg, FIRMWARE_UNLOAD); 1653228561Snp 1654228561Snp return (rc); 1655218792Snp} 1656218792Snp 1657228561Snp#define FW_PARAM_DEV(param) \ 1658228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ 1659228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) 1660228561Snp#define FW_PARAM_PFVF(param) \ 1661228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ 1662228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)) 1663228561Snp 1664228561Snp/* 1665228561Snp * Upload configuration file to card's memory. 1666228561Snp */ 1667218792Snpstatic int 1668228561Snpupload_config_file(struct adapter *sc, const struct firmware *fw, uint32_t *mt, 1669228561Snp uint32_t *ma) 1670222551Snp{ 1671228561Snp int rc, i; 1672228561Snp uint32_t param, val, mtype, maddr, bar, off, win, remaining; 1673228561Snp const uint32_t *b; 1674222551Snp 1675228561Snp /* Figure out where the firmware wants us to upload it. */ 1676228561Snp param = FW_PARAM_DEV(CF); 1677228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 1678222551Snp if (rc != 0) { 1679228561Snp /* Firmwares without config file support will fail this way */ 1680222551Snp device_printf(sc->dev, 1681228561Snp "failed to query config file location: %d.\n", rc); 1682222551Snp return (rc); 1683222551Snp } 1684228561Snp *mt = mtype = G_FW_PARAMS_PARAM_Y(val); 1685228561Snp *ma = maddr = G_FW_PARAMS_PARAM_Z(val) << 16; 1686222551Snp 1687228561Snp if (maddr & 3) { 1688228561Snp device_printf(sc->dev, 1689228561Snp "cannot upload config file (type %u, addr %x).\n", 1690228561Snp mtype, maddr); 1691228561Snp return (EFAULT); 1692228561Snp } 1693222551Snp 1694228561Snp /* Translate mtype/maddr to an address suitable for the PCIe window */ 1695228561Snp val = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 1696228561Snp val &= F_EDRAM0_ENABLE | F_EDRAM1_ENABLE | F_EXT_MEM_ENABLE; 1697228561Snp switch (mtype) { 1698228561Snp case FW_MEMTYPE_CF_EDC0: 1699228561Snp if (!(val & F_EDRAM0_ENABLE)) 1700228561Snp goto err; 1701228561Snp bar = t4_read_reg(sc, A_MA_EDRAM0_BAR); 1702228561Snp maddr += G_EDRAM0_BASE(bar) << 20; 1703228561Snp break; 1704228561Snp 1705228561Snp case FW_MEMTYPE_CF_EDC1: 1706228561Snp if (!(val & F_EDRAM1_ENABLE)) 1707228561Snp goto err; 1708228561Snp bar = t4_read_reg(sc, A_MA_EDRAM1_BAR); 1709228561Snp maddr += G_EDRAM1_BASE(bar) << 20; 1710228561Snp break; 1711228561Snp 1712228561Snp case FW_MEMTYPE_CF_EXTMEM: 1713228561Snp if (!(val & F_EXT_MEM_ENABLE)) 1714228561Snp goto err; 1715228561Snp bar = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 1716228561Snp maddr += G_EXT_MEM_BASE(bar) << 20; 1717228561Snp break; 1718228561Snp 1719228561Snp default: 1720228561Snperr: 1721228561Snp device_printf(sc->dev, 1722228561Snp "cannot upload config file (type %u, enabled %u).\n", 1723228561Snp mtype, val); 1724228561Snp return (EFAULT); 1725228561Snp } 1726228561Snp 1727228561Snp /* 1728228561Snp * Position the PCIe window (we use memwin2) to the 16B aligned area 1729228561Snp * just at/before the upload location. 1730228561Snp */ 1731228561Snp win = maddr & ~0xf; 1732228561Snp off = maddr - win; /* offset from the start of the window. */ 1733228561Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2), win); 1734228561Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2)); 1735228561Snp 1736228561Snp remaining = fw->datasize; 1737228561Snp if (remaining > FLASH_CFG_MAX_SIZE || 1738228561Snp remaining > MEMWIN2_APERTURE - off) { 1739228561Snp device_printf(sc->dev, "cannot upload config file all at once " 1740228561Snp "(size %u, max %u, room %u).\n", 1741228561Snp remaining, FLASH_CFG_MAX_SIZE, MEMWIN2_APERTURE - off); 1742228561Snp return (EFBIG); 1743228561Snp } 1744228561Snp 1745228561Snp /* 1746228561Snp * XXX: sheer laziness. We deliberately added 4 bytes of useless 1747228561Snp * stuffing/comments at the end of the config file so it's ok to simply 1748228561Snp * throw away the last remaining bytes when the config file is not an 1749228561Snp * exact multiple of 4. 1750228561Snp */ 1751228561Snp b = fw->data; 1752228561Snp for (i = 0; remaining >= 4; i += 4, remaining -= 4) 1753228561Snp t4_write_reg(sc, MEMWIN2_BASE + off + i, *b++); 1754228561Snp 1755228561Snp return (rc); 1756222551Snp} 1757222551Snp 1758228561Snp/* 1759228561Snp * Partition chip resources for use between various PFs, VFs, etc. This is done 1760228561Snp * by uploading the firmware configuration file to the adapter and instructing 1761228561Snp * the firmware to process it. 1762228561Snp */ 1763222551Snpstatic int 1764228561Snppartition_resources(struct adapter *sc, const struct firmware *cfg) 1765218792Snp{ 1766218792Snp int rc; 1767228561Snp struct fw_caps_config_cmd caps; 1768228561Snp uint32_t mtype, maddr, finicsum, cfcsum; 1769218792Snp 1770228561Snp rc = cfg ? upload_config_file(sc, cfg, &mtype, &maddr) : ENOENT; 1771228561Snp if (rc != 0) { 1772228561Snp mtype = FW_MEMTYPE_CF_FLASH; 1773228561Snp maddr = t4_flash_cfg_addr(sc); 1774228561Snp } 1775228561Snp 1776228561Snp bzero(&caps, sizeof(caps)); 1777228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1778218792Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1779228561Snp caps.cfvalid_to_len16 = htobe32(F_FW_CAPS_CONFIG_CMD_CFVALID | 1780228561Snp V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) | 1781228561Snp V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(maddr >> 16) | FW_LEN16(caps)); 1782228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 1783228561Snp if (rc != 0) { 1784228561Snp device_printf(sc->dev, 1785228561Snp "failed to pre-process config file: %d.\n", rc); 1786218792Snp return (rc); 1787228561Snp } 1788218792Snp 1789228561Snp finicsum = be32toh(caps.finicsum); 1790228561Snp cfcsum = be32toh(caps.cfcsum); 1791228561Snp if (finicsum != cfcsum) { 1792228561Snp device_printf(sc->dev, 1793228561Snp "WARNING: config file checksum mismatch: %08x %08x\n", 1794228561Snp finicsum, cfcsum); 1795228561Snp } 1796228561Snp sc->cfcsum = cfcsum; 1797218792Snp 1798228561Snp#define LIMIT_CAPS(x) do { \ 1799228561Snp caps.x &= htobe16(t4_##x##_allowed); \ 1800228561Snp sc->x = htobe16(caps.x); \ 1801228561Snp} while (0) 1802228561Snp 1803228561Snp /* 1804228561Snp * Let the firmware know what features will (not) be used so it can tune 1805228561Snp * things accordingly. 1806228561Snp */ 1807228561Snp LIMIT_CAPS(linkcaps); 1808228561Snp LIMIT_CAPS(niccaps); 1809228561Snp LIMIT_CAPS(toecaps); 1810228561Snp LIMIT_CAPS(rdmacaps); 1811228561Snp LIMIT_CAPS(iscsicaps); 1812228561Snp LIMIT_CAPS(fcoecaps); 1813228561Snp#undef LIMIT_CAPS 1814228561Snp 1815228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1816218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE); 1817228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 1818228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), NULL); 1819228561Snp if (rc != 0) { 1820228561Snp device_printf(sc->dev, 1821228561Snp "failed to process config file: %d.\n", rc); 1822228561Snp return (rc); 1823228561Snp } 1824218792Snp 1825228561Snp return (0); 1826218792Snp} 1827218792Snp 1828228561Snp/* 1829228561Snp * Retrieve parameters that are needed (or nice to have) prior to calling 1830228561Snp * t4_sge_init and t4_fw_initialize. 1831228561Snp */ 1832218792Snpstatic int 1833228561Snpget_params__pre_init(struct adapter *sc) 1834218792Snp{ 1835218792Snp int rc; 1836228561Snp uint32_t param[2], val[2]; 1837228561Snp struct fw_devlog_cmd cmd; 1838228561Snp struct devlog_params *dlog = &sc->params.devlog; 1839218792Snp 1840228561Snp param[0] = FW_PARAM_DEV(PORTVEC); 1841228561Snp param[1] = FW_PARAM_DEV(CCLK); 1842228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 1843218792Snp if (rc != 0) { 1844218792Snp device_printf(sc->dev, 1845228561Snp "failed to query parameters (pre_init): %d.\n", rc); 1846228561Snp return (rc); 1847218792Snp } 1848218792Snp 1849218792Snp sc->params.portvec = val[0]; 1850240452Snp sc->params.nports = bitcount32(val[0]); 1851228561Snp sc->params.vpd.cclk = val[1]; 1852218792Snp 1853228561Snp /* Read device log parameters. */ 1854228561Snp bzero(&cmd, sizeof(cmd)); 1855228561Snp cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) | 1856228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1857228561Snp cmd.retval_len16 = htobe32(FW_LEN16(cmd)); 1858228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &cmd, sizeof(cmd), &cmd); 1859228561Snp if (rc != 0) { 1860228561Snp device_printf(sc->dev, 1861228561Snp "failed to get devlog parameters: %d.\n", rc); 1862228561Snp bzero(dlog, sizeof (*dlog)); 1863228561Snp rc = 0; /* devlog isn't critical for device operation */ 1864228561Snp } else { 1865228561Snp val[0] = be32toh(cmd.memtype_devlog_memaddr16_devlog); 1866228561Snp dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(val[0]); 1867228561Snp dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(val[0]) << 4; 1868228561Snp dlog->size = be32toh(cmd.memsize_devlog); 1869228561Snp } 1870228561Snp 1871228561Snp return (rc); 1872228561Snp} 1873228561Snp 1874228561Snp/* 1875228561Snp * Retrieve various parameters that are of interest to the driver. The device 1876228561Snp * has been initialized by the firmware at this point. 1877228561Snp */ 1878228561Snpstatic int 1879228561Snpget_params__post_init(struct adapter *sc) 1880228561Snp{ 1881228561Snp int rc; 1882228561Snp uint32_t param[7], val[7]; 1883228561Snp struct fw_caps_config_cmd caps; 1884228561Snp 1885228561Snp param[0] = FW_PARAM_PFVF(IQFLINT_START); 1886228561Snp param[1] = FW_PARAM_PFVF(EQ_START); 1887228561Snp param[2] = FW_PARAM_PFVF(FILTER_START); 1888228561Snp param[3] = FW_PARAM_PFVF(FILTER_END); 1889228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 4, param, val); 1890228561Snp if (rc != 0) { 1891228561Snp device_printf(sc->dev, 1892228561Snp "failed to query parameters (post_init): %d.\n", rc); 1893228561Snp return (rc); 1894228561Snp } 1895228561Snp 1896228561Snp sc->sge.iq_start = val[0]; 1897228561Snp sc->sge.eq_start = val[1]; 1898228561Snp sc->tids.ftid_base = val[2]; 1899228561Snp sc->tids.nftids = val[3] - val[2] + 1; 1900228561Snp 1901228561Snp /* get capabilites */ 1902228561Snp bzero(&caps, sizeof(caps)); 1903228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1904228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1905228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 1906228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 1907228561Snp if (rc != 0) { 1908228561Snp device_printf(sc->dev, 1909228561Snp "failed to get card capabilities: %d.\n", rc); 1910228561Snp return (rc); 1911228561Snp } 1912228561Snp 1913228561Snp if (caps.toecaps) { 1914218792Snp /* query offload-related parameters */ 1915228561Snp param[0] = FW_PARAM_DEV(NTID); 1916228561Snp param[1] = FW_PARAM_PFVF(SERVER_START); 1917228561Snp param[2] = FW_PARAM_PFVF(SERVER_END); 1918228561Snp param[3] = FW_PARAM_PFVF(TDDP_START); 1919228561Snp param[4] = FW_PARAM_PFVF(TDDP_END); 1920228561Snp param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 1921228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 1922218792Snp if (rc != 0) { 1923218792Snp device_printf(sc->dev, 1924218792Snp "failed to query TOE parameters: %d.\n", rc); 1925228561Snp return (rc); 1926218792Snp } 1927218792Snp sc->tids.ntids = val[0]; 1928218792Snp sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS); 1929218792Snp sc->tids.stid_base = val[1]; 1930218792Snp sc->tids.nstids = val[2] - val[1] + 1; 1931218792Snp sc->vres.ddp.start = val[3]; 1932218792Snp sc->vres.ddp.size = val[4] - val[3] + 1; 1933218792Snp sc->params.ofldq_wr_cred = val[5]; 1934218792Snp sc->params.offload = 1; 1935218792Snp } 1936228561Snp if (caps.rdmacaps) { 1937228561Snp param[0] = FW_PARAM_PFVF(STAG_START); 1938228561Snp param[1] = FW_PARAM_PFVF(STAG_END); 1939228561Snp param[2] = FW_PARAM_PFVF(RQ_START); 1940228561Snp param[3] = FW_PARAM_PFVF(RQ_END); 1941228561Snp param[4] = FW_PARAM_PFVF(PBL_START); 1942228561Snp param[5] = FW_PARAM_PFVF(PBL_END); 1943228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 1944218792Snp if (rc != 0) { 1945218792Snp device_printf(sc->dev, 1946228561Snp "failed to query RDMA parameters(1): %d.\n", rc); 1947228561Snp return (rc); 1948218792Snp } 1949218792Snp sc->vres.stag.start = val[0]; 1950218792Snp sc->vres.stag.size = val[1] - val[0] + 1; 1951218792Snp sc->vres.rq.start = val[2]; 1952218792Snp sc->vres.rq.size = val[3] - val[2] + 1; 1953218792Snp sc->vres.pbl.start = val[4]; 1954218792Snp sc->vres.pbl.size = val[5] - val[4] + 1; 1955228561Snp 1956228561Snp param[0] = FW_PARAM_PFVF(SQRQ_START); 1957228561Snp param[1] = FW_PARAM_PFVF(SQRQ_END); 1958228561Snp param[2] = FW_PARAM_PFVF(CQ_START); 1959228561Snp param[3] = FW_PARAM_PFVF(CQ_END); 1960228561Snp param[4] = FW_PARAM_PFVF(OCQ_START); 1961228561Snp param[5] = FW_PARAM_PFVF(OCQ_END); 1962228561Snp rc = -t4_query_params(sc, 0, 0, 0, 6, param, val); 1963228561Snp if (rc != 0) { 1964228561Snp device_printf(sc->dev, 1965228561Snp "failed to query RDMA parameters(2): %d.\n", rc); 1966228561Snp return (rc); 1967228561Snp } 1968228561Snp sc->vres.qp.start = val[0]; 1969228561Snp sc->vres.qp.size = val[1] - val[0] + 1; 1970228561Snp sc->vres.cq.start = val[2]; 1971228561Snp sc->vres.cq.size = val[3] - val[2] + 1; 1972228561Snp sc->vres.ocq.start = val[4]; 1973228561Snp sc->vres.ocq.size = val[5] - val[4] + 1; 1974218792Snp } 1975228561Snp if (caps.iscsicaps) { 1976228561Snp param[0] = FW_PARAM_PFVF(ISCSI_START); 1977228561Snp param[1] = FW_PARAM_PFVF(ISCSI_END); 1978228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 1979218792Snp if (rc != 0) { 1980218792Snp device_printf(sc->dev, 1981218792Snp "failed to query iSCSI parameters: %d.\n", rc); 1982228561Snp return (rc); 1983218792Snp } 1984218792Snp sc->vres.iscsi.start = val[0]; 1985218792Snp sc->vres.iscsi.size = val[1] - val[0] + 1; 1986218792Snp } 1987218792Snp 1988228561Snp /* These are finalized by FW initialization, load their values now */ 1989228561Snp val[0] = t4_read_reg(sc, A_TP_TIMER_RESOLUTION); 1990228561Snp sc->params.tp.tre = G_TIMERRESOLUTION(val[0]); 1991228561Snp sc->params.tp.dack_re = G_DELAYEDACKRESOLUTION(val[0]); 1992228561Snp t4_read_mtu_tbl(sc, sc->params.mtus, NULL); 1993228561Snp 1994218792Snp return (rc); 1995218792Snp} 1996218792Snp 1997228561Snp#undef FW_PARAM_PFVF 1998228561Snp#undef FW_PARAM_DEV 1999228561Snp 2000218792Snpstatic void 2001218792Snpt4_set_desc(struct adapter *sc) 2002218792Snp{ 2003218792Snp char buf[128]; 2004218792Snp struct adapter_params *p = &sc->params; 2005218792Snp 2006228561Snp snprintf(buf, sizeof(buf), "Chelsio %s %sNIC (rev %d), S/N:%s, E/C:%s", 2007228561Snp p->vpd.id, is_offload(sc) ? "R" : "", p->rev, p->vpd.sn, p->vpd.ec); 2008218792Snp 2009218792Snp device_set_desc_copy(sc->dev, buf); 2010218792Snp} 2011218792Snp 2012218792Snpstatic void 2013218792Snpbuild_medialist(struct port_info *pi) 2014218792Snp{ 2015218792Snp struct ifmedia *media = &pi->media; 2016218792Snp int data, m; 2017218792Snp 2018218792Snp PORT_LOCK(pi); 2019218792Snp 2020218792Snp ifmedia_removeall(media); 2021218792Snp 2022218792Snp m = IFM_ETHER | IFM_FDX; 2023218792Snp data = (pi->port_type << 8) | pi->mod_type; 2024218792Snp 2025218792Snp switch(pi->port_type) { 2026218792Snp case FW_PORT_TYPE_BT_XFI: 2027218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2028218792Snp break; 2029218792Snp 2030218792Snp case FW_PORT_TYPE_BT_XAUI: 2031218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2032218792Snp /* fall through */ 2033218792Snp 2034218792Snp case FW_PORT_TYPE_BT_SGMII: 2035218792Snp ifmedia_add(media, m | IFM_1000_T, data, NULL); 2036218792Snp ifmedia_add(media, m | IFM_100_TX, data, NULL); 2037218792Snp ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL); 2038218792Snp ifmedia_set(media, IFM_ETHER | IFM_AUTO); 2039218792Snp break; 2040218792Snp 2041218792Snp case FW_PORT_TYPE_CX4: 2042218792Snp ifmedia_add(media, m | IFM_10G_CX4, data, NULL); 2043218792Snp ifmedia_set(media, m | IFM_10G_CX4); 2044218792Snp break; 2045218792Snp 2046218792Snp case FW_PORT_TYPE_SFP: 2047218792Snp case FW_PORT_TYPE_FIBER_XFI: 2048218792Snp case FW_PORT_TYPE_FIBER_XAUI: 2049218792Snp switch (pi->mod_type) { 2050218792Snp 2051218792Snp case FW_PORT_MOD_TYPE_LR: 2052218792Snp ifmedia_add(media, m | IFM_10G_LR, data, NULL); 2053218792Snp ifmedia_set(media, m | IFM_10G_LR); 2054218792Snp break; 2055218792Snp 2056218792Snp case FW_PORT_MOD_TYPE_SR: 2057218792Snp ifmedia_add(media, m | IFM_10G_SR, data, NULL); 2058218792Snp ifmedia_set(media, m | IFM_10G_SR); 2059218792Snp break; 2060218792Snp 2061218792Snp case FW_PORT_MOD_TYPE_LRM: 2062218792Snp ifmedia_add(media, m | IFM_10G_LRM, data, NULL); 2063218792Snp ifmedia_set(media, m | IFM_10G_LRM); 2064218792Snp break; 2065218792Snp 2066218792Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2067218792Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2068218792Snp ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL); 2069218792Snp ifmedia_set(media, m | IFM_10G_TWINAX); 2070218792Snp break; 2071218792Snp 2072218792Snp case FW_PORT_MOD_TYPE_NONE: 2073218792Snp m &= ~IFM_FDX; 2074218792Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2075218792Snp ifmedia_set(media, m | IFM_NONE); 2076218792Snp break; 2077218792Snp 2078218792Snp case FW_PORT_MOD_TYPE_NA: 2079218792Snp case FW_PORT_MOD_TYPE_ER: 2080218792Snp default: 2081218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2082218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2083218792Snp break; 2084218792Snp } 2085218792Snp break; 2086218792Snp 2087218792Snp case FW_PORT_TYPE_KX4: 2088218792Snp case FW_PORT_TYPE_KX: 2089218792Snp case FW_PORT_TYPE_KR: 2090218792Snp default: 2091218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2092218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2093218792Snp break; 2094218792Snp } 2095218792Snp 2096218792Snp PORT_UNLOCK(pi); 2097218792Snp} 2098218792Snp 2099231172Snp#define FW_MAC_EXACT_CHUNK 7 2100231172Snp 2101218792Snp/* 2102218792Snp * Program the port's XGMAC based on parameters in ifnet. The caller also 2103218792Snp * indicates which parameters should be programmed (the rest are left alone). 2104218792Snp */ 2105218792Snpstatic int 2106218792Snpupdate_mac_settings(struct port_info *pi, int flags) 2107218792Snp{ 2108218792Snp int rc; 2109218792Snp struct ifnet *ifp = pi->ifp; 2110218792Snp struct adapter *sc = pi->adapter; 2111218792Snp int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1; 2112218792Snp 2113218792Snp PORT_LOCK_ASSERT_OWNED(pi); 2114218792Snp KASSERT(flags, ("%s: not told what to update.", __func__)); 2115218792Snp 2116218792Snp if (flags & XGMAC_MTU) 2117218792Snp mtu = ifp->if_mtu; 2118218792Snp 2119218792Snp if (flags & XGMAC_PROMISC) 2120218792Snp promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0; 2121218792Snp 2122218792Snp if (flags & XGMAC_ALLMULTI) 2123218792Snp allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0; 2124218792Snp 2125218792Snp if (flags & XGMAC_VLANEX) 2126218792Snp vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0; 2127218792Snp 2128218792Snp rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, mtu, promisc, allmulti, 1, 2129218792Snp vlanex, false); 2130218792Snp if (rc) { 2131218792Snp if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, rc); 2132218792Snp return (rc); 2133218792Snp } 2134218792Snp 2135218792Snp if (flags & XGMAC_UCADDR) { 2136218792Snp uint8_t ucaddr[ETHER_ADDR_LEN]; 2137218792Snp 2138218792Snp bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr)); 2139218792Snp rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, 2140218792Snp ucaddr, true, true); 2141218792Snp if (rc < 0) { 2142218792Snp rc = -rc; 2143218792Snp if_printf(ifp, "change_mac failed: %d\n", rc); 2144218792Snp return (rc); 2145218792Snp } else { 2146218792Snp pi->xact_addr_filt = rc; 2147218792Snp rc = 0; 2148218792Snp } 2149218792Snp } 2150218792Snp 2151218792Snp if (flags & XGMAC_MCADDRS) { 2152231172Snp const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK]; 2153218792Snp int del = 1; 2154218792Snp uint64_t hash = 0; 2155218792Snp struct ifmultiaddr *ifma; 2156231172Snp int i = 0, j; 2157218792Snp 2158218792Snp if_maddr_rlock(ifp); 2159218792Snp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2160238054Snp if (ifma->ifma_addr->sa_family != AF_LINK) 2161218792Snp continue; 2162231172Snp mcaddr[i++] = 2163231172Snp LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 2164218792Snp 2165231172Snp if (i == FW_MAC_EXACT_CHUNK) { 2166231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2167231172Snp del, i, mcaddr, NULL, &hash, 0); 2168231172Snp if (rc < 0) { 2169231172Snp rc = -rc; 2170231172Snp for (j = 0; j < i; j++) { 2171231172Snp if_printf(ifp, 2172231172Snp "failed to add mc address" 2173231172Snp " %02x:%02x:%02x:" 2174231172Snp "%02x:%02x:%02x rc=%d\n", 2175231172Snp mcaddr[j][0], mcaddr[j][1], 2176231172Snp mcaddr[j][2], mcaddr[j][3], 2177231172Snp mcaddr[j][4], mcaddr[j][5], 2178231172Snp rc); 2179231172Snp } 2180231172Snp goto mcfail; 2181231172Snp } 2182231172Snp del = 0; 2183231172Snp i = 0; 2184231172Snp } 2185231172Snp } 2186231172Snp if (i > 0) { 2187231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2188231172Snp del, i, mcaddr, NULL, &hash, 0); 2189218792Snp if (rc < 0) { 2190218792Snp rc = -rc; 2191231172Snp for (j = 0; j < i; j++) { 2192231172Snp if_printf(ifp, 2193231172Snp "failed to add mc address" 2194231172Snp " %02x:%02x:%02x:" 2195231172Snp "%02x:%02x:%02x rc=%d\n", 2196231172Snp mcaddr[j][0], mcaddr[j][1], 2197231172Snp mcaddr[j][2], mcaddr[j][3], 2198231172Snp mcaddr[j][4], mcaddr[j][5], 2199231172Snp rc); 2200231172Snp } 2201218792Snp goto mcfail; 2202218792Snp } 2203218792Snp } 2204218792Snp 2205218792Snp rc = -t4_set_addr_hash(sc, sc->mbox, pi->viid, 0, hash, 0); 2206218792Snp if (rc != 0) 2207218792Snp if_printf(ifp, "failed to set mc address hash: %d", rc); 2208218792Snpmcfail: 2209218792Snp if_maddr_runlock(ifp); 2210218792Snp } 2211218792Snp 2212218792Snp return (rc); 2213218792Snp} 2214218792Snp 2215218792Snpstatic int 2216218792Snpcxgbe_init_locked(struct port_info *pi) 2217218792Snp{ 2218218792Snp struct adapter *sc = pi->adapter; 2219218792Snp int rc = 0; 2220218792Snp 2221218792Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 2222218792Snp 2223218792Snp while (!IS_DOOMED(pi) && IS_BUSY(sc)) { 2224218792Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4init", 0)) { 2225218792Snp rc = EINTR; 2226218792Snp goto done; 2227218792Snp } 2228218792Snp } 2229218792Snp if (IS_DOOMED(pi)) { 2230218792Snp rc = ENXIO; 2231218792Snp goto done; 2232218792Snp } 2233218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 2234218792Snp 2235218792Snp /* Give up the adapter lock, port init code can sleep. */ 2236218792Snp SET_BUSY(sc); 2237218792Snp ADAPTER_UNLOCK(sc); 2238218792Snp 2239218792Snp rc = cxgbe_init_synchronized(pi); 2240218792Snp 2241218792Snpdone: 2242218792Snp ADAPTER_LOCK(sc); 2243218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 2244218792Snp CLR_BUSY(sc); 2245218792Snp wakeup_one(&sc->flags); 2246218792Snp ADAPTER_UNLOCK(sc); 2247218792Snp return (rc); 2248218792Snp} 2249218792Snp 2250218792Snpstatic int 2251218792Snpcxgbe_init_synchronized(struct port_info *pi) 2252218792Snp{ 2253218792Snp struct adapter *sc = pi->adapter; 2254218792Snp struct ifnet *ifp = pi->ifp; 2255228561Snp int rc = 0; 2256218792Snp 2257218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2258218792Snp 2259218792Snp if (isset(&sc->open_device_map, pi->port_id)) { 2260218792Snp KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, 2261218792Snp ("mismatch between open_device_map and if_drv_flags")); 2262218792Snp return (0); /* already running */ 2263218792Snp } 2264218792Snp 2265228561Snp if (!(sc->flags & FULL_INIT_DONE) && 2266228561Snp ((rc = adapter_full_init(sc)) != 0)) 2267218792Snp return (rc); /* error message displayed already */ 2268218792Snp 2269228561Snp if (!(pi->flags & PORT_INIT_DONE) && 2270228561Snp ((rc = port_full_init(pi)) != 0)) 2271228561Snp return (rc); /* error message displayed already */ 2272218792Snp 2273218792Snp PORT_LOCK(pi); 2274218792Snp rc = update_mac_settings(pi, XGMAC_ALL); 2275218792Snp PORT_UNLOCK(pi); 2276218792Snp if (rc) 2277218792Snp goto done; /* error message displayed already */ 2278218792Snp 2279218792Snp rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg); 2280218792Snp if (rc != 0) { 2281218792Snp if_printf(ifp, "start_link failed: %d\n", rc); 2282218792Snp goto done; 2283218792Snp } 2284218792Snp 2285218792Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true); 2286218792Snp if (rc != 0) { 2287218792Snp if_printf(ifp, "enable_vi failed: %d\n", rc); 2288218792Snp goto done; 2289218792Snp } 2290218792Snp 2291218792Snp /* all ok */ 2292218792Snp setbit(&sc->open_device_map, pi->port_id); 2293218792Snp ifp->if_drv_flags |= IFF_DRV_RUNNING; 2294218792Snp 2295218792Snp callout_reset(&pi->tick, hz, cxgbe_tick, pi); 2296218792Snpdone: 2297218792Snp if (rc != 0) 2298218792Snp cxgbe_uninit_synchronized(pi); 2299218792Snp 2300218792Snp return (rc); 2301218792Snp} 2302218792Snp 2303218792Snpstatic int 2304218792Snpcxgbe_uninit_locked(struct port_info *pi) 2305218792Snp{ 2306218792Snp struct adapter *sc = pi->adapter; 2307218792Snp int rc; 2308218792Snp 2309218792Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 2310218792Snp 2311218792Snp while (!IS_DOOMED(pi) && IS_BUSY(sc)) { 2312218792Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4uninit", 0)) { 2313218792Snp rc = EINTR; 2314218792Snp goto done; 2315218792Snp } 2316218792Snp } 2317218792Snp if (IS_DOOMED(pi)) { 2318218792Snp rc = ENXIO; 2319218792Snp goto done; 2320218792Snp } 2321218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 2322218792Snp SET_BUSY(sc); 2323218792Snp ADAPTER_UNLOCK(sc); 2324218792Snp 2325218792Snp rc = cxgbe_uninit_synchronized(pi); 2326218792Snp 2327218792Snp ADAPTER_LOCK(sc); 2328218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 2329218792Snp CLR_BUSY(sc); 2330218792Snp wakeup_one(&sc->flags); 2331218792Snpdone: 2332218792Snp ADAPTER_UNLOCK(sc); 2333218792Snp return (rc); 2334218792Snp} 2335218792Snp 2336218792Snp/* 2337218792Snp * Idempotent. 2338218792Snp */ 2339218792Snpstatic int 2340218792Snpcxgbe_uninit_synchronized(struct port_info *pi) 2341218792Snp{ 2342218792Snp struct adapter *sc = pi->adapter; 2343218792Snp struct ifnet *ifp = pi->ifp; 2344218792Snp int rc; 2345218792Snp 2346218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2347218792Snp 2348218792Snp /* 2349228561Snp * Disable the VI so that all its data in either direction is discarded 2350228561Snp * by the MPS. Leave everything else (the queues, interrupts, and 1Hz 2351228561Snp * tick) intact as the TP can deliver negative advice or data that it's 2352228561Snp * holding in its RAM (for an offloaded connection) even after the VI is 2353228561Snp * disabled. 2354218792Snp */ 2355228561Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false); 2356228561Snp if (rc) { 2357228561Snp if_printf(ifp, "disable_vi failed: %d\n", rc); 2358228561Snp return (rc); 2359228561Snp } 2360228561Snp 2361218792Snp clrbit(&sc->open_device_map, pi->port_id); 2362228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2363218792Snp 2364218792Snp pi->link_cfg.link_ok = 0; 2365218792Snp pi->link_cfg.speed = 0; 2366218792Snp t4_os_link_changed(sc, pi->port_id, 0); 2367218792Snp 2368218792Snp return (0); 2369218792Snp} 2370218792Snp 2371240453Snp/* 2372240453Snp * It is ok for this function to fail midway and return right away. t4_detach 2373240453Snp * will walk the entire sc->irq list and clean up whatever is valid. 2374240453Snp */ 2375218792Snpstatic int 2376240453Snpsetup_intr_handlers(struct adapter *sc) 2377218792Snp{ 2378240453Snp int rc, rid, p, q; 2379222510Snp char s[8]; 2380222510Snp struct irq *irq; 2381228561Snp struct port_info *pi; 2382228561Snp struct sge_rxq *rxq; 2383237263Snp#ifdef TCP_OFFLOAD 2384228561Snp struct sge_ofld_rxq *ofld_rxq; 2385228561Snp#endif 2386218792Snp 2387218792Snp /* 2388218792Snp * Setup interrupts. 2389218792Snp */ 2390222510Snp irq = &sc->irq[0]; 2391222510Snp rid = sc->intr_type == INTR_INTX ? 0 : 1; 2392218792Snp if (sc->intr_count == 1) { 2393228561Snp KASSERT(!(sc->flags & INTR_DIRECT), 2394228561Snp ("%s: single interrupt && INTR_DIRECT?", __func__)); 2395222510Snp 2396240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_all, sc, "all"); 2397240453Snp if (rc != 0) 2398240453Snp return (rc); 2399218792Snp } else { 2400228561Snp /* Multiple interrupts. */ 2401228561Snp KASSERT(sc->intr_count >= T4_EXTRA_INTR + sc->params.nports, 2402228561Snp ("%s: too few intr.", __func__)); 2403228561Snp 2404228561Snp /* The first one is always error intr */ 2405240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_err, sc, "err"); 2406240453Snp if (rc != 0) 2407240453Snp return (rc); 2408222510Snp irq++; 2409222510Snp rid++; 2410218792Snp 2411228561Snp /* The second one is always the firmware event queue */ 2412240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_evt, &sc->sge.fwq, 2413240453Snp "evt"); 2414240453Snp if (rc != 0) 2415240453Snp return (rc); 2416228561Snp irq++; 2417228561Snp rid++; 2418222510Snp 2419228561Snp /* 2420228561Snp * Note that if INTR_DIRECT is not set then either the NIC rx 2421228561Snp * queues or (exclusive or) the TOE rx queueus will be taking 2422228561Snp * direct interrupts. 2423228561Snp * 2424228561Snp * There is no need to check for is_offload(sc) as nofldrxq 2425228561Snp * will be 0 if offload is disabled. 2426228561Snp */ 2427228561Snp for_each_port(sc, p) { 2428228561Snp pi = sc->port[p]; 2429222510Snp 2430237263Snp#ifdef TCP_OFFLOAD 2431228561Snp /* 2432228561Snp * Skip over the NIC queues if they aren't taking direct 2433228561Snp * interrupts. 2434228561Snp */ 2435228561Snp if (!(sc->flags & INTR_DIRECT) && 2436228561Snp pi->nofldrxq > pi->nrxq) 2437228561Snp goto ofld_queues; 2438228561Snp#endif 2439228561Snp rxq = &sc->sge.rxq[pi->first_rxq]; 2440228561Snp for (q = 0; q < pi->nrxq; q++, rxq++) { 2441228561Snp snprintf(s, sizeof(s), "%d.%d", p, q); 2442240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, rxq, 2443240453Snp s); 2444240453Snp if (rc != 0) 2445240453Snp return (rc); 2446222510Snp irq++; 2447222510Snp rid++; 2448218792Snp } 2449218792Snp 2450237263Snp#ifdef TCP_OFFLOAD 2451228561Snp /* 2452228561Snp * Skip over the offload queues if they aren't taking 2453228561Snp * direct interrupts. 2454228561Snp */ 2455228561Snp if (!(sc->flags & INTR_DIRECT)) 2456228561Snp continue; 2457228561Snpofld_queues: 2458228561Snp ofld_rxq = &sc->sge.ofld_rxq[pi->first_ofld_rxq]; 2459228561Snp for (q = 0; q < pi->nofldrxq; q++, ofld_rxq++) { 2460228561Snp snprintf(s, sizeof(s), "%d,%d", p, q); 2461240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, 2462240453Snp ofld_rxq, s); 2463240453Snp if (rc != 0) 2464240453Snp return (rc); 2465228561Snp irq++; 2466228561Snp rid++; 2467218792Snp } 2468228561Snp#endif 2469218792Snp } 2470218792Snp } 2471218792Snp 2472240453Snp return (0); 2473240453Snp} 2474240453Snp 2475240453Snpstatic int 2476240453Snpadapter_full_init(struct adapter *sc) 2477240453Snp{ 2478240453Snp int rc, i; 2479240453Snp 2480240453Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2481240453Snp KASSERT((sc->flags & FULL_INIT_DONE) == 0, 2482240453Snp ("%s: FULL_INIT_DONE already", __func__)); 2483240453Snp 2484240453Snp /* 2485240453Snp * queues that belong to the adapter (not any particular port). 2486240453Snp */ 2487240453Snp rc = t4_setup_adapter_queues(sc); 2488240453Snp if (rc != 0) 2489240453Snp goto done; 2490240453Snp 2491240453Snp for (i = 0; i < nitems(sc->tq); i++) { 2492240453Snp sc->tq[i] = taskqueue_create("t4 taskq", M_NOWAIT, 2493240453Snp taskqueue_thread_enqueue, &sc->tq[i]); 2494240453Snp if (sc->tq[i] == NULL) { 2495240453Snp device_printf(sc->dev, 2496240453Snp "failed to allocate task queue %d\n", i); 2497240453Snp rc = ENOMEM; 2498240453Snp goto done; 2499240453Snp } 2500240453Snp taskqueue_start_threads(&sc->tq[i], 1, PI_NET, "%s tq%d", 2501240453Snp device_get_nameunit(sc->dev), i); 2502240453Snp } 2503240453Snp 2504218792Snp t4_intr_enable(sc); 2505218792Snp sc->flags |= FULL_INIT_DONE; 2506218792Snpdone: 2507218792Snp if (rc != 0) 2508228561Snp adapter_full_uninit(sc); 2509218792Snp 2510218792Snp return (rc); 2511218792Snp} 2512218792Snp 2513218792Snpstatic int 2514228561Snpadapter_full_uninit(struct adapter *sc) 2515218792Snp{ 2516218792Snp int i; 2517218792Snp 2518218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2519218792Snp 2520220873Snp t4_teardown_adapter_queues(sc); 2521218792Snp 2522240452Snp for (i = 0; i < nitems(sc->tq) && sc->tq[i]; i++) { 2523228561Snp taskqueue_free(sc->tq[i]); 2524228561Snp sc->tq[i] = NULL; 2525228561Snp } 2526228561Snp 2527218792Snp sc->flags &= ~FULL_INIT_DONE; 2528218792Snp 2529218792Snp return (0); 2530218792Snp} 2531218792Snp 2532218792Snpstatic int 2533228561Snpport_full_init(struct port_info *pi) 2534228561Snp{ 2535228561Snp struct adapter *sc = pi->adapter; 2536228561Snp struct ifnet *ifp = pi->ifp; 2537228561Snp uint16_t *rss; 2538228561Snp struct sge_rxq *rxq; 2539228561Snp int rc, i; 2540228561Snp 2541228561Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2542228561Snp KASSERT((pi->flags & PORT_INIT_DONE) == 0, 2543228561Snp ("%s: PORT_INIT_DONE already", __func__)); 2544228561Snp 2545228561Snp sysctl_ctx_init(&pi->ctx); 2546228561Snp pi->flags |= PORT_SYSCTL_CTX; 2547228561Snp 2548228561Snp /* 2549228561Snp * Allocate tx/rx/fl queues for this port. 2550228561Snp */ 2551228561Snp rc = t4_setup_port_queues(pi); 2552228561Snp if (rc != 0) 2553228561Snp goto done; /* error message displayed already */ 2554228561Snp 2555228561Snp /* 2556228561Snp * Setup RSS for this port. 2557228561Snp */ 2558228561Snp rss = malloc(pi->nrxq * sizeof (*rss), M_CXGBE, 2559228561Snp M_ZERO | M_WAITOK); 2560228561Snp for_each_rxq(pi, i, rxq) { 2561228561Snp rss[i] = rxq->iq.abs_id; 2562228561Snp } 2563228561Snp rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, 2564228561Snp pi->rss_size, rss, pi->nrxq); 2565228561Snp free(rss, M_CXGBE); 2566228561Snp if (rc != 0) { 2567228561Snp if_printf(ifp, "rss_config failed: %d\n", rc); 2568228561Snp goto done; 2569228561Snp } 2570228561Snp 2571228561Snp pi->flags |= PORT_INIT_DONE; 2572228561Snpdone: 2573228561Snp if (rc != 0) 2574228561Snp port_full_uninit(pi); 2575228561Snp 2576228561Snp return (rc); 2577228561Snp} 2578228561Snp 2579228561Snp/* 2580228561Snp * Idempotent. 2581228561Snp */ 2582228561Snpstatic int 2583228561Snpport_full_uninit(struct port_info *pi) 2584228561Snp{ 2585228561Snp struct adapter *sc = pi->adapter; 2586228561Snp int i; 2587228561Snp struct sge_rxq *rxq; 2588228561Snp struct sge_txq *txq; 2589237263Snp#ifdef TCP_OFFLOAD 2590228561Snp struct sge_ofld_rxq *ofld_rxq; 2591228561Snp struct sge_wrq *ofld_txq; 2592228561Snp#endif 2593228561Snp 2594228561Snp if (pi->flags & PORT_INIT_DONE) { 2595228561Snp 2596228561Snp /* Need to quiesce queues. XXX: ctrl queues? */ 2597228561Snp 2598228561Snp for_each_txq(pi, i, txq) { 2599228561Snp quiesce_eq(sc, &txq->eq); 2600228561Snp } 2601228561Snp 2602237263Snp#ifdef TCP_OFFLOAD 2603228561Snp for_each_ofld_txq(pi, i, ofld_txq) { 2604228561Snp quiesce_eq(sc, &ofld_txq->eq); 2605228561Snp } 2606228561Snp#endif 2607228561Snp 2608228561Snp for_each_rxq(pi, i, rxq) { 2609228561Snp quiesce_iq(sc, &rxq->iq); 2610228561Snp quiesce_fl(sc, &rxq->fl); 2611228561Snp } 2612228561Snp 2613237263Snp#ifdef TCP_OFFLOAD 2614228561Snp for_each_ofld_rxq(pi, i, ofld_rxq) { 2615228561Snp quiesce_iq(sc, &ofld_rxq->iq); 2616228561Snp quiesce_fl(sc, &ofld_rxq->fl); 2617228561Snp } 2618228561Snp#endif 2619228561Snp } 2620228561Snp 2621228561Snp t4_teardown_port_queues(pi); 2622228561Snp pi->flags &= ~PORT_INIT_DONE; 2623228561Snp 2624228561Snp return (0); 2625228561Snp} 2626228561Snp 2627228561Snpstatic void 2628228561Snpquiesce_eq(struct adapter *sc, struct sge_eq *eq) 2629228561Snp{ 2630228561Snp EQ_LOCK(eq); 2631228561Snp eq->flags |= EQ_DOOMED; 2632228561Snp 2633228561Snp /* 2634228561Snp * Wait for the response to a credit flush if one's 2635228561Snp * pending. 2636228561Snp */ 2637228561Snp while (eq->flags & EQ_CRFLUSHED) 2638228561Snp mtx_sleep(eq, &eq->eq_lock, 0, "crflush", 0); 2639228561Snp EQ_UNLOCK(eq); 2640228561Snp 2641228561Snp callout_drain(&eq->tx_callout); /* XXX: iffy */ 2642228561Snp pause("callout", 10); /* Still iffy */ 2643228561Snp 2644228561Snp taskqueue_drain(sc->tq[eq->tx_chan], &eq->tx_task); 2645228561Snp} 2646228561Snp 2647228561Snpstatic void 2648228561Snpquiesce_iq(struct adapter *sc, struct sge_iq *iq) 2649228561Snp{ 2650228561Snp (void) sc; /* unused */ 2651228561Snp 2652228561Snp /* Synchronize with the interrupt handler */ 2653228561Snp while (!atomic_cmpset_int(&iq->state, IQS_IDLE, IQS_DISABLED)) 2654228561Snp pause("iqfree", 1); 2655228561Snp} 2656228561Snp 2657228561Snpstatic void 2658228561Snpquiesce_fl(struct adapter *sc, struct sge_fl *fl) 2659228561Snp{ 2660228561Snp mtx_lock(&sc->sfl_lock); 2661228561Snp FL_LOCK(fl); 2662228561Snp fl->flags |= FL_DOOMED; 2663228561Snp FL_UNLOCK(fl); 2664228561Snp mtx_unlock(&sc->sfl_lock); 2665228561Snp 2666228561Snp callout_drain(&sc->sfl_callout); 2667228561Snp KASSERT((fl->flags & FL_STARVING) == 0, 2668228561Snp ("%s: still starving", __func__)); 2669228561Snp} 2670228561Snp 2671228561Snpstatic int 2672218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid, 2673228561Snp driver_intr_t *handler, void *arg, char *name) 2674218792Snp{ 2675218792Snp int rc; 2676218792Snp 2677218792Snp irq->rid = rid; 2678218792Snp irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid, 2679218792Snp RF_SHAREABLE | RF_ACTIVE); 2680218792Snp if (irq->res == NULL) { 2681218792Snp device_printf(sc->dev, 2682218792Snp "failed to allocate IRQ for rid %d, name %s.\n", rid, name); 2683218792Snp return (ENOMEM); 2684218792Snp } 2685218792Snp 2686218792Snp rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET, 2687218792Snp NULL, handler, arg, &irq->tag); 2688218792Snp if (rc != 0) { 2689218792Snp device_printf(sc->dev, 2690218792Snp "failed to setup interrupt for rid %d, name %s: %d\n", 2691218792Snp rid, name, rc); 2692218792Snp } else if (name) 2693218792Snp bus_describe_intr(sc->dev, irq->res, irq->tag, name); 2694218792Snp 2695218792Snp return (rc); 2696218792Snp} 2697218792Snp 2698218792Snpstatic int 2699218792Snpt4_free_irq(struct adapter *sc, struct irq *irq) 2700218792Snp{ 2701218792Snp if (irq->tag) 2702218792Snp bus_teardown_intr(sc->dev, irq->res, irq->tag); 2703218792Snp if (irq->res) 2704218792Snp bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res); 2705218792Snp 2706218792Snp bzero(irq, sizeof(*irq)); 2707218792Snp 2708218792Snp return (0); 2709218792Snp} 2710218792Snp 2711218792Snpstatic void 2712218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start, 2713218792Snp unsigned int end) 2714218792Snp{ 2715218792Snp uint32_t *p = (uint32_t *)(buf + start); 2716218792Snp 2717218792Snp for ( ; start <= end; start += sizeof(uint32_t)) 2718218792Snp *p++ = t4_read_reg(sc, start); 2719218792Snp} 2720218792Snp 2721218792Snpstatic void 2722218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf) 2723218792Snp{ 2724218792Snp int i; 2725218792Snp static const unsigned int reg_ranges[] = { 2726218792Snp 0x1008, 0x1108, 2727218792Snp 0x1180, 0x11b4, 2728218792Snp 0x11fc, 0x123c, 2729218792Snp 0x1300, 0x173c, 2730218792Snp 0x1800, 0x18fc, 2731218792Snp 0x3000, 0x30d8, 2732218792Snp 0x30e0, 0x5924, 2733218792Snp 0x5960, 0x59d4, 2734218792Snp 0x5a00, 0x5af8, 2735218792Snp 0x6000, 0x6098, 2736218792Snp 0x6100, 0x6150, 2737218792Snp 0x6200, 0x6208, 2738218792Snp 0x6240, 0x6248, 2739218792Snp 0x6280, 0x6338, 2740218792Snp 0x6370, 0x638c, 2741218792Snp 0x6400, 0x643c, 2742218792Snp 0x6500, 0x6524, 2743218792Snp 0x6a00, 0x6a38, 2744218792Snp 0x6a60, 0x6a78, 2745218792Snp 0x6b00, 0x6b84, 2746218792Snp 0x6bf0, 0x6c84, 2747218792Snp 0x6cf0, 0x6d84, 2748218792Snp 0x6df0, 0x6e84, 2749218792Snp 0x6ef0, 0x6f84, 2750218792Snp 0x6ff0, 0x7084, 2751218792Snp 0x70f0, 0x7184, 2752218792Snp 0x71f0, 0x7284, 2753218792Snp 0x72f0, 0x7384, 2754218792Snp 0x73f0, 0x7450, 2755218792Snp 0x7500, 0x7530, 2756218792Snp 0x7600, 0x761c, 2757218792Snp 0x7680, 0x76cc, 2758218792Snp 0x7700, 0x7798, 2759218792Snp 0x77c0, 0x77fc, 2760218792Snp 0x7900, 0x79fc, 2761218792Snp 0x7b00, 0x7c38, 2762218792Snp 0x7d00, 0x7efc, 2763218792Snp 0x8dc0, 0x8e1c, 2764218792Snp 0x8e30, 0x8e78, 2765218792Snp 0x8ea0, 0x8f6c, 2766218792Snp 0x8fc0, 0x9074, 2767218792Snp 0x90fc, 0x90fc, 2768218792Snp 0x9400, 0x9458, 2769218792Snp 0x9600, 0x96bc, 2770218792Snp 0x9800, 0x9808, 2771218792Snp 0x9820, 0x983c, 2772218792Snp 0x9850, 0x9864, 2773218792Snp 0x9c00, 0x9c6c, 2774218792Snp 0x9c80, 0x9cec, 2775218792Snp 0x9d00, 0x9d6c, 2776218792Snp 0x9d80, 0x9dec, 2777218792Snp 0x9e00, 0x9e6c, 2778218792Snp 0x9e80, 0x9eec, 2779218792Snp 0x9f00, 0x9f6c, 2780218792Snp 0x9f80, 0x9fec, 2781218792Snp 0xd004, 0xd03c, 2782218792Snp 0xdfc0, 0xdfe0, 2783218792Snp 0xe000, 0xea7c, 2784218792Snp 0xf000, 0x11190, 2785237439Snp 0x19040, 0x1906c, 2786237439Snp 0x19078, 0x19080, 2787237439Snp 0x1908c, 0x19124, 2788218792Snp 0x19150, 0x191b0, 2789218792Snp 0x191d0, 0x191e8, 2790218792Snp 0x19238, 0x1924c, 2791218792Snp 0x193f8, 0x19474, 2792218792Snp 0x19490, 0x194f8, 2793218792Snp 0x19800, 0x19f30, 2794218792Snp 0x1a000, 0x1a06c, 2795218792Snp 0x1a0b0, 0x1a120, 2796218792Snp 0x1a128, 0x1a138, 2797218792Snp 0x1a190, 0x1a1c4, 2798218792Snp 0x1a1fc, 0x1a1fc, 2799218792Snp 0x1e040, 0x1e04c, 2800237439Snp 0x1e284, 0x1e28c, 2801218792Snp 0x1e2c0, 0x1e2c0, 2802218792Snp 0x1e2e0, 0x1e2e0, 2803218792Snp 0x1e300, 0x1e384, 2804218792Snp 0x1e3c0, 0x1e3c8, 2805218792Snp 0x1e440, 0x1e44c, 2806237439Snp 0x1e684, 0x1e68c, 2807218792Snp 0x1e6c0, 0x1e6c0, 2808218792Snp 0x1e6e0, 0x1e6e0, 2809218792Snp 0x1e700, 0x1e784, 2810218792Snp 0x1e7c0, 0x1e7c8, 2811218792Snp 0x1e840, 0x1e84c, 2812237439Snp 0x1ea84, 0x1ea8c, 2813218792Snp 0x1eac0, 0x1eac0, 2814218792Snp 0x1eae0, 0x1eae0, 2815218792Snp 0x1eb00, 0x1eb84, 2816218792Snp 0x1ebc0, 0x1ebc8, 2817218792Snp 0x1ec40, 0x1ec4c, 2818237439Snp 0x1ee84, 0x1ee8c, 2819218792Snp 0x1eec0, 0x1eec0, 2820218792Snp 0x1eee0, 0x1eee0, 2821218792Snp 0x1ef00, 0x1ef84, 2822218792Snp 0x1efc0, 0x1efc8, 2823218792Snp 0x1f040, 0x1f04c, 2824237439Snp 0x1f284, 0x1f28c, 2825218792Snp 0x1f2c0, 0x1f2c0, 2826218792Snp 0x1f2e0, 0x1f2e0, 2827218792Snp 0x1f300, 0x1f384, 2828218792Snp 0x1f3c0, 0x1f3c8, 2829218792Snp 0x1f440, 0x1f44c, 2830237439Snp 0x1f684, 0x1f68c, 2831218792Snp 0x1f6c0, 0x1f6c0, 2832218792Snp 0x1f6e0, 0x1f6e0, 2833218792Snp 0x1f700, 0x1f784, 2834218792Snp 0x1f7c0, 0x1f7c8, 2835218792Snp 0x1f840, 0x1f84c, 2836237439Snp 0x1fa84, 0x1fa8c, 2837218792Snp 0x1fac0, 0x1fac0, 2838218792Snp 0x1fae0, 0x1fae0, 2839218792Snp 0x1fb00, 0x1fb84, 2840218792Snp 0x1fbc0, 0x1fbc8, 2841218792Snp 0x1fc40, 0x1fc4c, 2842237439Snp 0x1fe84, 0x1fe8c, 2843218792Snp 0x1fec0, 0x1fec0, 2844218792Snp 0x1fee0, 0x1fee0, 2845218792Snp 0x1ff00, 0x1ff84, 2846218792Snp 0x1ffc0, 0x1ffc8, 2847218792Snp 0x20000, 0x2002c, 2848218792Snp 0x20100, 0x2013c, 2849218792Snp 0x20190, 0x201c8, 2850218792Snp 0x20200, 0x20318, 2851218792Snp 0x20400, 0x20528, 2852218792Snp 0x20540, 0x20614, 2853218792Snp 0x21000, 0x21040, 2854218792Snp 0x2104c, 0x21060, 2855218792Snp 0x210c0, 0x210ec, 2856218792Snp 0x21200, 0x21268, 2857218792Snp 0x21270, 0x21284, 2858218792Snp 0x212fc, 0x21388, 2859218792Snp 0x21400, 0x21404, 2860218792Snp 0x21500, 0x21518, 2861218792Snp 0x2152c, 0x2153c, 2862218792Snp 0x21550, 0x21554, 2863218792Snp 0x21600, 0x21600, 2864218792Snp 0x21608, 0x21628, 2865218792Snp 0x21630, 0x2163c, 2866218792Snp 0x21700, 0x2171c, 2867218792Snp 0x21780, 0x2178c, 2868218792Snp 0x21800, 0x21c38, 2869218792Snp 0x21c80, 0x21d7c, 2870218792Snp 0x21e00, 0x21e04, 2871218792Snp 0x22000, 0x2202c, 2872218792Snp 0x22100, 0x2213c, 2873218792Snp 0x22190, 0x221c8, 2874218792Snp 0x22200, 0x22318, 2875218792Snp 0x22400, 0x22528, 2876218792Snp 0x22540, 0x22614, 2877218792Snp 0x23000, 0x23040, 2878218792Snp 0x2304c, 0x23060, 2879218792Snp 0x230c0, 0x230ec, 2880218792Snp 0x23200, 0x23268, 2881218792Snp 0x23270, 0x23284, 2882218792Snp 0x232fc, 0x23388, 2883218792Snp 0x23400, 0x23404, 2884218792Snp 0x23500, 0x23518, 2885218792Snp 0x2352c, 0x2353c, 2886218792Snp 0x23550, 0x23554, 2887218792Snp 0x23600, 0x23600, 2888218792Snp 0x23608, 0x23628, 2889218792Snp 0x23630, 0x2363c, 2890218792Snp 0x23700, 0x2371c, 2891218792Snp 0x23780, 0x2378c, 2892218792Snp 0x23800, 0x23c38, 2893218792Snp 0x23c80, 0x23d7c, 2894218792Snp 0x23e00, 0x23e04, 2895218792Snp 0x24000, 0x2402c, 2896218792Snp 0x24100, 0x2413c, 2897218792Snp 0x24190, 0x241c8, 2898218792Snp 0x24200, 0x24318, 2899218792Snp 0x24400, 0x24528, 2900218792Snp 0x24540, 0x24614, 2901218792Snp 0x25000, 0x25040, 2902218792Snp 0x2504c, 0x25060, 2903218792Snp 0x250c0, 0x250ec, 2904218792Snp 0x25200, 0x25268, 2905218792Snp 0x25270, 0x25284, 2906218792Snp 0x252fc, 0x25388, 2907218792Snp 0x25400, 0x25404, 2908218792Snp 0x25500, 0x25518, 2909218792Snp 0x2552c, 0x2553c, 2910218792Snp 0x25550, 0x25554, 2911218792Snp 0x25600, 0x25600, 2912218792Snp 0x25608, 0x25628, 2913218792Snp 0x25630, 0x2563c, 2914218792Snp 0x25700, 0x2571c, 2915218792Snp 0x25780, 0x2578c, 2916218792Snp 0x25800, 0x25c38, 2917218792Snp 0x25c80, 0x25d7c, 2918218792Snp 0x25e00, 0x25e04, 2919218792Snp 0x26000, 0x2602c, 2920218792Snp 0x26100, 0x2613c, 2921218792Snp 0x26190, 0x261c8, 2922218792Snp 0x26200, 0x26318, 2923218792Snp 0x26400, 0x26528, 2924218792Snp 0x26540, 0x26614, 2925218792Snp 0x27000, 0x27040, 2926218792Snp 0x2704c, 0x27060, 2927218792Snp 0x270c0, 0x270ec, 2928218792Snp 0x27200, 0x27268, 2929218792Snp 0x27270, 0x27284, 2930218792Snp 0x272fc, 0x27388, 2931218792Snp 0x27400, 0x27404, 2932218792Snp 0x27500, 0x27518, 2933218792Snp 0x2752c, 0x2753c, 2934218792Snp 0x27550, 0x27554, 2935218792Snp 0x27600, 0x27600, 2936218792Snp 0x27608, 0x27628, 2937218792Snp 0x27630, 0x2763c, 2938218792Snp 0x27700, 0x2771c, 2939218792Snp 0x27780, 0x2778c, 2940218792Snp 0x27800, 0x27c38, 2941218792Snp 0x27c80, 0x27d7c, 2942218792Snp 0x27e00, 0x27e04 2943218792Snp }; 2944218792Snp 2945218792Snp regs->version = 4 | (sc->params.rev << 10); 2946240452Snp for (i = 0; i < nitems(reg_ranges); i += 2) 2947218792Snp reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]); 2948218792Snp} 2949218792Snp 2950218792Snpstatic void 2951218792Snpcxgbe_tick(void *arg) 2952218792Snp{ 2953218792Snp struct port_info *pi = arg; 2954218792Snp struct ifnet *ifp = pi->ifp; 2955218792Snp struct sge_txq *txq; 2956218792Snp int i, drops; 2957218792Snp struct port_stats *s = &pi->stats; 2958218792Snp 2959218792Snp PORT_LOCK(pi); 2960218792Snp if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2961218792Snp PORT_UNLOCK(pi); 2962218792Snp return; /* without scheduling another callout */ 2963218792Snp } 2964218792Snp 2965218792Snp t4_get_port_stats(pi->adapter, pi->tx_chan, s); 2966218792Snp 2967228561Snp ifp->if_opackets = s->tx_frames - s->tx_pause; 2968228561Snp ifp->if_ipackets = s->rx_frames - s->rx_pause; 2969228561Snp ifp->if_obytes = s->tx_octets - s->tx_pause * 64; 2970228561Snp ifp->if_ibytes = s->rx_octets - s->rx_pause * 64; 2971228561Snp ifp->if_omcasts = s->tx_mcast_frames - s->tx_pause; 2972228561Snp ifp->if_imcasts = s->rx_mcast_frames - s->rx_pause; 2973218792Snp ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 + 2974239259Snp s->rx_ovflow3 + s->rx_trunc0 + s->rx_trunc1 + s->rx_trunc2 + 2975239259Snp s->rx_trunc3; 2976218792Snp 2977218792Snp drops = s->tx_drop; 2978218792Snp for_each_txq(pi, i, txq) 2979220873Snp drops += txq->br->br_drops; 2980218792Snp ifp->if_snd.ifq_drops = drops; 2981218792Snp 2982218792Snp ifp->if_oerrors = s->tx_error_frames; 2983218792Snp ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long + 2984218792Snp s->rx_fcs_err + s->rx_len_err; 2985218792Snp 2986218792Snp callout_schedule(&pi->tick, hz); 2987218792Snp PORT_UNLOCK(pi); 2988218792Snp} 2989218792Snp 2990237263Snpstatic void 2991237263Snpcxgbe_vlan_config(void *arg, struct ifnet *ifp, uint16_t vid) 2992237263Snp{ 2993237263Snp struct ifnet *vlan; 2994237263Snp 2995241494Snp if (arg != ifp || ifp->if_type != IFT_ETHER) 2996237263Snp return; 2997237263Snp 2998237263Snp vlan = VLAN_DEVAT(ifp, vid); 2999237263Snp VLAN_SETCOOKIE(vlan, ifp); 3000237263Snp} 3001237263Snp 3002218792Snpstatic int 3003228561Snpcpl_not_handled(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 3004228561Snp{ 3005237263Snp 3006228561Snp#ifdef INVARIANTS 3007237263Snp panic("%s: opcode 0x%02x on iq %p with payload %p", 3008228561Snp __func__, rss->opcode, iq, m); 3009228561Snp#else 3010239336Snp log(LOG_ERR, "%s: opcode 0x%02x on iq %p with payload %p\n", 3011228561Snp __func__, rss->opcode, iq, m); 3012228561Snp m_freem(m); 3013228561Snp#endif 3014228561Snp return (EDOOFUS); 3015228561Snp} 3016228561Snp 3017228561Snpint 3018228561Snpt4_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h) 3019228561Snp{ 3020228561Snp uintptr_t *loc, new; 3021228561Snp 3022240452Snp if (opcode >= nitems(sc->cpl_handler)) 3023228561Snp return (EINVAL); 3024228561Snp 3025228561Snp new = h ? (uintptr_t)h : (uintptr_t)cpl_not_handled; 3026228561Snp loc = (uintptr_t *) &sc->cpl_handler[opcode]; 3027228561Snp atomic_store_rel_ptr(loc, new); 3028228561Snp 3029228561Snp return (0); 3030228561Snp} 3031228561Snp 3032228561Snpstatic int 3033237263Snpan_not_handled(struct sge_iq *iq, const struct rsp_ctrl *ctrl) 3034237263Snp{ 3035237263Snp 3036237263Snp#ifdef INVARIANTS 3037237263Snp panic("%s: async notification on iq %p (ctrl %p)", __func__, iq, ctrl); 3038237263Snp#else 3039239336Snp log(LOG_ERR, "%s: async notification on iq %p (ctrl %p)\n", 3040237263Snp __func__, iq, ctrl); 3041237263Snp#endif 3042237263Snp return (EDOOFUS); 3043237263Snp} 3044237263Snp 3045237263Snpint 3046237263Snpt4_register_an_handler(struct adapter *sc, an_handler_t h) 3047237263Snp{ 3048237263Snp uintptr_t *loc, new; 3049237263Snp 3050237263Snp new = h ? (uintptr_t)h : (uintptr_t)an_not_handled; 3051237263Snp loc = (uintptr_t *) &sc->an_handler; 3052237263Snp atomic_store_rel_ptr(loc, new); 3053237263Snp 3054237263Snp return (0); 3055237263Snp} 3056237263Snp 3057237263Snpstatic int 3058239336Snpfw_msg_not_handled(struct adapter *sc, const __be64 *rpl) 3059239336Snp{ 3060241733Sed const struct cpl_fw6_msg *cpl = 3061241733Sed __containerof(rpl, struct cpl_fw6_msg, data[0]); 3062239336Snp 3063239336Snp#ifdef INVARIANTS 3064239336Snp panic("%s: fw_msg type %d", __func__, cpl->type); 3065239336Snp#else 3066239336Snp log(LOG_ERR, "%s: fw_msg type %d\n", __func__, cpl->type); 3067239336Snp#endif 3068239336Snp return (EDOOFUS); 3069239336Snp} 3070239336Snp 3071239336Snpint 3072239336Snpt4_register_fw_msg_handler(struct adapter *sc, int type, fw_msg_handler_t h) 3073239336Snp{ 3074239336Snp uintptr_t *loc, new; 3075239336Snp 3076240452Snp if (type >= nitems(sc->fw_msg_handler)) 3077239336Snp return (EINVAL); 3078239336Snp 3079239336Snp new = h ? (uintptr_t)h : (uintptr_t)fw_msg_not_handled; 3080239336Snp loc = (uintptr_t *) &sc->fw_msg_handler[type]; 3081239336Snp atomic_store_rel_ptr(loc, new); 3082239336Snp 3083239336Snp return (0); 3084239336Snp} 3085239336Snp 3086239336Snpstatic int 3087218792Snpt4_sysctls(struct adapter *sc) 3088218792Snp{ 3089218792Snp struct sysctl_ctx_list *ctx; 3090218792Snp struct sysctl_oid *oid; 3091228561Snp struct sysctl_oid_list *children, *c0; 3092228561Snp static char *caps[] = { 3093228561Snp "\20\1PPP\2QFC\3DCBX", /* caps[0] linkcaps */ 3094228561Snp "\20\1NIC\2VM\3IDS\4UM\5UM_ISGL", /* caps[1] niccaps */ 3095228561Snp "\20\1TOE", /* caps[2] toecaps */ 3096228561Snp "\20\1RDDP\2RDMAC", /* caps[3] rdmacaps */ 3097228561Snp "\20\1INITIATOR_PDU\2TARGET_PDU" /* caps[4] iscsicaps */ 3098228561Snp "\3INITIATOR_CNXOFLD\4TARGET_CNXOFLD" 3099228561Snp "\5INITIATOR_SSNOFLD\6TARGET_SSNOFLD", 3100228561Snp "\20\1INITIATOR\2TARGET\3CTRL_OFLD" /* caps[5] fcoecaps */ 3101228561Snp }; 3102218792Snp 3103218792Snp ctx = device_get_sysctl_ctx(sc->dev); 3104228561Snp 3105228561Snp /* 3106228561Snp * dev.t4nex.X. 3107228561Snp */ 3108218792Snp oid = device_get_sysctl_tree(sc->dev); 3109228561Snp c0 = children = SYSCTL_CHILDREN(oid); 3110218792Snp 3111218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, 3112218792Snp &sc->params.nports, 0, "# of ports"); 3113218792Snp 3114218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD, 3115218792Snp &sc->params.rev, 0, "chip hardware revision"); 3116218792Snp 3117218792Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 3118218792Snp CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 3119218792Snp 3120228561Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "cf", 3121228561Snp CTLFLAG_RD, &t4_cfg_file, 0, "configuration file"); 3122218792Snp 3123228561Snp SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cfcsum", CTLFLAG_RD, 3124228561Snp &sc->cfcsum, 0, "config file checksum"); 3125228561Snp 3126228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkcaps", 3127228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[0], sc->linkcaps, 3128228561Snp sysctl_bitfield, "A", "available link capabilities"); 3129228561Snp 3130228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "niccaps", 3131228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[1], sc->niccaps, 3132228561Snp sysctl_bitfield, "A", "available NIC capabilities"); 3133228561Snp 3134228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "toecaps", 3135228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[2], sc->toecaps, 3136228561Snp sysctl_bitfield, "A", "available TCP offload capabilities"); 3137228561Snp 3138228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdmacaps", 3139228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[3], sc->rdmacaps, 3140228561Snp sysctl_bitfield, "A", "available RDMA capabilities"); 3141228561Snp 3142228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "iscsicaps", 3143228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[4], sc->iscsicaps, 3144228561Snp sysctl_bitfield, "A", "available iSCSI capabilities"); 3145228561Snp 3146228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoecaps", 3147228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[5], sc->fcoecaps, 3148228561Snp sysctl_bitfield, "A", "available FCoE capabilities"); 3149228561Snp 3150218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, 3151218792Snp &sc->params.vpd.cclk, 0, "core clock frequency (in KHz)"); 3152218792Snp 3153219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers", 3154228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.timer_val, 3155228561Snp sizeof(sc->sge.timer_val), sysctl_int_array, "A", 3156228561Snp "interrupt holdoff timer values (us)"); 3157218792Snp 3158219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts", 3159228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.counter_val, 3160228561Snp sizeof(sc->sge.counter_val), sysctl_int_array, "A", 3161228561Snp "interrupt holdoff packet counter values"); 3162218792Snp 3163231115Snp#ifdef SBUF_DRAIN 3164228561Snp /* 3165228561Snp * dev.t4nex.X.misc. Marked CTLFLAG_SKIP to avoid information overload. 3166228561Snp */ 3167228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "misc", 3168228561Snp CTLFLAG_RD | CTLFLAG_SKIP, NULL, 3169228561Snp "logs and miscellaneous information"); 3170228561Snp children = SYSCTL_CHILDREN(oid); 3171228561Snp 3172228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cctrl", 3173228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3174228561Snp sysctl_cctrl, "A", "congestion control"); 3175228561Snp 3176228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats", 3177228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3178228561Snp sysctl_cpl_stats, "A", "CPL statistics"); 3179228561Snp 3180228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ddp_stats", 3181228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3182228561Snp sysctl_ddp_stats, "A", "DDP statistics"); 3183228561Snp 3184222551Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog", 3185222551Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3186228561Snp sysctl_devlog, "A", "firmware's device log"); 3187222551Snp 3188228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoe_stats", 3189228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3190228561Snp sysctl_fcoe_stats, "A", "FCoE statistics"); 3191228561Snp 3192228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hw_sched", 3193228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3194228561Snp sysctl_hw_sched, "A", "hardware scheduler "); 3195228561Snp 3196228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "l2t", 3197228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3198228561Snp sysctl_l2t, "A", "hardware L2 table"); 3199228561Snp 3200228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats", 3201228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3202228561Snp sysctl_lb_stats, "A", "loopback statistics"); 3203228561Snp 3204228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "meminfo", 3205228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3206228561Snp sysctl_meminfo, "A", "memory regions"); 3207228561Snp 3208228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "path_mtus", 3209228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3210228561Snp sysctl_path_mtus, "A", "path MTUs"); 3211228561Snp 3212228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pm_stats", 3213228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3214228561Snp sysctl_pm_stats, "A", "PM statistics"); 3215228561Snp 3216228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_stats", 3217228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3218228561Snp sysctl_rdma_stats, "A", "RDMA statistics"); 3219228561Snp 3220228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tcp_stats", 3221228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3222228561Snp sysctl_tcp_stats, "A", "TCP statistics"); 3223228561Snp 3224228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tids", 3225228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3226228561Snp sysctl_tids, "A", "TID information"); 3227228561Snp 3228228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_err_stats", 3229228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3230228561Snp sysctl_tp_err_stats, "A", "TP error statistics"); 3231228561Snp 3232228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_rate", 3233228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3234228561Snp sysctl_tx_rate, "A", "Tx rate"); 3235231115Snp#endif 3236228561Snp 3237237263Snp#ifdef TCP_OFFLOAD 3238228561Snp if (is_offload(sc)) { 3239228561Snp /* 3240228561Snp * dev.t4nex.X.toe. 3241228561Snp */ 3242228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "toe", CTLFLAG_RD, 3243228561Snp NULL, "TOE parameters"); 3244228561Snp children = SYSCTL_CHILDREN(oid); 3245228561Snp 3246228561Snp sc->tt.sndbuf = 256 * 1024; 3247228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "sndbuf", CTLFLAG_RW, 3248228561Snp &sc->tt.sndbuf, 0, "max hardware send buffer size"); 3249228561Snp 3250228561Snp sc->tt.ddp = 0; 3251228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp", CTLFLAG_RW, 3252228561Snp &sc->tt.ddp, 0, "DDP allowed"); 3253239341Snp 3254239341Snp sc->tt.indsz = G_INDICATESIZE(t4_read_reg(sc, A_TP_PARA_REG5)); 3255228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "indsz", CTLFLAG_RW, 3256228561Snp &sc->tt.indsz, 0, "DDP max indicate size allowed"); 3257239341Snp 3258239341Snp sc->tt.ddp_thres = 3259239341Snp G_RXCOALESCESIZE(t4_read_reg(sc, A_TP_PARA_REG2)); 3260228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp_thres", CTLFLAG_RW, 3261228561Snp &sc->tt.ddp_thres, 0, "DDP threshold"); 3262228561Snp } 3263228561Snp#endif 3264228561Snp 3265228561Snp 3266218792Snp return (0); 3267218792Snp} 3268218792Snp 3269218792Snpstatic int 3270218792Snpcxgbe_sysctls(struct port_info *pi) 3271218792Snp{ 3272218792Snp struct sysctl_ctx_list *ctx; 3273218792Snp struct sysctl_oid *oid; 3274218792Snp struct sysctl_oid_list *children; 3275218792Snp 3276218792Snp ctx = device_get_sysctl_ctx(pi->dev); 3277218792Snp 3278218792Snp /* 3279218792Snp * dev.cxgbe.X. 3280218792Snp */ 3281218792Snp oid = device_get_sysctl_tree(pi->dev); 3282218792Snp children = SYSCTL_CHILDREN(oid); 3283218792Snp 3284218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD, 3285218792Snp &pi->nrxq, 0, "# of rx queues"); 3286218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD, 3287218792Snp &pi->ntxq, 0, "# of tx queues"); 3288218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD, 3289218792Snp &pi->first_rxq, 0, "index of first rx queue"); 3290218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD, 3291218792Snp &pi->first_txq, 0, "index of first tx queue"); 3292218792Snp 3293237263Snp#ifdef TCP_OFFLOAD 3294228561Snp if (is_offload(pi->adapter)) { 3295228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldrxq", CTLFLAG_RD, 3296228561Snp &pi->nofldrxq, 0, 3297228561Snp "# of rx queues for offloaded TCP connections"); 3298228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldtxq", CTLFLAG_RD, 3299228561Snp &pi->nofldtxq, 0, 3300228561Snp "# of tx queues for offloaded TCP connections"); 3301228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_rxq", 3302228561Snp CTLFLAG_RD, &pi->first_ofld_rxq, 0, 3303228561Snp "index of first TOE rx queue"); 3304228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_txq", 3305228561Snp CTLFLAG_RD, &pi->first_ofld_txq, 0, 3306228561Snp "index of first TOE tx queue"); 3307228561Snp } 3308228561Snp#endif 3309228561Snp 3310218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx", 3311218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I", 3312218792Snp "holdoff timer index"); 3313218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx", 3314218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I", 3315218792Snp "holdoff packet counter index"); 3316218792Snp 3317218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq", 3318218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I", 3319218792Snp "rx queue size"); 3320218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq", 3321218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I", 3322218792Snp "tx queue size"); 3323218792Snp 3324218792Snp /* 3325218792Snp * dev.cxgbe.X.stats. 3326218792Snp */ 3327218792Snp oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, 3328218792Snp NULL, "port statistics"); 3329218792Snp children = SYSCTL_CHILDREN(oid); 3330218792Snp 3331218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \ 3332218792Snp SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \ 3333218792Snp CTLTYPE_U64 | CTLFLAG_RD, pi->adapter, reg, \ 3334218792Snp sysctl_handle_t4_reg64, "QU", desc) 3335218792Snp 3336218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames", 3337218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L)); 3338218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames", 3339218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L)); 3340218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames", 3341218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L)); 3342218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames", 3343218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L)); 3344218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames", 3345218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L)); 3346218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames", 3347218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L)); 3348218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_64", 3349218792Snp "# of tx frames in this range", 3350218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L)); 3351218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127", 3352218792Snp "# of tx frames in this range", 3353218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L)); 3354218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255", 3355218792Snp "# of tx frames in this range", 3356218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L)); 3357218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511", 3358218792Snp "# of tx frames in this range", 3359218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L)); 3360218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023", 3361218792Snp "# of tx frames in this range", 3362218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L)); 3363218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518", 3364218792Snp "# of tx frames in this range", 3365218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L)); 3366218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max", 3367218792Snp "# of tx frames in this range", 3368218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L)); 3369218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames", 3370218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L)); 3371218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted", 3372218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L)); 3373218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted", 3374218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L)); 3375218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted", 3376218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L)); 3377218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted", 3378218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L)); 3379218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted", 3380218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L)); 3381218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted", 3382218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L)); 3383218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted", 3384218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L)); 3385218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted", 3386218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L)); 3387218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted", 3388218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L)); 3389218792Snp 3390218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames", 3391218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L)); 3392218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames", 3393218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L)); 3394218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames", 3395218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L)); 3396218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames", 3397218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L)); 3398218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames", 3399218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L)); 3400218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU", 3401218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L)); 3402218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames", 3403218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L)); 3404218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err", 3405218792Snp "# of frames received with bad FCS", 3406218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L)); 3407218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_len_err", 3408218792Snp "# of frames received with length error", 3409218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L)); 3410218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors", 3411218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L)); 3412218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received", 3413218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L)); 3414218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_64", 3415218792Snp "# of rx frames in this range", 3416218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L)); 3417218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127", 3418218792Snp "# of rx frames in this range", 3419218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L)); 3420218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255", 3421218792Snp "# of rx frames in this range", 3422218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L)); 3423218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511", 3424218792Snp "# of rx frames in this range", 3425218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L)); 3426218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023", 3427218792Snp "# of rx frames in this range", 3428218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L)); 3429218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518", 3430218792Snp "# of rx frames in this range", 3431218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L)); 3432218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max", 3433218792Snp "# of rx frames in this range", 3434218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L)); 3435218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received", 3436218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L)); 3437218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received", 3438218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L)); 3439218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received", 3440218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L)); 3441218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received", 3442218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L)); 3443218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received", 3444218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L)); 3445218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received", 3446218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L)); 3447218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received", 3448218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L)); 3449218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received", 3450218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L)); 3451218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received", 3452218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L)); 3453218792Snp 3454218792Snp#undef SYSCTL_ADD_T4_REG64 3455218792Snp 3456218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \ 3457218792Snp SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \ 3458218792Snp &pi->stats.name, desc) 3459218792Snp 3460218792Snp /* We get these from port_stats and they may be stale by upto 1s */ 3461218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0, 3462218792Snp "# drops due to buffer-group 0 overflows"); 3463218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1, 3464218792Snp "# drops due to buffer-group 1 overflows"); 3465218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2, 3466218792Snp "# drops due to buffer-group 2 overflows"); 3467218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3, 3468218792Snp "# drops due to buffer-group 3 overflows"); 3469218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc0, 3470218792Snp "# of buffer-group 0 truncated packets"); 3471218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc1, 3472218792Snp "# of buffer-group 1 truncated packets"); 3473218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc2, 3474218792Snp "# of buffer-group 2 truncated packets"); 3475218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc3, 3476218792Snp "# of buffer-group 3 truncated packets"); 3477218792Snp 3478218792Snp#undef SYSCTL_ADD_T4_PORTSTAT 3479218792Snp 3480218792Snp return (0); 3481218792Snp} 3482218792Snp 3483218792Snpstatic int 3484219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS) 3485219436Snp{ 3486219436Snp int rc, *i; 3487219436Snp struct sbuf sb; 3488219436Snp 3489219436Snp sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); 3490219436Snp for (i = arg1; arg2; arg2 -= sizeof(int), i++) 3491219436Snp sbuf_printf(&sb, "%d ", *i); 3492219436Snp sbuf_trim(&sb); 3493219436Snp sbuf_finish(&sb); 3494219436Snp rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 3495219436Snp sbuf_delete(&sb); 3496219436Snp return (rc); 3497219436Snp} 3498219436Snp 3499219436Snpstatic int 3500228561Snpsysctl_bitfield(SYSCTL_HANDLER_ARGS) 3501228561Snp{ 3502228561Snp int rc; 3503228561Snp struct sbuf *sb; 3504228561Snp 3505228561Snp rc = sysctl_wire_old_buffer(req, 0); 3506228561Snp if (rc != 0) 3507228561Snp return(rc); 3508228561Snp 3509228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 3510228561Snp if (sb == NULL) 3511228561Snp return (ENOMEM); 3512228561Snp 3513228561Snp sbuf_printf(sb, "%b", (int)arg2, (char *)arg1); 3514228561Snp rc = sbuf_finish(sb); 3515228561Snp sbuf_delete(sb); 3516228561Snp 3517228561Snp return (rc); 3518228561Snp} 3519228561Snp 3520228561Snpstatic int 3521218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS) 3522218792Snp{ 3523218792Snp struct port_info *pi = arg1; 3524218792Snp struct adapter *sc = pi->adapter; 3525218792Snp int idx, rc, i; 3526218792Snp 3527218792Snp idx = pi->tmr_idx; 3528218792Snp 3529218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 3530218792Snp if (rc != 0 || req->newptr == NULL) 3531218792Snp return (rc); 3532218792Snp 3533218792Snp if (idx < 0 || idx >= SGE_NTIMERS) 3534218792Snp return (EINVAL); 3535218792Snp 3536218792Snp ADAPTER_LOCK(sc); 3537218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3538218792Snp if (rc == 0) { 3539228561Snp struct sge_rxq *rxq; 3540228561Snp uint8_t v; 3541228561Snp 3542228561Snp v = V_QINTR_TIMER_IDX(idx) | V_QINTR_CNT_EN(pi->pktc_idx != -1); 3543218792Snp for_each_rxq(pi, i, rxq) { 3544228561Snp#ifdef atomic_store_rel_8 3545228561Snp atomic_store_rel_8(&rxq->iq.intr_params, v); 3546228561Snp#else 3547228561Snp rxq->iq.intr_params = v; 3548228561Snp#endif 3549218792Snp } 3550218792Snp pi->tmr_idx = idx; 3551218792Snp } 3552218792Snp 3553218792Snp ADAPTER_UNLOCK(sc); 3554218792Snp return (rc); 3555218792Snp} 3556218792Snp 3557218792Snpstatic int 3558218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS) 3559218792Snp{ 3560218792Snp struct port_info *pi = arg1; 3561218792Snp struct adapter *sc = pi->adapter; 3562218792Snp int idx, rc; 3563218792Snp 3564218792Snp idx = pi->pktc_idx; 3565218792Snp 3566218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 3567218792Snp if (rc != 0 || req->newptr == NULL) 3568218792Snp return (rc); 3569218792Snp 3570218792Snp if (idx < -1 || idx >= SGE_NCOUNTERS) 3571218792Snp return (EINVAL); 3572218792Snp 3573218792Snp ADAPTER_LOCK(sc); 3574218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3575228561Snp if (rc == 0 && pi->flags & PORT_INIT_DONE) 3576228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 3577218792Snp 3578218792Snp if (rc == 0) 3579218792Snp pi->pktc_idx = idx; 3580218792Snp 3581218792Snp ADAPTER_UNLOCK(sc); 3582218792Snp return (rc); 3583218792Snp} 3584218792Snp 3585218792Snpstatic int 3586218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS) 3587218792Snp{ 3588218792Snp struct port_info *pi = arg1; 3589218792Snp struct adapter *sc = pi->adapter; 3590218792Snp int qsize, rc; 3591218792Snp 3592218792Snp qsize = pi->qsize_rxq; 3593218792Snp 3594218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 3595218792Snp if (rc != 0 || req->newptr == NULL) 3596218792Snp return (rc); 3597218792Snp 3598218792Snp if (qsize < 128 || (qsize & 7)) 3599218792Snp return (EINVAL); 3600218792Snp 3601218792Snp ADAPTER_LOCK(sc); 3602218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3603228561Snp if (rc == 0 && pi->flags & PORT_INIT_DONE) 3604228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 3605218792Snp 3606218792Snp if (rc == 0) 3607218792Snp pi->qsize_rxq = qsize; 3608218792Snp 3609218792Snp ADAPTER_UNLOCK(sc); 3610218792Snp return (rc); 3611218792Snp} 3612218792Snp 3613218792Snpstatic int 3614218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS) 3615218792Snp{ 3616218792Snp struct port_info *pi = arg1; 3617218792Snp struct adapter *sc = pi->adapter; 3618218792Snp int qsize, rc; 3619218792Snp 3620218792Snp qsize = pi->qsize_txq; 3621218792Snp 3622218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 3623218792Snp if (rc != 0 || req->newptr == NULL) 3624218792Snp return (rc); 3625218792Snp 3626218792Snp if (qsize < 128) 3627218792Snp return (EINVAL); 3628218792Snp 3629218792Snp ADAPTER_LOCK(sc); 3630218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3631228561Snp if (rc == 0 && pi->flags & PORT_INIT_DONE) 3632228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 3633218792Snp 3634218792Snp if (rc == 0) 3635218792Snp pi->qsize_txq = qsize; 3636218792Snp 3637218792Snp ADAPTER_UNLOCK(sc); 3638218792Snp return (rc); 3639218792Snp} 3640218792Snp 3641218792Snpstatic int 3642218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS) 3643218792Snp{ 3644218792Snp struct adapter *sc = arg1; 3645218792Snp int reg = arg2; 3646218792Snp uint64_t val; 3647218792Snp 3648218792Snp val = t4_read_reg64(sc, reg); 3649218792Snp 3650218792Snp return (sysctl_handle_64(oidp, &val, 0, req)); 3651218792Snp} 3652218792Snp 3653231115Snp#ifdef SBUF_DRAIN 3654228561Snpstatic int 3655228561Snpsysctl_cctrl(SYSCTL_HANDLER_ARGS) 3656228561Snp{ 3657228561Snp struct adapter *sc = arg1; 3658228561Snp struct sbuf *sb; 3659228561Snp int rc, i; 3660228561Snp uint16_t incr[NMTUS][NCCTRL_WIN]; 3661228561Snp static const char *dec_fac[] = { 3662228561Snp "0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875", 3663228561Snp "0.9375" 3664228561Snp }; 3665228561Snp 3666228561Snp rc = sysctl_wire_old_buffer(req, 0); 3667228561Snp if (rc != 0) 3668228561Snp return (rc); 3669228561Snp 3670228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3671228561Snp if (sb == NULL) 3672228561Snp return (ENOMEM); 3673228561Snp 3674228561Snp t4_read_cong_tbl(sc, incr); 3675228561Snp 3676228561Snp for (i = 0; i < NCCTRL_WIN; ++i) { 3677228561Snp sbuf_printf(sb, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i, 3678228561Snp incr[0][i], incr[1][i], incr[2][i], incr[3][i], incr[4][i], 3679228561Snp incr[5][i], incr[6][i], incr[7][i]); 3680228561Snp sbuf_printf(sb, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n", 3681228561Snp incr[8][i], incr[9][i], incr[10][i], incr[11][i], 3682228561Snp incr[12][i], incr[13][i], incr[14][i], incr[15][i], 3683228561Snp sc->params.a_wnd[i], dec_fac[sc->params.b_wnd[i]]); 3684228561Snp } 3685228561Snp 3686228561Snp rc = sbuf_finish(sb); 3687228561Snp sbuf_delete(sb); 3688228561Snp 3689228561Snp return (rc); 3690228561Snp} 3691228561Snp 3692228561Snpstatic int 3693228561Snpsysctl_cpl_stats(SYSCTL_HANDLER_ARGS) 3694228561Snp{ 3695228561Snp struct adapter *sc = arg1; 3696228561Snp struct sbuf *sb; 3697228561Snp int rc; 3698228561Snp struct tp_cpl_stats stats; 3699228561Snp 3700228561Snp rc = sysctl_wire_old_buffer(req, 0); 3701228561Snp if (rc != 0) 3702228561Snp return (rc); 3703228561Snp 3704228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3705228561Snp if (sb == NULL) 3706228561Snp return (ENOMEM); 3707228561Snp 3708228561Snp t4_tp_get_cpl_stats(sc, &stats); 3709228561Snp 3710228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 3711228561Snp "channel 3\n"); 3712228561Snp sbuf_printf(sb, "CPL requests: %10u %10u %10u %10u\n", 3713228561Snp stats.req[0], stats.req[1], stats.req[2], stats.req[3]); 3714228561Snp sbuf_printf(sb, "CPL responses: %10u %10u %10u %10u", 3715228561Snp stats.rsp[0], stats.rsp[1], stats.rsp[2], stats.rsp[3]); 3716228561Snp 3717228561Snp rc = sbuf_finish(sb); 3718228561Snp sbuf_delete(sb); 3719228561Snp 3720228561Snp return (rc); 3721228561Snp} 3722228561Snp 3723228561Snpstatic int 3724228561Snpsysctl_ddp_stats(SYSCTL_HANDLER_ARGS) 3725228561Snp{ 3726228561Snp struct adapter *sc = arg1; 3727228561Snp struct sbuf *sb; 3728228561Snp int rc; 3729228561Snp struct tp_usm_stats stats; 3730228561Snp 3731228561Snp rc = sysctl_wire_old_buffer(req, 0); 3732228561Snp if (rc != 0) 3733228561Snp return(rc); 3734228561Snp 3735228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3736228561Snp if (sb == NULL) 3737228561Snp return (ENOMEM); 3738228561Snp 3739228561Snp t4_get_usm_stats(sc, &stats); 3740228561Snp 3741228561Snp sbuf_printf(sb, "Frames: %u\n", stats.frames); 3742228561Snp sbuf_printf(sb, "Octets: %ju\n", stats.octets); 3743228561Snp sbuf_printf(sb, "Drops: %u", stats.drops); 3744228561Snp 3745228561Snp rc = sbuf_finish(sb); 3746228561Snp sbuf_delete(sb); 3747228561Snp 3748228561Snp return (rc); 3749228561Snp} 3750228561Snp 3751222551Snpconst char *devlog_level_strings[] = { 3752222551Snp [FW_DEVLOG_LEVEL_EMERG] = "EMERG", 3753222551Snp [FW_DEVLOG_LEVEL_CRIT] = "CRIT", 3754222551Snp [FW_DEVLOG_LEVEL_ERR] = "ERR", 3755222551Snp [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", 3756222551Snp [FW_DEVLOG_LEVEL_INFO] = "INFO", 3757222551Snp [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" 3758222551Snp}; 3759222551Snp 3760222551Snpconst char *devlog_facility_strings[] = { 3761222551Snp [FW_DEVLOG_FACILITY_CORE] = "CORE", 3762222551Snp [FW_DEVLOG_FACILITY_SCHED] = "SCHED", 3763222551Snp [FW_DEVLOG_FACILITY_TIMER] = "TIMER", 3764222551Snp [FW_DEVLOG_FACILITY_RES] = "RES", 3765222551Snp [FW_DEVLOG_FACILITY_HW] = "HW", 3766222551Snp [FW_DEVLOG_FACILITY_FLR] = "FLR", 3767222551Snp [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", 3768222551Snp [FW_DEVLOG_FACILITY_PHY] = "PHY", 3769222551Snp [FW_DEVLOG_FACILITY_MAC] = "MAC", 3770222551Snp [FW_DEVLOG_FACILITY_PORT] = "PORT", 3771222551Snp [FW_DEVLOG_FACILITY_VI] = "VI", 3772222551Snp [FW_DEVLOG_FACILITY_FILTER] = "FILTER", 3773222551Snp [FW_DEVLOG_FACILITY_ACL] = "ACL", 3774222551Snp [FW_DEVLOG_FACILITY_TM] = "TM", 3775222551Snp [FW_DEVLOG_FACILITY_QFC] = "QFC", 3776222551Snp [FW_DEVLOG_FACILITY_DCB] = "DCB", 3777222551Snp [FW_DEVLOG_FACILITY_ETH] = "ETH", 3778222551Snp [FW_DEVLOG_FACILITY_OFLD] = "OFLD", 3779222551Snp [FW_DEVLOG_FACILITY_RI] = "RI", 3780222551Snp [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", 3781222551Snp [FW_DEVLOG_FACILITY_FCOE] = "FCOE", 3782222551Snp [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", 3783222551Snp [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE" 3784222551Snp}; 3785222551Snp 3786222551Snpstatic int 3787222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS) 3788222551Snp{ 3789222551Snp struct adapter *sc = arg1; 3790222551Snp struct devlog_params *dparams = &sc->params.devlog; 3791222551Snp struct fw_devlog_e *buf, *e; 3792222551Snp int i, j, rc, nentries, first = 0; 3793222551Snp struct sbuf *sb; 3794222551Snp uint64_t ftstamp = UINT64_MAX; 3795222551Snp 3796222551Snp if (dparams->start == 0) 3797222551Snp return (ENXIO); 3798222551Snp 3799222551Snp nentries = dparams->size / sizeof(struct fw_devlog_e); 3800222551Snp 3801222551Snp buf = malloc(dparams->size, M_CXGBE, M_NOWAIT); 3802222551Snp if (buf == NULL) 3803222551Snp return (ENOMEM); 3804222551Snp 3805222551Snp rc = -t4_mem_read(sc, dparams->memtype, dparams->start, dparams->size, 3806222551Snp (void *)buf); 3807222551Snp if (rc != 0) 3808222551Snp goto done; 3809222551Snp 3810222551Snp for (i = 0; i < nentries; i++) { 3811222551Snp e = &buf[i]; 3812222551Snp 3813222551Snp if (e->timestamp == 0) 3814222551Snp break; /* end */ 3815222551Snp 3816222551Snp e->timestamp = be64toh(e->timestamp); 3817222551Snp e->seqno = be32toh(e->seqno); 3818222551Snp for (j = 0; j < 8; j++) 3819222551Snp e->params[j] = be32toh(e->params[j]); 3820222551Snp 3821222551Snp if (e->timestamp < ftstamp) { 3822222551Snp ftstamp = e->timestamp; 3823222551Snp first = i; 3824222551Snp } 3825222551Snp } 3826222551Snp 3827222551Snp if (buf[first].timestamp == 0) 3828222551Snp goto done; /* nothing in the log */ 3829222551Snp 3830222551Snp rc = sysctl_wire_old_buffer(req, 0); 3831222551Snp if (rc != 0) 3832222551Snp goto done; 3833222551Snp 3834222551Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3835228561Snp if (sb == NULL) { 3836228561Snp rc = ENOMEM; 3837228561Snp goto done; 3838228561Snp } 3839228561Snp sbuf_printf(sb, "%10s %15s %8s %8s %s\n", 3840222551Snp "Seq#", "Tstamp", "Level", "Facility", "Message"); 3841222551Snp 3842222551Snp i = first; 3843222551Snp do { 3844222551Snp e = &buf[i]; 3845222551Snp if (e->timestamp == 0) 3846222551Snp break; /* end */ 3847222551Snp 3848222551Snp sbuf_printf(sb, "%10d %15ju %8s %8s ", 3849222551Snp e->seqno, e->timestamp, 3850240452Snp (e->level < nitems(devlog_level_strings) ? 3851222551Snp devlog_level_strings[e->level] : "UNKNOWN"), 3852240452Snp (e->facility < nitems(devlog_facility_strings) ? 3853222551Snp devlog_facility_strings[e->facility] : "UNKNOWN")); 3854222551Snp sbuf_printf(sb, e->fmt, e->params[0], e->params[1], 3855222551Snp e->params[2], e->params[3], e->params[4], 3856222551Snp e->params[5], e->params[6], e->params[7]); 3857222551Snp 3858222551Snp if (++i == nentries) 3859222551Snp i = 0; 3860222551Snp } while (i != first); 3861222551Snp 3862222551Snp rc = sbuf_finish(sb); 3863222551Snp sbuf_delete(sb); 3864222551Snpdone: 3865222551Snp free(buf, M_CXGBE); 3866222551Snp return (rc); 3867222551Snp} 3868222551Snp 3869228561Snpstatic int 3870228561Snpsysctl_fcoe_stats(SYSCTL_HANDLER_ARGS) 3871228561Snp{ 3872228561Snp struct adapter *sc = arg1; 3873228561Snp struct sbuf *sb; 3874228561Snp int rc; 3875228561Snp struct tp_fcoe_stats stats[4]; 3876228561Snp 3877228561Snp rc = sysctl_wire_old_buffer(req, 0); 3878228561Snp if (rc != 0) 3879228561Snp return (rc); 3880228561Snp 3881228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3882228561Snp if (sb == NULL) 3883228561Snp return (ENOMEM); 3884228561Snp 3885228561Snp t4_get_fcoe_stats(sc, 0, &stats[0]); 3886228561Snp t4_get_fcoe_stats(sc, 1, &stats[1]); 3887228561Snp t4_get_fcoe_stats(sc, 2, &stats[2]); 3888228561Snp t4_get_fcoe_stats(sc, 3, &stats[3]); 3889228561Snp 3890228561Snp sbuf_printf(sb, " channel 0 channel 1 " 3891228561Snp "channel 2 channel 3\n"); 3892228561Snp sbuf_printf(sb, "octetsDDP: %16ju %16ju %16ju %16ju\n", 3893228561Snp stats[0].octetsDDP, stats[1].octetsDDP, stats[2].octetsDDP, 3894228561Snp stats[3].octetsDDP); 3895228561Snp sbuf_printf(sb, "framesDDP: %16u %16u %16u %16u\n", stats[0].framesDDP, 3896228561Snp stats[1].framesDDP, stats[2].framesDDP, stats[3].framesDDP); 3897228561Snp sbuf_printf(sb, "framesDrop: %16u %16u %16u %16u", 3898228561Snp stats[0].framesDrop, stats[1].framesDrop, stats[2].framesDrop, 3899228561Snp stats[3].framesDrop); 3900228561Snp 3901228561Snp rc = sbuf_finish(sb); 3902228561Snp sbuf_delete(sb); 3903228561Snp 3904228561Snp return (rc); 3905228561Snp} 3906228561Snp 3907228561Snpstatic int 3908228561Snpsysctl_hw_sched(SYSCTL_HANDLER_ARGS) 3909228561Snp{ 3910228561Snp struct adapter *sc = arg1; 3911228561Snp struct sbuf *sb; 3912228561Snp int rc, i; 3913228561Snp unsigned int map, kbps, ipg, mode; 3914228561Snp unsigned int pace_tab[NTX_SCHED]; 3915228561Snp 3916228561Snp rc = sysctl_wire_old_buffer(req, 0); 3917228561Snp if (rc != 0) 3918228561Snp return (rc); 3919228561Snp 3920228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3921228561Snp if (sb == NULL) 3922228561Snp return (ENOMEM); 3923228561Snp 3924228561Snp map = t4_read_reg(sc, A_TP_TX_MOD_QUEUE_REQ_MAP); 3925228561Snp mode = G_TIMERMODE(t4_read_reg(sc, A_TP_MOD_CONFIG)); 3926228561Snp t4_read_pace_tbl(sc, pace_tab); 3927228561Snp 3928228561Snp sbuf_printf(sb, "Scheduler Mode Channel Rate (Kbps) " 3929228561Snp "Class IPG (0.1 ns) Flow IPG (us)"); 3930228561Snp 3931228561Snp for (i = 0; i < NTX_SCHED; ++i, map >>= 2) { 3932228561Snp t4_get_tx_sched(sc, i, &kbps, &ipg); 3933228561Snp sbuf_printf(sb, "\n %u %-5s %u ", i, 3934228561Snp (mode & (1 << i)) ? "flow" : "class", map & 3); 3935228561Snp if (kbps) 3936228561Snp sbuf_printf(sb, "%9u ", kbps); 3937228561Snp else 3938228561Snp sbuf_printf(sb, " disabled "); 3939228561Snp 3940228561Snp if (ipg) 3941228561Snp sbuf_printf(sb, "%13u ", ipg); 3942228561Snp else 3943228561Snp sbuf_printf(sb, " disabled "); 3944228561Snp 3945228561Snp if (pace_tab[i]) 3946228561Snp sbuf_printf(sb, "%10u", pace_tab[i]); 3947228561Snp else 3948228561Snp sbuf_printf(sb, " disabled"); 3949228561Snp } 3950228561Snp 3951228561Snp rc = sbuf_finish(sb); 3952228561Snp sbuf_delete(sb); 3953228561Snp 3954228561Snp return (rc); 3955228561Snp} 3956228561Snp 3957228561Snpstatic int 3958228561Snpsysctl_lb_stats(SYSCTL_HANDLER_ARGS) 3959228561Snp{ 3960228561Snp struct adapter *sc = arg1; 3961228561Snp struct sbuf *sb; 3962228561Snp int rc, i, j; 3963228561Snp uint64_t *p0, *p1; 3964228561Snp struct lb_port_stats s[2]; 3965228561Snp static const char *stat_name[] = { 3966228561Snp "OctetsOK:", "FramesOK:", "BcastFrames:", "McastFrames:", 3967228561Snp "UcastFrames:", "ErrorFrames:", "Frames64:", "Frames65To127:", 3968228561Snp "Frames128To255:", "Frames256To511:", "Frames512To1023:", 3969228561Snp "Frames1024To1518:", "Frames1519ToMax:", "FramesDropped:", 3970228561Snp "BG0FramesDropped:", "BG1FramesDropped:", "BG2FramesDropped:", 3971228561Snp "BG3FramesDropped:", "BG0FramesTrunc:", "BG1FramesTrunc:", 3972228561Snp "BG2FramesTrunc:", "BG3FramesTrunc:" 3973228561Snp }; 3974228561Snp 3975228561Snp rc = sysctl_wire_old_buffer(req, 0); 3976228561Snp if (rc != 0) 3977228561Snp return (rc); 3978228561Snp 3979228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3980228561Snp if (sb == NULL) 3981228561Snp return (ENOMEM); 3982228561Snp 3983228561Snp memset(s, 0, sizeof(s)); 3984228561Snp 3985228561Snp for (i = 0; i < 4; i += 2) { 3986228561Snp t4_get_lb_stats(sc, i, &s[0]); 3987228561Snp t4_get_lb_stats(sc, i + 1, &s[1]); 3988228561Snp 3989228561Snp p0 = &s[0].octets; 3990228561Snp p1 = &s[1].octets; 3991228561Snp sbuf_printf(sb, "%s Loopback %u" 3992228561Snp " Loopback %u", i == 0 ? "" : "\n", i, i + 1); 3993228561Snp 3994240452Snp for (j = 0; j < nitems(stat_name); j++) 3995228561Snp sbuf_printf(sb, "\n%-17s %20ju %20ju", stat_name[j], 3996228561Snp *p0++, *p1++); 3997228561Snp } 3998228561Snp 3999228561Snp rc = sbuf_finish(sb); 4000228561Snp sbuf_delete(sb); 4001228561Snp 4002228561Snp return (rc); 4003228561Snp} 4004228561Snp 4005228561Snpstruct mem_desc { 4006228561Snp unsigned int base; 4007228561Snp unsigned int limit; 4008228561Snp unsigned int idx; 4009228561Snp}; 4010228561Snp 4011228561Snpstatic int 4012228561Snpmem_desc_cmp(const void *a, const void *b) 4013228561Snp{ 4014228561Snp return ((const struct mem_desc *)a)->base - 4015228561Snp ((const struct mem_desc *)b)->base; 4016228561Snp} 4017228561Snp 4018228561Snpstatic void 4019228561Snpmem_region_show(struct sbuf *sb, const char *name, unsigned int from, 4020228561Snp unsigned int to) 4021228561Snp{ 4022228561Snp unsigned int size; 4023228561Snp 4024228561Snp size = to - from + 1; 4025228561Snp if (size == 0) 4026228561Snp return; 4027228561Snp 4028228561Snp /* XXX: need humanize_number(3) in libkern for a more readable 'size' */ 4029228561Snp sbuf_printf(sb, "%-15s %#x-%#x [%u]\n", name, from, to, size); 4030228561Snp} 4031228561Snp 4032228561Snpstatic int 4033228561Snpsysctl_meminfo(SYSCTL_HANDLER_ARGS) 4034228561Snp{ 4035228561Snp struct adapter *sc = arg1; 4036228561Snp struct sbuf *sb; 4037228561Snp int rc, i, n; 4038228561Snp uint32_t lo, hi; 4039228561Snp static const char *memory[] = { "EDC0:", "EDC1:", "MC:" }; 4040228561Snp static const char *region[] = { 4041228561Snp "DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:", 4042228561Snp "Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:", 4043228561Snp "Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:", 4044228561Snp "TDDP region:", "TPT region:", "STAG region:", "RQ region:", 4045228561Snp "RQUDP region:", "PBL region:", "TXPBL region:", "ULPRX state:", 4046228561Snp "ULPTX state:", "On-chip queues:" 4047228561Snp }; 4048228561Snp struct mem_desc avail[3]; 4049240452Snp struct mem_desc mem[nitems(region) + 3]; /* up to 3 holes */ 4050228561Snp struct mem_desc *md = mem; 4051228561Snp 4052228561Snp rc = sysctl_wire_old_buffer(req, 0); 4053228561Snp if (rc != 0) 4054228561Snp return (rc); 4055228561Snp 4056228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 4057228561Snp if (sb == NULL) 4058228561Snp return (ENOMEM); 4059228561Snp 4060240452Snp for (i = 0; i < nitems(mem); i++) { 4061228561Snp mem[i].limit = 0; 4062228561Snp mem[i].idx = i; 4063228561Snp } 4064228561Snp 4065228561Snp /* Find and sort the populated memory ranges */ 4066228561Snp i = 0; 4067228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 4068228561Snp if (lo & F_EDRAM0_ENABLE) { 4069228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 4070228561Snp avail[i].base = G_EDRAM0_BASE(hi) << 20; 4071228561Snp avail[i].limit = avail[i].base + (G_EDRAM0_SIZE(hi) << 20); 4072228561Snp avail[i].idx = 0; 4073228561Snp i++; 4074228561Snp } 4075228561Snp if (lo & F_EDRAM1_ENABLE) { 4076228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 4077228561Snp avail[i].base = G_EDRAM1_BASE(hi) << 20; 4078228561Snp avail[i].limit = avail[i].base + (G_EDRAM1_SIZE(hi) << 20); 4079228561Snp avail[i].idx = 1; 4080228561Snp i++; 4081228561Snp } 4082228561Snp if (lo & F_EXT_MEM_ENABLE) { 4083228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 4084228561Snp avail[i].base = G_EXT_MEM_BASE(hi) << 20; 4085228561Snp avail[i].limit = avail[i].base + (G_EXT_MEM_SIZE(hi) << 20); 4086228561Snp avail[i].idx = 2; 4087228561Snp i++; 4088228561Snp } 4089228561Snp if (!i) /* no memory available */ 4090228561Snp return 0; 4091228561Snp qsort(avail, i, sizeof(struct mem_desc), mem_desc_cmp); 4092228561Snp 4093228561Snp (md++)->base = t4_read_reg(sc, A_SGE_DBQ_CTXT_BADDR); 4094228561Snp (md++)->base = t4_read_reg(sc, A_SGE_IMSG_CTXT_BADDR); 4095228561Snp (md++)->base = t4_read_reg(sc, A_SGE_FLM_CACHE_BADDR); 4096228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 4097228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_BASE); 4098228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TIMER_BASE); 4099228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_RX_FLST_BASE); 4100228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_TX_FLST_BASE); 4101228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_PS_FLST_BASE); 4102228561Snp 4103228561Snp /* the next few have explicit upper bounds */ 4104228561Snp md->base = t4_read_reg(sc, A_TP_PMM_TX_BASE); 4105228561Snp md->limit = md->base - 1 + 4106228561Snp t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE) * 4107228561Snp G_PMTXMAXPAGE(t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE)); 4108228561Snp md++; 4109228561Snp 4110228561Snp md->base = t4_read_reg(sc, A_TP_PMM_RX_BASE); 4111228561Snp md->limit = md->base - 1 + 4112228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) * 4113228561Snp G_PMRXMAXPAGE(t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE)); 4114228561Snp md++; 4115228561Snp 4116228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 4117228561Snp hi = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4; 4118228561Snp md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE); 4119228561Snp md->limit = (sc->tids.ntids - hi) * 16 + md->base - 1; 4120228561Snp } else { 4121228561Snp md->base = 0; 4122240452Snp md->idx = nitems(region); /* hide it */ 4123228561Snp } 4124228561Snp md++; 4125228561Snp 4126228561Snp#define ulp_region(reg) \ 4127228561Snp md->base = t4_read_reg(sc, A_ULP_ ## reg ## _LLIMIT);\ 4128228561Snp (md++)->limit = t4_read_reg(sc, A_ULP_ ## reg ## _ULIMIT) 4129228561Snp 4130228561Snp ulp_region(RX_ISCSI); 4131228561Snp ulp_region(RX_TDDP); 4132228561Snp ulp_region(TX_TPT); 4133228561Snp ulp_region(RX_STAG); 4134228561Snp ulp_region(RX_RQ); 4135228561Snp ulp_region(RX_RQUDP); 4136228561Snp ulp_region(RX_PBL); 4137228561Snp ulp_region(TX_PBL); 4138228561Snp#undef ulp_region 4139228561Snp 4140228561Snp md->base = t4_read_reg(sc, A_ULP_RX_CTX_BASE); 4141228561Snp md->limit = md->base + sc->tids.ntids - 1; 4142228561Snp md++; 4143228561Snp md->base = t4_read_reg(sc, A_ULP_TX_ERR_TABLE_BASE); 4144228561Snp md->limit = md->base + sc->tids.ntids - 1; 4145228561Snp md++; 4146228561Snp 4147228561Snp md->base = sc->vres.ocq.start; 4148228561Snp if (sc->vres.ocq.size) 4149228561Snp md->limit = md->base + sc->vres.ocq.size - 1; 4150228561Snp else 4151240452Snp md->idx = nitems(region); /* hide it */ 4152228561Snp md++; 4153228561Snp 4154228561Snp /* add any address-space holes, there can be up to 3 */ 4155228561Snp for (n = 0; n < i - 1; n++) 4156228561Snp if (avail[n].limit < avail[n + 1].base) 4157228561Snp (md++)->base = avail[n].limit; 4158228561Snp if (avail[n].limit) 4159228561Snp (md++)->base = avail[n].limit; 4160228561Snp 4161228561Snp n = md - mem; 4162228561Snp qsort(mem, n, sizeof(struct mem_desc), mem_desc_cmp); 4163228561Snp 4164228561Snp for (lo = 0; lo < i; lo++) 4165228561Snp mem_region_show(sb, memory[avail[lo].idx], avail[lo].base, 4166228561Snp avail[lo].limit - 1); 4167228561Snp 4168228561Snp sbuf_printf(sb, "\n"); 4169228561Snp for (i = 0; i < n; i++) { 4170240452Snp if (mem[i].idx >= nitems(region)) 4171228561Snp continue; /* skip holes */ 4172228561Snp if (!mem[i].limit) 4173228561Snp mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0; 4174228561Snp mem_region_show(sb, region[mem[i].idx], mem[i].base, 4175228561Snp mem[i].limit); 4176228561Snp } 4177228561Snp 4178228561Snp sbuf_printf(sb, "\n"); 4179228561Snp lo = t4_read_reg(sc, A_CIM_SDRAM_BASE_ADDR); 4180228561Snp hi = t4_read_reg(sc, A_CIM_SDRAM_ADDR_SIZE) + lo - 1; 4181228561Snp mem_region_show(sb, "uP RAM:", lo, hi); 4182228561Snp 4183228561Snp lo = t4_read_reg(sc, A_CIM_EXTMEM2_BASE_ADDR); 4184228561Snp hi = t4_read_reg(sc, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1; 4185228561Snp mem_region_show(sb, "uP Extmem2:", lo, hi); 4186228561Snp 4187228561Snp lo = t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE); 4188228561Snp sbuf_printf(sb, "\n%u Rx pages of size %uKiB for %u channels\n", 4189228561Snp G_PMRXMAXPAGE(lo), 4190228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) >> 10, 4191228561Snp (lo & F_PMRXNUMCHN) ? 2 : 1); 4192228561Snp 4193228561Snp lo = t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE); 4194228561Snp hi = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE); 4195228561Snp sbuf_printf(sb, "%u Tx pages of size %u%ciB for %u channels\n", 4196228561Snp G_PMTXMAXPAGE(lo), 4197228561Snp hi >= (1 << 20) ? (hi >> 20) : (hi >> 10), 4198228561Snp hi >= (1 << 20) ? 'M' : 'K', 1 << G_PMTXNUMCHN(lo)); 4199228561Snp sbuf_printf(sb, "%u p-structs\n", 4200228561Snp t4_read_reg(sc, A_TP_CMM_MM_MAX_PSTRUCT)); 4201228561Snp 4202228561Snp for (i = 0; i < 4; i++) { 4203228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV0 + i * 4); 4204228561Snp sbuf_printf(sb, "\nPort %d using %u pages out of %u allocated", 4205228561Snp i, G_USED(lo), G_ALLOC(lo)); 4206228561Snp } 4207228561Snp for (i = 0; i < 4; i++) { 4208228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV4 + i * 4); 4209228561Snp sbuf_printf(sb, 4210228561Snp "\nLoopback %d using %u pages out of %u allocated", 4211228561Snp i, G_USED(lo), G_ALLOC(lo)); 4212228561Snp } 4213228561Snp 4214228561Snp rc = sbuf_finish(sb); 4215228561Snp sbuf_delete(sb); 4216228561Snp 4217228561Snp return (rc); 4218228561Snp} 4219228561Snp 4220228561Snpstatic int 4221228561Snpsysctl_path_mtus(SYSCTL_HANDLER_ARGS) 4222228561Snp{ 4223228561Snp struct adapter *sc = arg1; 4224228561Snp struct sbuf *sb; 4225228561Snp int rc; 4226228561Snp uint16_t mtus[NMTUS]; 4227228561Snp 4228228561Snp rc = sysctl_wire_old_buffer(req, 0); 4229228561Snp if (rc != 0) 4230228561Snp return (rc); 4231228561Snp 4232228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4233228561Snp if (sb == NULL) 4234228561Snp return (ENOMEM); 4235228561Snp 4236228561Snp t4_read_mtu_tbl(sc, mtus, NULL); 4237228561Snp 4238228561Snp sbuf_printf(sb, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", 4239228561Snp mtus[0], mtus[1], mtus[2], mtus[3], mtus[4], mtus[5], mtus[6], 4240228561Snp mtus[7], mtus[8], mtus[9], mtus[10], mtus[11], mtus[12], mtus[13], 4241228561Snp mtus[14], mtus[15]); 4242228561Snp 4243228561Snp rc = sbuf_finish(sb); 4244228561Snp sbuf_delete(sb); 4245228561Snp 4246228561Snp return (rc); 4247228561Snp} 4248228561Snp 4249228561Snpstatic int 4250228561Snpsysctl_pm_stats(SYSCTL_HANDLER_ARGS) 4251228561Snp{ 4252228561Snp struct adapter *sc = arg1; 4253228561Snp struct sbuf *sb; 4254228561Snp int rc, i; 4255228561Snp uint32_t tx_cnt[PM_NSTATS], rx_cnt[PM_NSTATS]; 4256228561Snp uint64_t tx_cyc[PM_NSTATS], rx_cyc[PM_NSTATS]; 4257228561Snp static const char *pm_stats[] = { 4258228561Snp "Read:", "Write bypass:", "Write mem:", "Flush:", "FIFO wait:" 4259228561Snp }; 4260228561Snp 4261228561Snp rc = sysctl_wire_old_buffer(req, 0); 4262228561Snp if (rc != 0) 4263228561Snp return (rc); 4264228561Snp 4265228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4266228561Snp if (sb == NULL) 4267228561Snp return (ENOMEM); 4268228561Snp 4269228561Snp t4_pmtx_get_stats(sc, tx_cnt, tx_cyc); 4270228561Snp t4_pmrx_get_stats(sc, rx_cnt, rx_cyc); 4271228561Snp 4272228561Snp sbuf_printf(sb, " Tx count Tx cycles " 4273228561Snp "Rx count Rx cycles"); 4274228561Snp for (i = 0; i < PM_NSTATS; i++) 4275228561Snp sbuf_printf(sb, "\n%-13s %10u %20ju %10u %20ju", 4276228561Snp pm_stats[i], tx_cnt[i], tx_cyc[i], rx_cnt[i], rx_cyc[i]); 4277228561Snp 4278228561Snp rc = sbuf_finish(sb); 4279228561Snp sbuf_delete(sb); 4280228561Snp 4281228561Snp return (rc); 4282228561Snp} 4283228561Snp 4284228561Snpstatic int 4285228561Snpsysctl_rdma_stats(SYSCTL_HANDLER_ARGS) 4286228561Snp{ 4287228561Snp struct adapter *sc = arg1; 4288228561Snp struct sbuf *sb; 4289228561Snp int rc; 4290228561Snp struct tp_rdma_stats stats; 4291228561Snp 4292228561Snp rc = sysctl_wire_old_buffer(req, 0); 4293228561Snp if (rc != 0) 4294228561Snp return (rc); 4295228561Snp 4296228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4297228561Snp if (sb == NULL) 4298228561Snp return (ENOMEM); 4299228561Snp 4300228561Snp t4_tp_get_rdma_stats(sc, &stats); 4301228561Snp sbuf_printf(sb, "NoRQEModDefferals: %u\n", stats.rqe_dfr_mod); 4302228561Snp sbuf_printf(sb, "NoRQEPktDefferals: %u", stats.rqe_dfr_pkt); 4303228561Snp 4304228561Snp rc = sbuf_finish(sb); 4305228561Snp sbuf_delete(sb); 4306228561Snp 4307228561Snp return (rc); 4308228561Snp} 4309228561Snp 4310228561Snpstatic int 4311228561Snpsysctl_tcp_stats(SYSCTL_HANDLER_ARGS) 4312228561Snp{ 4313228561Snp struct adapter *sc = arg1; 4314228561Snp struct sbuf *sb; 4315228561Snp int rc; 4316228561Snp struct tp_tcp_stats v4, v6; 4317228561Snp 4318228561Snp rc = sysctl_wire_old_buffer(req, 0); 4319228561Snp if (rc != 0) 4320228561Snp return (rc); 4321228561Snp 4322228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4323228561Snp if (sb == NULL) 4324228561Snp return (ENOMEM); 4325228561Snp 4326228561Snp t4_tp_get_tcp_stats(sc, &v4, &v6); 4327228561Snp sbuf_printf(sb, 4328228561Snp " IP IPv6\n"); 4329228561Snp sbuf_printf(sb, "OutRsts: %20u %20u\n", 4330228561Snp v4.tcpOutRsts, v6.tcpOutRsts); 4331228561Snp sbuf_printf(sb, "InSegs: %20ju %20ju\n", 4332228561Snp v4.tcpInSegs, v6.tcpInSegs); 4333228561Snp sbuf_printf(sb, "OutSegs: %20ju %20ju\n", 4334228561Snp v4.tcpOutSegs, v6.tcpOutSegs); 4335228561Snp sbuf_printf(sb, "RetransSegs: %20ju %20ju", 4336228561Snp v4.tcpRetransSegs, v6.tcpRetransSegs); 4337228561Snp 4338228561Snp rc = sbuf_finish(sb); 4339228561Snp sbuf_delete(sb); 4340228561Snp 4341228561Snp return (rc); 4342228561Snp} 4343228561Snp 4344228561Snpstatic int 4345228561Snpsysctl_tids(SYSCTL_HANDLER_ARGS) 4346228561Snp{ 4347228561Snp struct adapter *sc = arg1; 4348228561Snp struct sbuf *sb; 4349228561Snp int rc; 4350228561Snp struct tid_info *t = &sc->tids; 4351228561Snp 4352228561Snp rc = sysctl_wire_old_buffer(req, 0); 4353228561Snp if (rc != 0) 4354228561Snp return (rc); 4355228561Snp 4356228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4357228561Snp if (sb == NULL) 4358228561Snp return (ENOMEM); 4359228561Snp 4360228561Snp if (t->natids) { 4361228561Snp sbuf_printf(sb, "ATID range: 0-%u, in use: %u\n", t->natids - 1, 4362228561Snp t->atids_in_use); 4363228561Snp } 4364228561Snp 4365228561Snp if (t->ntids) { 4366228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 4367228561Snp uint32_t b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4; 4368228561Snp 4369228561Snp if (b) { 4370228561Snp sbuf_printf(sb, "TID range: 0-%u, %u-%u", b - 1, 4371228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 4372228561Snp t->ntids - 1); 4373228561Snp } else { 4374228561Snp sbuf_printf(sb, "TID range: %u-%u", 4375228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 4376228561Snp t->ntids - 1); 4377228561Snp } 4378228561Snp } else 4379228561Snp sbuf_printf(sb, "TID range: 0-%u", t->ntids - 1); 4380228561Snp sbuf_printf(sb, ", in use: %u\n", 4381228561Snp atomic_load_acq_int(&t->tids_in_use)); 4382228561Snp } 4383228561Snp 4384228561Snp if (t->nstids) { 4385228561Snp sbuf_printf(sb, "STID range: %u-%u, in use: %u\n", t->stid_base, 4386228561Snp t->stid_base + t->nstids - 1, t->stids_in_use); 4387228561Snp } 4388228561Snp 4389228561Snp if (t->nftids) { 4390228561Snp sbuf_printf(sb, "FTID range: %u-%u\n", t->ftid_base, 4391228561Snp t->ftid_base + t->nftids - 1); 4392228561Snp } 4393228561Snp 4394228561Snp sbuf_printf(sb, "HW TID usage: %u IP users, %u IPv6 users", 4395228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV4), 4396228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV6)); 4397228561Snp 4398228561Snp rc = sbuf_finish(sb); 4399228561Snp sbuf_delete(sb); 4400228561Snp 4401228561Snp return (rc); 4402228561Snp} 4403228561Snp 4404228561Snpstatic int 4405228561Snpsysctl_tp_err_stats(SYSCTL_HANDLER_ARGS) 4406228561Snp{ 4407228561Snp struct adapter *sc = arg1; 4408228561Snp struct sbuf *sb; 4409228561Snp int rc; 4410228561Snp struct tp_err_stats stats; 4411228561Snp 4412228561Snp rc = sysctl_wire_old_buffer(req, 0); 4413228561Snp if (rc != 0) 4414228561Snp return (rc); 4415228561Snp 4416228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4417228561Snp if (sb == NULL) 4418228561Snp return (ENOMEM); 4419228561Snp 4420228561Snp t4_tp_get_err_stats(sc, &stats); 4421228561Snp 4422228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 4423228561Snp "channel 3\n"); 4424228561Snp sbuf_printf(sb, "macInErrs: %10u %10u %10u %10u\n", 4425228561Snp stats.macInErrs[0], stats.macInErrs[1], stats.macInErrs[2], 4426228561Snp stats.macInErrs[3]); 4427228561Snp sbuf_printf(sb, "hdrInErrs: %10u %10u %10u %10u\n", 4428228561Snp stats.hdrInErrs[0], stats.hdrInErrs[1], stats.hdrInErrs[2], 4429228561Snp stats.hdrInErrs[3]); 4430228561Snp sbuf_printf(sb, "tcpInErrs: %10u %10u %10u %10u\n", 4431228561Snp stats.tcpInErrs[0], stats.tcpInErrs[1], stats.tcpInErrs[2], 4432228561Snp stats.tcpInErrs[3]); 4433228561Snp sbuf_printf(sb, "tcp6InErrs: %10u %10u %10u %10u\n", 4434228561Snp stats.tcp6InErrs[0], stats.tcp6InErrs[1], stats.tcp6InErrs[2], 4435228561Snp stats.tcp6InErrs[3]); 4436228561Snp sbuf_printf(sb, "tnlCongDrops: %10u %10u %10u %10u\n", 4437228561Snp stats.tnlCongDrops[0], stats.tnlCongDrops[1], stats.tnlCongDrops[2], 4438228561Snp stats.tnlCongDrops[3]); 4439228561Snp sbuf_printf(sb, "tnlTxDrops: %10u %10u %10u %10u\n", 4440228561Snp stats.tnlTxDrops[0], stats.tnlTxDrops[1], stats.tnlTxDrops[2], 4441228561Snp stats.tnlTxDrops[3]); 4442228561Snp sbuf_printf(sb, "ofldVlanDrops: %10u %10u %10u %10u\n", 4443228561Snp stats.ofldVlanDrops[0], stats.ofldVlanDrops[1], 4444228561Snp stats.ofldVlanDrops[2], stats.ofldVlanDrops[3]); 4445228561Snp sbuf_printf(sb, "ofldChanDrops: %10u %10u %10u %10u\n\n", 4446228561Snp stats.ofldChanDrops[0], stats.ofldChanDrops[1], 4447228561Snp stats.ofldChanDrops[2], stats.ofldChanDrops[3]); 4448228561Snp sbuf_printf(sb, "ofldNoNeigh: %u\nofldCongDefer: %u", 4449228561Snp stats.ofldNoNeigh, stats.ofldCongDefer); 4450228561Snp 4451228561Snp rc = sbuf_finish(sb); 4452228561Snp sbuf_delete(sb); 4453228561Snp 4454228561Snp return (rc); 4455228561Snp} 4456228561Snp 4457228561Snpstatic int 4458228561Snpsysctl_tx_rate(SYSCTL_HANDLER_ARGS) 4459228561Snp{ 4460228561Snp struct adapter *sc = arg1; 4461228561Snp struct sbuf *sb; 4462228561Snp int rc; 4463228561Snp u64 nrate[NCHAN], orate[NCHAN]; 4464228561Snp 4465228561Snp rc = sysctl_wire_old_buffer(req, 0); 4466228561Snp if (rc != 0) 4467228561Snp return (rc); 4468228561Snp 4469228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4470228561Snp if (sb == NULL) 4471228561Snp return (ENOMEM); 4472228561Snp 4473228561Snp t4_get_chan_txrate(sc, nrate, orate); 4474228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 4475228561Snp "channel 3\n"); 4476228561Snp sbuf_printf(sb, "NIC B/s: %10ju %10ju %10ju %10ju\n", 4477228561Snp nrate[0], nrate[1], nrate[2], nrate[3]); 4478228561Snp sbuf_printf(sb, "Offload B/s: %10ju %10ju %10ju %10ju", 4479228561Snp orate[0], orate[1], orate[2], orate[3]); 4480228561Snp 4481228561Snp rc = sbuf_finish(sb); 4482228561Snp sbuf_delete(sb); 4483228561Snp 4484228561Snp return (rc); 4485228561Snp} 4486231115Snp#endif 4487228561Snp 4488219286Snpstatic inline void 4489219286Snptxq_start(struct ifnet *ifp, struct sge_txq *txq) 4490219286Snp{ 4491219286Snp struct buf_ring *br; 4492219286Snp struct mbuf *m; 4493219286Snp 4494219286Snp TXQ_LOCK_ASSERT_OWNED(txq); 4495219286Snp 4496220873Snp br = txq->br; 4497219286Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 4498219286Snp if (m) 4499219286Snp t4_eth_tx(ifp, txq, m); 4500219286Snp} 4501219286Snp 4502219286Snpvoid 4503228561Snpt4_tx_callout(void *arg) 4504219286Snp{ 4505228561Snp struct sge_eq *eq = arg; 4506228561Snp struct adapter *sc; 4507219286Snp 4508228561Snp if (EQ_TRYLOCK(eq) == 0) 4509228561Snp goto reschedule; 4510228561Snp 4511228561Snp if (eq->flags & EQ_STALLED && !can_resume_tx(eq)) { 4512228561Snp EQ_UNLOCK(eq); 4513228561Snpreschedule: 4514228561Snp if (__predict_true(!(eq->flags && EQ_DOOMED))) 4515228561Snp callout_schedule(&eq->tx_callout, 1); 4516228561Snp return; 4517228561Snp } 4518228561Snp 4519228561Snp EQ_LOCK_ASSERT_OWNED(eq); 4520228561Snp 4521228561Snp if (__predict_true((eq->flags & EQ_DOOMED) == 0)) { 4522228561Snp 4523228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 4524228561Snp struct sge_txq *txq = arg; 4525228561Snp struct port_info *pi = txq->ifp->if_softc; 4526228561Snp 4527228561Snp sc = pi->adapter; 4528228561Snp } else { 4529228561Snp struct sge_wrq *wrq = arg; 4530228561Snp 4531228561Snp sc = wrq->adapter; 4532228561Snp } 4533228561Snp 4534228561Snp taskqueue_enqueue(sc->tq[eq->tx_chan], &eq->tx_task); 4535228561Snp } 4536228561Snp 4537228561Snp EQ_UNLOCK(eq); 4538228561Snp} 4539228561Snp 4540228561Snpvoid 4541228561Snpt4_tx_task(void *arg, int count) 4542228561Snp{ 4543228561Snp struct sge_eq *eq = arg; 4544228561Snp 4545228561Snp EQ_LOCK(eq); 4546228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 4547228561Snp struct sge_txq *txq = arg; 4548220649Snp txq_start(txq->ifp, txq); 4549228561Snp } else { 4550228561Snp struct sge_wrq *wrq = arg; 4551228561Snp t4_wrq_tx_locked(wrq->adapter, wrq, NULL); 4552228561Snp } 4553228561Snp EQ_UNLOCK(eq); 4554219286Snp} 4555219286Snp 4556221474Snpstatic uint32_t 4557221474Snpfconf_to_mode(uint32_t fconf) 4558221474Snp{ 4559221474Snp uint32_t mode; 4560221474Snp 4561221474Snp mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR | 4562221474Snp T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT; 4563221474Snp 4564221474Snp if (fconf & F_FRAGMENTATION) 4565221474Snp mode |= T4_FILTER_IP_FRAGMENT; 4566221474Snp 4567221474Snp if (fconf & F_MPSHITTYPE) 4568221474Snp mode |= T4_FILTER_MPS_HIT_TYPE; 4569221474Snp 4570221474Snp if (fconf & F_MACMATCH) 4571221474Snp mode |= T4_FILTER_MAC_IDX; 4572221474Snp 4573221474Snp if (fconf & F_ETHERTYPE) 4574221474Snp mode |= T4_FILTER_ETH_TYPE; 4575221474Snp 4576221474Snp if (fconf & F_PROTOCOL) 4577221474Snp mode |= T4_FILTER_IP_PROTO; 4578221474Snp 4579221474Snp if (fconf & F_TOS) 4580221474Snp mode |= T4_FILTER_IP_TOS; 4581221474Snp 4582221474Snp if (fconf & F_VLAN) 4583228561Snp mode |= T4_FILTER_VLAN; 4584221474Snp 4585221474Snp if (fconf & F_VNIC_ID) 4586228561Snp mode |= T4_FILTER_VNIC; 4587221474Snp 4588221474Snp if (fconf & F_PORT) 4589221474Snp mode |= T4_FILTER_PORT; 4590221474Snp 4591221474Snp if (fconf & F_FCOE) 4592221474Snp mode |= T4_FILTER_FCoE; 4593221474Snp 4594221474Snp return (mode); 4595221474Snp} 4596221474Snp 4597221474Snpstatic uint32_t 4598221474Snpmode_to_fconf(uint32_t mode) 4599221474Snp{ 4600221474Snp uint32_t fconf = 0; 4601221474Snp 4602221474Snp if (mode & T4_FILTER_IP_FRAGMENT) 4603221474Snp fconf |= F_FRAGMENTATION; 4604221474Snp 4605221474Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 4606221474Snp fconf |= F_MPSHITTYPE; 4607221474Snp 4608221474Snp if (mode & T4_FILTER_MAC_IDX) 4609221474Snp fconf |= F_MACMATCH; 4610221474Snp 4611221474Snp if (mode & T4_FILTER_ETH_TYPE) 4612221474Snp fconf |= F_ETHERTYPE; 4613221474Snp 4614221474Snp if (mode & T4_FILTER_IP_PROTO) 4615221474Snp fconf |= F_PROTOCOL; 4616221474Snp 4617221474Snp if (mode & T4_FILTER_IP_TOS) 4618221474Snp fconf |= F_TOS; 4619221474Snp 4620228561Snp if (mode & T4_FILTER_VLAN) 4621221474Snp fconf |= F_VLAN; 4622221474Snp 4623228561Snp if (mode & T4_FILTER_VNIC) 4624221474Snp fconf |= F_VNIC_ID; 4625221474Snp 4626221474Snp if (mode & T4_FILTER_PORT) 4627221474Snp fconf |= F_PORT; 4628221474Snp 4629221474Snp if (mode & T4_FILTER_FCoE) 4630221474Snp fconf |= F_FCOE; 4631221474Snp 4632221474Snp return (fconf); 4633221474Snp} 4634221474Snp 4635221474Snpstatic uint32_t 4636221474Snpfspec_to_fconf(struct t4_filter_specification *fs) 4637221474Snp{ 4638221474Snp uint32_t fconf = 0; 4639221474Snp 4640221474Snp if (fs->val.frag || fs->mask.frag) 4641221474Snp fconf |= F_FRAGMENTATION; 4642221474Snp 4643221474Snp if (fs->val.matchtype || fs->mask.matchtype) 4644221474Snp fconf |= F_MPSHITTYPE; 4645221474Snp 4646221474Snp if (fs->val.macidx || fs->mask.macidx) 4647221474Snp fconf |= F_MACMATCH; 4648221474Snp 4649221474Snp if (fs->val.ethtype || fs->mask.ethtype) 4650221474Snp fconf |= F_ETHERTYPE; 4651221474Snp 4652221474Snp if (fs->val.proto || fs->mask.proto) 4653221474Snp fconf |= F_PROTOCOL; 4654221474Snp 4655221474Snp if (fs->val.tos || fs->mask.tos) 4656221474Snp fconf |= F_TOS; 4657221474Snp 4658228561Snp if (fs->val.vlan_vld || fs->mask.vlan_vld) 4659221474Snp fconf |= F_VLAN; 4660221474Snp 4661228561Snp if (fs->val.vnic_vld || fs->mask.vnic_vld) 4662221474Snp fconf |= F_VNIC_ID; 4663221474Snp 4664221474Snp if (fs->val.iport || fs->mask.iport) 4665221474Snp fconf |= F_PORT; 4666221474Snp 4667221474Snp if (fs->val.fcoe || fs->mask.fcoe) 4668221474Snp fconf |= F_FCOE; 4669221474Snp 4670221474Snp return (fconf); 4671221474Snp} 4672221474Snp 4673221474Snpstatic int 4674221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode) 4675221474Snp{ 4676221474Snp uint32_t fconf; 4677221474Snp 4678221474Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1, 4679221474Snp A_TP_VLAN_PRI_MAP); 4680221474Snp 4681228561Snp if (sc->filter_mode != fconf) { 4682228561Snp log(LOG_WARNING, "%s: cached filter mode out of sync %x %x.\n", 4683228561Snp device_get_nameunit(sc->dev), sc->filter_mode, fconf); 4684228561Snp sc->filter_mode = fconf; 4685228561Snp } 4686221474Snp 4687228561Snp *mode = fconf_to_mode(sc->filter_mode); 4688228561Snp 4689221474Snp return (0); 4690221474Snp} 4691221474Snp 4692221474Snpstatic int 4693221474Snpset_filter_mode(struct adapter *sc, uint32_t mode) 4694221474Snp{ 4695221474Snp uint32_t fconf; 4696221474Snp int rc; 4697221474Snp 4698221474Snp fconf = mode_to_fconf(mode); 4699221474Snp 4700221474Snp ADAPTER_LOCK(sc); 4701221474Snp if (IS_BUSY(sc)) { 4702221474Snp rc = EAGAIN; 4703221474Snp goto done; 4704221474Snp } 4705221474Snp 4706221474Snp if (sc->tids.ftids_in_use > 0) { 4707221474Snp rc = EBUSY; 4708221474Snp goto done; 4709221474Snp } 4710221474Snp 4711237263Snp#ifdef TCP_OFFLOAD 4712228561Snp if (sc->offload_map) { 4713228561Snp rc = EBUSY; 4714228561Snp goto done; 4715228561Snp } 4716228561Snp#endif 4717228561Snp 4718228561Snp#ifdef notyet 4719221474Snp rc = -t4_set_filter_mode(sc, fconf); 4720228561Snp if (rc == 0) 4721228561Snp sc->filter_mode = fconf; 4722228561Snp#else 4723228561Snp rc = ENOTSUP; 4724228561Snp#endif 4725228561Snp 4726221474Snpdone: 4727221474Snp ADAPTER_UNLOCK(sc); 4728221474Snp return (rc); 4729221474Snp} 4730221474Snp 4731222552Snpstatic inline uint64_t 4732222552Snpget_filter_hits(struct adapter *sc, uint32_t fid) 4733222552Snp{ 4734222552Snp uint32_t tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 4735222552Snp uint64_t hits; 4736222552Snp 4737222552Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0), 4738222552Snp tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE); 4739222552Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0)); 4740222552Snp hits = t4_read_reg64(sc, MEMWIN0_BASE + 16); 4741222552Snp 4742222552Snp return (be64toh(hits)); 4743222552Snp} 4744222552Snp 4745221474Snpstatic int 4746221474Snpget_filter(struct adapter *sc, struct t4_filter *t) 4747221474Snp{ 4748221474Snp int i, nfilters = sc->tids.nftids; 4749221474Snp struct filter_entry *f; 4750221474Snp 4751221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4752221474Snp 4753221474Snp if (IS_BUSY(sc)) 4754221474Snp return (EAGAIN); 4755221474Snp 4756221474Snp if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL || 4757221474Snp t->idx >= nfilters) { 4758221474Snp t->idx = 0xffffffff; 4759221474Snp return (0); 4760221474Snp } 4761221474Snp 4762221474Snp f = &sc->tids.ftid_tab[t->idx]; 4763221474Snp for (i = t->idx; i < nfilters; i++, f++) { 4764221474Snp if (f->valid) { 4765221474Snp t->idx = i; 4766222509Snp t->l2tidx = f->l2t ? f->l2t->idx : 0; 4767222509Snp t->smtidx = f->smtidx; 4768222552Snp if (f->fs.hitcnts) 4769222552Snp t->hits = get_filter_hits(sc, t->idx); 4770222552Snp else 4771222552Snp t->hits = UINT64_MAX; 4772221474Snp t->fs = f->fs; 4773221474Snp 4774221474Snp return (0); 4775221474Snp } 4776221474Snp } 4777221474Snp 4778221474Snp t->idx = 0xffffffff; 4779221474Snp return (0); 4780221474Snp} 4781221474Snp 4782221474Snpstatic int 4783221474Snpset_filter(struct adapter *sc, struct t4_filter *t) 4784221474Snp{ 4785221474Snp unsigned int nfilters, nports; 4786221474Snp struct filter_entry *f; 4787221474Snp int i; 4788221474Snp 4789221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4790221474Snp 4791221474Snp nfilters = sc->tids.nftids; 4792221474Snp nports = sc->params.nports; 4793221474Snp 4794221474Snp if (nfilters == 0) 4795221474Snp return (ENOTSUP); 4796221474Snp 4797221474Snp if (!(sc->flags & FULL_INIT_DONE)) 4798221474Snp return (EAGAIN); 4799221474Snp 4800221474Snp if (t->idx >= nfilters) 4801221474Snp return (EINVAL); 4802221474Snp 4803221474Snp /* Validate against the global filter mode */ 4804228561Snp if ((sc->filter_mode | fspec_to_fconf(&t->fs)) != sc->filter_mode) 4805221474Snp return (E2BIG); 4806221474Snp 4807221474Snp if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) 4808221474Snp return (EINVAL); 4809221474Snp 4810221474Snp if (t->fs.val.iport >= nports) 4811221474Snp return (EINVAL); 4812221474Snp 4813221474Snp /* Can't specify an iq if not steering to it */ 4814221474Snp if (!t->fs.dirsteer && t->fs.iq) 4815221474Snp return (EINVAL); 4816221474Snp 4817221474Snp /* IPv6 filter idx must be 4 aligned */ 4818221474Snp if (t->fs.type == 1 && 4819221474Snp ((t->idx & 0x3) || t->idx + 4 >= nfilters)) 4820221474Snp return (EINVAL); 4821221474Snp 4822221474Snp if (sc->tids.ftid_tab == NULL) { 4823221474Snp KASSERT(sc->tids.ftids_in_use == 0, 4824221474Snp ("%s: no memory allocated but filters_in_use > 0", 4825221474Snp __func__)); 4826221474Snp 4827221474Snp sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) * 4828221474Snp nfilters, M_CXGBE, M_NOWAIT | M_ZERO); 4829221474Snp if (sc->tids.ftid_tab == NULL) 4830221474Snp return (ENOMEM); 4831221474Snp } 4832221474Snp 4833221474Snp for (i = 0; i < 4; i++) { 4834221474Snp f = &sc->tids.ftid_tab[t->idx + i]; 4835221474Snp 4836221474Snp if (f->pending || f->valid) 4837221474Snp return (EBUSY); 4838221474Snp if (f->locked) 4839221474Snp return (EPERM); 4840221474Snp 4841221474Snp if (t->fs.type == 0) 4842221474Snp break; 4843221474Snp } 4844221474Snp 4845221474Snp f = &sc->tids.ftid_tab[t->idx]; 4846221474Snp f->fs = t->fs; 4847221474Snp 4848221474Snp return set_filter_wr(sc, t->idx); 4849221474Snp} 4850221474Snp 4851221474Snpstatic int 4852221474Snpdel_filter(struct adapter *sc, struct t4_filter *t) 4853221474Snp{ 4854221474Snp unsigned int nfilters; 4855221474Snp struct filter_entry *f; 4856221474Snp 4857221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4858221474Snp 4859221474Snp if (IS_BUSY(sc)) 4860221474Snp return (EAGAIN); 4861221474Snp 4862221474Snp nfilters = sc->tids.nftids; 4863221474Snp 4864221474Snp if (nfilters == 0) 4865221474Snp return (ENOTSUP); 4866221474Snp 4867221474Snp if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 || 4868221474Snp t->idx >= nfilters) 4869221474Snp return (EINVAL); 4870221474Snp 4871221474Snp if (!(sc->flags & FULL_INIT_DONE)) 4872221474Snp return (EAGAIN); 4873221474Snp 4874221474Snp f = &sc->tids.ftid_tab[t->idx]; 4875221474Snp 4876221474Snp if (f->pending) 4877221474Snp return (EBUSY); 4878221474Snp if (f->locked) 4879221474Snp return (EPERM); 4880221474Snp 4881221474Snp if (f->valid) { 4882221474Snp t->fs = f->fs; /* extra info for the caller */ 4883221474Snp return del_filter_wr(sc, t->idx); 4884221474Snp } 4885221474Snp 4886221474Snp return (0); 4887221474Snp} 4888221474Snp 4889221474Snpstatic void 4890222509Snpclear_filter(struct filter_entry *f) 4891221474Snp{ 4892222509Snp if (f->l2t) 4893222509Snp t4_l2t_release(f->l2t); 4894222509Snp 4895221474Snp bzero(f, sizeof (*f)); 4896221474Snp} 4897221474Snp 4898221474Snpstatic int 4899221474Snpset_filter_wr(struct adapter *sc, int fidx) 4900221474Snp{ 4901221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 4902237263Snp struct wrqe *wr; 4903221474Snp struct fw_filter_wr *fwr; 4904221474Snp unsigned int ftid; 4905221474Snp 4906221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4907221474Snp 4908222509Snp if (f->fs.newdmac || f->fs.newvlan) { 4909222509Snp /* This filter needs an L2T entry; allocate one. */ 4910222509Snp f->l2t = t4_l2t_alloc_switching(sc->l2t); 4911222509Snp if (f->l2t == NULL) 4912222509Snp return (EAGAIN); 4913222509Snp if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport, 4914222509Snp f->fs.dmac)) { 4915222509Snp t4_l2t_release(f->l2t); 4916222509Snp f->l2t = NULL; 4917222509Snp return (ENOMEM); 4918222509Snp } 4919222509Snp } 4920221474Snp 4921221474Snp ftid = sc->tids.ftid_base + fidx; 4922221474Snp 4923237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 4924237263Snp if (wr == NULL) 4925221474Snp return (ENOMEM); 4926221474Snp 4927237263Snp fwr = wrtod(wr); 4928221474Snp bzero(fwr, sizeof (*fwr)); 4929221474Snp 4930221474Snp fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR)); 4931221474Snp fwr->len16_pkd = htobe32(FW_LEN16(*fwr)); 4932221474Snp fwr->tid_to_iq = 4933221474Snp htobe32(V_FW_FILTER_WR_TID(ftid) | 4934221474Snp V_FW_FILTER_WR_RQTYPE(f->fs.type) | 4935221474Snp V_FW_FILTER_WR_NOREPLY(0) | 4936221474Snp V_FW_FILTER_WR_IQ(f->fs.iq)); 4937221474Snp fwr->del_filter_to_l2tix = 4938221474Snp htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) | 4939221474Snp V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) | 4940221474Snp V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) | 4941221474Snp V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) | 4942221474Snp V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) | 4943221474Snp V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) | 4944221474Snp V_FW_FILTER_WR_DMAC(f->fs.newdmac) | 4945221474Snp V_FW_FILTER_WR_SMAC(f->fs.newsmac) | 4946221474Snp V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT || 4947221474Snp f->fs.newvlan == VLAN_REWRITE) | 4948221474Snp V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE || 4949221474Snp f->fs.newvlan == VLAN_REWRITE) | 4950221474Snp V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) | 4951221474Snp V_FW_FILTER_WR_TXCHAN(f->fs.eport) | 4952221474Snp V_FW_FILTER_WR_PRIO(f->fs.prio) | 4953222509Snp V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0)); 4954221474Snp fwr->ethtype = htobe16(f->fs.val.ethtype); 4955221474Snp fwr->ethtypem = htobe16(f->fs.mask.ethtype); 4956221474Snp fwr->frag_to_ovlan_vldm = 4957221474Snp (V_FW_FILTER_WR_FRAG(f->fs.val.frag) | 4958221474Snp V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) | 4959228561Snp V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) | 4960228561Snp V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.vnic_vld) | 4961228561Snp V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) | 4962228561Snp V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.vnic_vld)); 4963221474Snp fwr->smac_sel = 0; 4964221474Snp fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) | 4965228561Snp V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id)); 4966221474Snp fwr->maci_to_matchtypem = 4967221474Snp htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) | 4968221474Snp V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) | 4969221474Snp V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) | 4970221474Snp V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) | 4971221474Snp V_FW_FILTER_WR_PORT(f->fs.val.iport) | 4972221474Snp V_FW_FILTER_WR_PORTM(f->fs.mask.iport) | 4973221474Snp V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) | 4974221474Snp V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype)); 4975221474Snp fwr->ptcl = f->fs.val.proto; 4976221474Snp fwr->ptclm = f->fs.mask.proto; 4977221474Snp fwr->ttyp = f->fs.val.tos; 4978221474Snp fwr->ttypm = f->fs.mask.tos; 4979228561Snp fwr->ivlan = htobe16(f->fs.val.vlan); 4980228561Snp fwr->ivlanm = htobe16(f->fs.mask.vlan); 4981228561Snp fwr->ovlan = htobe16(f->fs.val.vnic); 4982228561Snp fwr->ovlanm = htobe16(f->fs.mask.vnic); 4983221474Snp bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip)); 4984221474Snp bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm)); 4985221474Snp bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip)); 4986221474Snp bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm)); 4987221474Snp fwr->lp = htobe16(f->fs.val.dport); 4988221474Snp fwr->lpm = htobe16(f->fs.mask.dport); 4989221474Snp fwr->fp = htobe16(f->fs.val.sport); 4990221474Snp fwr->fpm = htobe16(f->fs.mask.sport); 4991221474Snp if (f->fs.newsmac) 4992221474Snp bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma)); 4993221474Snp 4994221474Snp f->pending = 1; 4995221474Snp sc->tids.ftids_in_use++; 4996228561Snp 4997237263Snp t4_wrq_tx(sc, wr); 4998228561Snp return (0); 4999221474Snp} 5000221474Snp 5001221474Snpstatic int 5002221474Snpdel_filter_wr(struct adapter *sc, int fidx) 5003221474Snp{ 5004221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 5005237263Snp struct wrqe *wr; 5006221474Snp struct fw_filter_wr *fwr; 5007228561Snp unsigned int ftid; 5008221474Snp 5009221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 5010221474Snp 5011221474Snp ftid = sc->tids.ftid_base + fidx; 5012221474Snp 5013237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 5014237263Snp if (wr == NULL) 5015221474Snp return (ENOMEM); 5016237263Snp fwr = wrtod(wr); 5017221474Snp bzero(fwr, sizeof (*fwr)); 5018221474Snp 5019228561Snp t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id); 5020221474Snp 5021221474Snp f->pending = 1; 5022237263Snp t4_wrq_tx(sc, wr); 5023228561Snp return (0); 5024221474Snp} 5025221474Snp 5026239338Snpint 5027239338Snpt4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 5028221474Snp{ 5029228561Snp struct adapter *sc = iq->adapter; 5030228561Snp const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1); 5031221474Snp unsigned int idx = GET_TID(rpl); 5032221474Snp 5033228561Snp KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__, 5034228561Snp rss->opcode)); 5035228561Snp 5036221474Snp if (idx >= sc->tids.ftid_base && 5037221474Snp (idx -= sc->tids.ftid_base) < sc->tids.nftids) { 5038221474Snp unsigned int rc = G_COOKIE(rpl->cookie); 5039221474Snp struct filter_entry *f = &sc->tids.ftid_tab[idx]; 5040221474Snp 5041231120Snp ADAPTER_LOCK(sc); 5042228561Snp if (rc == FW_FILTER_WR_FLT_ADDED) { 5043221474Snp f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff; 5044221474Snp f->pending = 0; /* asynchronous setup completed */ 5045221474Snp f->valid = 1; 5046231120Snp } else { 5047231120Snp if (rc != FW_FILTER_WR_FLT_DELETED) { 5048231120Snp /* Add or delete failed, display an error */ 5049231120Snp log(LOG_ERR, 5050231120Snp "filter %u setup failed with error %u\n", 5051231120Snp idx, rc); 5052231120Snp } 5053228561Snp 5054231120Snp clear_filter(f); 5055231120Snp sc->tids.ftids_in_use--; 5056221474Snp } 5057228561Snp ADAPTER_UNLOCK(sc); 5058221474Snp } 5059228561Snp 5060228561Snp return (0); 5061221474Snp} 5062221474Snp 5063222973Snpstatic int 5064222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt) 5065222973Snp{ 5066222973Snp int rc = EINVAL; 5067222973Snp 5068222973Snp if (cntxt->cid > M_CTXTQID) 5069222973Snp return (rc); 5070222973Snp 5071222973Snp if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS && 5072222973Snp cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM) 5073222973Snp return (rc); 5074222973Snp 5075222973Snp if (sc->flags & FW_OK) { 5076222973Snp ADAPTER_LOCK(sc); /* Avoid parallel t4_wr_mbox */ 5077222973Snp rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id, 5078222973Snp &cntxt->data[0]); 5079222973Snp ADAPTER_UNLOCK(sc); 5080222973Snp } 5081222973Snp 5082222973Snp if (rc != 0) { 5083222973Snp /* Read via firmware failed or wasn't even attempted */ 5084222973Snp 5085222973Snp rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id, 5086222973Snp &cntxt->data[0]); 5087222973Snp } 5088222973Snp 5089222973Snp return (rc); 5090222973Snp} 5091222973Snp 5092228561Snpstatic int 5093228561Snpread_card_mem(struct adapter *sc, struct t4_mem_range *mr) 5094228561Snp{ 5095228561Snp uint32_t base, size, lo, hi, win, off, remaining, i, n; 5096228561Snp uint32_t *buf, *b; 5097228561Snp int rc; 5098228561Snp 5099228561Snp /* reads are in multiples of 32 bits */ 5100228561Snp if (mr->addr & 3 || mr->len & 3 || mr->len == 0) 5101228561Snp return (EINVAL); 5102228561Snp 5103228561Snp /* 5104228561Snp * We don't want to deal with potential holes so we mandate that the 5105228561Snp * requested region must lie entirely within one of the 3 memories. 5106228561Snp */ 5107228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 5108228561Snp if (lo & F_EDRAM0_ENABLE) { 5109228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 5110228561Snp base = G_EDRAM0_BASE(hi) << 20; 5111228561Snp size = G_EDRAM0_SIZE(hi) << 20; 5112228561Snp if (size > 0 && 5113228561Snp mr->addr >= base && mr->addr < base + size && 5114228561Snp mr->addr + mr->len <= base + size) 5115228561Snp goto proceed; 5116228561Snp } 5117228561Snp if (lo & F_EDRAM1_ENABLE) { 5118228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 5119228561Snp base = G_EDRAM1_BASE(hi) << 20; 5120228561Snp size = G_EDRAM1_SIZE(hi) << 20; 5121228561Snp if (size > 0 && 5122228561Snp mr->addr >= base && mr->addr < base + size && 5123228561Snp mr->addr + mr->len <= base + size) 5124228561Snp goto proceed; 5125228561Snp } 5126228561Snp if (lo & F_EXT_MEM_ENABLE) { 5127228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 5128228561Snp base = G_EXT_MEM_BASE(hi) << 20; 5129228561Snp size = G_EXT_MEM_SIZE(hi) << 20; 5130228561Snp if (size > 0 && 5131228561Snp mr->addr >= base && mr->addr < base + size && 5132228561Snp mr->addr + mr->len <= base + size) 5133228561Snp goto proceed; 5134228561Snp } 5135228561Snp return (ENXIO); 5136228561Snp 5137228561Snpproceed: 5138228561Snp buf = b = malloc(mr->len, M_CXGBE, M_WAITOK); 5139228561Snp 5140228561Snp /* 5141228561Snp * Position the PCIe window (we use memwin2) to the 16B aligned area 5142228561Snp * just at/before the requested region. 5143228561Snp */ 5144228561Snp win = mr->addr & ~0xf; 5145228561Snp off = mr->addr - win; /* offset of the requested region in the win */ 5146228561Snp remaining = mr->len; 5147228561Snp 5148228561Snp while (remaining) { 5149228561Snp t4_write_reg(sc, 5150228561Snp PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2), win); 5151228561Snp t4_read_reg(sc, 5152228561Snp PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2)); 5153228561Snp 5154228561Snp /* number of bytes that we'll copy in the inner loop */ 5155228561Snp n = min(remaining, MEMWIN2_APERTURE - off); 5156228561Snp 5157228561Snp for (i = 0; i < n; i += 4, remaining -= 4) 5158228561Snp *b++ = t4_read_reg(sc, MEMWIN2_BASE + off + i); 5159228561Snp 5160228561Snp win += MEMWIN2_APERTURE; 5161228561Snp off = 0; 5162228561Snp } 5163228561Snp 5164228561Snp rc = copyout(buf, mr->data, mr->len); 5165228561Snp free(buf, M_CXGBE); 5166228561Snp 5167228561Snp return (rc); 5168228561Snp} 5169228561Snp 5170241399Snpstatic int 5171241399Snpread_i2c(struct adapter *sc, struct t4_i2c_data *i2cd) 5172241399Snp{ 5173241399Snp int rc; 5174241399Snp 5175241399Snp ADAPTER_LOCK_ASSERT_OWNED(sc); /* for mbox */ 5176241399Snp 5177241399Snp if (i2cd->len == 0 || i2cd->port_id >= sc->params.nports) 5178241399Snp return (EINVAL); 5179241399Snp 5180241399Snp if (i2cd->len > 1) { 5181241399Snp /* XXX: need fw support for longer reads in one go */ 5182241399Snp return (ENOTSUP); 5183241399Snp } 5184241399Snp 5185241399Snp rc = -t4_i2c_rd(sc, sc->mbox, i2cd->port_id, i2cd->dev_addr, 5186241399Snp i2cd->offset, &i2cd->data[0]); 5187241399Snp 5188241399Snp return (rc); 5189241399Snp} 5190241399Snp 5191218792Snpint 5192218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap) 5193218792Snp{ 5194222102Snp int i; 5195218792Snp 5196222102Snp return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0); 5197218792Snp} 5198218792Snp 5199218792Snpint 5200218792Snpt4_os_pci_save_state(struct adapter *sc) 5201218792Snp{ 5202218792Snp device_t dev; 5203218792Snp struct pci_devinfo *dinfo; 5204218792Snp 5205218792Snp dev = sc->dev; 5206218792Snp dinfo = device_get_ivars(dev); 5207218792Snp 5208218792Snp pci_cfg_save(dev, dinfo, 0); 5209218792Snp return (0); 5210218792Snp} 5211218792Snp 5212218792Snpint 5213218792Snpt4_os_pci_restore_state(struct adapter *sc) 5214218792Snp{ 5215218792Snp device_t dev; 5216218792Snp struct pci_devinfo *dinfo; 5217218792Snp 5218218792Snp dev = sc->dev; 5219218792Snp dinfo = device_get_ivars(dev); 5220218792Snp 5221218792Snp pci_cfg_restore(dev, dinfo); 5222218792Snp return (0); 5223218792Snp} 5224219299Snp 5225218792Snpvoid 5226218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx) 5227218792Snp{ 5228218792Snp struct port_info *pi = sc->port[idx]; 5229218792Snp static const char *mod_str[] = { 5230220232Snp NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM" 5231218792Snp }; 5232218792Snp 5233218792Snp if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 5234218792Snp if_printf(pi->ifp, "transceiver unplugged.\n"); 5235220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) 5236220232Snp if_printf(pi->ifp, "unknown transceiver inserted.\n"); 5237220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) 5238220232Snp if_printf(pi->ifp, "unsupported transceiver inserted.\n"); 5239240452Snp else if (pi->mod_type > 0 && pi->mod_type < nitems(mod_str)) { 5240218792Snp if_printf(pi->ifp, "%s transceiver inserted.\n", 5241218792Snp mod_str[pi->mod_type]); 5242219299Snp } else { 5243219299Snp if_printf(pi->ifp, "transceiver (type %d) inserted.\n", 5244219299Snp pi->mod_type); 5245219299Snp } 5246218792Snp} 5247218792Snp 5248218792Snpvoid 5249218792Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat) 5250218792Snp{ 5251218792Snp struct port_info *pi = sc->port[idx]; 5252218792Snp struct ifnet *ifp = pi->ifp; 5253218792Snp 5254218792Snp if (link_stat) { 5255218792Snp ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed); 5256218792Snp if_link_state_change(ifp, LINK_STATE_UP); 5257218792Snp } else 5258218792Snp if_link_state_change(ifp, LINK_STATE_DOWN); 5259218792Snp} 5260218792Snp 5261228561Snpvoid 5262228561Snpt4_iterate(void (*func)(struct adapter *, void *), void *arg) 5263228561Snp{ 5264228561Snp struct adapter *sc; 5265228561Snp 5266228561Snp mtx_lock(&t4_list_lock); 5267228561Snp SLIST_FOREACH(sc, &t4_list, link) { 5268228561Snp /* 5269228561Snp * func should not make any assumptions about what state sc is 5270228561Snp * in - the only guarantee is that sc->sc_lock is a valid lock. 5271228561Snp */ 5272228561Snp func(sc, arg); 5273228561Snp } 5274228561Snp mtx_unlock(&t4_list_lock); 5275228561Snp} 5276228561Snp 5277218792Snpstatic int 5278218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td) 5279218792Snp{ 5280218792Snp return (0); 5281218792Snp} 5282218792Snp 5283218792Snpstatic int 5284218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td) 5285218792Snp{ 5286218792Snp return (0); 5287218792Snp} 5288218792Snp 5289218792Snpstatic int 5290218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag, 5291218792Snp struct thread *td) 5292218792Snp{ 5293218792Snp int rc; 5294218792Snp struct adapter *sc = dev->si_drv1; 5295218792Snp 5296218792Snp rc = priv_check(td, PRIV_DRIVER); 5297218792Snp if (rc != 0) 5298218792Snp return (rc); 5299218792Snp 5300218792Snp switch (cmd) { 5301220410Snp case CHELSIO_T4_GETREG: { 5302220410Snp struct t4_reg *edata = (struct t4_reg *)data; 5303220410Snp 5304218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 5305218792Snp return (EFAULT); 5306220410Snp 5307220410Snp if (edata->size == 4) 5308220410Snp edata->val = t4_read_reg(sc, edata->addr); 5309220410Snp else if (edata->size == 8) 5310220410Snp edata->val = t4_read_reg64(sc, edata->addr); 5311220410Snp else 5312220410Snp return (EINVAL); 5313220410Snp 5314218792Snp break; 5315218792Snp } 5316220410Snp case CHELSIO_T4_SETREG: { 5317220410Snp struct t4_reg *edata = (struct t4_reg *)data; 5318220410Snp 5319218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 5320218792Snp return (EFAULT); 5321220410Snp 5322220410Snp if (edata->size == 4) { 5323220410Snp if (edata->val & 0xffffffff00000000) 5324220410Snp return (EINVAL); 5325220410Snp t4_write_reg(sc, edata->addr, (uint32_t) edata->val); 5326220410Snp } else if (edata->size == 8) 5327220410Snp t4_write_reg64(sc, edata->addr, edata->val); 5328220410Snp else 5329220410Snp return (EINVAL); 5330218792Snp break; 5331218792Snp } 5332218792Snp case CHELSIO_T4_REGDUMP: { 5333218792Snp struct t4_regdump *regs = (struct t4_regdump *)data; 5334218792Snp int reglen = T4_REGDUMP_SIZE; 5335218792Snp uint8_t *buf; 5336218792Snp 5337218792Snp if (regs->len < reglen) { 5338218792Snp regs->len = reglen; /* hint to the caller */ 5339218792Snp return (ENOBUFS); 5340218792Snp } 5341218792Snp 5342218792Snp regs->len = reglen; 5343218792Snp buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO); 5344218792Snp t4_get_regs(sc, regs, buf); 5345218792Snp rc = copyout(buf, regs->data, reglen); 5346218792Snp free(buf, M_CXGBE); 5347218792Snp break; 5348218792Snp } 5349221474Snp case CHELSIO_T4_GET_FILTER_MODE: 5350221474Snp rc = get_filter_mode(sc, (uint32_t *)data); 5351221474Snp break; 5352221474Snp case CHELSIO_T4_SET_FILTER_MODE: 5353221474Snp rc = set_filter_mode(sc, *(uint32_t *)data); 5354221474Snp break; 5355221474Snp case CHELSIO_T4_GET_FILTER: 5356221474Snp ADAPTER_LOCK(sc); 5357221474Snp rc = get_filter(sc, (struct t4_filter *)data); 5358221474Snp ADAPTER_UNLOCK(sc); 5359221474Snp break; 5360221474Snp case CHELSIO_T4_SET_FILTER: 5361221474Snp ADAPTER_LOCK(sc); 5362221474Snp rc = set_filter(sc, (struct t4_filter *)data); 5363221474Snp ADAPTER_UNLOCK(sc); 5364221474Snp break; 5365221474Snp case CHELSIO_T4_DEL_FILTER: 5366221474Snp ADAPTER_LOCK(sc); 5367221474Snp rc = del_filter(sc, (struct t4_filter *)data); 5368221474Snp ADAPTER_UNLOCK(sc); 5369221474Snp break; 5370222973Snp case CHELSIO_T4_GET_SGE_CONTEXT: 5371222973Snp rc = get_sge_context(sc, (struct t4_sge_context *)data); 5372222973Snp break; 5373228561Snp case CHELSIO_T4_LOAD_FW: { 5374228561Snp struct t4_data *fw = (struct t4_data *)data; 5375228561Snp uint8_t *fw_data; 5376228561Snp 5377228561Snp if (sc->flags & FULL_INIT_DONE) 5378228561Snp return (EBUSY); 5379228561Snp 5380228561Snp fw_data = malloc(fw->len, M_CXGBE, M_NOWAIT); 5381228561Snp if (fw_data == NULL) 5382228561Snp return (ENOMEM); 5383228561Snp 5384228561Snp rc = copyin(fw->data, fw_data, fw->len); 5385228561Snp if (rc == 0) 5386228561Snp rc = -t4_load_fw(sc, fw_data, fw->len); 5387228561Snp 5388228561Snp free(fw_data, M_CXGBE); 5389228561Snp break; 5390228561Snp } 5391228561Snp case CHELSIO_T4_GET_MEM: 5392228561Snp rc = read_card_mem(sc, (struct t4_mem_range *)data); 5393228561Snp break; 5394241399Snp case CHELSIO_T4_GET_I2C: 5395241399Snp ADAPTER_LOCK(sc); 5396241399Snp rc = read_i2c(sc, (struct t4_i2c_data *)data); 5397241399Snp ADAPTER_UNLOCK(sc); 5398241399Snp break; 5399241409Snp case CHELSIO_T4_CLEAR_STATS: { 5400241409Snp u_int port_id = *(uint32_t *)data; 5401241409Snp 5402241409Snp if (port_id >= sc->params.nports) 5403241409Snp return (EINVAL); 5404241409Snp 5405241409Snp t4_clr_port_stats(sc, port_id); 5406241409Snp break; 5407241409Snp } 5408218792Snp default: 5409218792Snp rc = EINVAL; 5410218792Snp } 5411218792Snp 5412218792Snp return (rc); 5413218792Snp} 5414218792Snp 5415237263Snp#ifdef TCP_OFFLOAD 5416219392Snpstatic int 5417228561Snptoe_capability(struct port_info *pi, int enable) 5418228561Snp{ 5419228561Snp int rc; 5420228561Snp struct adapter *sc = pi->adapter; 5421228561Snp 5422228561Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 5423228561Snp 5424228561Snp if (!is_offload(sc)) 5425228561Snp return (ENODEV); 5426228561Snp 5427228561Snp if (enable) { 5428237263Snp if (!(sc->flags & FULL_INIT_DONE)) { 5429237263Snp log(LOG_WARNING, 5430237263Snp "You must enable a cxgbe interface first\n"); 5431237263Snp return (EAGAIN); 5432237263Snp } 5433237263Snp 5434228561Snp if (isset(&sc->offload_map, pi->port_id)) 5435228561Snp return (0); 5436228561Snp 5437237263Snp if (!(sc->flags & TOM_INIT_DONE)) { 5438237263Snp rc = t4_activate_uld(sc, ULD_TOM); 5439237263Snp if (rc == EAGAIN) { 5440237263Snp log(LOG_WARNING, 5441237263Snp "You must kldload t4_tom.ko before trying " 5442237263Snp "to enable TOE on a cxgbe interface.\n"); 5443237263Snp } 5444228561Snp if (rc != 0) 5445228561Snp return (rc); 5446237263Snp KASSERT(sc->tom_softc != NULL, 5447237263Snp ("%s: TOM activated but softc NULL", __func__)); 5448237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 5449237263Snp ("%s: TOM activated but flag not set", __func__)); 5450228561Snp } 5451228561Snp 5452228561Snp setbit(&sc->offload_map, pi->port_id); 5453228561Snp } else { 5454228561Snp if (!isset(&sc->offload_map, pi->port_id)) 5455228561Snp return (0); 5456228561Snp 5457237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 5458237263Snp ("%s: TOM never initialized?", __func__)); 5459228561Snp clrbit(&sc->offload_map, pi->port_id); 5460228561Snp } 5461228561Snp 5462228561Snp return (0); 5463228561Snp} 5464228561Snp 5465228561Snp/* 5466228561Snp * Add an upper layer driver to the global list. 5467228561Snp */ 5468228561Snpint 5469228561Snpt4_register_uld(struct uld_info *ui) 5470228561Snp{ 5471228561Snp int rc = 0; 5472228561Snp struct uld_info *u; 5473228561Snp 5474228561Snp mtx_lock(&t4_uld_list_lock); 5475228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 5476228561Snp if (u->uld_id == ui->uld_id) { 5477228561Snp rc = EEXIST; 5478228561Snp goto done; 5479228561Snp } 5480228561Snp } 5481228561Snp 5482228561Snp SLIST_INSERT_HEAD(&t4_uld_list, ui, link); 5483228561Snp ui->refcount = 0; 5484228561Snpdone: 5485228561Snp mtx_unlock(&t4_uld_list_lock); 5486228561Snp return (rc); 5487228561Snp} 5488228561Snp 5489228561Snpint 5490228561Snpt4_unregister_uld(struct uld_info *ui) 5491228561Snp{ 5492228561Snp int rc = EINVAL; 5493228561Snp struct uld_info *u; 5494228561Snp 5495228561Snp mtx_lock(&t4_uld_list_lock); 5496228561Snp 5497228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 5498228561Snp if (u == ui) { 5499228561Snp if (ui->refcount > 0) { 5500228561Snp rc = EBUSY; 5501228561Snp goto done; 5502228561Snp } 5503228561Snp 5504228561Snp SLIST_REMOVE(&t4_uld_list, ui, uld_info, link); 5505228561Snp rc = 0; 5506228561Snp goto done; 5507228561Snp } 5508228561Snp } 5509228561Snpdone: 5510228561Snp mtx_unlock(&t4_uld_list_lock); 5511228561Snp return (rc); 5512228561Snp} 5513228561Snp 5514237263Snpint 5515237263Snpt4_activate_uld(struct adapter *sc, int id) 5516228561Snp{ 5517228561Snp int rc = EAGAIN; 5518228561Snp struct uld_info *ui; 5519228561Snp 5520228561Snp mtx_lock(&t4_uld_list_lock); 5521228561Snp 5522228561Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 5523228561Snp if (ui->uld_id == id) { 5524237263Snp rc = ui->activate(sc); 5525237263Snp if (rc == 0) 5526228561Snp ui->refcount++; 5527228561Snp goto done; 5528228561Snp } 5529228561Snp } 5530228561Snpdone: 5531228561Snp mtx_unlock(&t4_uld_list_lock); 5532228561Snp 5533228561Snp return (rc); 5534228561Snp} 5535228561Snp 5536237263Snpint 5537237263Snpt4_deactivate_uld(struct adapter *sc, int id) 5538228561Snp{ 5539237263Snp int rc = EINVAL; 5540237263Snp struct uld_info *ui; 5541228561Snp 5542228561Snp mtx_lock(&t4_uld_list_lock); 5543228561Snp 5544237263Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 5545237263Snp if (ui->uld_id == id) { 5546237263Snp rc = ui->deactivate(sc); 5547237263Snp if (rc == 0) 5548237263Snp ui->refcount--; 5549237263Snp goto done; 5550237263Snp } 5551228561Snp } 5552228561Snpdone: 5553228561Snp mtx_unlock(&t4_uld_list_lock); 5554228561Snp 5555228561Snp return (rc); 5556228561Snp} 5557228561Snp#endif 5558228561Snp 5559228561Snp/* 5560228561Snp * Come up with reasonable defaults for some of the tunables, provided they're 5561228561Snp * not set by the user (in which case we'll use the values as is). 5562228561Snp */ 5563228561Snpstatic void 5564228561Snptweak_tunables(void) 5565228561Snp{ 5566228561Snp int nc = mp_ncpus; /* our snapshot of the number of CPUs */ 5567228561Snp 5568228561Snp if (t4_ntxq10g < 1) 5569228561Snp t4_ntxq10g = min(nc, NTXQ_10G); 5570228561Snp 5571228561Snp if (t4_ntxq1g < 1) 5572228561Snp t4_ntxq1g = min(nc, NTXQ_1G); 5573228561Snp 5574228561Snp if (t4_nrxq10g < 1) 5575228561Snp t4_nrxq10g = min(nc, NRXQ_10G); 5576228561Snp 5577228561Snp if (t4_nrxq1g < 1) 5578228561Snp t4_nrxq1g = min(nc, NRXQ_1G); 5579228561Snp 5580237263Snp#ifdef TCP_OFFLOAD 5581228561Snp if (t4_nofldtxq10g < 1) 5582228561Snp t4_nofldtxq10g = min(nc, NOFLDTXQ_10G); 5583228561Snp 5584228561Snp if (t4_nofldtxq1g < 1) 5585228561Snp t4_nofldtxq1g = min(nc, NOFLDTXQ_1G); 5586228561Snp 5587228561Snp if (t4_nofldrxq10g < 1) 5588228561Snp t4_nofldrxq10g = min(nc, NOFLDRXQ_10G); 5589228561Snp 5590228561Snp if (t4_nofldrxq1g < 1) 5591228561Snp t4_nofldrxq1g = min(nc, NOFLDRXQ_1G); 5592238028Snp 5593238028Snp if (t4_toecaps_allowed == -1) 5594238028Snp t4_toecaps_allowed = FW_CAPS_CONFIG_TOE; 5595238028Snp#else 5596238028Snp if (t4_toecaps_allowed == -1) 5597238028Snp t4_toecaps_allowed = 0; 5598228561Snp#endif 5599228561Snp 5600228561Snp if (t4_tmr_idx_10g < 0 || t4_tmr_idx_10g >= SGE_NTIMERS) 5601228561Snp t4_tmr_idx_10g = TMR_IDX_10G; 5602228561Snp 5603228561Snp if (t4_pktc_idx_10g < -1 || t4_pktc_idx_10g >= SGE_NCOUNTERS) 5604228561Snp t4_pktc_idx_10g = PKTC_IDX_10G; 5605228561Snp 5606228561Snp if (t4_tmr_idx_1g < 0 || t4_tmr_idx_1g >= SGE_NTIMERS) 5607228561Snp t4_tmr_idx_1g = TMR_IDX_1G; 5608228561Snp 5609228561Snp if (t4_pktc_idx_1g < -1 || t4_pktc_idx_1g >= SGE_NCOUNTERS) 5610228561Snp t4_pktc_idx_1g = PKTC_IDX_1G; 5611228561Snp 5612228561Snp if (t4_qsize_txq < 128) 5613228561Snp t4_qsize_txq = 128; 5614228561Snp 5615228561Snp if (t4_qsize_rxq < 128) 5616228561Snp t4_qsize_rxq = 128; 5617228561Snp while (t4_qsize_rxq & 7) 5618228561Snp t4_qsize_rxq++; 5619228561Snp 5620228561Snp t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX; 5621228561Snp} 5622228561Snp 5623228561Snpstatic int 5624219392Snpt4_mod_event(module_t mod, int cmd, void *arg) 5625219392Snp{ 5626228561Snp int rc = 0; 5627219392Snp 5628228561Snp switch (cmd) { 5629228561Snp case MOD_LOAD: 5630219392Snp t4_sge_modload(); 5631228561Snp mtx_init(&t4_list_lock, "T4 adapters", 0, MTX_DEF); 5632228561Snp SLIST_INIT(&t4_list); 5633237263Snp#ifdef TCP_OFFLOAD 5634228561Snp mtx_init(&t4_uld_list_lock, "T4 ULDs", 0, MTX_DEF); 5635228561Snp SLIST_INIT(&t4_uld_list); 5636228561Snp#endif 5637228561Snp tweak_tunables(); 5638228561Snp break; 5639219392Snp 5640228561Snp case MOD_UNLOAD: 5641237263Snp#ifdef TCP_OFFLOAD 5642228561Snp mtx_lock(&t4_uld_list_lock); 5643228561Snp if (!SLIST_EMPTY(&t4_uld_list)) { 5644228561Snp rc = EBUSY; 5645228561Snp mtx_unlock(&t4_uld_list_lock); 5646228561Snp break; 5647228561Snp } 5648228561Snp mtx_unlock(&t4_uld_list_lock); 5649228561Snp mtx_destroy(&t4_uld_list_lock); 5650228561Snp#endif 5651228561Snp mtx_lock(&t4_list_lock); 5652228561Snp if (!SLIST_EMPTY(&t4_list)) { 5653228561Snp rc = EBUSY; 5654228561Snp mtx_unlock(&t4_list_lock); 5655228561Snp break; 5656228561Snp } 5657228561Snp mtx_unlock(&t4_list_lock); 5658228561Snp mtx_destroy(&t4_list_lock); 5659228561Snp break; 5660228561Snp } 5661228561Snp 5662228561Snp return (rc); 5663219392Snp} 5664219392Snp 5665218792Snpstatic devclass_t t4_devclass; 5666218792Snpstatic devclass_t cxgbe_devclass; 5667218792Snp 5668219392SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, t4_mod_event, 0); 5669218792SnpMODULE_VERSION(t4nex, 1); 5670218792Snp 5671218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0); 5672218792SnpMODULE_VERSION(cxgbe, 1); 5673