t4_main.c revision 245274
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 245274 2013-01-10 23:56:50Z np $"); 30218792Snp 31218792Snp#include "opt_inet.h" 32237819Snp#include "opt_inet6.h" 33218792Snp 34218792Snp#include <sys/param.h> 35218792Snp#include <sys/conf.h> 36218792Snp#include <sys/priv.h> 37218792Snp#include <sys/kernel.h> 38218792Snp#include <sys/bus.h> 39218792Snp#include <sys/module.h> 40219286Snp#include <sys/malloc.h> 41219286Snp#include <sys/queue.h> 42219286Snp#include <sys/taskqueue.h> 43218792Snp#include <sys/pciio.h> 44218792Snp#include <dev/pci/pcireg.h> 45218792Snp#include <dev/pci/pcivar.h> 46218792Snp#include <dev/pci/pci_private.h> 47218792Snp#include <sys/firmware.h> 48219436Snp#include <sys/sbuf.h> 49218792Snp#include <sys/smp.h> 50218792Snp#include <sys/socket.h> 51218792Snp#include <sys/sockio.h> 52218792Snp#include <sys/sysctl.h> 53218792Snp#include <net/ethernet.h> 54218792Snp#include <net/if.h> 55218792Snp#include <net/if_types.h> 56218792Snp#include <net/if_dl.h> 57222003Snp#include <net/if_vlan_var.h> 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_synchronized(struct port_info *); 288218792Snpstatic int cxgbe_uninit_synchronized(struct port_info *); 289240453Snpstatic int setup_intr_handlers(struct adapter *); 290228561Snpstatic int adapter_full_init(struct adapter *); 291228561Snpstatic int adapter_full_uninit(struct adapter *); 292228561Snpstatic int port_full_init(struct port_info *); 293228561Snpstatic int port_full_uninit(struct port_info *); 294228561Snpstatic void quiesce_eq(struct adapter *, struct sge_eq *); 295228561Snpstatic void quiesce_iq(struct adapter *, struct sge_iq *); 296228561Snpstatic void quiesce_fl(struct adapter *, struct sge_fl *); 297218792Snpstatic int t4_alloc_irq(struct adapter *, struct irq *, int rid, 298228561Snp driver_intr_t *, void *, char *); 299218792Snpstatic int t4_free_irq(struct adapter *, struct irq *); 300218792Snpstatic void reg_block_dump(struct adapter *, uint8_t *, unsigned int, 301218792Snp unsigned int); 302218792Snpstatic void t4_get_regs(struct adapter *, struct t4_regdump *, uint8_t *); 303218792Snpstatic void cxgbe_tick(void *); 304237263Snpstatic void cxgbe_vlan_config(void *, struct ifnet *, uint16_t); 305228561Snpstatic int cpl_not_handled(struct sge_iq *, const struct rss_header *, 306228561Snp struct mbuf *); 307237263Snpstatic int an_not_handled(struct sge_iq *, const struct rsp_ctrl *); 308239336Snpstatic int fw_msg_not_handled(struct adapter *, const __be64 *); 309218792Snpstatic int t4_sysctls(struct adapter *); 310218792Snpstatic int cxgbe_sysctls(struct port_info *); 311219436Snpstatic int sysctl_int_array(SYSCTL_HANDLER_ARGS); 312228561Snpstatic int sysctl_bitfield(SYSCTL_HANDLER_ARGS); 313218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS); 314218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS); 315218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS); 316218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS); 317218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS); 318231115Snp#ifdef SBUF_DRAIN 319228561Snpstatic int sysctl_cctrl(SYSCTL_HANDLER_ARGS); 320228561Snpstatic int sysctl_cpl_stats(SYSCTL_HANDLER_ARGS); 321228561Snpstatic int sysctl_ddp_stats(SYSCTL_HANDLER_ARGS); 322222551Snpstatic int sysctl_devlog(SYSCTL_HANDLER_ARGS); 323228561Snpstatic int sysctl_fcoe_stats(SYSCTL_HANDLER_ARGS); 324228561Snpstatic int sysctl_hw_sched(SYSCTL_HANDLER_ARGS); 325228561Snpstatic int sysctl_lb_stats(SYSCTL_HANDLER_ARGS); 326228561Snpstatic int sysctl_meminfo(SYSCTL_HANDLER_ARGS); 327228561Snpstatic int sysctl_path_mtus(SYSCTL_HANDLER_ARGS); 328228561Snpstatic int sysctl_pm_stats(SYSCTL_HANDLER_ARGS); 329228561Snpstatic int sysctl_rdma_stats(SYSCTL_HANDLER_ARGS); 330228561Snpstatic int sysctl_tcp_stats(SYSCTL_HANDLER_ARGS); 331228561Snpstatic int sysctl_tids(SYSCTL_HANDLER_ARGS); 332228561Snpstatic int sysctl_tp_err_stats(SYSCTL_HANDLER_ARGS); 333228561Snpstatic int sysctl_tx_rate(SYSCTL_HANDLER_ARGS); 334231115Snp#endif 335219286Snpstatic inline void txq_start(struct ifnet *, struct sge_txq *); 336221474Snpstatic uint32_t fconf_to_mode(uint32_t); 337221474Snpstatic uint32_t mode_to_fconf(uint32_t); 338221474Snpstatic uint32_t fspec_to_fconf(struct t4_filter_specification *); 339221474Snpstatic int get_filter_mode(struct adapter *, uint32_t *); 340221474Snpstatic int set_filter_mode(struct adapter *, uint32_t); 341222552Snpstatic inline uint64_t get_filter_hits(struct adapter *, uint32_t); 342221474Snpstatic int get_filter(struct adapter *, struct t4_filter *); 343221474Snpstatic int set_filter(struct adapter *, struct t4_filter *); 344221474Snpstatic int del_filter(struct adapter *, struct t4_filter *); 345222509Snpstatic void clear_filter(struct filter_entry *); 346221474Snpstatic int set_filter_wr(struct adapter *, int); 347221474Snpstatic int del_filter_wr(struct adapter *, int); 348222973Snpstatic int get_sge_context(struct adapter *, struct t4_sge_context *); 349245274Snpstatic int load_fw(struct adapter *, struct t4_data *); 350228561Snpstatic int read_card_mem(struct adapter *, struct t4_mem_range *); 351241399Snpstatic int read_i2c(struct adapter *, struct t4_i2c_data *); 352237263Snp#ifdef TCP_OFFLOAD 353228561Snpstatic int toe_capability(struct port_info *, int); 354228561Snp#endif 355219392Snpstatic int t4_mod_event(module_t, int, void *); 356218792Snp 357218792Snpstruct t4_pciids { 358218792Snp uint16_t device; 359218792Snp char *desc; 360218792Snp} t4_pciids[] = { 361237587Snp {0xa000, "Chelsio Terminator 4 FPGA"}, 362237587Snp {0x4400, "Chelsio T440-dbg"}, 363237587Snp {0x4401, "Chelsio T420-CR"}, 364237587Snp {0x4402, "Chelsio T422-CR"}, 365237587Snp {0x4403, "Chelsio T440-CR"}, 366237587Snp {0x4404, "Chelsio T420-BCH"}, 367237587Snp {0x4405, "Chelsio T440-BCH"}, 368237587Snp {0x4406, "Chelsio T440-CH"}, 369237587Snp {0x4407, "Chelsio T420-SO"}, 370237587Snp {0x4408, "Chelsio T420-CX"}, 371237587Snp {0x4409, "Chelsio T420-BT"}, 372237587Snp {0x440a, "Chelsio T404-BT"}, 373244580Snp {0x440e, "Chelsio T440-LP-CR"}, 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 822245274Snp if (mtx_initialized(&sc->tids.ftid_lock)) 823245274Snp mtx_destroy(&sc->tids.ftid_lock); 824228561Snp if (mtx_initialized(&sc->sfl_lock)) 825228561Snp mtx_destroy(&sc->sfl_lock); 826228561Snp 827218792Snp bzero(sc, sizeof(*sc)); 828218792Snp 829218792Snp return (0); 830218792Snp} 831218792Snp 832218792Snp 833218792Snpstatic int 834218792Snpcxgbe_probe(device_t dev) 835218792Snp{ 836218792Snp char buf[128]; 837218792Snp struct port_info *pi = device_get_softc(dev); 838218792Snp 839228561Snp snprintf(buf, sizeof(buf), "port %d", pi->port_id); 840218792Snp device_set_desc_copy(dev, buf); 841218792Snp 842218792Snp return (BUS_PROBE_DEFAULT); 843218792Snp} 844218792Snp 845218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \ 846218792Snp IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \ 847237831Snp IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6) 848237819Snp#define T4_CAP_ENABLE (T4_CAP) 849218792Snp 850218792Snpstatic int 851218792Snpcxgbe_attach(device_t dev) 852218792Snp{ 853218792Snp struct port_info *pi = device_get_softc(dev); 854218792Snp struct ifnet *ifp; 855218792Snp 856218792Snp /* Allocate an ifnet and set it up */ 857218792Snp ifp = if_alloc(IFT_ETHER); 858218792Snp if (ifp == NULL) { 859218792Snp device_printf(dev, "Cannot allocate ifnet\n"); 860218792Snp return (ENOMEM); 861218792Snp } 862218792Snp pi->ifp = ifp; 863218792Snp ifp->if_softc = pi; 864218792Snp 865218792Snp callout_init(&pi->tick, CALLOUT_MPSAFE); 866218792Snp 867218792Snp if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 868218792Snp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 869218792Snp 870218792Snp ifp->if_init = cxgbe_init; 871218792Snp ifp->if_ioctl = cxgbe_ioctl; 872218792Snp ifp->if_transmit = cxgbe_transmit; 873218792Snp ifp->if_qflush = cxgbe_qflush; 874218792Snp 875218792Snp ifp->if_capabilities = T4_CAP; 876237263Snp#ifdef TCP_OFFLOAD 877228561Snp if (is_offload(pi->adapter)) 878228561Snp ifp->if_capabilities |= IFCAP_TOE4; 879228561Snp#endif 880218792Snp ifp->if_capenable = T4_CAP_ENABLE; 881237799Snp ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO | 882237799Snp CSUM_UDP_IPV6 | CSUM_TCP_IPV6; 883218792Snp 884218792Snp /* Initialize ifmedia for this port */ 885218792Snp ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change, 886218792Snp cxgbe_media_status); 887218792Snp build_medialist(pi); 888218792Snp 889237263Snp pi->vlan_c = EVENTHANDLER_REGISTER(vlan_config, cxgbe_vlan_config, ifp, 890237263Snp EVENTHANDLER_PRI_ANY); 891237263Snp 892218792Snp ether_ifattach(ifp, pi->hw_addr); 893218792Snp 894237263Snp#ifdef TCP_OFFLOAD 895228561Snp if (is_offload(pi->adapter)) { 896228561Snp device_printf(dev, 897228561Snp "%d txq, %d rxq (NIC); %d txq, %d rxq (TOE)\n", 898228561Snp pi->ntxq, pi->nrxq, pi->nofldtxq, pi->nofldrxq); 899228561Snp } else 900218792Snp#endif 901228561Snp device_printf(dev, "%d txq, %d rxq\n", pi->ntxq, pi->nrxq); 902218792Snp 903218792Snp cxgbe_sysctls(pi); 904218792Snp 905218792Snp return (0); 906218792Snp} 907218792Snp 908218792Snpstatic int 909218792Snpcxgbe_detach(device_t dev) 910218792Snp{ 911218792Snp struct port_info *pi = device_get_softc(dev); 912218792Snp struct adapter *sc = pi->adapter; 913228561Snp struct ifnet *ifp = pi->ifp; 914218792Snp 915218792Snp /* Tell if_ioctl and if_init that the port is going away */ 916218792Snp ADAPTER_LOCK(sc); 917218792Snp SET_DOOMED(pi); 918218792Snp wakeup(&sc->flags); 919218792Snp while (IS_BUSY(sc)) 920218792Snp mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0); 921218792Snp SET_BUSY(sc); 922245274Snp#ifdef INVARIANTS 923245274Snp sc->last_op = "t4detach"; 924245274Snp sc->last_op_thr = curthread; 925245274Snp#endif 926218792Snp ADAPTER_UNLOCK(sc); 927218792Snp 928237263Snp if (pi->vlan_c) 929237263Snp EVENTHANDLER_DEREGISTER(vlan_config, pi->vlan_c); 930237263Snp 931228561Snp PORT_LOCK(pi); 932228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 933228561Snp callout_stop(&pi->tick); 934228561Snp PORT_UNLOCK(pi); 935228561Snp callout_drain(&pi->tick); 936218792Snp 937228561Snp /* Let detach proceed even if these fail. */ 938228561Snp cxgbe_uninit_synchronized(pi); 939228561Snp port_full_uninit(pi); 940219286Snp 941218792Snp ifmedia_removeall(&pi->media); 942218792Snp ether_ifdetach(pi->ifp); 943218792Snp if_free(pi->ifp); 944218792Snp 945218792Snp ADAPTER_LOCK(sc); 946218792Snp CLR_BUSY(sc); 947245274Snp wakeup(&sc->flags); 948218792Snp ADAPTER_UNLOCK(sc); 949218792Snp 950218792Snp return (0); 951218792Snp} 952218792Snp 953218792Snpstatic void 954218792Snpcxgbe_init(void *arg) 955218792Snp{ 956218792Snp struct port_info *pi = arg; 957218792Snp struct adapter *sc = pi->adapter; 958218792Snp 959245274Snp if (begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4init") != 0) 960245274Snp return; 961245274Snp cxgbe_init_synchronized(pi); 962245274Snp end_synchronized_op(sc, 0); 963218792Snp} 964218792Snp 965218792Snpstatic int 966218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) 967218792Snp{ 968218792Snp int rc = 0, mtu, flags; 969218792Snp struct port_info *pi = ifp->if_softc; 970218792Snp struct adapter *sc = pi->adapter; 971218792Snp struct ifreq *ifr = (struct ifreq *)data; 972218792Snp uint32_t mask; 973218792Snp 974218792Snp switch (cmd) { 975218792Snp case SIOCSIFMTU: 976245274Snp mtu = ifr->ifr_mtu; 977245274Snp if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) 978245274Snp return (EINVAL); 979245274Snp 980245274Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4mtu"); 981245274Snp if (rc) 982218792Snp return (rc); 983245274Snp ifp->if_mtu = mtu; 984245274Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 985245274Snp t4_update_fl_bufsize(ifp); 986245274Snp rc = update_mac_settings(pi, XGMAC_MTU); 987218792Snp } 988245274Snp end_synchronized_op(sc, 0); 989218792Snp break; 990218792Snp 991218792Snp case SIOCSIFFLAGS: 992245274Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4flg"); 993245274Snp if (rc) 994245274Snp return (rc); 995245274Snp 996218792Snp if (ifp->if_flags & IFF_UP) { 997218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 998218792Snp flags = pi->if_flags; 999218792Snp if ((ifp->if_flags ^ flags) & 1000218792Snp (IFF_PROMISC | IFF_ALLMULTI)) { 1001218792Snp rc = update_mac_settings(pi, 1002218792Snp XGMAC_PROMISC | XGMAC_ALLMULTI); 1003218792Snp } 1004218792Snp } else 1005245274Snp rc = cxgbe_init_synchronized(pi); 1006218792Snp pi->if_flags = ifp->if_flags; 1007218792Snp } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1008245274Snp rc = cxgbe_uninit_synchronized(pi); 1009245274Snp end_synchronized_op(sc, 0); 1010218792Snp break; 1011218792Snp 1012218792Snp case SIOCADDMULTI: 1013245274Snp case SIOCDELMULTI: /* these two are called with a mutex held :-( */ 1014245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK, "t4multi"); 1015218792Snp if (rc) 1016245274Snp return (rc); 1017245274Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1018218792Snp rc = update_mac_settings(pi, XGMAC_MCADDRS); 1019245274Snp end_synchronized_op(sc, LOCK_HELD); 1020218792Snp break; 1021218792Snp 1022218792Snp case SIOCSIFCAP: 1023245274Snp rc = begin_synchronized_op(sc, pi, SLEEP_OK | INTR_OK, "t4cap"); 1024218792Snp if (rc) 1025245274Snp return (rc); 1026218792Snp 1027218792Snp mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1028218792Snp if (mask & IFCAP_TXCSUM) { 1029218792Snp ifp->if_capenable ^= IFCAP_TXCSUM; 1030218792Snp ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 1031218792Snp 1032237831Snp if (IFCAP_TSO4 & ifp->if_capenable && 1033218792Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1034237799Snp ifp->if_capenable &= ~IFCAP_TSO4; 1035218792Snp if_printf(ifp, 1036237831Snp "tso4 disabled due to -txcsum.\n"); 1037218792Snp } 1038218792Snp } 1039237799Snp if (mask & IFCAP_TXCSUM_IPV6) { 1040237799Snp ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 1041237799Snp ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); 1042237799Snp 1043237799Snp if (IFCAP_TSO6 & ifp->if_capenable && 1044237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1045237799Snp ifp->if_capenable &= ~IFCAP_TSO6; 1046237799Snp if_printf(ifp, 1047237799Snp "tso6 disabled due to -txcsum6.\n"); 1048237799Snp } 1049237799Snp } 1050218792Snp if (mask & IFCAP_RXCSUM) 1051218792Snp ifp->if_capenable ^= IFCAP_RXCSUM; 1052237799Snp if (mask & IFCAP_RXCSUM_IPV6) 1053237799Snp ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 1054237799Snp 1055237799Snp /* 1056237799Snp * Note that we leave CSUM_TSO alone (it is always set). The 1057237799Snp * kernel takes both IFCAP_TSOx and CSUM_TSO into account before 1058237799Snp * sending a TSO request our way, so it's sufficient to toggle 1059237799Snp * IFCAP_TSOx only. 1060237799Snp */ 1061218792Snp if (mask & IFCAP_TSO4) { 1062237799Snp if (!(IFCAP_TSO4 & ifp->if_capenable) && 1063237799Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1064237799Snp if_printf(ifp, "enable txcsum first.\n"); 1065237799Snp rc = EAGAIN; 1066237799Snp goto fail; 1067237799Snp } 1068218792Snp ifp->if_capenable ^= IFCAP_TSO4; 1069218792Snp } 1070237799Snp if (mask & IFCAP_TSO6) { 1071237799Snp if (!(IFCAP_TSO6 & ifp->if_capenable) && 1072237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1073237799Snp if_printf(ifp, "enable txcsum6 first.\n"); 1074237799Snp rc = EAGAIN; 1075237799Snp goto fail; 1076237799Snp } 1077237799Snp ifp->if_capenable ^= IFCAP_TSO6; 1078237799Snp } 1079218792Snp if (mask & IFCAP_LRO) { 1080237819Snp#if defined(INET) || defined(INET6) 1081218792Snp int i; 1082218792Snp struct sge_rxq *rxq; 1083218792Snp 1084218792Snp ifp->if_capenable ^= IFCAP_LRO; 1085218792Snp for_each_rxq(pi, i, rxq) { 1086218792Snp if (ifp->if_capenable & IFCAP_LRO) 1087228561Snp rxq->iq.flags |= IQ_LRO_ENABLED; 1088218792Snp else 1089228561Snp rxq->iq.flags &= ~IQ_LRO_ENABLED; 1090218792Snp } 1091218792Snp#endif 1092218792Snp } 1093237263Snp#ifdef TCP_OFFLOAD 1094228561Snp if (mask & IFCAP_TOE) { 1095228561Snp int enable = (ifp->if_capenable ^ mask) & IFCAP_TOE; 1096228561Snp 1097228561Snp rc = toe_capability(pi, enable); 1098228561Snp if (rc != 0) 1099228561Snp goto fail; 1100228561Snp 1101228561Snp ifp->if_capenable ^= mask; 1102218792Snp } 1103218792Snp#endif 1104218792Snp if (mask & IFCAP_VLAN_HWTAGGING) { 1105218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1106245274Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1107218792Snp rc = update_mac_settings(pi, XGMAC_VLANEX); 1108218792Snp } 1109218792Snp if (mask & IFCAP_VLAN_MTU) { 1110218792Snp ifp->if_capenable ^= IFCAP_VLAN_MTU; 1111218792Snp 1112218792Snp /* Need to find out how to disable auto-mtu-inflation */ 1113218792Snp } 1114218792Snp if (mask & IFCAP_VLAN_HWTSO) 1115218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1116218792Snp if (mask & IFCAP_VLAN_HWCSUM) 1117218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 1118218792Snp 1119218792Snp#ifdef VLAN_CAPABILITIES 1120218792Snp VLAN_CAPABILITIES(ifp); 1121218792Snp#endif 1122245274Snpfail: 1123245274Snp end_synchronized_op(sc, 0); 1124218792Snp break; 1125218792Snp 1126218792Snp case SIOCSIFMEDIA: 1127218792Snp case SIOCGIFMEDIA: 1128218792Snp ifmedia_ioctl(ifp, ifr, &pi->media, cmd); 1129218792Snp break; 1130218792Snp 1131218792Snp default: 1132218792Snp rc = ether_ioctl(ifp, cmd, data); 1133218792Snp } 1134218792Snp 1135218792Snp return (rc); 1136218792Snp} 1137218792Snp 1138218792Snpstatic int 1139218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m) 1140218792Snp{ 1141218792Snp struct port_info *pi = ifp->if_softc; 1142218792Snp struct adapter *sc = pi->adapter; 1143218792Snp struct sge_txq *txq = &sc->sge.txq[pi->first_txq]; 1144218792Snp struct buf_ring *br; 1145218792Snp int rc; 1146218792Snp 1147218792Snp M_ASSERTPKTHDR(m); 1148218792Snp 1149228561Snp if (__predict_false(pi->link_cfg.link_ok == 0)) { 1150218792Snp m_freem(m); 1151228561Snp return (ENETDOWN); 1152218792Snp } 1153218792Snp 1154218792Snp if (m->m_flags & M_FLOWID) 1155218792Snp txq += (m->m_pkthdr.flowid % pi->ntxq); 1156220873Snp br = txq->br; 1157218792Snp 1158218792Snp if (TXQ_TRYLOCK(txq) == 0) { 1159228561Snp struct sge_eq *eq = &txq->eq; 1160228561Snp 1161218792Snp /* 1162228561Snp * It is possible that t4_eth_tx finishes up and releases the 1163228561Snp * lock between the TRYLOCK above and the drbr_enqueue here. We 1164228561Snp * need to make sure that this mbuf doesn't just sit there in 1165228561Snp * the drbr. 1166218792Snp */ 1167218792Snp 1168228561Snp rc = drbr_enqueue(ifp, br, m); 1169228561Snp if (rc == 0 && callout_pending(&eq->tx_callout) == 0 && 1170228561Snp !(eq->flags & EQ_DOOMED)) 1171228561Snp callout_reset(&eq->tx_callout, 1, t4_tx_callout, eq); 1172228561Snp return (rc); 1173218792Snp } 1174218792Snp 1175218792Snp /* 1176218792Snp * txq->m is the mbuf that is held up due to a temporary shortage of 1177218792Snp * resources and it should be put on the wire first. Then what's in 1178218792Snp * drbr and finally the mbuf that was just passed in to us. 1179218792Snp * 1180218792Snp * Return code should indicate the fate of the mbuf that was passed in 1181218792Snp * this time. 1182218792Snp */ 1183218792Snp 1184218792Snp TXQ_LOCK_ASSERT_OWNED(txq); 1185218792Snp if (drbr_needs_enqueue(ifp, br) || txq->m) { 1186218792Snp 1187218792Snp /* Queued for transmission. */ 1188218792Snp 1189218792Snp rc = drbr_enqueue(ifp, br, m); 1190218792Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 1191218792Snp (void) t4_eth_tx(ifp, txq, m); 1192218792Snp TXQ_UNLOCK(txq); 1193218792Snp return (rc); 1194218792Snp } 1195218792Snp 1196218792Snp /* Direct transmission. */ 1197218792Snp rc = t4_eth_tx(ifp, txq, m); 1198218792Snp if (rc != 0 && txq->m) 1199218792Snp rc = 0; /* held, will be transmitted soon (hopefully) */ 1200218792Snp 1201218792Snp TXQ_UNLOCK(txq); 1202218792Snp return (rc); 1203218792Snp} 1204218792Snp 1205218792Snpstatic void 1206218792Snpcxgbe_qflush(struct ifnet *ifp) 1207218792Snp{ 1208218792Snp struct port_info *pi = ifp->if_softc; 1209220649Snp struct sge_txq *txq; 1210220649Snp int i; 1211220649Snp struct mbuf *m; 1212218792Snp 1213228561Snp /* queues do not exist if !PORT_INIT_DONE. */ 1214228561Snp if (pi->flags & PORT_INIT_DONE) { 1215220649Snp for_each_txq(pi, i, txq) { 1216220649Snp TXQ_LOCK(txq); 1217220649Snp m_freem(txq->m); 1218228561Snp txq->m = NULL; 1219220873Snp while ((m = buf_ring_dequeue_sc(txq->br)) != NULL) 1220220649Snp m_freem(m); 1221220649Snp TXQ_UNLOCK(txq); 1222220649Snp } 1223220649Snp } 1224220649Snp if_qflush(ifp); 1225218792Snp} 1226218792Snp 1227218792Snpstatic int 1228218792Snpcxgbe_media_change(struct ifnet *ifp) 1229218792Snp{ 1230218792Snp struct port_info *pi = ifp->if_softc; 1231218792Snp 1232218792Snp device_printf(pi->dev, "%s unimplemented.\n", __func__); 1233218792Snp 1234218792Snp return (EOPNOTSUPP); 1235218792Snp} 1236218792Snp 1237218792Snpstatic void 1238218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1239218792Snp{ 1240218792Snp struct port_info *pi = ifp->if_softc; 1241218792Snp struct ifmedia_entry *cur = pi->media.ifm_cur; 1242218792Snp int speed = pi->link_cfg.speed; 1243218792Snp int data = (pi->port_type << 8) | pi->mod_type; 1244218792Snp 1245218792Snp if (cur->ifm_data != data) { 1246218792Snp build_medialist(pi); 1247218792Snp cur = pi->media.ifm_cur; 1248218792Snp } 1249218792Snp 1250218792Snp ifmr->ifm_status = IFM_AVALID; 1251218792Snp if (!pi->link_cfg.link_ok) 1252218792Snp return; 1253218792Snp 1254218792Snp ifmr->ifm_status |= IFM_ACTIVE; 1255218792Snp 1256218792Snp /* active and current will differ iff current media is autoselect. */ 1257218792Snp if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO) 1258218792Snp return; 1259218792Snp 1260218792Snp ifmr->ifm_active = IFM_ETHER | IFM_FDX; 1261218792Snp if (speed == SPEED_10000) 1262218792Snp ifmr->ifm_active |= IFM_10G_T; 1263218792Snp else if (speed == SPEED_1000) 1264218792Snp ifmr->ifm_active |= IFM_1000_T; 1265218792Snp else if (speed == SPEED_100) 1266218792Snp ifmr->ifm_active |= IFM_100_TX; 1267218792Snp else if (speed == SPEED_10) 1268218792Snp ifmr->ifm_active |= IFM_10_T; 1269218792Snp else 1270218792Snp KASSERT(0, ("%s: link up but speed unknown (%u)", __func__, 1271218792Snp speed)); 1272218792Snp} 1273218792Snp 1274218792Snpvoid 1275218792Snpt4_fatal_err(struct adapter *sc) 1276218792Snp{ 1277218792Snp t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0); 1278218792Snp t4_intr_disable(sc); 1279218792Snp log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n", 1280218792Snp device_get_nameunit(sc->dev)); 1281218792Snp} 1282218792Snp 1283218792Snpstatic int 1284218792Snpmap_bars(struct adapter *sc) 1285218792Snp{ 1286218792Snp sc->regs_rid = PCIR_BAR(0); 1287218792Snp sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1288218792Snp &sc->regs_rid, RF_ACTIVE); 1289218792Snp if (sc->regs_res == NULL) { 1290218792Snp device_printf(sc->dev, "cannot map registers.\n"); 1291218792Snp return (ENXIO); 1292218792Snp } 1293218792Snp sc->bt = rman_get_bustag(sc->regs_res); 1294218792Snp sc->bh = rman_get_bushandle(sc->regs_res); 1295218792Snp sc->mmio_len = rman_get_size(sc->regs_res); 1296218792Snp 1297218792Snp sc->msix_rid = PCIR_BAR(4); 1298218792Snp sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1299218792Snp &sc->msix_rid, RF_ACTIVE); 1300218792Snp if (sc->msix_res == NULL) { 1301218792Snp device_printf(sc->dev, "cannot map MSI-X BAR.\n"); 1302218792Snp return (ENXIO); 1303218792Snp } 1304218792Snp 1305218792Snp return (0); 1306218792Snp} 1307218792Snp 1308218792Snpstatic void 1309218792Snpsetup_memwin(struct adapter *sc) 1310218792Snp{ 1311237587Snp uint32_t bar0; 1312218792Snp 1313237587Snp /* 1314237587Snp * Read low 32b of bar0 indirectly via the hardware backdoor mechanism. 1315237587Snp * Works from within PCI passthrough environments too, where 1316237587Snp * rman_get_start() can return a different value. We need to program 1317237587Snp * the memory window decoders with the actual addresses that will be 1318237587Snp * coming across the PCIe link. 1319237587Snp */ 1320237587Snp bar0 = t4_hw_pci_read_cfg4(sc, PCIR_BAR(0)); 1321237587Snp bar0 &= (uint32_t) PCIM_BAR_MEM_BASE; 1322218792Snp 1323218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 0), 1324218792Snp (bar0 + MEMWIN0_BASE) | V_BIR(0) | 1325218792Snp V_WINDOW(ilog2(MEMWIN0_APERTURE) - 10)); 1326218792Snp 1327218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 1), 1328218792Snp (bar0 + MEMWIN1_BASE) | V_BIR(0) | 1329218792Snp V_WINDOW(ilog2(MEMWIN1_APERTURE) - 10)); 1330218792Snp 1331218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2), 1332218792Snp (bar0 + MEMWIN2_BASE) | V_BIR(0) | 1333218792Snp V_WINDOW(ilog2(MEMWIN2_APERTURE) - 10)); 1334237587Snp 1335237587Snp /* flush */ 1336237587Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2)); 1337218792Snp} 1338218792Snp 1339218792Snpstatic int 1340218792Snpcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g, 1341218792Snp struct intrs_and_queues *iaq) 1342218792Snp{ 1343228561Snp int rc, itype, navail, nrxq10g, nrxq1g, n; 1344228561Snp int nofldrxq10g = 0, nofldrxq1g = 0; 1345218792Snp 1346218792Snp bzero(iaq, sizeof(*iaq)); 1347218792Snp 1348228561Snp iaq->ntxq10g = t4_ntxq10g; 1349228561Snp iaq->ntxq1g = t4_ntxq1g; 1350228561Snp iaq->nrxq10g = nrxq10g = t4_nrxq10g; 1351228561Snp iaq->nrxq1g = nrxq1g = t4_nrxq1g; 1352237263Snp#ifdef TCP_OFFLOAD 1353237463Snp if (is_offload(sc)) { 1354237463Snp iaq->nofldtxq10g = t4_nofldtxq10g; 1355237463Snp iaq->nofldtxq1g = t4_nofldtxq1g; 1356237463Snp iaq->nofldrxq10g = nofldrxq10g = t4_nofldrxq10g; 1357237463Snp iaq->nofldrxq1g = nofldrxq1g = t4_nofldrxq1g; 1358237463Snp } 1359228561Snp#endif 1360228561Snp 1361219944Snp for (itype = INTR_MSIX; itype; itype >>= 1) { 1362218792Snp 1363228561Snp if ((itype & t4_intr_types) == 0) 1364218792Snp continue; /* not allowed */ 1365218792Snp 1366219944Snp if (itype == INTR_MSIX) 1367218792Snp navail = pci_msix_count(sc->dev); 1368219944Snp else if (itype == INTR_MSI) 1369218792Snp navail = pci_msi_count(sc->dev); 1370218792Snp else 1371218792Snp navail = 1; 1372228561Snprestart: 1373218792Snp if (navail == 0) 1374218792Snp continue; 1375218792Snp 1376218792Snp iaq->intr_type = itype; 1377228561Snp iaq->intr_flags = 0; 1378218792Snp 1379228561Snp /* 1380228561Snp * Best option: an interrupt vector for errors, one for the 1381228561Snp * firmware event queue, and one each for each rxq (NIC as well 1382228561Snp * as offload). 1383228561Snp */ 1384228561Snp iaq->nirq = T4_EXTRA_INTR; 1385228561Snp iaq->nirq += n10g * (nrxq10g + nofldrxq10g); 1386228561Snp iaq->nirq += n1g * (nrxq1g + nofldrxq1g); 1387228561Snp if (iaq->nirq <= navail && 1388228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) { 1389228561Snp iaq->intr_flags |= INTR_DIRECT; 1390228561Snp goto allocate; 1391228561Snp } 1392218792Snp 1393228561Snp /* 1394228561Snp * Second best option: an interrupt vector for errors, one for 1395228561Snp * the firmware event queue, and one each for either NIC or 1396228561Snp * offload rxq's. 1397228561Snp */ 1398228561Snp iaq->nirq = T4_EXTRA_INTR; 1399228561Snp iaq->nirq += n10g * max(nrxq10g, nofldrxq10g); 1400228561Snp iaq->nirq += n1g * max(nrxq1g, nofldrxq1g); 1401228561Snp if (iaq->nirq <= navail && 1402228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) 1403228561Snp goto allocate; 1404218792Snp 1405228561Snp /* 1406228561Snp * Next best option: an interrupt vector for errors, one for the 1407228561Snp * firmware event queue, and at least one per port. At this 1408228561Snp * point we know we'll have to downsize nrxq or nofldrxq to fit 1409228561Snp * what's available to us. 1410228561Snp */ 1411228561Snp iaq->nirq = T4_EXTRA_INTR; 1412228561Snp iaq->nirq += n10g + n1g; 1413228561Snp if (iaq->nirq <= navail) { 1414228561Snp int leftover = navail - iaq->nirq; 1415218792Snp 1416228561Snp if (n10g > 0) { 1417228561Snp int target = max(nrxq10g, nofldrxq10g); 1418219944Snp 1419228561Snp n = 1; 1420228561Snp while (n < target && leftover >= n10g) { 1421228561Snp leftover -= n10g; 1422228561Snp iaq->nirq += n10g; 1423228561Snp n++; 1424228561Snp } 1425228561Snp iaq->nrxq10g = min(n, nrxq10g); 1426237263Snp#ifdef TCP_OFFLOAD 1427237463Snp if (is_offload(sc)) 1428237463Snp iaq->nofldrxq10g = min(n, nofldrxq10g); 1429228561Snp#endif 1430228561Snp } 1431218792Snp 1432228561Snp if (n1g > 0) { 1433228561Snp int target = max(nrxq1g, nofldrxq1g); 1434219944Snp 1435228561Snp n = 1; 1436228561Snp while (n < target && leftover >= n1g) { 1437228561Snp leftover -= n1g; 1438228561Snp iaq->nirq += n1g; 1439228561Snp n++; 1440219944Snp } 1441228561Snp iaq->nrxq1g = min(n, nrxq1g); 1442237263Snp#ifdef TCP_OFFLOAD 1443237463Snp if (is_offload(sc)) 1444237463Snp iaq->nofldrxq1g = min(n, nofldrxq1g); 1445228561Snp#endif 1446219944Snp } 1447219944Snp 1448228561Snp if (itype != INTR_MSI || powerof2(iaq->nirq)) 1449228561Snp goto allocate; 1450218792Snp } 1451218792Snp 1452228561Snp /* 1453228561Snp * Least desirable option: one interrupt vector for everything. 1454228561Snp */ 1455228561Snp iaq->nirq = iaq->nrxq10g = iaq->nrxq1g = 1; 1456237263Snp#ifdef TCP_OFFLOAD 1457237463Snp if (is_offload(sc)) 1458237463Snp iaq->nofldrxq10g = iaq->nofldrxq1g = 1; 1459228561Snp#endif 1460228561Snp 1461228561Snpallocate: 1462218792Snp navail = iaq->nirq; 1463218792Snp rc = 0; 1464219944Snp if (itype == INTR_MSIX) 1465218792Snp rc = pci_alloc_msix(sc->dev, &navail); 1466219944Snp else if (itype == INTR_MSI) 1467218792Snp rc = pci_alloc_msi(sc->dev, &navail); 1468218792Snp 1469218792Snp if (rc == 0) { 1470218792Snp if (navail == iaq->nirq) 1471218792Snp return (0); 1472218792Snp 1473218792Snp /* 1474218792Snp * Didn't get the number requested. Use whatever number 1475218792Snp * the kernel is willing to allocate (it's in navail). 1476218792Snp */ 1477228561Snp device_printf(sc->dev, "fewer vectors than requested, " 1478228561Snp "type=%d, req=%d, rcvd=%d; will downshift req.\n", 1479228561Snp itype, iaq->nirq, navail); 1480218792Snp pci_release_msi(sc->dev); 1481228561Snp goto restart; 1482218792Snp } 1483218792Snp 1484218792Snp device_printf(sc->dev, 1485218792Snp "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n", 1486218792Snp itype, rc, iaq->nirq, navail); 1487218792Snp } 1488218792Snp 1489218792Snp device_printf(sc->dev, 1490218792Snp "failed to find a usable interrupt type. " 1491228561Snp "allowed=%d, msi-x=%d, msi=%d, intx=1", t4_intr_types, 1492218792Snp pci_msix_count(sc->dev), pci_msi_count(sc->dev)); 1493218792Snp 1494218792Snp return (ENXIO); 1495218792Snp} 1496218792Snp 1497218792Snp/* 1498228561Snp * Install a compatible firmware (if required), establish contact with it (by 1499228561Snp * saying hello), and reset the device. If we end up as the master driver, 1500228561Snp * partition adapter resources by providing a configuration file to the 1501228561Snp * firmware. 1502218792Snp */ 1503218792Snpstatic int 1504218792Snpprep_firmware(struct adapter *sc) 1505218792Snp{ 1506228561Snp const struct firmware *fw = NULL, *cfg = NULL, *default_cfg; 1507218792Snp int rc; 1508218792Snp enum dev_state state; 1509218792Snp 1510228561Snp default_cfg = firmware_get(T4_CFGNAME); 1511228561Snp 1512218792Snp /* Check firmware version and install a different one if necessary */ 1513218792Snp rc = t4_check_fw_version(sc); 1514234831Snp snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u", 1515234831Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1516234831Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1517234831Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1518234831Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 1519228561Snp if (rc != 0) { 1520219287Snp uint32_t v = 0; 1521218792Snp 1522218792Snp fw = firmware_get(T4_FWNAME); 1523219287Snp if (fw != NULL) { 1524219287Snp const struct fw_hdr *hdr = (const void *)fw->data; 1525219287Snp 1526219287Snp v = ntohl(hdr->fw_ver); 1527219287Snp 1528219287Snp /* 1529219287Snp * The firmware module will not be used if it isn't the 1530219287Snp * same major version as what the driver was compiled 1531228561Snp * with. 1532219287Snp */ 1533219287Snp if (G_FW_HDR_FW_VER_MAJOR(v) != FW_VERSION_MAJOR) { 1534219287Snp device_printf(sc->dev, 1535219287Snp "Found firmware image but version %d " 1536219287Snp "can not be used with this driver (%d)\n", 1537219287Snp G_FW_HDR_FW_VER_MAJOR(v), FW_VERSION_MAJOR); 1538219287Snp 1539219287Snp firmware_put(fw, FIRMWARE_UNLOAD); 1540219287Snp fw = NULL; 1541219287Snp } 1542218792Snp } 1543218792Snp 1544228561Snp if (fw == NULL && rc < 0) { 1545219287Snp device_printf(sc->dev, "No usable firmware. " 1546228561Snp "card has %d.%d.%d, driver compiled with %d.%d.%d", 1547219287Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1548219287Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1549219287Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1550219287Snp FW_VERSION_MAJOR, FW_VERSION_MINOR, 1551228561Snp FW_VERSION_MICRO); 1552228561Snp rc = EAGAIN; 1553228561Snp goto done; 1554219287Snp } 1555219287Snp 1556219287Snp /* 1557219287Snp * Always upgrade, even for minor/micro/build mismatches. 1558219287Snp * Downgrade only for a major version mismatch or if 1559219287Snp * force_firmware_install was specified. 1560219287Snp */ 1561228561Snp if (fw != NULL && (rc < 0 || v > sc->params.fw_vers)) { 1562218792Snp device_printf(sc->dev, 1563219287Snp "installing firmware %d.%d.%d.%d on card.\n", 1564219287Snp G_FW_HDR_FW_VER_MAJOR(v), G_FW_HDR_FW_VER_MINOR(v), 1565219287Snp G_FW_HDR_FW_VER_MICRO(v), G_FW_HDR_FW_VER_BUILD(v)); 1566219287Snp 1567219287Snp rc = -t4_load_fw(sc, fw->data, fw->datasize); 1568219287Snp if (rc != 0) { 1569219287Snp device_printf(sc->dev, 1570219287Snp "failed to install firmware: %d\n", rc); 1571228561Snp goto done; 1572219287Snp } else { 1573219287Snp /* refresh */ 1574219287Snp (void) t4_check_fw_version(sc); 1575234831Snp snprintf(sc->fw_version, 1576234831Snp sizeof(sc->fw_version), "%u.%u.%u.%u", 1577234831Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1578234831Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1579234831Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1580234831Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 1581219287Snp } 1582218792Snp } 1583218792Snp } 1584218792Snp 1585228561Snp /* Contact firmware. */ 1586228561Snp rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state); 1587218792Snp if (rc < 0) { 1588218792Snp rc = -rc; 1589218792Snp device_printf(sc->dev, 1590218792Snp "failed to connect to the firmware: %d.\n", rc); 1591228561Snp goto done; 1592218792Snp } 1593228561Snp if (rc == sc->mbox) 1594228561Snp sc->flags |= MASTER_PF; 1595218792Snp 1596218792Snp /* Reset device */ 1597218792Snp rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST); 1598218792Snp if (rc != 0) { 1599218792Snp device_printf(sc->dev, "firmware reset failed: %d.\n", rc); 1600218792Snp if (rc != ETIMEDOUT && rc != EIO) 1601218792Snp t4_fw_bye(sc, sc->mbox); 1602228561Snp goto done; 1603218792Snp } 1604218792Snp 1605228561Snp /* Partition adapter resources as specified in the config file. */ 1606228561Snp if (sc->flags & MASTER_PF) { 1607228561Snp if (strncmp(t4_cfg_file, "default", sizeof(t4_cfg_file))) { 1608228561Snp char s[32]; 1609228561Snp 1610228561Snp snprintf(s, sizeof(s), "t4fw_cfg_%s", t4_cfg_file); 1611228561Snp cfg = firmware_get(s); 1612228561Snp if (cfg == NULL) { 1613228561Snp device_printf(sc->dev, 1614228561Snp "unable to locate %s module, " 1615228561Snp "will use default config file.\n", s); 1616228561Snp } 1617228561Snp } 1618228561Snp 1619228561Snp rc = partition_resources(sc, cfg ? cfg : default_cfg); 1620228561Snp if (rc != 0) 1621228561Snp goto done; /* error message displayed already */ 1622228561Snp } 1623228561Snp 1624218792Snp sc->flags |= FW_OK; 1625218792Snp 1626228561Snpdone: 1627228561Snp if (fw != NULL) 1628228561Snp firmware_put(fw, FIRMWARE_UNLOAD); 1629228561Snp if (cfg != NULL) 1630228561Snp firmware_put(cfg, FIRMWARE_UNLOAD); 1631228561Snp if (default_cfg != NULL) 1632228561Snp firmware_put(default_cfg, FIRMWARE_UNLOAD); 1633228561Snp 1634228561Snp return (rc); 1635218792Snp} 1636218792Snp 1637228561Snp#define FW_PARAM_DEV(param) \ 1638228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ 1639228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) 1640228561Snp#define FW_PARAM_PFVF(param) \ 1641228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ 1642228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)) 1643228561Snp 1644228561Snp/* 1645228561Snp * Upload configuration file to card's memory. 1646228561Snp */ 1647218792Snpstatic int 1648228561Snpupload_config_file(struct adapter *sc, const struct firmware *fw, uint32_t *mt, 1649228561Snp uint32_t *ma) 1650222551Snp{ 1651228561Snp int rc, i; 1652228561Snp uint32_t param, val, mtype, maddr, bar, off, win, remaining; 1653228561Snp const uint32_t *b; 1654222551Snp 1655228561Snp /* Figure out where the firmware wants us to upload it. */ 1656228561Snp param = FW_PARAM_DEV(CF); 1657228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 1658222551Snp if (rc != 0) { 1659228561Snp /* Firmwares without config file support will fail this way */ 1660222551Snp device_printf(sc->dev, 1661228561Snp "failed to query config file location: %d.\n", rc); 1662222551Snp return (rc); 1663222551Snp } 1664228561Snp *mt = mtype = G_FW_PARAMS_PARAM_Y(val); 1665228561Snp *ma = maddr = G_FW_PARAMS_PARAM_Z(val) << 16; 1666222551Snp 1667228561Snp if (maddr & 3) { 1668228561Snp device_printf(sc->dev, 1669228561Snp "cannot upload config file (type %u, addr %x).\n", 1670228561Snp mtype, maddr); 1671228561Snp return (EFAULT); 1672228561Snp } 1673222551Snp 1674228561Snp /* Translate mtype/maddr to an address suitable for the PCIe window */ 1675228561Snp val = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 1676228561Snp val &= F_EDRAM0_ENABLE | F_EDRAM1_ENABLE | F_EXT_MEM_ENABLE; 1677228561Snp switch (mtype) { 1678228561Snp case FW_MEMTYPE_CF_EDC0: 1679228561Snp if (!(val & F_EDRAM0_ENABLE)) 1680228561Snp goto err; 1681228561Snp bar = t4_read_reg(sc, A_MA_EDRAM0_BAR); 1682228561Snp maddr += G_EDRAM0_BASE(bar) << 20; 1683228561Snp break; 1684228561Snp 1685228561Snp case FW_MEMTYPE_CF_EDC1: 1686228561Snp if (!(val & F_EDRAM1_ENABLE)) 1687228561Snp goto err; 1688228561Snp bar = t4_read_reg(sc, A_MA_EDRAM1_BAR); 1689228561Snp maddr += G_EDRAM1_BASE(bar) << 20; 1690228561Snp break; 1691228561Snp 1692228561Snp case FW_MEMTYPE_CF_EXTMEM: 1693228561Snp if (!(val & F_EXT_MEM_ENABLE)) 1694228561Snp goto err; 1695228561Snp bar = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 1696228561Snp maddr += G_EXT_MEM_BASE(bar) << 20; 1697228561Snp break; 1698228561Snp 1699228561Snp default: 1700228561Snperr: 1701228561Snp device_printf(sc->dev, 1702228561Snp "cannot upload config file (type %u, enabled %u).\n", 1703228561Snp mtype, val); 1704228561Snp return (EFAULT); 1705228561Snp } 1706228561Snp 1707228561Snp /* 1708228561Snp * Position the PCIe window (we use memwin2) to the 16B aligned area 1709228561Snp * just at/before the upload location. 1710228561Snp */ 1711228561Snp win = maddr & ~0xf; 1712228561Snp off = maddr - win; /* offset from the start of the window. */ 1713228561Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2), win); 1714228561Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2)); 1715228561Snp 1716228561Snp remaining = fw->datasize; 1717228561Snp if (remaining > FLASH_CFG_MAX_SIZE || 1718228561Snp remaining > MEMWIN2_APERTURE - off) { 1719228561Snp device_printf(sc->dev, "cannot upload config file all at once " 1720228561Snp "(size %u, max %u, room %u).\n", 1721228561Snp remaining, FLASH_CFG_MAX_SIZE, MEMWIN2_APERTURE - off); 1722228561Snp return (EFBIG); 1723228561Snp } 1724228561Snp 1725228561Snp /* 1726228561Snp * XXX: sheer laziness. We deliberately added 4 bytes of useless 1727228561Snp * stuffing/comments at the end of the config file so it's ok to simply 1728228561Snp * throw away the last remaining bytes when the config file is not an 1729228561Snp * exact multiple of 4. 1730228561Snp */ 1731228561Snp b = fw->data; 1732228561Snp for (i = 0; remaining >= 4; i += 4, remaining -= 4) 1733228561Snp t4_write_reg(sc, MEMWIN2_BASE + off + i, *b++); 1734228561Snp 1735228561Snp return (rc); 1736222551Snp} 1737222551Snp 1738228561Snp/* 1739228561Snp * Partition chip resources for use between various PFs, VFs, etc. This is done 1740228561Snp * by uploading the firmware configuration file to the adapter and instructing 1741228561Snp * the firmware to process it. 1742228561Snp */ 1743222551Snpstatic int 1744228561Snppartition_resources(struct adapter *sc, const struct firmware *cfg) 1745218792Snp{ 1746218792Snp int rc; 1747228561Snp struct fw_caps_config_cmd caps; 1748228561Snp uint32_t mtype, maddr, finicsum, cfcsum; 1749218792Snp 1750228561Snp rc = cfg ? upload_config_file(sc, cfg, &mtype, &maddr) : ENOENT; 1751228561Snp if (rc != 0) { 1752228561Snp mtype = FW_MEMTYPE_CF_FLASH; 1753228561Snp maddr = t4_flash_cfg_addr(sc); 1754228561Snp } 1755228561Snp 1756228561Snp bzero(&caps, sizeof(caps)); 1757228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1758218792Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1759228561Snp caps.cfvalid_to_len16 = htobe32(F_FW_CAPS_CONFIG_CMD_CFVALID | 1760228561Snp V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) | 1761228561Snp V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(maddr >> 16) | FW_LEN16(caps)); 1762228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 1763228561Snp if (rc != 0) { 1764228561Snp device_printf(sc->dev, 1765228561Snp "failed to pre-process config file: %d.\n", rc); 1766218792Snp return (rc); 1767228561Snp } 1768218792Snp 1769228561Snp finicsum = be32toh(caps.finicsum); 1770228561Snp cfcsum = be32toh(caps.cfcsum); 1771228561Snp if (finicsum != cfcsum) { 1772228561Snp device_printf(sc->dev, 1773228561Snp "WARNING: config file checksum mismatch: %08x %08x\n", 1774228561Snp finicsum, cfcsum); 1775228561Snp } 1776228561Snp sc->cfcsum = cfcsum; 1777218792Snp 1778228561Snp#define LIMIT_CAPS(x) do { \ 1779228561Snp caps.x &= htobe16(t4_##x##_allowed); \ 1780228561Snp sc->x = htobe16(caps.x); \ 1781228561Snp} while (0) 1782228561Snp 1783228561Snp /* 1784228561Snp * Let the firmware know what features will (not) be used so it can tune 1785228561Snp * things accordingly. 1786228561Snp */ 1787228561Snp LIMIT_CAPS(linkcaps); 1788228561Snp LIMIT_CAPS(niccaps); 1789228561Snp LIMIT_CAPS(toecaps); 1790228561Snp LIMIT_CAPS(rdmacaps); 1791228561Snp LIMIT_CAPS(iscsicaps); 1792228561Snp LIMIT_CAPS(fcoecaps); 1793228561Snp#undef LIMIT_CAPS 1794228561Snp 1795228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1796218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE); 1797228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 1798228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), NULL); 1799228561Snp if (rc != 0) { 1800228561Snp device_printf(sc->dev, 1801228561Snp "failed to process config file: %d.\n", rc); 1802228561Snp return (rc); 1803228561Snp } 1804218792Snp 1805228561Snp return (0); 1806218792Snp} 1807218792Snp 1808228561Snp/* 1809228561Snp * Retrieve parameters that are needed (or nice to have) prior to calling 1810228561Snp * t4_sge_init and t4_fw_initialize. 1811228561Snp */ 1812218792Snpstatic int 1813228561Snpget_params__pre_init(struct adapter *sc) 1814218792Snp{ 1815218792Snp int rc; 1816228561Snp uint32_t param[2], val[2]; 1817228561Snp struct fw_devlog_cmd cmd; 1818228561Snp struct devlog_params *dlog = &sc->params.devlog; 1819218792Snp 1820228561Snp param[0] = FW_PARAM_DEV(PORTVEC); 1821228561Snp param[1] = FW_PARAM_DEV(CCLK); 1822228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 1823218792Snp if (rc != 0) { 1824218792Snp device_printf(sc->dev, 1825228561Snp "failed to query parameters (pre_init): %d.\n", rc); 1826228561Snp return (rc); 1827218792Snp } 1828218792Snp 1829218792Snp sc->params.portvec = val[0]; 1830240452Snp sc->params.nports = bitcount32(val[0]); 1831228561Snp sc->params.vpd.cclk = val[1]; 1832218792Snp 1833228561Snp /* Read device log parameters. */ 1834228561Snp bzero(&cmd, sizeof(cmd)); 1835228561Snp cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) | 1836228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1837228561Snp cmd.retval_len16 = htobe32(FW_LEN16(cmd)); 1838228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &cmd, sizeof(cmd), &cmd); 1839228561Snp if (rc != 0) { 1840228561Snp device_printf(sc->dev, 1841228561Snp "failed to get devlog parameters: %d.\n", rc); 1842228561Snp bzero(dlog, sizeof (*dlog)); 1843228561Snp rc = 0; /* devlog isn't critical for device operation */ 1844228561Snp } else { 1845228561Snp val[0] = be32toh(cmd.memtype_devlog_memaddr16_devlog); 1846228561Snp dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(val[0]); 1847228561Snp dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(val[0]) << 4; 1848228561Snp dlog->size = be32toh(cmd.memsize_devlog); 1849228561Snp } 1850228561Snp 1851228561Snp return (rc); 1852228561Snp} 1853228561Snp 1854228561Snp/* 1855228561Snp * Retrieve various parameters that are of interest to the driver. The device 1856228561Snp * has been initialized by the firmware at this point. 1857228561Snp */ 1858228561Snpstatic int 1859228561Snpget_params__post_init(struct adapter *sc) 1860228561Snp{ 1861228561Snp int rc; 1862228561Snp uint32_t param[7], val[7]; 1863228561Snp struct fw_caps_config_cmd caps; 1864228561Snp 1865228561Snp param[0] = FW_PARAM_PFVF(IQFLINT_START); 1866228561Snp param[1] = FW_PARAM_PFVF(EQ_START); 1867228561Snp param[2] = FW_PARAM_PFVF(FILTER_START); 1868228561Snp param[3] = FW_PARAM_PFVF(FILTER_END); 1869228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 4, param, val); 1870228561Snp if (rc != 0) { 1871228561Snp device_printf(sc->dev, 1872228561Snp "failed to query parameters (post_init): %d.\n", rc); 1873228561Snp return (rc); 1874228561Snp } 1875228561Snp 1876228561Snp sc->sge.iq_start = val[0]; 1877228561Snp sc->sge.eq_start = val[1]; 1878228561Snp sc->tids.ftid_base = val[2]; 1879228561Snp sc->tids.nftids = val[3] - val[2] + 1; 1880228561Snp 1881228561Snp /* get capabilites */ 1882228561Snp bzero(&caps, sizeof(caps)); 1883228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1884228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1885228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 1886228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 1887228561Snp if (rc != 0) { 1888228561Snp device_printf(sc->dev, 1889228561Snp "failed to get card capabilities: %d.\n", rc); 1890228561Snp return (rc); 1891228561Snp } 1892228561Snp 1893228561Snp if (caps.toecaps) { 1894218792Snp /* query offload-related parameters */ 1895228561Snp param[0] = FW_PARAM_DEV(NTID); 1896228561Snp param[1] = FW_PARAM_PFVF(SERVER_START); 1897228561Snp param[2] = FW_PARAM_PFVF(SERVER_END); 1898228561Snp param[3] = FW_PARAM_PFVF(TDDP_START); 1899228561Snp param[4] = FW_PARAM_PFVF(TDDP_END); 1900228561Snp param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 1901228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 1902218792Snp if (rc != 0) { 1903218792Snp device_printf(sc->dev, 1904218792Snp "failed to query TOE parameters: %d.\n", rc); 1905228561Snp return (rc); 1906218792Snp } 1907218792Snp sc->tids.ntids = val[0]; 1908218792Snp sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS); 1909218792Snp sc->tids.stid_base = val[1]; 1910218792Snp sc->tids.nstids = val[2] - val[1] + 1; 1911218792Snp sc->vres.ddp.start = val[3]; 1912218792Snp sc->vres.ddp.size = val[4] - val[3] + 1; 1913218792Snp sc->params.ofldq_wr_cred = val[5]; 1914218792Snp sc->params.offload = 1; 1915218792Snp } 1916228561Snp if (caps.rdmacaps) { 1917228561Snp param[0] = FW_PARAM_PFVF(STAG_START); 1918228561Snp param[1] = FW_PARAM_PFVF(STAG_END); 1919228561Snp param[2] = FW_PARAM_PFVF(RQ_START); 1920228561Snp param[3] = FW_PARAM_PFVF(RQ_END); 1921228561Snp param[4] = FW_PARAM_PFVF(PBL_START); 1922228561Snp param[5] = FW_PARAM_PFVF(PBL_END); 1923228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 1924218792Snp if (rc != 0) { 1925218792Snp device_printf(sc->dev, 1926228561Snp "failed to query RDMA parameters(1): %d.\n", rc); 1927228561Snp return (rc); 1928218792Snp } 1929218792Snp sc->vres.stag.start = val[0]; 1930218792Snp sc->vres.stag.size = val[1] - val[0] + 1; 1931218792Snp sc->vres.rq.start = val[2]; 1932218792Snp sc->vres.rq.size = val[3] - val[2] + 1; 1933218792Snp sc->vres.pbl.start = val[4]; 1934218792Snp sc->vres.pbl.size = val[5] - val[4] + 1; 1935228561Snp 1936228561Snp param[0] = FW_PARAM_PFVF(SQRQ_START); 1937228561Snp param[1] = FW_PARAM_PFVF(SQRQ_END); 1938228561Snp param[2] = FW_PARAM_PFVF(CQ_START); 1939228561Snp param[3] = FW_PARAM_PFVF(CQ_END); 1940228561Snp param[4] = FW_PARAM_PFVF(OCQ_START); 1941228561Snp param[5] = FW_PARAM_PFVF(OCQ_END); 1942228561Snp rc = -t4_query_params(sc, 0, 0, 0, 6, param, val); 1943228561Snp if (rc != 0) { 1944228561Snp device_printf(sc->dev, 1945228561Snp "failed to query RDMA parameters(2): %d.\n", rc); 1946228561Snp return (rc); 1947228561Snp } 1948228561Snp sc->vres.qp.start = val[0]; 1949228561Snp sc->vres.qp.size = val[1] - val[0] + 1; 1950228561Snp sc->vres.cq.start = val[2]; 1951228561Snp sc->vres.cq.size = val[3] - val[2] + 1; 1952228561Snp sc->vres.ocq.start = val[4]; 1953228561Snp sc->vres.ocq.size = val[5] - val[4] + 1; 1954218792Snp } 1955228561Snp if (caps.iscsicaps) { 1956228561Snp param[0] = FW_PARAM_PFVF(ISCSI_START); 1957228561Snp param[1] = FW_PARAM_PFVF(ISCSI_END); 1958228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 1959218792Snp if (rc != 0) { 1960218792Snp device_printf(sc->dev, 1961218792Snp "failed to query iSCSI parameters: %d.\n", rc); 1962228561Snp return (rc); 1963218792Snp } 1964218792Snp sc->vres.iscsi.start = val[0]; 1965218792Snp sc->vres.iscsi.size = val[1] - val[0] + 1; 1966218792Snp } 1967218792Snp 1968228561Snp /* These are finalized by FW initialization, load their values now */ 1969228561Snp val[0] = t4_read_reg(sc, A_TP_TIMER_RESOLUTION); 1970228561Snp sc->params.tp.tre = G_TIMERRESOLUTION(val[0]); 1971228561Snp sc->params.tp.dack_re = G_DELAYEDACKRESOLUTION(val[0]); 1972228561Snp t4_read_mtu_tbl(sc, sc->params.mtus, NULL); 1973228561Snp 1974218792Snp return (rc); 1975218792Snp} 1976218792Snp 1977228561Snp#undef FW_PARAM_PFVF 1978228561Snp#undef FW_PARAM_DEV 1979228561Snp 1980218792Snpstatic void 1981218792Snpt4_set_desc(struct adapter *sc) 1982218792Snp{ 1983218792Snp char buf[128]; 1984218792Snp struct adapter_params *p = &sc->params; 1985218792Snp 1986228561Snp snprintf(buf, sizeof(buf), "Chelsio %s %sNIC (rev %d), S/N:%s, E/C:%s", 1987228561Snp p->vpd.id, is_offload(sc) ? "R" : "", p->rev, p->vpd.sn, p->vpd.ec); 1988218792Snp 1989218792Snp device_set_desc_copy(sc->dev, buf); 1990218792Snp} 1991218792Snp 1992218792Snpstatic void 1993218792Snpbuild_medialist(struct port_info *pi) 1994218792Snp{ 1995218792Snp struct ifmedia *media = &pi->media; 1996218792Snp int data, m; 1997218792Snp 1998218792Snp PORT_LOCK(pi); 1999218792Snp 2000218792Snp ifmedia_removeall(media); 2001218792Snp 2002218792Snp m = IFM_ETHER | IFM_FDX; 2003218792Snp data = (pi->port_type << 8) | pi->mod_type; 2004218792Snp 2005218792Snp switch(pi->port_type) { 2006218792Snp case FW_PORT_TYPE_BT_XFI: 2007218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2008218792Snp break; 2009218792Snp 2010218792Snp case FW_PORT_TYPE_BT_XAUI: 2011218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2012218792Snp /* fall through */ 2013218792Snp 2014218792Snp case FW_PORT_TYPE_BT_SGMII: 2015218792Snp ifmedia_add(media, m | IFM_1000_T, data, NULL); 2016218792Snp ifmedia_add(media, m | IFM_100_TX, data, NULL); 2017218792Snp ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL); 2018218792Snp ifmedia_set(media, IFM_ETHER | IFM_AUTO); 2019218792Snp break; 2020218792Snp 2021218792Snp case FW_PORT_TYPE_CX4: 2022218792Snp ifmedia_add(media, m | IFM_10G_CX4, data, NULL); 2023218792Snp ifmedia_set(media, m | IFM_10G_CX4); 2024218792Snp break; 2025218792Snp 2026218792Snp case FW_PORT_TYPE_SFP: 2027218792Snp case FW_PORT_TYPE_FIBER_XFI: 2028218792Snp case FW_PORT_TYPE_FIBER_XAUI: 2029218792Snp switch (pi->mod_type) { 2030218792Snp 2031218792Snp case FW_PORT_MOD_TYPE_LR: 2032218792Snp ifmedia_add(media, m | IFM_10G_LR, data, NULL); 2033218792Snp ifmedia_set(media, m | IFM_10G_LR); 2034218792Snp break; 2035218792Snp 2036218792Snp case FW_PORT_MOD_TYPE_SR: 2037218792Snp ifmedia_add(media, m | IFM_10G_SR, data, NULL); 2038218792Snp ifmedia_set(media, m | IFM_10G_SR); 2039218792Snp break; 2040218792Snp 2041218792Snp case FW_PORT_MOD_TYPE_LRM: 2042218792Snp ifmedia_add(media, m | IFM_10G_LRM, data, NULL); 2043218792Snp ifmedia_set(media, m | IFM_10G_LRM); 2044218792Snp break; 2045218792Snp 2046218792Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2047218792Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2048218792Snp ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL); 2049218792Snp ifmedia_set(media, m | IFM_10G_TWINAX); 2050218792Snp break; 2051218792Snp 2052218792Snp case FW_PORT_MOD_TYPE_NONE: 2053218792Snp m &= ~IFM_FDX; 2054218792Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2055218792Snp ifmedia_set(media, m | IFM_NONE); 2056218792Snp break; 2057218792Snp 2058218792Snp case FW_PORT_MOD_TYPE_NA: 2059218792Snp case FW_PORT_MOD_TYPE_ER: 2060218792Snp default: 2061218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2062218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2063218792Snp break; 2064218792Snp } 2065218792Snp break; 2066218792Snp 2067218792Snp case FW_PORT_TYPE_KX4: 2068218792Snp case FW_PORT_TYPE_KX: 2069218792Snp case FW_PORT_TYPE_KR: 2070218792Snp default: 2071218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2072218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2073218792Snp break; 2074218792Snp } 2075218792Snp 2076218792Snp PORT_UNLOCK(pi); 2077218792Snp} 2078218792Snp 2079231172Snp#define FW_MAC_EXACT_CHUNK 7 2080231172Snp 2081218792Snp/* 2082218792Snp * Program the port's XGMAC based on parameters in ifnet. The caller also 2083218792Snp * indicates which parameters should be programmed (the rest are left alone). 2084218792Snp */ 2085218792Snpstatic int 2086218792Snpupdate_mac_settings(struct port_info *pi, int flags) 2087218792Snp{ 2088218792Snp int rc; 2089218792Snp struct ifnet *ifp = pi->ifp; 2090218792Snp struct adapter *sc = pi->adapter; 2091218792Snp int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1; 2092218792Snp 2093245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2094218792Snp KASSERT(flags, ("%s: not told what to update.", __func__)); 2095218792Snp 2096218792Snp if (flags & XGMAC_MTU) 2097218792Snp mtu = ifp->if_mtu; 2098218792Snp 2099218792Snp if (flags & XGMAC_PROMISC) 2100218792Snp promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0; 2101218792Snp 2102218792Snp if (flags & XGMAC_ALLMULTI) 2103218792Snp allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0; 2104218792Snp 2105218792Snp if (flags & XGMAC_VLANEX) 2106218792Snp vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0; 2107218792Snp 2108218792Snp rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, mtu, promisc, allmulti, 1, 2109218792Snp vlanex, false); 2110218792Snp if (rc) { 2111218792Snp if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, rc); 2112218792Snp return (rc); 2113218792Snp } 2114218792Snp 2115218792Snp if (flags & XGMAC_UCADDR) { 2116218792Snp uint8_t ucaddr[ETHER_ADDR_LEN]; 2117218792Snp 2118218792Snp bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr)); 2119218792Snp rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, 2120218792Snp ucaddr, true, true); 2121218792Snp if (rc < 0) { 2122218792Snp rc = -rc; 2123218792Snp if_printf(ifp, "change_mac failed: %d\n", rc); 2124218792Snp return (rc); 2125218792Snp } else { 2126218792Snp pi->xact_addr_filt = rc; 2127218792Snp rc = 0; 2128218792Snp } 2129218792Snp } 2130218792Snp 2131218792Snp if (flags & XGMAC_MCADDRS) { 2132231172Snp const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK]; 2133218792Snp int del = 1; 2134218792Snp uint64_t hash = 0; 2135218792Snp struct ifmultiaddr *ifma; 2136231172Snp int i = 0, j; 2137218792Snp 2138218792Snp if_maddr_rlock(ifp); 2139218792Snp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2140238054Snp if (ifma->ifma_addr->sa_family != AF_LINK) 2141218792Snp continue; 2142231172Snp mcaddr[i++] = 2143231172Snp LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 2144218792Snp 2145231172Snp if (i == FW_MAC_EXACT_CHUNK) { 2146231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2147231172Snp del, i, mcaddr, NULL, &hash, 0); 2148231172Snp if (rc < 0) { 2149231172Snp rc = -rc; 2150231172Snp for (j = 0; j < i; j++) { 2151231172Snp if_printf(ifp, 2152231172Snp "failed to add mc address" 2153231172Snp " %02x:%02x:%02x:" 2154231172Snp "%02x:%02x:%02x rc=%d\n", 2155231172Snp mcaddr[j][0], mcaddr[j][1], 2156231172Snp mcaddr[j][2], mcaddr[j][3], 2157231172Snp mcaddr[j][4], mcaddr[j][5], 2158231172Snp rc); 2159231172Snp } 2160231172Snp goto mcfail; 2161231172Snp } 2162231172Snp del = 0; 2163231172Snp i = 0; 2164231172Snp } 2165231172Snp } 2166231172Snp if (i > 0) { 2167231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2168231172Snp del, i, mcaddr, NULL, &hash, 0); 2169218792Snp if (rc < 0) { 2170218792Snp rc = -rc; 2171231172Snp for (j = 0; j < i; j++) { 2172231172Snp if_printf(ifp, 2173231172Snp "failed to add mc address" 2174231172Snp " %02x:%02x:%02x:" 2175231172Snp "%02x:%02x:%02x rc=%d\n", 2176231172Snp mcaddr[j][0], mcaddr[j][1], 2177231172Snp mcaddr[j][2], mcaddr[j][3], 2178231172Snp mcaddr[j][4], mcaddr[j][5], 2179231172Snp rc); 2180231172Snp } 2181218792Snp goto mcfail; 2182218792Snp } 2183218792Snp } 2184218792Snp 2185218792Snp rc = -t4_set_addr_hash(sc, sc->mbox, pi->viid, 0, hash, 0); 2186218792Snp if (rc != 0) 2187218792Snp if_printf(ifp, "failed to set mc address hash: %d", rc); 2188218792Snpmcfail: 2189218792Snp if_maddr_runlock(ifp); 2190218792Snp } 2191218792Snp 2192218792Snp return (rc); 2193218792Snp} 2194218792Snp 2195245274Snpint 2196245274Snpbegin_synchronized_op(struct adapter *sc, struct port_info *pi, int flags, 2197245274Snp char *wmesg) 2198218792Snp{ 2199245274Snp int rc, pri; 2200218792Snp 2201245274Snp#ifdef WITNESS 2202245274Snp /* the caller thinks it's ok to sleep, but is it really? */ 2203245274Snp if (flags & SLEEP_OK) 2204245274Snp pause("t4slptst", 1); 2205245274Snp#endif 2206218792Snp 2207245274Snp if (INTR_OK) 2208245274Snp pri = PCATCH; 2209245274Snp else 2210245274Snp pri = 0; 2211245274Snp 2212245274Snp ADAPTER_LOCK(sc); 2213245274Snp for (;;) { 2214245274Snp 2215245274Snp if (pi && IS_DOOMED(pi)) { 2216245274Snp rc = ENXIO; 2217245274Snp goto done; 2218245274Snp } 2219245274Snp 2220245274Snp if (!IS_BUSY(sc)) { 2221245274Snp rc = 0; 2222245274Snp break; 2223245274Snp } 2224245274Snp 2225245274Snp if (!(flags & SLEEP_OK)) { 2226245274Snp rc = EBUSY; 2227245274Snp goto done; 2228245274Snp } 2229245274Snp 2230245274Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, pri, wmesg, 0)) { 2231218792Snp rc = EINTR; 2232218792Snp goto done; 2233218792Snp } 2234218792Snp } 2235245274Snp 2236218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 2237218792Snp SET_BUSY(sc); 2238245274Snp#ifdef INVARIANTS 2239245274Snp sc->last_op = wmesg; 2240245274Snp sc->last_op_thr = curthread; 2241245274Snp#endif 2242218792Snp 2243245274Snpdone: 2244245274Snp if (!(flags & HOLD_LOCK) || rc) 2245245274Snp ADAPTER_UNLOCK(sc); 2246218792Snp 2247245274Snp return (rc); 2248245274Snp} 2249245274Snp 2250245274Snpvoid 2251245274Snpend_synchronized_op(struct adapter *sc, int flags) 2252245274Snp{ 2253245274Snp 2254245274Snp if (flags & LOCK_HELD) 2255245274Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 2256245274Snp else 2257245274Snp ADAPTER_LOCK(sc); 2258245274Snp 2259218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 2260218792Snp CLR_BUSY(sc); 2261245274Snp wakeup(&sc->flags); 2262218792Snp ADAPTER_UNLOCK(sc); 2263218792Snp} 2264218792Snp 2265218792Snpstatic int 2266218792Snpcxgbe_init_synchronized(struct port_info *pi) 2267218792Snp{ 2268218792Snp struct adapter *sc = pi->adapter; 2269218792Snp struct ifnet *ifp = pi->ifp; 2270228561Snp int rc = 0; 2271218792Snp 2272245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2273218792Snp 2274218792Snp if (isset(&sc->open_device_map, pi->port_id)) { 2275218792Snp KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, 2276218792Snp ("mismatch between open_device_map and if_drv_flags")); 2277218792Snp return (0); /* already running */ 2278218792Snp } 2279218792Snp 2280228561Snp if (!(sc->flags & FULL_INIT_DONE) && 2281228561Snp ((rc = adapter_full_init(sc)) != 0)) 2282218792Snp return (rc); /* error message displayed already */ 2283218792Snp 2284228561Snp if (!(pi->flags & PORT_INIT_DONE) && 2285228561Snp ((rc = port_full_init(pi)) != 0)) 2286228561Snp return (rc); /* error message displayed already */ 2287218792Snp 2288218792Snp rc = update_mac_settings(pi, XGMAC_ALL); 2289218792Snp if (rc) 2290218792Snp goto done; /* error message displayed already */ 2291218792Snp 2292218792Snp rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg); 2293218792Snp if (rc != 0) { 2294218792Snp if_printf(ifp, "start_link failed: %d\n", rc); 2295218792Snp goto done; 2296218792Snp } 2297218792Snp 2298218792Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true); 2299218792Snp if (rc != 0) { 2300218792Snp if_printf(ifp, "enable_vi failed: %d\n", rc); 2301218792Snp goto done; 2302218792Snp } 2303218792Snp 2304218792Snp /* all ok */ 2305218792Snp setbit(&sc->open_device_map, pi->port_id); 2306245274Snp PORT_LOCK(pi); 2307218792Snp ifp->if_drv_flags |= IFF_DRV_RUNNING; 2308245274Snp PORT_UNLOCK(pi); 2309218792Snp 2310218792Snp callout_reset(&pi->tick, hz, cxgbe_tick, pi); 2311218792Snpdone: 2312218792Snp if (rc != 0) 2313218792Snp cxgbe_uninit_synchronized(pi); 2314218792Snp 2315218792Snp return (rc); 2316218792Snp} 2317218792Snp 2318218792Snp/* 2319218792Snp * Idempotent. 2320218792Snp */ 2321218792Snpstatic int 2322218792Snpcxgbe_uninit_synchronized(struct port_info *pi) 2323218792Snp{ 2324218792Snp struct adapter *sc = pi->adapter; 2325218792Snp struct ifnet *ifp = pi->ifp; 2326218792Snp int rc; 2327218792Snp 2328245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2329218792Snp 2330218792Snp /* 2331228561Snp * Disable the VI so that all its data in either direction is discarded 2332228561Snp * by the MPS. Leave everything else (the queues, interrupts, and 1Hz 2333228561Snp * tick) intact as the TP can deliver negative advice or data that it's 2334228561Snp * holding in its RAM (for an offloaded connection) even after the VI is 2335228561Snp * disabled. 2336218792Snp */ 2337228561Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false); 2338228561Snp if (rc) { 2339228561Snp if_printf(ifp, "disable_vi failed: %d\n", rc); 2340228561Snp return (rc); 2341228561Snp } 2342228561Snp 2343218792Snp clrbit(&sc->open_device_map, pi->port_id); 2344245274Snp PORT_LOCK(pi); 2345228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2346245274Snp PORT_UNLOCK(pi); 2347218792Snp 2348218792Snp pi->link_cfg.link_ok = 0; 2349218792Snp pi->link_cfg.speed = 0; 2350218792Snp t4_os_link_changed(sc, pi->port_id, 0); 2351218792Snp 2352218792Snp return (0); 2353218792Snp} 2354218792Snp 2355240453Snp/* 2356240453Snp * It is ok for this function to fail midway and return right away. t4_detach 2357240453Snp * will walk the entire sc->irq list and clean up whatever is valid. 2358240453Snp */ 2359218792Snpstatic int 2360240453Snpsetup_intr_handlers(struct adapter *sc) 2361218792Snp{ 2362240453Snp int rc, rid, p, q; 2363222510Snp char s[8]; 2364222510Snp struct irq *irq; 2365228561Snp struct port_info *pi; 2366228561Snp struct sge_rxq *rxq; 2367237263Snp#ifdef TCP_OFFLOAD 2368228561Snp struct sge_ofld_rxq *ofld_rxq; 2369228561Snp#endif 2370218792Snp 2371218792Snp /* 2372218792Snp * Setup interrupts. 2373218792Snp */ 2374222510Snp irq = &sc->irq[0]; 2375222510Snp rid = sc->intr_type == INTR_INTX ? 0 : 1; 2376218792Snp if (sc->intr_count == 1) { 2377228561Snp KASSERT(!(sc->flags & INTR_DIRECT), 2378228561Snp ("%s: single interrupt && INTR_DIRECT?", __func__)); 2379222510Snp 2380240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_all, sc, "all"); 2381240453Snp if (rc != 0) 2382240453Snp return (rc); 2383218792Snp } else { 2384228561Snp /* Multiple interrupts. */ 2385228561Snp KASSERT(sc->intr_count >= T4_EXTRA_INTR + sc->params.nports, 2386228561Snp ("%s: too few intr.", __func__)); 2387228561Snp 2388228561Snp /* The first one is always error intr */ 2389240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_err, sc, "err"); 2390240453Snp if (rc != 0) 2391240453Snp return (rc); 2392222510Snp irq++; 2393222510Snp rid++; 2394218792Snp 2395228561Snp /* The second one is always the firmware event queue */ 2396240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr_evt, &sc->sge.fwq, 2397240453Snp "evt"); 2398240453Snp if (rc != 0) 2399240453Snp return (rc); 2400228561Snp irq++; 2401228561Snp rid++; 2402222510Snp 2403228561Snp /* 2404228561Snp * Note that if INTR_DIRECT is not set then either the NIC rx 2405228561Snp * queues or (exclusive or) the TOE rx queueus will be taking 2406228561Snp * direct interrupts. 2407228561Snp * 2408228561Snp * There is no need to check for is_offload(sc) as nofldrxq 2409228561Snp * will be 0 if offload is disabled. 2410228561Snp */ 2411228561Snp for_each_port(sc, p) { 2412228561Snp pi = sc->port[p]; 2413222510Snp 2414237263Snp#ifdef TCP_OFFLOAD 2415228561Snp /* 2416228561Snp * Skip over the NIC queues if they aren't taking direct 2417228561Snp * interrupts. 2418228561Snp */ 2419228561Snp if (!(sc->flags & INTR_DIRECT) && 2420228561Snp pi->nofldrxq > pi->nrxq) 2421228561Snp goto ofld_queues; 2422228561Snp#endif 2423228561Snp rxq = &sc->sge.rxq[pi->first_rxq]; 2424228561Snp for (q = 0; q < pi->nrxq; q++, rxq++) { 2425228561Snp snprintf(s, sizeof(s), "%d.%d", p, q); 2426240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, rxq, 2427240453Snp s); 2428240453Snp if (rc != 0) 2429240453Snp return (rc); 2430222510Snp irq++; 2431222510Snp rid++; 2432218792Snp } 2433218792Snp 2434237263Snp#ifdef TCP_OFFLOAD 2435228561Snp /* 2436228561Snp * Skip over the offload queues if they aren't taking 2437228561Snp * direct interrupts. 2438228561Snp */ 2439228561Snp if (!(sc->flags & INTR_DIRECT)) 2440228561Snp continue; 2441228561Snpofld_queues: 2442228561Snp ofld_rxq = &sc->sge.ofld_rxq[pi->first_ofld_rxq]; 2443228561Snp for (q = 0; q < pi->nofldrxq; q++, ofld_rxq++) { 2444228561Snp snprintf(s, sizeof(s), "%d,%d", p, q); 2445240453Snp rc = t4_alloc_irq(sc, irq, rid, t4_intr, 2446240453Snp ofld_rxq, s); 2447240453Snp if (rc != 0) 2448240453Snp return (rc); 2449228561Snp irq++; 2450228561Snp rid++; 2451218792Snp } 2452228561Snp#endif 2453218792Snp } 2454218792Snp } 2455218792Snp 2456240453Snp return (0); 2457240453Snp} 2458240453Snp 2459240453Snpstatic int 2460240453Snpadapter_full_init(struct adapter *sc) 2461240453Snp{ 2462240453Snp int rc, i; 2463240453Snp 2464240453Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2465240453Snp KASSERT((sc->flags & FULL_INIT_DONE) == 0, 2466240453Snp ("%s: FULL_INIT_DONE already", __func__)); 2467240453Snp 2468240453Snp /* 2469240453Snp * queues that belong to the adapter (not any particular port). 2470240453Snp */ 2471240453Snp rc = t4_setup_adapter_queues(sc); 2472240453Snp if (rc != 0) 2473240453Snp goto done; 2474240453Snp 2475240453Snp for (i = 0; i < nitems(sc->tq); i++) { 2476240453Snp sc->tq[i] = taskqueue_create("t4 taskq", M_NOWAIT, 2477240453Snp taskqueue_thread_enqueue, &sc->tq[i]); 2478240453Snp if (sc->tq[i] == NULL) { 2479240453Snp device_printf(sc->dev, 2480240453Snp "failed to allocate task queue %d\n", i); 2481240453Snp rc = ENOMEM; 2482240453Snp goto done; 2483240453Snp } 2484240453Snp taskqueue_start_threads(&sc->tq[i], 1, PI_NET, "%s tq%d", 2485240453Snp device_get_nameunit(sc->dev), i); 2486240453Snp } 2487240453Snp 2488218792Snp t4_intr_enable(sc); 2489218792Snp sc->flags |= FULL_INIT_DONE; 2490218792Snpdone: 2491218792Snp if (rc != 0) 2492228561Snp adapter_full_uninit(sc); 2493218792Snp 2494218792Snp return (rc); 2495218792Snp} 2496218792Snp 2497218792Snpstatic int 2498228561Snpadapter_full_uninit(struct adapter *sc) 2499218792Snp{ 2500218792Snp int i; 2501218792Snp 2502218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2503218792Snp 2504220873Snp t4_teardown_adapter_queues(sc); 2505218792Snp 2506240452Snp for (i = 0; i < nitems(sc->tq) && sc->tq[i]; i++) { 2507228561Snp taskqueue_free(sc->tq[i]); 2508228561Snp sc->tq[i] = NULL; 2509228561Snp } 2510228561Snp 2511218792Snp sc->flags &= ~FULL_INIT_DONE; 2512218792Snp 2513218792Snp return (0); 2514218792Snp} 2515218792Snp 2516218792Snpstatic int 2517228561Snpport_full_init(struct port_info *pi) 2518228561Snp{ 2519228561Snp struct adapter *sc = pi->adapter; 2520228561Snp struct ifnet *ifp = pi->ifp; 2521228561Snp uint16_t *rss; 2522228561Snp struct sge_rxq *rxq; 2523228561Snp int rc, i; 2524228561Snp 2525245274Snp ASSERT_SYNCHRONIZED_OP(sc); 2526228561Snp KASSERT((pi->flags & PORT_INIT_DONE) == 0, 2527228561Snp ("%s: PORT_INIT_DONE already", __func__)); 2528228561Snp 2529228561Snp sysctl_ctx_init(&pi->ctx); 2530228561Snp pi->flags |= PORT_SYSCTL_CTX; 2531228561Snp 2532228561Snp /* 2533228561Snp * Allocate tx/rx/fl queues for this port. 2534228561Snp */ 2535228561Snp rc = t4_setup_port_queues(pi); 2536228561Snp if (rc != 0) 2537228561Snp goto done; /* error message displayed already */ 2538228561Snp 2539228561Snp /* 2540228561Snp * Setup RSS for this port. 2541228561Snp */ 2542228561Snp rss = malloc(pi->nrxq * sizeof (*rss), M_CXGBE, 2543228561Snp M_ZERO | M_WAITOK); 2544228561Snp for_each_rxq(pi, i, rxq) { 2545228561Snp rss[i] = rxq->iq.abs_id; 2546228561Snp } 2547228561Snp rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, 2548228561Snp pi->rss_size, rss, pi->nrxq); 2549228561Snp free(rss, M_CXGBE); 2550228561Snp if (rc != 0) { 2551228561Snp if_printf(ifp, "rss_config failed: %d\n", rc); 2552228561Snp goto done; 2553228561Snp } 2554228561Snp 2555228561Snp pi->flags |= PORT_INIT_DONE; 2556228561Snpdone: 2557228561Snp if (rc != 0) 2558228561Snp port_full_uninit(pi); 2559228561Snp 2560228561Snp return (rc); 2561228561Snp} 2562228561Snp 2563228561Snp/* 2564228561Snp * Idempotent. 2565228561Snp */ 2566228561Snpstatic int 2567228561Snpport_full_uninit(struct port_info *pi) 2568228561Snp{ 2569228561Snp struct adapter *sc = pi->adapter; 2570228561Snp int i; 2571228561Snp struct sge_rxq *rxq; 2572228561Snp struct sge_txq *txq; 2573237263Snp#ifdef TCP_OFFLOAD 2574228561Snp struct sge_ofld_rxq *ofld_rxq; 2575228561Snp struct sge_wrq *ofld_txq; 2576228561Snp#endif 2577228561Snp 2578228561Snp if (pi->flags & PORT_INIT_DONE) { 2579228561Snp 2580228561Snp /* Need to quiesce queues. XXX: ctrl queues? */ 2581228561Snp 2582228561Snp for_each_txq(pi, i, txq) { 2583228561Snp quiesce_eq(sc, &txq->eq); 2584228561Snp } 2585228561Snp 2586237263Snp#ifdef TCP_OFFLOAD 2587228561Snp for_each_ofld_txq(pi, i, ofld_txq) { 2588228561Snp quiesce_eq(sc, &ofld_txq->eq); 2589228561Snp } 2590228561Snp#endif 2591228561Snp 2592228561Snp for_each_rxq(pi, i, rxq) { 2593228561Snp quiesce_iq(sc, &rxq->iq); 2594228561Snp quiesce_fl(sc, &rxq->fl); 2595228561Snp } 2596228561Snp 2597237263Snp#ifdef TCP_OFFLOAD 2598228561Snp for_each_ofld_rxq(pi, i, ofld_rxq) { 2599228561Snp quiesce_iq(sc, &ofld_rxq->iq); 2600228561Snp quiesce_fl(sc, &ofld_rxq->fl); 2601228561Snp } 2602228561Snp#endif 2603228561Snp } 2604228561Snp 2605228561Snp t4_teardown_port_queues(pi); 2606228561Snp pi->flags &= ~PORT_INIT_DONE; 2607228561Snp 2608228561Snp return (0); 2609228561Snp} 2610228561Snp 2611228561Snpstatic void 2612228561Snpquiesce_eq(struct adapter *sc, struct sge_eq *eq) 2613228561Snp{ 2614228561Snp EQ_LOCK(eq); 2615228561Snp eq->flags |= EQ_DOOMED; 2616228561Snp 2617228561Snp /* 2618228561Snp * Wait for the response to a credit flush if one's 2619228561Snp * pending. 2620228561Snp */ 2621228561Snp while (eq->flags & EQ_CRFLUSHED) 2622228561Snp mtx_sleep(eq, &eq->eq_lock, 0, "crflush", 0); 2623228561Snp EQ_UNLOCK(eq); 2624228561Snp 2625228561Snp callout_drain(&eq->tx_callout); /* XXX: iffy */ 2626228561Snp pause("callout", 10); /* Still iffy */ 2627228561Snp 2628228561Snp taskqueue_drain(sc->tq[eq->tx_chan], &eq->tx_task); 2629228561Snp} 2630228561Snp 2631228561Snpstatic void 2632228561Snpquiesce_iq(struct adapter *sc, struct sge_iq *iq) 2633228561Snp{ 2634228561Snp (void) sc; /* unused */ 2635228561Snp 2636228561Snp /* Synchronize with the interrupt handler */ 2637228561Snp while (!atomic_cmpset_int(&iq->state, IQS_IDLE, IQS_DISABLED)) 2638228561Snp pause("iqfree", 1); 2639228561Snp} 2640228561Snp 2641228561Snpstatic void 2642228561Snpquiesce_fl(struct adapter *sc, struct sge_fl *fl) 2643228561Snp{ 2644228561Snp mtx_lock(&sc->sfl_lock); 2645228561Snp FL_LOCK(fl); 2646228561Snp fl->flags |= FL_DOOMED; 2647228561Snp FL_UNLOCK(fl); 2648228561Snp mtx_unlock(&sc->sfl_lock); 2649228561Snp 2650228561Snp callout_drain(&sc->sfl_callout); 2651228561Snp KASSERT((fl->flags & FL_STARVING) == 0, 2652228561Snp ("%s: still starving", __func__)); 2653228561Snp} 2654228561Snp 2655228561Snpstatic int 2656218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid, 2657228561Snp driver_intr_t *handler, void *arg, char *name) 2658218792Snp{ 2659218792Snp int rc; 2660218792Snp 2661218792Snp irq->rid = rid; 2662218792Snp irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid, 2663218792Snp RF_SHAREABLE | RF_ACTIVE); 2664218792Snp if (irq->res == NULL) { 2665218792Snp device_printf(sc->dev, 2666218792Snp "failed to allocate IRQ for rid %d, name %s.\n", rid, name); 2667218792Snp return (ENOMEM); 2668218792Snp } 2669218792Snp 2670218792Snp rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET, 2671218792Snp NULL, handler, arg, &irq->tag); 2672218792Snp if (rc != 0) { 2673218792Snp device_printf(sc->dev, 2674218792Snp "failed to setup interrupt for rid %d, name %s: %d\n", 2675218792Snp rid, name, rc); 2676218792Snp } else if (name) 2677218792Snp bus_describe_intr(sc->dev, irq->res, irq->tag, name); 2678218792Snp 2679218792Snp return (rc); 2680218792Snp} 2681218792Snp 2682218792Snpstatic int 2683218792Snpt4_free_irq(struct adapter *sc, struct irq *irq) 2684218792Snp{ 2685218792Snp if (irq->tag) 2686218792Snp bus_teardown_intr(sc->dev, irq->res, irq->tag); 2687218792Snp if (irq->res) 2688218792Snp bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res); 2689218792Snp 2690218792Snp bzero(irq, sizeof(*irq)); 2691218792Snp 2692218792Snp return (0); 2693218792Snp} 2694218792Snp 2695218792Snpstatic void 2696218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start, 2697218792Snp unsigned int end) 2698218792Snp{ 2699218792Snp uint32_t *p = (uint32_t *)(buf + start); 2700218792Snp 2701218792Snp for ( ; start <= end; start += sizeof(uint32_t)) 2702218792Snp *p++ = t4_read_reg(sc, start); 2703218792Snp} 2704218792Snp 2705218792Snpstatic void 2706218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf) 2707218792Snp{ 2708218792Snp int i; 2709218792Snp static const unsigned int reg_ranges[] = { 2710218792Snp 0x1008, 0x1108, 2711218792Snp 0x1180, 0x11b4, 2712218792Snp 0x11fc, 0x123c, 2713218792Snp 0x1300, 0x173c, 2714218792Snp 0x1800, 0x18fc, 2715218792Snp 0x3000, 0x30d8, 2716218792Snp 0x30e0, 0x5924, 2717218792Snp 0x5960, 0x59d4, 2718218792Snp 0x5a00, 0x5af8, 2719218792Snp 0x6000, 0x6098, 2720218792Snp 0x6100, 0x6150, 2721218792Snp 0x6200, 0x6208, 2722218792Snp 0x6240, 0x6248, 2723218792Snp 0x6280, 0x6338, 2724218792Snp 0x6370, 0x638c, 2725218792Snp 0x6400, 0x643c, 2726218792Snp 0x6500, 0x6524, 2727218792Snp 0x6a00, 0x6a38, 2728218792Snp 0x6a60, 0x6a78, 2729218792Snp 0x6b00, 0x6b84, 2730218792Snp 0x6bf0, 0x6c84, 2731218792Snp 0x6cf0, 0x6d84, 2732218792Snp 0x6df0, 0x6e84, 2733218792Snp 0x6ef0, 0x6f84, 2734218792Snp 0x6ff0, 0x7084, 2735218792Snp 0x70f0, 0x7184, 2736218792Snp 0x71f0, 0x7284, 2737218792Snp 0x72f0, 0x7384, 2738218792Snp 0x73f0, 0x7450, 2739218792Snp 0x7500, 0x7530, 2740218792Snp 0x7600, 0x761c, 2741218792Snp 0x7680, 0x76cc, 2742218792Snp 0x7700, 0x7798, 2743218792Snp 0x77c0, 0x77fc, 2744218792Snp 0x7900, 0x79fc, 2745218792Snp 0x7b00, 0x7c38, 2746218792Snp 0x7d00, 0x7efc, 2747218792Snp 0x8dc0, 0x8e1c, 2748218792Snp 0x8e30, 0x8e78, 2749218792Snp 0x8ea0, 0x8f6c, 2750218792Snp 0x8fc0, 0x9074, 2751218792Snp 0x90fc, 0x90fc, 2752218792Snp 0x9400, 0x9458, 2753218792Snp 0x9600, 0x96bc, 2754218792Snp 0x9800, 0x9808, 2755218792Snp 0x9820, 0x983c, 2756218792Snp 0x9850, 0x9864, 2757218792Snp 0x9c00, 0x9c6c, 2758218792Snp 0x9c80, 0x9cec, 2759218792Snp 0x9d00, 0x9d6c, 2760218792Snp 0x9d80, 0x9dec, 2761218792Snp 0x9e00, 0x9e6c, 2762218792Snp 0x9e80, 0x9eec, 2763218792Snp 0x9f00, 0x9f6c, 2764218792Snp 0x9f80, 0x9fec, 2765218792Snp 0xd004, 0xd03c, 2766218792Snp 0xdfc0, 0xdfe0, 2767218792Snp 0xe000, 0xea7c, 2768218792Snp 0xf000, 0x11190, 2769237439Snp 0x19040, 0x1906c, 2770237439Snp 0x19078, 0x19080, 2771237439Snp 0x1908c, 0x19124, 2772218792Snp 0x19150, 0x191b0, 2773218792Snp 0x191d0, 0x191e8, 2774218792Snp 0x19238, 0x1924c, 2775218792Snp 0x193f8, 0x19474, 2776218792Snp 0x19490, 0x194f8, 2777218792Snp 0x19800, 0x19f30, 2778218792Snp 0x1a000, 0x1a06c, 2779218792Snp 0x1a0b0, 0x1a120, 2780218792Snp 0x1a128, 0x1a138, 2781218792Snp 0x1a190, 0x1a1c4, 2782218792Snp 0x1a1fc, 0x1a1fc, 2783218792Snp 0x1e040, 0x1e04c, 2784237439Snp 0x1e284, 0x1e28c, 2785218792Snp 0x1e2c0, 0x1e2c0, 2786218792Snp 0x1e2e0, 0x1e2e0, 2787218792Snp 0x1e300, 0x1e384, 2788218792Snp 0x1e3c0, 0x1e3c8, 2789218792Snp 0x1e440, 0x1e44c, 2790237439Snp 0x1e684, 0x1e68c, 2791218792Snp 0x1e6c0, 0x1e6c0, 2792218792Snp 0x1e6e0, 0x1e6e0, 2793218792Snp 0x1e700, 0x1e784, 2794218792Snp 0x1e7c0, 0x1e7c8, 2795218792Snp 0x1e840, 0x1e84c, 2796237439Snp 0x1ea84, 0x1ea8c, 2797218792Snp 0x1eac0, 0x1eac0, 2798218792Snp 0x1eae0, 0x1eae0, 2799218792Snp 0x1eb00, 0x1eb84, 2800218792Snp 0x1ebc0, 0x1ebc8, 2801218792Snp 0x1ec40, 0x1ec4c, 2802237439Snp 0x1ee84, 0x1ee8c, 2803218792Snp 0x1eec0, 0x1eec0, 2804218792Snp 0x1eee0, 0x1eee0, 2805218792Snp 0x1ef00, 0x1ef84, 2806218792Snp 0x1efc0, 0x1efc8, 2807218792Snp 0x1f040, 0x1f04c, 2808237439Snp 0x1f284, 0x1f28c, 2809218792Snp 0x1f2c0, 0x1f2c0, 2810218792Snp 0x1f2e0, 0x1f2e0, 2811218792Snp 0x1f300, 0x1f384, 2812218792Snp 0x1f3c0, 0x1f3c8, 2813218792Snp 0x1f440, 0x1f44c, 2814237439Snp 0x1f684, 0x1f68c, 2815218792Snp 0x1f6c0, 0x1f6c0, 2816218792Snp 0x1f6e0, 0x1f6e0, 2817218792Snp 0x1f700, 0x1f784, 2818218792Snp 0x1f7c0, 0x1f7c8, 2819218792Snp 0x1f840, 0x1f84c, 2820237439Snp 0x1fa84, 0x1fa8c, 2821218792Snp 0x1fac0, 0x1fac0, 2822218792Snp 0x1fae0, 0x1fae0, 2823218792Snp 0x1fb00, 0x1fb84, 2824218792Snp 0x1fbc0, 0x1fbc8, 2825218792Snp 0x1fc40, 0x1fc4c, 2826237439Snp 0x1fe84, 0x1fe8c, 2827218792Snp 0x1fec0, 0x1fec0, 2828218792Snp 0x1fee0, 0x1fee0, 2829218792Snp 0x1ff00, 0x1ff84, 2830218792Snp 0x1ffc0, 0x1ffc8, 2831218792Snp 0x20000, 0x2002c, 2832218792Snp 0x20100, 0x2013c, 2833218792Snp 0x20190, 0x201c8, 2834218792Snp 0x20200, 0x20318, 2835218792Snp 0x20400, 0x20528, 2836218792Snp 0x20540, 0x20614, 2837218792Snp 0x21000, 0x21040, 2838218792Snp 0x2104c, 0x21060, 2839218792Snp 0x210c0, 0x210ec, 2840218792Snp 0x21200, 0x21268, 2841218792Snp 0x21270, 0x21284, 2842218792Snp 0x212fc, 0x21388, 2843218792Snp 0x21400, 0x21404, 2844218792Snp 0x21500, 0x21518, 2845218792Snp 0x2152c, 0x2153c, 2846218792Snp 0x21550, 0x21554, 2847218792Snp 0x21600, 0x21600, 2848218792Snp 0x21608, 0x21628, 2849218792Snp 0x21630, 0x2163c, 2850218792Snp 0x21700, 0x2171c, 2851218792Snp 0x21780, 0x2178c, 2852218792Snp 0x21800, 0x21c38, 2853218792Snp 0x21c80, 0x21d7c, 2854218792Snp 0x21e00, 0x21e04, 2855218792Snp 0x22000, 0x2202c, 2856218792Snp 0x22100, 0x2213c, 2857218792Snp 0x22190, 0x221c8, 2858218792Snp 0x22200, 0x22318, 2859218792Snp 0x22400, 0x22528, 2860218792Snp 0x22540, 0x22614, 2861218792Snp 0x23000, 0x23040, 2862218792Snp 0x2304c, 0x23060, 2863218792Snp 0x230c0, 0x230ec, 2864218792Snp 0x23200, 0x23268, 2865218792Snp 0x23270, 0x23284, 2866218792Snp 0x232fc, 0x23388, 2867218792Snp 0x23400, 0x23404, 2868218792Snp 0x23500, 0x23518, 2869218792Snp 0x2352c, 0x2353c, 2870218792Snp 0x23550, 0x23554, 2871218792Snp 0x23600, 0x23600, 2872218792Snp 0x23608, 0x23628, 2873218792Snp 0x23630, 0x2363c, 2874218792Snp 0x23700, 0x2371c, 2875218792Snp 0x23780, 0x2378c, 2876218792Snp 0x23800, 0x23c38, 2877218792Snp 0x23c80, 0x23d7c, 2878218792Snp 0x23e00, 0x23e04, 2879218792Snp 0x24000, 0x2402c, 2880218792Snp 0x24100, 0x2413c, 2881218792Snp 0x24190, 0x241c8, 2882218792Snp 0x24200, 0x24318, 2883218792Snp 0x24400, 0x24528, 2884218792Snp 0x24540, 0x24614, 2885218792Snp 0x25000, 0x25040, 2886218792Snp 0x2504c, 0x25060, 2887218792Snp 0x250c0, 0x250ec, 2888218792Snp 0x25200, 0x25268, 2889218792Snp 0x25270, 0x25284, 2890218792Snp 0x252fc, 0x25388, 2891218792Snp 0x25400, 0x25404, 2892218792Snp 0x25500, 0x25518, 2893218792Snp 0x2552c, 0x2553c, 2894218792Snp 0x25550, 0x25554, 2895218792Snp 0x25600, 0x25600, 2896218792Snp 0x25608, 0x25628, 2897218792Snp 0x25630, 0x2563c, 2898218792Snp 0x25700, 0x2571c, 2899218792Snp 0x25780, 0x2578c, 2900218792Snp 0x25800, 0x25c38, 2901218792Snp 0x25c80, 0x25d7c, 2902218792Snp 0x25e00, 0x25e04, 2903218792Snp 0x26000, 0x2602c, 2904218792Snp 0x26100, 0x2613c, 2905218792Snp 0x26190, 0x261c8, 2906218792Snp 0x26200, 0x26318, 2907218792Snp 0x26400, 0x26528, 2908218792Snp 0x26540, 0x26614, 2909218792Snp 0x27000, 0x27040, 2910218792Snp 0x2704c, 0x27060, 2911218792Snp 0x270c0, 0x270ec, 2912218792Snp 0x27200, 0x27268, 2913218792Snp 0x27270, 0x27284, 2914218792Snp 0x272fc, 0x27388, 2915218792Snp 0x27400, 0x27404, 2916218792Snp 0x27500, 0x27518, 2917218792Snp 0x2752c, 0x2753c, 2918218792Snp 0x27550, 0x27554, 2919218792Snp 0x27600, 0x27600, 2920218792Snp 0x27608, 0x27628, 2921218792Snp 0x27630, 0x2763c, 2922218792Snp 0x27700, 0x2771c, 2923218792Snp 0x27780, 0x2778c, 2924218792Snp 0x27800, 0x27c38, 2925218792Snp 0x27c80, 0x27d7c, 2926218792Snp 0x27e00, 0x27e04 2927218792Snp }; 2928218792Snp 2929218792Snp regs->version = 4 | (sc->params.rev << 10); 2930240452Snp for (i = 0; i < nitems(reg_ranges); i += 2) 2931218792Snp reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]); 2932218792Snp} 2933218792Snp 2934218792Snpstatic void 2935218792Snpcxgbe_tick(void *arg) 2936218792Snp{ 2937218792Snp struct port_info *pi = arg; 2938218792Snp struct ifnet *ifp = pi->ifp; 2939218792Snp struct sge_txq *txq; 2940218792Snp int i, drops; 2941218792Snp struct port_stats *s = &pi->stats; 2942218792Snp 2943218792Snp PORT_LOCK(pi); 2944218792Snp if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2945218792Snp PORT_UNLOCK(pi); 2946218792Snp return; /* without scheduling another callout */ 2947218792Snp } 2948218792Snp 2949218792Snp t4_get_port_stats(pi->adapter, pi->tx_chan, s); 2950218792Snp 2951228561Snp ifp->if_opackets = s->tx_frames - s->tx_pause; 2952228561Snp ifp->if_ipackets = s->rx_frames - s->rx_pause; 2953228561Snp ifp->if_obytes = s->tx_octets - s->tx_pause * 64; 2954228561Snp ifp->if_ibytes = s->rx_octets - s->rx_pause * 64; 2955228561Snp ifp->if_omcasts = s->tx_mcast_frames - s->tx_pause; 2956228561Snp ifp->if_imcasts = s->rx_mcast_frames - s->rx_pause; 2957218792Snp ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 + 2958239259Snp s->rx_ovflow3 + s->rx_trunc0 + s->rx_trunc1 + s->rx_trunc2 + 2959239259Snp s->rx_trunc3; 2960218792Snp 2961218792Snp drops = s->tx_drop; 2962218792Snp for_each_txq(pi, i, txq) 2963220873Snp drops += txq->br->br_drops; 2964218792Snp ifp->if_snd.ifq_drops = drops; 2965218792Snp 2966218792Snp ifp->if_oerrors = s->tx_error_frames; 2967218792Snp ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long + 2968218792Snp s->rx_fcs_err + s->rx_len_err; 2969218792Snp 2970218792Snp callout_schedule(&pi->tick, hz); 2971218792Snp PORT_UNLOCK(pi); 2972218792Snp} 2973218792Snp 2974237263Snpstatic void 2975237263Snpcxgbe_vlan_config(void *arg, struct ifnet *ifp, uint16_t vid) 2976237263Snp{ 2977237263Snp struct ifnet *vlan; 2978237263Snp 2979241494Snp if (arg != ifp || ifp->if_type != IFT_ETHER) 2980237263Snp return; 2981237263Snp 2982237263Snp vlan = VLAN_DEVAT(ifp, vid); 2983237263Snp VLAN_SETCOOKIE(vlan, ifp); 2984237263Snp} 2985237263Snp 2986218792Snpstatic int 2987228561Snpcpl_not_handled(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 2988228561Snp{ 2989237263Snp 2990228561Snp#ifdef INVARIANTS 2991237263Snp panic("%s: opcode 0x%02x on iq %p with payload %p", 2992228561Snp __func__, rss->opcode, iq, m); 2993228561Snp#else 2994239336Snp log(LOG_ERR, "%s: opcode 0x%02x on iq %p with payload %p\n", 2995228561Snp __func__, rss->opcode, iq, m); 2996228561Snp m_freem(m); 2997228561Snp#endif 2998228561Snp return (EDOOFUS); 2999228561Snp} 3000228561Snp 3001228561Snpint 3002228561Snpt4_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h) 3003228561Snp{ 3004228561Snp uintptr_t *loc, new; 3005228561Snp 3006240452Snp if (opcode >= nitems(sc->cpl_handler)) 3007228561Snp return (EINVAL); 3008228561Snp 3009228561Snp new = h ? (uintptr_t)h : (uintptr_t)cpl_not_handled; 3010228561Snp loc = (uintptr_t *) &sc->cpl_handler[opcode]; 3011228561Snp atomic_store_rel_ptr(loc, new); 3012228561Snp 3013228561Snp return (0); 3014228561Snp} 3015228561Snp 3016228561Snpstatic int 3017237263Snpan_not_handled(struct sge_iq *iq, const struct rsp_ctrl *ctrl) 3018237263Snp{ 3019237263Snp 3020237263Snp#ifdef INVARIANTS 3021237263Snp panic("%s: async notification on iq %p (ctrl %p)", __func__, iq, ctrl); 3022237263Snp#else 3023239336Snp log(LOG_ERR, "%s: async notification on iq %p (ctrl %p)\n", 3024237263Snp __func__, iq, ctrl); 3025237263Snp#endif 3026237263Snp return (EDOOFUS); 3027237263Snp} 3028237263Snp 3029237263Snpint 3030237263Snpt4_register_an_handler(struct adapter *sc, an_handler_t h) 3031237263Snp{ 3032237263Snp uintptr_t *loc, new; 3033237263Snp 3034237263Snp new = h ? (uintptr_t)h : (uintptr_t)an_not_handled; 3035237263Snp loc = (uintptr_t *) &sc->an_handler; 3036237263Snp atomic_store_rel_ptr(loc, new); 3037237263Snp 3038237263Snp return (0); 3039237263Snp} 3040237263Snp 3041237263Snpstatic int 3042239336Snpfw_msg_not_handled(struct adapter *sc, const __be64 *rpl) 3043239336Snp{ 3044241733Sed const struct cpl_fw6_msg *cpl = 3045241733Sed __containerof(rpl, struct cpl_fw6_msg, data[0]); 3046239336Snp 3047239336Snp#ifdef INVARIANTS 3048239336Snp panic("%s: fw_msg type %d", __func__, cpl->type); 3049239336Snp#else 3050239336Snp log(LOG_ERR, "%s: fw_msg type %d\n", __func__, cpl->type); 3051239336Snp#endif 3052239336Snp return (EDOOFUS); 3053239336Snp} 3054239336Snp 3055239336Snpint 3056239336Snpt4_register_fw_msg_handler(struct adapter *sc, int type, fw_msg_handler_t h) 3057239336Snp{ 3058239336Snp uintptr_t *loc, new; 3059239336Snp 3060240452Snp if (type >= nitems(sc->fw_msg_handler)) 3061239336Snp return (EINVAL); 3062239336Snp 3063239336Snp new = h ? (uintptr_t)h : (uintptr_t)fw_msg_not_handled; 3064239336Snp loc = (uintptr_t *) &sc->fw_msg_handler[type]; 3065239336Snp atomic_store_rel_ptr(loc, new); 3066239336Snp 3067239336Snp return (0); 3068239336Snp} 3069239336Snp 3070239336Snpstatic int 3071218792Snpt4_sysctls(struct adapter *sc) 3072218792Snp{ 3073218792Snp struct sysctl_ctx_list *ctx; 3074218792Snp struct sysctl_oid *oid; 3075228561Snp struct sysctl_oid_list *children, *c0; 3076228561Snp static char *caps[] = { 3077228561Snp "\20\1PPP\2QFC\3DCBX", /* caps[0] linkcaps */ 3078228561Snp "\20\1NIC\2VM\3IDS\4UM\5UM_ISGL", /* caps[1] niccaps */ 3079228561Snp "\20\1TOE", /* caps[2] toecaps */ 3080228561Snp "\20\1RDDP\2RDMAC", /* caps[3] rdmacaps */ 3081228561Snp "\20\1INITIATOR_PDU\2TARGET_PDU" /* caps[4] iscsicaps */ 3082228561Snp "\3INITIATOR_CNXOFLD\4TARGET_CNXOFLD" 3083228561Snp "\5INITIATOR_SSNOFLD\6TARGET_SSNOFLD", 3084228561Snp "\20\1INITIATOR\2TARGET\3CTRL_OFLD" /* caps[5] fcoecaps */ 3085228561Snp }; 3086218792Snp 3087218792Snp ctx = device_get_sysctl_ctx(sc->dev); 3088228561Snp 3089228561Snp /* 3090228561Snp * dev.t4nex.X. 3091228561Snp */ 3092218792Snp oid = device_get_sysctl_tree(sc->dev); 3093228561Snp c0 = children = SYSCTL_CHILDREN(oid); 3094218792Snp 3095218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, 3096218792Snp &sc->params.nports, 0, "# of ports"); 3097218792Snp 3098218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD, 3099218792Snp &sc->params.rev, 0, "chip hardware revision"); 3100218792Snp 3101218792Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 3102218792Snp CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 3103218792Snp 3104228561Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "cf", 3105228561Snp CTLFLAG_RD, &t4_cfg_file, 0, "configuration file"); 3106218792Snp 3107228561Snp SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cfcsum", CTLFLAG_RD, 3108228561Snp &sc->cfcsum, 0, "config file checksum"); 3109228561Snp 3110228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkcaps", 3111228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[0], sc->linkcaps, 3112228561Snp sysctl_bitfield, "A", "available link capabilities"); 3113228561Snp 3114228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "niccaps", 3115228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[1], sc->niccaps, 3116228561Snp sysctl_bitfield, "A", "available NIC capabilities"); 3117228561Snp 3118228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "toecaps", 3119228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[2], sc->toecaps, 3120228561Snp sysctl_bitfield, "A", "available TCP offload capabilities"); 3121228561Snp 3122228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdmacaps", 3123228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[3], sc->rdmacaps, 3124228561Snp sysctl_bitfield, "A", "available RDMA capabilities"); 3125228561Snp 3126228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "iscsicaps", 3127228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[4], sc->iscsicaps, 3128228561Snp sysctl_bitfield, "A", "available iSCSI capabilities"); 3129228561Snp 3130228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoecaps", 3131228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[5], sc->fcoecaps, 3132228561Snp sysctl_bitfield, "A", "available FCoE capabilities"); 3133228561Snp 3134218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, 3135218792Snp &sc->params.vpd.cclk, 0, "core clock frequency (in KHz)"); 3136218792Snp 3137219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers", 3138228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.timer_val, 3139228561Snp sizeof(sc->sge.timer_val), sysctl_int_array, "A", 3140228561Snp "interrupt holdoff timer values (us)"); 3141218792Snp 3142219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts", 3143228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.counter_val, 3144228561Snp sizeof(sc->sge.counter_val), sysctl_int_array, "A", 3145228561Snp "interrupt holdoff packet counter values"); 3146218792Snp 3147231115Snp#ifdef SBUF_DRAIN 3148228561Snp /* 3149228561Snp * dev.t4nex.X.misc. Marked CTLFLAG_SKIP to avoid information overload. 3150228561Snp */ 3151228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "misc", 3152228561Snp CTLFLAG_RD | CTLFLAG_SKIP, NULL, 3153228561Snp "logs and miscellaneous information"); 3154228561Snp children = SYSCTL_CHILDREN(oid); 3155228561Snp 3156228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cctrl", 3157228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3158228561Snp sysctl_cctrl, "A", "congestion control"); 3159228561Snp 3160228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats", 3161228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3162228561Snp sysctl_cpl_stats, "A", "CPL statistics"); 3163228561Snp 3164228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ddp_stats", 3165228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3166228561Snp sysctl_ddp_stats, "A", "DDP statistics"); 3167228561Snp 3168222551Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog", 3169222551Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3170228561Snp sysctl_devlog, "A", "firmware's device log"); 3171222551Snp 3172228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoe_stats", 3173228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3174228561Snp sysctl_fcoe_stats, "A", "FCoE statistics"); 3175228561Snp 3176228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hw_sched", 3177228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3178228561Snp sysctl_hw_sched, "A", "hardware scheduler "); 3179228561Snp 3180228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "l2t", 3181228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3182228561Snp sysctl_l2t, "A", "hardware L2 table"); 3183228561Snp 3184228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats", 3185228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3186228561Snp sysctl_lb_stats, "A", "loopback statistics"); 3187228561Snp 3188228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "meminfo", 3189228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3190228561Snp sysctl_meminfo, "A", "memory regions"); 3191228561Snp 3192228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "path_mtus", 3193228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3194228561Snp sysctl_path_mtus, "A", "path MTUs"); 3195228561Snp 3196228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pm_stats", 3197228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3198228561Snp sysctl_pm_stats, "A", "PM statistics"); 3199228561Snp 3200228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_stats", 3201228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3202228561Snp sysctl_rdma_stats, "A", "RDMA statistics"); 3203228561Snp 3204228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tcp_stats", 3205228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3206228561Snp sysctl_tcp_stats, "A", "TCP statistics"); 3207228561Snp 3208228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tids", 3209228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3210228561Snp sysctl_tids, "A", "TID information"); 3211228561Snp 3212228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_err_stats", 3213228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3214228561Snp sysctl_tp_err_stats, "A", "TP error statistics"); 3215228561Snp 3216228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_rate", 3217228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3218228561Snp sysctl_tx_rate, "A", "Tx rate"); 3219231115Snp#endif 3220228561Snp 3221237263Snp#ifdef TCP_OFFLOAD 3222228561Snp if (is_offload(sc)) { 3223228561Snp /* 3224228561Snp * dev.t4nex.X.toe. 3225228561Snp */ 3226228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "toe", CTLFLAG_RD, 3227228561Snp NULL, "TOE parameters"); 3228228561Snp children = SYSCTL_CHILDREN(oid); 3229228561Snp 3230228561Snp sc->tt.sndbuf = 256 * 1024; 3231228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "sndbuf", CTLFLAG_RW, 3232228561Snp &sc->tt.sndbuf, 0, "max hardware send buffer size"); 3233228561Snp 3234228561Snp sc->tt.ddp = 0; 3235228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp", CTLFLAG_RW, 3236228561Snp &sc->tt.ddp, 0, "DDP allowed"); 3237239341Snp 3238239341Snp sc->tt.indsz = G_INDICATESIZE(t4_read_reg(sc, A_TP_PARA_REG5)); 3239228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "indsz", CTLFLAG_RW, 3240228561Snp &sc->tt.indsz, 0, "DDP max indicate size allowed"); 3241239341Snp 3242239341Snp sc->tt.ddp_thres = 3243239341Snp G_RXCOALESCESIZE(t4_read_reg(sc, A_TP_PARA_REG2)); 3244228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp_thres", CTLFLAG_RW, 3245228561Snp &sc->tt.ddp_thres, 0, "DDP threshold"); 3246228561Snp } 3247228561Snp#endif 3248228561Snp 3249228561Snp 3250218792Snp return (0); 3251218792Snp} 3252218792Snp 3253218792Snpstatic int 3254218792Snpcxgbe_sysctls(struct port_info *pi) 3255218792Snp{ 3256218792Snp struct sysctl_ctx_list *ctx; 3257218792Snp struct sysctl_oid *oid; 3258218792Snp struct sysctl_oid_list *children; 3259218792Snp 3260218792Snp ctx = device_get_sysctl_ctx(pi->dev); 3261218792Snp 3262218792Snp /* 3263218792Snp * dev.cxgbe.X. 3264218792Snp */ 3265218792Snp oid = device_get_sysctl_tree(pi->dev); 3266218792Snp children = SYSCTL_CHILDREN(oid); 3267218792Snp 3268218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD, 3269218792Snp &pi->nrxq, 0, "# of rx queues"); 3270218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD, 3271218792Snp &pi->ntxq, 0, "# of tx queues"); 3272218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD, 3273218792Snp &pi->first_rxq, 0, "index of first rx queue"); 3274218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD, 3275218792Snp &pi->first_txq, 0, "index of first tx queue"); 3276218792Snp 3277237263Snp#ifdef TCP_OFFLOAD 3278228561Snp if (is_offload(pi->adapter)) { 3279228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldrxq", CTLFLAG_RD, 3280228561Snp &pi->nofldrxq, 0, 3281228561Snp "# of rx queues for offloaded TCP connections"); 3282228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldtxq", CTLFLAG_RD, 3283228561Snp &pi->nofldtxq, 0, 3284228561Snp "# of tx queues for offloaded TCP connections"); 3285228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_rxq", 3286228561Snp CTLFLAG_RD, &pi->first_ofld_rxq, 0, 3287228561Snp "index of first TOE rx queue"); 3288228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_txq", 3289228561Snp CTLFLAG_RD, &pi->first_ofld_txq, 0, 3290228561Snp "index of first TOE tx queue"); 3291228561Snp } 3292228561Snp#endif 3293228561Snp 3294218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx", 3295218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I", 3296218792Snp "holdoff timer index"); 3297218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx", 3298218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I", 3299218792Snp "holdoff packet counter index"); 3300218792Snp 3301218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq", 3302218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I", 3303218792Snp "rx queue size"); 3304218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq", 3305218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I", 3306218792Snp "tx queue size"); 3307218792Snp 3308218792Snp /* 3309218792Snp * dev.cxgbe.X.stats. 3310218792Snp */ 3311218792Snp oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, 3312218792Snp NULL, "port statistics"); 3313218792Snp children = SYSCTL_CHILDREN(oid); 3314218792Snp 3315218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \ 3316218792Snp SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \ 3317218792Snp CTLTYPE_U64 | CTLFLAG_RD, pi->adapter, reg, \ 3318218792Snp sysctl_handle_t4_reg64, "QU", desc) 3319218792Snp 3320218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames", 3321218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L)); 3322218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames", 3323218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L)); 3324218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames", 3325218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L)); 3326218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames", 3327218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L)); 3328218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames", 3329218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L)); 3330218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames", 3331218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L)); 3332218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_64", 3333218792Snp "# of tx frames in this range", 3334218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L)); 3335218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127", 3336218792Snp "# of tx frames in this range", 3337218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L)); 3338218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255", 3339218792Snp "# of tx frames in this range", 3340218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L)); 3341218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511", 3342218792Snp "# of tx frames in this range", 3343218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L)); 3344218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023", 3345218792Snp "# of tx frames in this range", 3346218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L)); 3347218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518", 3348218792Snp "# of tx frames in this range", 3349218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L)); 3350218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max", 3351218792Snp "# of tx frames in this range", 3352218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L)); 3353218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames", 3354218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L)); 3355218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted", 3356218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L)); 3357218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted", 3358218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L)); 3359218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted", 3360218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L)); 3361218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted", 3362218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L)); 3363218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted", 3364218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L)); 3365218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted", 3366218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L)); 3367218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted", 3368218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L)); 3369218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted", 3370218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L)); 3371218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted", 3372218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L)); 3373218792Snp 3374218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames", 3375218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L)); 3376218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames", 3377218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L)); 3378218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames", 3379218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L)); 3380218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames", 3381218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L)); 3382218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames", 3383218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L)); 3384218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU", 3385218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L)); 3386218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames", 3387218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L)); 3388218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err", 3389218792Snp "# of frames received with bad FCS", 3390218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L)); 3391218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_len_err", 3392218792Snp "# of frames received with length error", 3393218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L)); 3394218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors", 3395218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L)); 3396218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received", 3397218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L)); 3398218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_64", 3399218792Snp "# of rx frames in this range", 3400218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L)); 3401218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127", 3402218792Snp "# of rx frames in this range", 3403218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L)); 3404218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255", 3405218792Snp "# of rx frames in this range", 3406218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L)); 3407218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511", 3408218792Snp "# of rx frames in this range", 3409218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L)); 3410218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023", 3411218792Snp "# of rx frames in this range", 3412218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L)); 3413218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518", 3414218792Snp "# of rx frames in this range", 3415218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L)); 3416218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max", 3417218792Snp "# of rx frames in this range", 3418218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L)); 3419218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received", 3420218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L)); 3421218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received", 3422218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L)); 3423218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received", 3424218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L)); 3425218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received", 3426218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L)); 3427218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received", 3428218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L)); 3429218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received", 3430218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L)); 3431218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received", 3432218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L)); 3433218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received", 3434218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L)); 3435218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received", 3436218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L)); 3437218792Snp 3438218792Snp#undef SYSCTL_ADD_T4_REG64 3439218792Snp 3440218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \ 3441218792Snp SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \ 3442218792Snp &pi->stats.name, desc) 3443218792Snp 3444218792Snp /* We get these from port_stats and they may be stale by upto 1s */ 3445218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0, 3446218792Snp "# drops due to buffer-group 0 overflows"); 3447218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1, 3448218792Snp "# drops due to buffer-group 1 overflows"); 3449218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2, 3450218792Snp "# drops due to buffer-group 2 overflows"); 3451218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3, 3452218792Snp "# drops due to buffer-group 3 overflows"); 3453218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc0, 3454218792Snp "# of buffer-group 0 truncated packets"); 3455218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc1, 3456218792Snp "# of buffer-group 1 truncated packets"); 3457218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc2, 3458218792Snp "# of buffer-group 2 truncated packets"); 3459218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc3, 3460218792Snp "# of buffer-group 3 truncated packets"); 3461218792Snp 3462218792Snp#undef SYSCTL_ADD_T4_PORTSTAT 3463218792Snp 3464218792Snp return (0); 3465218792Snp} 3466218792Snp 3467218792Snpstatic int 3468219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS) 3469219436Snp{ 3470219436Snp int rc, *i; 3471219436Snp struct sbuf sb; 3472219436Snp 3473219436Snp sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); 3474219436Snp for (i = arg1; arg2; arg2 -= sizeof(int), i++) 3475219436Snp sbuf_printf(&sb, "%d ", *i); 3476219436Snp sbuf_trim(&sb); 3477219436Snp sbuf_finish(&sb); 3478219436Snp rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 3479219436Snp sbuf_delete(&sb); 3480219436Snp return (rc); 3481219436Snp} 3482219436Snp 3483219436Snpstatic int 3484228561Snpsysctl_bitfield(SYSCTL_HANDLER_ARGS) 3485228561Snp{ 3486228561Snp int rc; 3487228561Snp struct sbuf *sb; 3488228561Snp 3489228561Snp rc = sysctl_wire_old_buffer(req, 0); 3490228561Snp if (rc != 0) 3491228561Snp return(rc); 3492228561Snp 3493228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 3494228561Snp if (sb == NULL) 3495228561Snp return (ENOMEM); 3496228561Snp 3497228561Snp sbuf_printf(sb, "%b", (int)arg2, (char *)arg1); 3498228561Snp rc = sbuf_finish(sb); 3499228561Snp sbuf_delete(sb); 3500228561Snp 3501228561Snp return (rc); 3502228561Snp} 3503228561Snp 3504228561Snpstatic int 3505218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS) 3506218792Snp{ 3507218792Snp struct port_info *pi = arg1; 3508218792Snp struct adapter *sc = pi->adapter; 3509218792Snp int idx, rc, i; 3510245274Snp struct sge_rxq *rxq; 3511245274Snp uint8_t v; 3512218792Snp 3513218792Snp idx = pi->tmr_idx; 3514218792Snp 3515218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 3516218792Snp if (rc != 0 || req->newptr == NULL) 3517218792Snp return (rc); 3518218792Snp 3519218792Snp if (idx < 0 || idx >= SGE_NTIMERS) 3520218792Snp return (EINVAL); 3521218792Snp 3522245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 3523245274Snp "t4tmr"); 3524245274Snp if (rc) 3525245274Snp return (rc); 3526228561Snp 3527245274Snp v = V_QINTR_TIMER_IDX(idx) | V_QINTR_CNT_EN(pi->pktc_idx != -1); 3528245274Snp for_each_rxq(pi, i, rxq) { 3529228561Snp#ifdef atomic_store_rel_8 3530245274Snp atomic_store_rel_8(&rxq->iq.intr_params, v); 3531228561Snp#else 3532245274Snp rxq->iq.intr_params = v; 3533228561Snp#endif 3534218792Snp } 3535245274Snp pi->tmr_idx = idx; 3536218792Snp 3537245274Snp end_synchronized_op(sc, LOCK_HELD); 3538245274Snp return (0); 3539218792Snp} 3540218792Snp 3541218792Snpstatic int 3542218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS) 3543218792Snp{ 3544218792Snp struct port_info *pi = arg1; 3545218792Snp struct adapter *sc = pi->adapter; 3546218792Snp int idx, rc; 3547218792Snp 3548218792Snp idx = pi->pktc_idx; 3549218792Snp 3550218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 3551218792Snp if (rc != 0 || req->newptr == NULL) 3552218792Snp return (rc); 3553218792Snp 3554218792Snp if (idx < -1 || idx >= SGE_NCOUNTERS) 3555218792Snp return (EINVAL); 3556218792Snp 3557245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 3558245274Snp "t4pktc"); 3559245274Snp if (rc) 3560245274Snp return (rc); 3561245274Snp 3562245274Snp if (pi->flags & PORT_INIT_DONE) 3563228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 3564245274Snp else 3565218792Snp pi->pktc_idx = idx; 3566218792Snp 3567245274Snp end_synchronized_op(sc, LOCK_HELD); 3568218792Snp return (rc); 3569218792Snp} 3570218792Snp 3571218792Snpstatic int 3572218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS) 3573218792Snp{ 3574218792Snp struct port_info *pi = arg1; 3575218792Snp struct adapter *sc = pi->adapter; 3576218792Snp int qsize, rc; 3577218792Snp 3578218792Snp qsize = pi->qsize_rxq; 3579218792Snp 3580218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 3581218792Snp if (rc != 0 || req->newptr == NULL) 3582218792Snp return (rc); 3583218792Snp 3584218792Snp if (qsize < 128 || (qsize & 7)) 3585218792Snp return (EINVAL); 3586218792Snp 3587245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 3588245274Snp "t4rxqs"); 3589245274Snp if (rc) 3590245274Snp return (rc); 3591245274Snp 3592245274Snp if (pi->flags & PORT_INIT_DONE) 3593228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 3594245274Snp else 3595218792Snp pi->qsize_rxq = qsize; 3596218792Snp 3597245274Snp end_synchronized_op(sc, LOCK_HELD); 3598218792Snp return (rc); 3599218792Snp} 3600218792Snp 3601218792Snpstatic int 3602218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS) 3603218792Snp{ 3604218792Snp struct port_info *pi = arg1; 3605218792Snp struct adapter *sc = pi->adapter; 3606218792Snp int qsize, rc; 3607218792Snp 3608218792Snp qsize = pi->qsize_txq; 3609218792Snp 3610218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 3611218792Snp if (rc != 0 || req->newptr == NULL) 3612218792Snp return (rc); 3613218792Snp 3614245274Snp /* bufring size must be powerof2 */ 3615245274Snp if (qsize < 128 || !powerof2(qsize)) 3616218792Snp return (EINVAL); 3617218792Snp 3618245274Snp rc = begin_synchronized_op(sc, pi, HOLD_LOCK | SLEEP_OK | INTR_OK, 3619245274Snp "t4txqs"); 3620245274Snp if (rc) 3621245274Snp return (rc); 3622245274Snp 3623245274Snp if (pi->flags & PORT_INIT_DONE) 3624228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 3625245274Snp else 3626218792Snp pi->qsize_txq = qsize; 3627218792Snp 3628245274Snp end_synchronized_op(sc, LOCK_HELD); 3629218792Snp return (rc); 3630218792Snp} 3631218792Snp 3632218792Snpstatic int 3633218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS) 3634218792Snp{ 3635218792Snp struct adapter *sc = arg1; 3636218792Snp int reg = arg2; 3637218792Snp uint64_t val; 3638218792Snp 3639218792Snp val = t4_read_reg64(sc, reg); 3640218792Snp 3641218792Snp return (sysctl_handle_64(oidp, &val, 0, req)); 3642218792Snp} 3643218792Snp 3644231115Snp#ifdef SBUF_DRAIN 3645228561Snpstatic int 3646228561Snpsysctl_cctrl(SYSCTL_HANDLER_ARGS) 3647228561Snp{ 3648228561Snp struct adapter *sc = arg1; 3649228561Snp struct sbuf *sb; 3650228561Snp int rc, i; 3651228561Snp uint16_t incr[NMTUS][NCCTRL_WIN]; 3652228561Snp static const char *dec_fac[] = { 3653228561Snp "0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875", 3654228561Snp "0.9375" 3655228561Snp }; 3656228561Snp 3657228561Snp rc = sysctl_wire_old_buffer(req, 0); 3658228561Snp if (rc != 0) 3659228561Snp return (rc); 3660228561Snp 3661228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3662228561Snp if (sb == NULL) 3663228561Snp return (ENOMEM); 3664228561Snp 3665228561Snp t4_read_cong_tbl(sc, incr); 3666228561Snp 3667228561Snp for (i = 0; i < NCCTRL_WIN; ++i) { 3668228561Snp sbuf_printf(sb, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i, 3669228561Snp incr[0][i], incr[1][i], incr[2][i], incr[3][i], incr[4][i], 3670228561Snp incr[5][i], incr[6][i], incr[7][i]); 3671228561Snp sbuf_printf(sb, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n", 3672228561Snp incr[8][i], incr[9][i], incr[10][i], incr[11][i], 3673228561Snp incr[12][i], incr[13][i], incr[14][i], incr[15][i], 3674228561Snp sc->params.a_wnd[i], dec_fac[sc->params.b_wnd[i]]); 3675228561Snp } 3676228561Snp 3677228561Snp rc = sbuf_finish(sb); 3678228561Snp sbuf_delete(sb); 3679228561Snp 3680228561Snp return (rc); 3681228561Snp} 3682228561Snp 3683228561Snpstatic int 3684228561Snpsysctl_cpl_stats(SYSCTL_HANDLER_ARGS) 3685228561Snp{ 3686228561Snp struct adapter *sc = arg1; 3687228561Snp struct sbuf *sb; 3688228561Snp int rc; 3689228561Snp struct tp_cpl_stats stats; 3690228561Snp 3691228561Snp rc = sysctl_wire_old_buffer(req, 0); 3692228561Snp if (rc != 0) 3693228561Snp return (rc); 3694228561Snp 3695228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3696228561Snp if (sb == NULL) 3697228561Snp return (ENOMEM); 3698228561Snp 3699228561Snp t4_tp_get_cpl_stats(sc, &stats); 3700228561Snp 3701228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 3702228561Snp "channel 3\n"); 3703228561Snp sbuf_printf(sb, "CPL requests: %10u %10u %10u %10u\n", 3704228561Snp stats.req[0], stats.req[1], stats.req[2], stats.req[3]); 3705228561Snp sbuf_printf(sb, "CPL responses: %10u %10u %10u %10u", 3706228561Snp stats.rsp[0], stats.rsp[1], stats.rsp[2], stats.rsp[3]); 3707228561Snp 3708228561Snp rc = sbuf_finish(sb); 3709228561Snp sbuf_delete(sb); 3710228561Snp 3711228561Snp return (rc); 3712228561Snp} 3713228561Snp 3714228561Snpstatic int 3715228561Snpsysctl_ddp_stats(SYSCTL_HANDLER_ARGS) 3716228561Snp{ 3717228561Snp struct adapter *sc = arg1; 3718228561Snp struct sbuf *sb; 3719228561Snp int rc; 3720228561Snp struct tp_usm_stats stats; 3721228561Snp 3722228561Snp rc = sysctl_wire_old_buffer(req, 0); 3723228561Snp if (rc != 0) 3724228561Snp return(rc); 3725228561Snp 3726228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3727228561Snp if (sb == NULL) 3728228561Snp return (ENOMEM); 3729228561Snp 3730228561Snp t4_get_usm_stats(sc, &stats); 3731228561Snp 3732228561Snp sbuf_printf(sb, "Frames: %u\n", stats.frames); 3733228561Snp sbuf_printf(sb, "Octets: %ju\n", stats.octets); 3734228561Snp sbuf_printf(sb, "Drops: %u", stats.drops); 3735228561Snp 3736228561Snp rc = sbuf_finish(sb); 3737228561Snp sbuf_delete(sb); 3738228561Snp 3739228561Snp return (rc); 3740228561Snp} 3741228561Snp 3742222551Snpconst char *devlog_level_strings[] = { 3743222551Snp [FW_DEVLOG_LEVEL_EMERG] = "EMERG", 3744222551Snp [FW_DEVLOG_LEVEL_CRIT] = "CRIT", 3745222551Snp [FW_DEVLOG_LEVEL_ERR] = "ERR", 3746222551Snp [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", 3747222551Snp [FW_DEVLOG_LEVEL_INFO] = "INFO", 3748222551Snp [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" 3749222551Snp}; 3750222551Snp 3751222551Snpconst char *devlog_facility_strings[] = { 3752222551Snp [FW_DEVLOG_FACILITY_CORE] = "CORE", 3753222551Snp [FW_DEVLOG_FACILITY_SCHED] = "SCHED", 3754222551Snp [FW_DEVLOG_FACILITY_TIMER] = "TIMER", 3755222551Snp [FW_DEVLOG_FACILITY_RES] = "RES", 3756222551Snp [FW_DEVLOG_FACILITY_HW] = "HW", 3757222551Snp [FW_DEVLOG_FACILITY_FLR] = "FLR", 3758222551Snp [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", 3759222551Snp [FW_DEVLOG_FACILITY_PHY] = "PHY", 3760222551Snp [FW_DEVLOG_FACILITY_MAC] = "MAC", 3761222551Snp [FW_DEVLOG_FACILITY_PORT] = "PORT", 3762222551Snp [FW_DEVLOG_FACILITY_VI] = "VI", 3763222551Snp [FW_DEVLOG_FACILITY_FILTER] = "FILTER", 3764222551Snp [FW_DEVLOG_FACILITY_ACL] = "ACL", 3765222551Snp [FW_DEVLOG_FACILITY_TM] = "TM", 3766222551Snp [FW_DEVLOG_FACILITY_QFC] = "QFC", 3767222551Snp [FW_DEVLOG_FACILITY_DCB] = "DCB", 3768222551Snp [FW_DEVLOG_FACILITY_ETH] = "ETH", 3769222551Snp [FW_DEVLOG_FACILITY_OFLD] = "OFLD", 3770222551Snp [FW_DEVLOG_FACILITY_RI] = "RI", 3771222551Snp [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", 3772222551Snp [FW_DEVLOG_FACILITY_FCOE] = "FCOE", 3773222551Snp [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", 3774222551Snp [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE" 3775222551Snp}; 3776222551Snp 3777222551Snpstatic int 3778222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS) 3779222551Snp{ 3780222551Snp struct adapter *sc = arg1; 3781222551Snp struct devlog_params *dparams = &sc->params.devlog; 3782222551Snp struct fw_devlog_e *buf, *e; 3783222551Snp int i, j, rc, nentries, first = 0; 3784222551Snp struct sbuf *sb; 3785222551Snp uint64_t ftstamp = UINT64_MAX; 3786222551Snp 3787222551Snp if (dparams->start == 0) 3788222551Snp return (ENXIO); 3789222551Snp 3790222551Snp nentries = dparams->size / sizeof(struct fw_devlog_e); 3791222551Snp 3792222551Snp buf = malloc(dparams->size, M_CXGBE, M_NOWAIT); 3793222551Snp if (buf == NULL) 3794222551Snp return (ENOMEM); 3795222551Snp 3796222551Snp rc = -t4_mem_read(sc, dparams->memtype, dparams->start, dparams->size, 3797222551Snp (void *)buf); 3798222551Snp if (rc != 0) 3799222551Snp goto done; 3800222551Snp 3801222551Snp for (i = 0; i < nentries; i++) { 3802222551Snp e = &buf[i]; 3803222551Snp 3804222551Snp if (e->timestamp == 0) 3805222551Snp break; /* end */ 3806222551Snp 3807222551Snp e->timestamp = be64toh(e->timestamp); 3808222551Snp e->seqno = be32toh(e->seqno); 3809222551Snp for (j = 0; j < 8; j++) 3810222551Snp e->params[j] = be32toh(e->params[j]); 3811222551Snp 3812222551Snp if (e->timestamp < ftstamp) { 3813222551Snp ftstamp = e->timestamp; 3814222551Snp first = i; 3815222551Snp } 3816222551Snp } 3817222551Snp 3818222551Snp if (buf[first].timestamp == 0) 3819222551Snp goto done; /* nothing in the log */ 3820222551Snp 3821222551Snp rc = sysctl_wire_old_buffer(req, 0); 3822222551Snp if (rc != 0) 3823222551Snp goto done; 3824222551Snp 3825222551Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3826228561Snp if (sb == NULL) { 3827228561Snp rc = ENOMEM; 3828228561Snp goto done; 3829228561Snp } 3830228561Snp sbuf_printf(sb, "%10s %15s %8s %8s %s\n", 3831222551Snp "Seq#", "Tstamp", "Level", "Facility", "Message"); 3832222551Snp 3833222551Snp i = first; 3834222551Snp do { 3835222551Snp e = &buf[i]; 3836222551Snp if (e->timestamp == 0) 3837222551Snp break; /* end */ 3838222551Snp 3839222551Snp sbuf_printf(sb, "%10d %15ju %8s %8s ", 3840222551Snp e->seqno, e->timestamp, 3841240452Snp (e->level < nitems(devlog_level_strings) ? 3842222551Snp devlog_level_strings[e->level] : "UNKNOWN"), 3843240452Snp (e->facility < nitems(devlog_facility_strings) ? 3844222551Snp devlog_facility_strings[e->facility] : "UNKNOWN")); 3845222551Snp sbuf_printf(sb, e->fmt, e->params[0], e->params[1], 3846222551Snp e->params[2], e->params[3], e->params[4], 3847222551Snp e->params[5], e->params[6], e->params[7]); 3848222551Snp 3849222551Snp if (++i == nentries) 3850222551Snp i = 0; 3851222551Snp } while (i != first); 3852222551Snp 3853222551Snp rc = sbuf_finish(sb); 3854222551Snp sbuf_delete(sb); 3855222551Snpdone: 3856222551Snp free(buf, M_CXGBE); 3857222551Snp return (rc); 3858222551Snp} 3859222551Snp 3860228561Snpstatic int 3861228561Snpsysctl_fcoe_stats(SYSCTL_HANDLER_ARGS) 3862228561Snp{ 3863228561Snp struct adapter *sc = arg1; 3864228561Snp struct sbuf *sb; 3865228561Snp int rc; 3866228561Snp struct tp_fcoe_stats stats[4]; 3867228561Snp 3868228561Snp rc = sysctl_wire_old_buffer(req, 0); 3869228561Snp if (rc != 0) 3870228561Snp return (rc); 3871228561Snp 3872228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3873228561Snp if (sb == NULL) 3874228561Snp return (ENOMEM); 3875228561Snp 3876228561Snp t4_get_fcoe_stats(sc, 0, &stats[0]); 3877228561Snp t4_get_fcoe_stats(sc, 1, &stats[1]); 3878228561Snp t4_get_fcoe_stats(sc, 2, &stats[2]); 3879228561Snp t4_get_fcoe_stats(sc, 3, &stats[3]); 3880228561Snp 3881228561Snp sbuf_printf(sb, " channel 0 channel 1 " 3882228561Snp "channel 2 channel 3\n"); 3883228561Snp sbuf_printf(sb, "octetsDDP: %16ju %16ju %16ju %16ju\n", 3884228561Snp stats[0].octetsDDP, stats[1].octetsDDP, stats[2].octetsDDP, 3885228561Snp stats[3].octetsDDP); 3886228561Snp sbuf_printf(sb, "framesDDP: %16u %16u %16u %16u\n", stats[0].framesDDP, 3887228561Snp stats[1].framesDDP, stats[2].framesDDP, stats[3].framesDDP); 3888228561Snp sbuf_printf(sb, "framesDrop: %16u %16u %16u %16u", 3889228561Snp stats[0].framesDrop, stats[1].framesDrop, stats[2].framesDrop, 3890228561Snp stats[3].framesDrop); 3891228561Snp 3892228561Snp rc = sbuf_finish(sb); 3893228561Snp sbuf_delete(sb); 3894228561Snp 3895228561Snp return (rc); 3896228561Snp} 3897228561Snp 3898228561Snpstatic int 3899228561Snpsysctl_hw_sched(SYSCTL_HANDLER_ARGS) 3900228561Snp{ 3901228561Snp struct adapter *sc = arg1; 3902228561Snp struct sbuf *sb; 3903228561Snp int rc, i; 3904228561Snp unsigned int map, kbps, ipg, mode; 3905228561Snp unsigned int pace_tab[NTX_SCHED]; 3906228561Snp 3907228561Snp rc = sysctl_wire_old_buffer(req, 0); 3908228561Snp if (rc != 0) 3909228561Snp return (rc); 3910228561Snp 3911228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3912228561Snp if (sb == NULL) 3913228561Snp return (ENOMEM); 3914228561Snp 3915228561Snp map = t4_read_reg(sc, A_TP_TX_MOD_QUEUE_REQ_MAP); 3916228561Snp mode = G_TIMERMODE(t4_read_reg(sc, A_TP_MOD_CONFIG)); 3917228561Snp t4_read_pace_tbl(sc, pace_tab); 3918228561Snp 3919228561Snp sbuf_printf(sb, "Scheduler Mode Channel Rate (Kbps) " 3920228561Snp "Class IPG (0.1 ns) Flow IPG (us)"); 3921228561Snp 3922228561Snp for (i = 0; i < NTX_SCHED; ++i, map >>= 2) { 3923228561Snp t4_get_tx_sched(sc, i, &kbps, &ipg); 3924228561Snp sbuf_printf(sb, "\n %u %-5s %u ", i, 3925228561Snp (mode & (1 << i)) ? "flow" : "class", map & 3); 3926228561Snp if (kbps) 3927228561Snp sbuf_printf(sb, "%9u ", kbps); 3928228561Snp else 3929228561Snp sbuf_printf(sb, " disabled "); 3930228561Snp 3931228561Snp if (ipg) 3932228561Snp sbuf_printf(sb, "%13u ", ipg); 3933228561Snp else 3934228561Snp sbuf_printf(sb, " disabled "); 3935228561Snp 3936228561Snp if (pace_tab[i]) 3937228561Snp sbuf_printf(sb, "%10u", pace_tab[i]); 3938228561Snp else 3939228561Snp sbuf_printf(sb, " disabled"); 3940228561Snp } 3941228561Snp 3942228561Snp rc = sbuf_finish(sb); 3943228561Snp sbuf_delete(sb); 3944228561Snp 3945228561Snp return (rc); 3946228561Snp} 3947228561Snp 3948228561Snpstatic int 3949228561Snpsysctl_lb_stats(SYSCTL_HANDLER_ARGS) 3950228561Snp{ 3951228561Snp struct adapter *sc = arg1; 3952228561Snp struct sbuf *sb; 3953228561Snp int rc, i, j; 3954228561Snp uint64_t *p0, *p1; 3955228561Snp struct lb_port_stats s[2]; 3956228561Snp static const char *stat_name[] = { 3957228561Snp "OctetsOK:", "FramesOK:", "BcastFrames:", "McastFrames:", 3958228561Snp "UcastFrames:", "ErrorFrames:", "Frames64:", "Frames65To127:", 3959228561Snp "Frames128To255:", "Frames256To511:", "Frames512To1023:", 3960228561Snp "Frames1024To1518:", "Frames1519ToMax:", "FramesDropped:", 3961228561Snp "BG0FramesDropped:", "BG1FramesDropped:", "BG2FramesDropped:", 3962228561Snp "BG3FramesDropped:", "BG0FramesTrunc:", "BG1FramesTrunc:", 3963228561Snp "BG2FramesTrunc:", "BG3FramesTrunc:" 3964228561Snp }; 3965228561Snp 3966228561Snp rc = sysctl_wire_old_buffer(req, 0); 3967228561Snp if (rc != 0) 3968228561Snp return (rc); 3969228561Snp 3970228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3971228561Snp if (sb == NULL) 3972228561Snp return (ENOMEM); 3973228561Snp 3974228561Snp memset(s, 0, sizeof(s)); 3975228561Snp 3976228561Snp for (i = 0; i < 4; i += 2) { 3977228561Snp t4_get_lb_stats(sc, i, &s[0]); 3978228561Snp t4_get_lb_stats(sc, i + 1, &s[1]); 3979228561Snp 3980228561Snp p0 = &s[0].octets; 3981228561Snp p1 = &s[1].octets; 3982228561Snp sbuf_printf(sb, "%s Loopback %u" 3983228561Snp " Loopback %u", i == 0 ? "" : "\n", i, i + 1); 3984228561Snp 3985240452Snp for (j = 0; j < nitems(stat_name); j++) 3986228561Snp sbuf_printf(sb, "\n%-17s %20ju %20ju", stat_name[j], 3987228561Snp *p0++, *p1++); 3988228561Snp } 3989228561Snp 3990228561Snp rc = sbuf_finish(sb); 3991228561Snp sbuf_delete(sb); 3992228561Snp 3993228561Snp return (rc); 3994228561Snp} 3995228561Snp 3996228561Snpstruct mem_desc { 3997228561Snp unsigned int base; 3998228561Snp unsigned int limit; 3999228561Snp unsigned int idx; 4000228561Snp}; 4001228561Snp 4002228561Snpstatic int 4003228561Snpmem_desc_cmp(const void *a, const void *b) 4004228561Snp{ 4005228561Snp return ((const struct mem_desc *)a)->base - 4006228561Snp ((const struct mem_desc *)b)->base; 4007228561Snp} 4008228561Snp 4009228561Snpstatic void 4010228561Snpmem_region_show(struct sbuf *sb, const char *name, unsigned int from, 4011228561Snp unsigned int to) 4012228561Snp{ 4013228561Snp unsigned int size; 4014228561Snp 4015228561Snp size = to - from + 1; 4016228561Snp if (size == 0) 4017228561Snp return; 4018228561Snp 4019228561Snp /* XXX: need humanize_number(3) in libkern for a more readable 'size' */ 4020228561Snp sbuf_printf(sb, "%-15s %#x-%#x [%u]\n", name, from, to, size); 4021228561Snp} 4022228561Snp 4023228561Snpstatic int 4024228561Snpsysctl_meminfo(SYSCTL_HANDLER_ARGS) 4025228561Snp{ 4026228561Snp struct adapter *sc = arg1; 4027228561Snp struct sbuf *sb; 4028228561Snp int rc, i, n; 4029228561Snp uint32_t lo, hi; 4030228561Snp static const char *memory[] = { "EDC0:", "EDC1:", "MC:" }; 4031228561Snp static const char *region[] = { 4032228561Snp "DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:", 4033228561Snp "Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:", 4034228561Snp "Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:", 4035228561Snp "TDDP region:", "TPT region:", "STAG region:", "RQ region:", 4036228561Snp "RQUDP region:", "PBL region:", "TXPBL region:", "ULPRX state:", 4037228561Snp "ULPTX state:", "On-chip queues:" 4038228561Snp }; 4039228561Snp struct mem_desc avail[3]; 4040240452Snp struct mem_desc mem[nitems(region) + 3]; /* up to 3 holes */ 4041228561Snp struct mem_desc *md = mem; 4042228561Snp 4043228561Snp rc = sysctl_wire_old_buffer(req, 0); 4044228561Snp if (rc != 0) 4045228561Snp return (rc); 4046228561Snp 4047228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 4048228561Snp if (sb == NULL) 4049228561Snp return (ENOMEM); 4050228561Snp 4051240452Snp for (i = 0; i < nitems(mem); i++) { 4052228561Snp mem[i].limit = 0; 4053228561Snp mem[i].idx = i; 4054228561Snp } 4055228561Snp 4056228561Snp /* Find and sort the populated memory ranges */ 4057228561Snp i = 0; 4058228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 4059228561Snp if (lo & F_EDRAM0_ENABLE) { 4060228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 4061228561Snp avail[i].base = G_EDRAM0_BASE(hi) << 20; 4062228561Snp avail[i].limit = avail[i].base + (G_EDRAM0_SIZE(hi) << 20); 4063228561Snp avail[i].idx = 0; 4064228561Snp i++; 4065228561Snp } 4066228561Snp if (lo & F_EDRAM1_ENABLE) { 4067228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 4068228561Snp avail[i].base = G_EDRAM1_BASE(hi) << 20; 4069228561Snp avail[i].limit = avail[i].base + (G_EDRAM1_SIZE(hi) << 20); 4070228561Snp avail[i].idx = 1; 4071228561Snp i++; 4072228561Snp } 4073228561Snp if (lo & F_EXT_MEM_ENABLE) { 4074228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 4075228561Snp avail[i].base = G_EXT_MEM_BASE(hi) << 20; 4076228561Snp avail[i].limit = avail[i].base + (G_EXT_MEM_SIZE(hi) << 20); 4077228561Snp avail[i].idx = 2; 4078228561Snp i++; 4079228561Snp } 4080228561Snp if (!i) /* no memory available */ 4081228561Snp return 0; 4082228561Snp qsort(avail, i, sizeof(struct mem_desc), mem_desc_cmp); 4083228561Snp 4084228561Snp (md++)->base = t4_read_reg(sc, A_SGE_DBQ_CTXT_BADDR); 4085228561Snp (md++)->base = t4_read_reg(sc, A_SGE_IMSG_CTXT_BADDR); 4086228561Snp (md++)->base = t4_read_reg(sc, A_SGE_FLM_CACHE_BADDR); 4087228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 4088228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_BASE); 4089228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TIMER_BASE); 4090228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_RX_FLST_BASE); 4091228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_TX_FLST_BASE); 4092228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_PS_FLST_BASE); 4093228561Snp 4094228561Snp /* the next few have explicit upper bounds */ 4095228561Snp md->base = t4_read_reg(sc, A_TP_PMM_TX_BASE); 4096228561Snp md->limit = md->base - 1 + 4097228561Snp t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE) * 4098228561Snp G_PMTXMAXPAGE(t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE)); 4099228561Snp md++; 4100228561Snp 4101228561Snp md->base = t4_read_reg(sc, A_TP_PMM_RX_BASE); 4102228561Snp md->limit = md->base - 1 + 4103228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) * 4104228561Snp G_PMRXMAXPAGE(t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE)); 4105228561Snp md++; 4106228561Snp 4107228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 4108228561Snp hi = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4; 4109228561Snp md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE); 4110228561Snp md->limit = (sc->tids.ntids - hi) * 16 + md->base - 1; 4111228561Snp } else { 4112228561Snp md->base = 0; 4113240452Snp md->idx = nitems(region); /* hide it */ 4114228561Snp } 4115228561Snp md++; 4116228561Snp 4117228561Snp#define ulp_region(reg) \ 4118228561Snp md->base = t4_read_reg(sc, A_ULP_ ## reg ## _LLIMIT);\ 4119228561Snp (md++)->limit = t4_read_reg(sc, A_ULP_ ## reg ## _ULIMIT) 4120228561Snp 4121228561Snp ulp_region(RX_ISCSI); 4122228561Snp ulp_region(RX_TDDP); 4123228561Snp ulp_region(TX_TPT); 4124228561Snp ulp_region(RX_STAG); 4125228561Snp ulp_region(RX_RQ); 4126228561Snp ulp_region(RX_RQUDP); 4127228561Snp ulp_region(RX_PBL); 4128228561Snp ulp_region(TX_PBL); 4129228561Snp#undef ulp_region 4130228561Snp 4131228561Snp md->base = t4_read_reg(sc, A_ULP_RX_CTX_BASE); 4132228561Snp md->limit = md->base + sc->tids.ntids - 1; 4133228561Snp md++; 4134228561Snp md->base = t4_read_reg(sc, A_ULP_TX_ERR_TABLE_BASE); 4135228561Snp md->limit = md->base + sc->tids.ntids - 1; 4136228561Snp md++; 4137228561Snp 4138228561Snp md->base = sc->vres.ocq.start; 4139228561Snp if (sc->vres.ocq.size) 4140228561Snp md->limit = md->base + sc->vres.ocq.size - 1; 4141228561Snp else 4142240452Snp md->idx = nitems(region); /* hide it */ 4143228561Snp md++; 4144228561Snp 4145228561Snp /* add any address-space holes, there can be up to 3 */ 4146228561Snp for (n = 0; n < i - 1; n++) 4147228561Snp if (avail[n].limit < avail[n + 1].base) 4148228561Snp (md++)->base = avail[n].limit; 4149228561Snp if (avail[n].limit) 4150228561Snp (md++)->base = avail[n].limit; 4151228561Snp 4152228561Snp n = md - mem; 4153228561Snp qsort(mem, n, sizeof(struct mem_desc), mem_desc_cmp); 4154228561Snp 4155228561Snp for (lo = 0; lo < i; lo++) 4156228561Snp mem_region_show(sb, memory[avail[lo].idx], avail[lo].base, 4157228561Snp avail[lo].limit - 1); 4158228561Snp 4159228561Snp sbuf_printf(sb, "\n"); 4160228561Snp for (i = 0; i < n; i++) { 4161240452Snp if (mem[i].idx >= nitems(region)) 4162228561Snp continue; /* skip holes */ 4163228561Snp if (!mem[i].limit) 4164228561Snp mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0; 4165228561Snp mem_region_show(sb, region[mem[i].idx], mem[i].base, 4166228561Snp mem[i].limit); 4167228561Snp } 4168228561Snp 4169228561Snp sbuf_printf(sb, "\n"); 4170228561Snp lo = t4_read_reg(sc, A_CIM_SDRAM_BASE_ADDR); 4171228561Snp hi = t4_read_reg(sc, A_CIM_SDRAM_ADDR_SIZE) + lo - 1; 4172228561Snp mem_region_show(sb, "uP RAM:", lo, hi); 4173228561Snp 4174228561Snp lo = t4_read_reg(sc, A_CIM_EXTMEM2_BASE_ADDR); 4175228561Snp hi = t4_read_reg(sc, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1; 4176228561Snp mem_region_show(sb, "uP Extmem2:", lo, hi); 4177228561Snp 4178228561Snp lo = t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE); 4179228561Snp sbuf_printf(sb, "\n%u Rx pages of size %uKiB for %u channels\n", 4180228561Snp G_PMRXMAXPAGE(lo), 4181228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) >> 10, 4182228561Snp (lo & F_PMRXNUMCHN) ? 2 : 1); 4183228561Snp 4184228561Snp lo = t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE); 4185228561Snp hi = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE); 4186228561Snp sbuf_printf(sb, "%u Tx pages of size %u%ciB for %u channels\n", 4187228561Snp G_PMTXMAXPAGE(lo), 4188228561Snp hi >= (1 << 20) ? (hi >> 20) : (hi >> 10), 4189228561Snp hi >= (1 << 20) ? 'M' : 'K', 1 << G_PMTXNUMCHN(lo)); 4190228561Snp sbuf_printf(sb, "%u p-structs\n", 4191228561Snp t4_read_reg(sc, A_TP_CMM_MM_MAX_PSTRUCT)); 4192228561Snp 4193228561Snp for (i = 0; i < 4; i++) { 4194228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV0 + i * 4); 4195228561Snp sbuf_printf(sb, "\nPort %d using %u pages out of %u allocated", 4196228561Snp i, G_USED(lo), G_ALLOC(lo)); 4197228561Snp } 4198228561Snp for (i = 0; i < 4; i++) { 4199228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV4 + i * 4); 4200228561Snp sbuf_printf(sb, 4201228561Snp "\nLoopback %d using %u pages out of %u allocated", 4202228561Snp i, G_USED(lo), G_ALLOC(lo)); 4203228561Snp } 4204228561Snp 4205228561Snp rc = sbuf_finish(sb); 4206228561Snp sbuf_delete(sb); 4207228561Snp 4208228561Snp return (rc); 4209228561Snp} 4210228561Snp 4211228561Snpstatic int 4212228561Snpsysctl_path_mtus(SYSCTL_HANDLER_ARGS) 4213228561Snp{ 4214228561Snp struct adapter *sc = arg1; 4215228561Snp struct sbuf *sb; 4216228561Snp int rc; 4217228561Snp uint16_t mtus[NMTUS]; 4218228561Snp 4219228561Snp rc = sysctl_wire_old_buffer(req, 0); 4220228561Snp if (rc != 0) 4221228561Snp return (rc); 4222228561Snp 4223228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4224228561Snp if (sb == NULL) 4225228561Snp return (ENOMEM); 4226228561Snp 4227228561Snp t4_read_mtu_tbl(sc, mtus, NULL); 4228228561Snp 4229228561Snp sbuf_printf(sb, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", 4230228561Snp mtus[0], mtus[1], mtus[2], mtus[3], mtus[4], mtus[5], mtus[6], 4231228561Snp mtus[7], mtus[8], mtus[9], mtus[10], mtus[11], mtus[12], mtus[13], 4232228561Snp mtus[14], mtus[15]); 4233228561Snp 4234228561Snp rc = sbuf_finish(sb); 4235228561Snp sbuf_delete(sb); 4236228561Snp 4237228561Snp return (rc); 4238228561Snp} 4239228561Snp 4240228561Snpstatic int 4241228561Snpsysctl_pm_stats(SYSCTL_HANDLER_ARGS) 4242228561Snp{ 4243228561Snp struct adapter *sc = arg1; 4244228561Snp struct sbuf *sb; 4245228561Snp int rc, i; 4246228561Snp uint32_t tx_cnt[PM_NSTATS], rx_cnt[PM_NSTATS]; 4247228561Snp uint64_t tx_cyc[PM_NSTATS], rx_cyc[PM_NSTATS]; 4248228561Snp static const char *pm_stats[] = { 4249228561Snp "Read:", "Write bypass:", "Write mem:", "Flush:", "FIFO wait:" 4250228561Snp }; 4251228561Snp 4252228561Snp rc = sysctl_wire_old_buffer(req, 0); 4253228561Snp if (rc != 0) 4254228561Snp return (rc); 4255228561Snp 4256228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4257228561Snp if (sb == NULL) 4258228561Snp return (ENOMEM); 4259228561Snp 4260228561Snp t4_pmtx_get_stats(sc, tx_cnt, tx_cyc); 4261228561Snp t4_pmrx_get_stats(sc, rx_cnt, rx_cyc); 4262228561Snp 4263228561Snp sbuf_printf(sb, " Tx count Tx cycles " 4264228561Snp "Rx count Rx cycles"); 4265228561Snp for (i = 0; i < PM_NSTATS; i++) 4266228561Snp sbuf_printf(sb, "\n%-13s %10u %20ju %10u %20ju", 4267228561Snp pm_stats[i], tx_cnt[i], tx_cyc[i], rx_cnt[i], rx_cyc[i]); 4268228561Snp 4269228561Snp rc = sbuf_finish(sb); 4270228561Snp sbuf_delete(sb); 4271228561Snp 4272228561Snp return (rc); 4273228561Snp} 4274228561Snp 4275228561Snpstatic int 4276228561Snpsysctl_rdma_stats(SYSCTL_HANDLER_ARGS) 4277228561Snp{ 4278228561Snp struct adapter *sc = arg1; 4279228561Snp struct sbuf *sb; 4280228561Snp int rc; 4281228561Snp struct tp_rdma_stats stats; 4282228561Snp 4283228561Snp rc = sysctl_wire_old_buffer(req, 0); 4284228561Snp if (rc != 0) 4285228561Snp return (rc); 4286228561Snp 4287228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4288228561Snp if (sb == NULL) 4289228561Snp return (ENOMEM); 4290228561Snp 4291228561Snp t4_tp_get_rdma_stats(sc, &stats); 4292228561Snp sbuf_printf(sb, "NoRQEModDefferals: %u\n", stats.rqe_dfr_mod); 4293228561Snp sbuf_printf(sb, "NoRQEPktDefferals: %u", stats.rqe_dfr_pkt); 4294228561Snp 4295228561Snp rc = sbuf_finish(sb); 4296228561Snp sbuf_delete(sb); 4297228561Snp 4298228561Snp return (rc); 4299228561Snp} 4300228561Snp 4301228561Snpstatic int 4302228561Snpsysctl_tcp_stats(SYSCTL_HANDLER_ARGS) 4303228561Snp{ 4304228561Snp struct adapter *sc = arg1; 4305228561Snp struct sbuf *sb; 4306228561Snp int rc; 4307228561Snp struct tp_tcp_stats v4, v6; 4308228561Snp 4309228561Snp rc = sysctl_wire_old_buffer(req, 0); 4310228561Snp if (rc != 0) 4311228561Snp return (rc); 4312228561Snp 4313228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4314228561Snp if (sb == NULL) 4315228561Snp return (ENOMEM); 4316228561Snp 4317228561Snp t4_tp_get_tcp_stats(sc, &v4, &v6); 4318228561Snp sbuf_printf(sb, 4319228561Snp " IP IPv6\n"); 4320228561Snp sbuf_printf(sb, "OutRsts: %20u %20u\n", 4321228561Snp v4.tcpOutRsts, v6.tcpOutRsts); 4322228561Snp sbuf_printf(sb, "InSegs: %20ju %20ju\n", 4323228561Snp v4.tcpInSegs, v6.tcpInSegs); 4324228561Snp sbuf_printf(sb, "OutSegs: %20ju %20ju\n", 4325228561Snp v4.tcpOutSegs, v6.tcpOutSegs); 4326228561Snp sbuf_printf(sb, "RetransSegs: %20ju %20ju", 4327228561Snp v4.tcpRetransSegs, v6.tcpRetransSegs); 4328228561Snp 4329228561Snp rc = sbuf_finish(sb); 4330228561Snp sbuf_delete(sb); 4331228561Snp 4332228561Snp return (rc); 4333228561Snp} 4334228561Snp 4335228561Snpstatic int 4336228561Snpsysctl_tids(SYSCTL_HANDLER_ARGS) 4337228561Snp{ 4338228561Snp struct adapter *sc = arg1; 4339228561Snp struct sbuf *sb; 4340228561Snp int rc; 4341228561Snp struct tid_info *t = &sc->tids; 4342228561Snp 4343228561Snp rc = sysctl_wire_old_buffer(req, 0); 4344228561Snp if (rc != 0) 4345228561Snp return (rc); 4346228561Snp 4347228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4348228561Snp if (sb == NULL) 4349228561Snp return (ENOMEM); 4350228561Snp 4351228561Snp if (t->natids) { 4352228561Snp sbuf_printf(sb, "ATID range: 0-%u, in use: %u\n", t->natids - 1, 4353228561Snp t->atids_in_use); 4354228561Snp } 4355228561Snp 4356228561Snp if (t->ntids) { 4357228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 4358228561Snp uint32_t b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4; 4359228561Snp 4360228561Snp if (b) { 4361228561Snp sbuf_printf(sb, "TID range: 0-%u, %u-%u", b - 1, 4362228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 4363228561Snp t->ntids - 1); 4364228561Snp } else { 4365228561Snp sbuf_printf(sb, "TID range: %u-%u", 4366228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 4367228561Snp t->ntids - 1); 4368228561Snp } 4369228561Snp } else 4370228561Snp sbuf_printf(sb, "TID range: 0-%u", t->ntids - 1); 4371228561Snp sbuf_printf(sb, ", in use: %u\n", 4372228561Snp atomic_load_acq_int(&t->tids_in_use)); 4373228561Snp } 4374228561Snp 4375228561Snp if (t->nstids) { 4376228561Snp sbuf_printf(sb, "STID range: %u-%u, in use: %u\n", t->stid_base, 4377228561Snp t->stid_base + t->nstids - 1, t->stids_in_use); 4378228561Snp } 4379228561Snp 4380228561Snp if (t->nftids) { 4381228561Snp sbuf_printf(sb, "FTID range: %u-%u\n", t->ftid_base, 4382228561Snp t->ftid_base + t->nftids - 1); 4383228561Snp } 4384228561Snp 4385228561Snp sbuf_printf(sb, "HW TID usage: %u IP users, %u IPv6 users", 4386228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV4), 4387228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV6)); 4388228561Snp 4389228561Snp rc = sbuf_finish(sb); 4390228561Snp sbuf_delete(sb); 4391228561Snp 4392228561Snp return (rc); 4393228561Snp} 4394228561Snp 4395228561Snpstatic int 4396228561Snpsysctl_tp_err_stats(SYSCTL_HANDLER_ARGS) 4397228561Snp{ 4398228561Snp struct adapter *sc = arg1; 4399228561Snp struct sbuf *sb; 4400228561Snp int rc; 4401228561Snp struct tp_err_stats stats; 4402228561Snp 4403228561Snp rc = sysctl_wire_old_buffer(req, 0); 4404228561Snp if (rc != 0) 4405228561Snp return (rc); 4406228561Snp 4407228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4408228561Snp if (sb == NULL) 4409228561Snp return (ENOMEM); 4410228561Snp 4411228561Snp t4_tp_get_err_stats(sc, &stats); 4412228561Snp 4413228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 4414228561Snp "channel 3\n"); 4415228561Snp sbuf_printf(sb, "macInErrs: %10u %10u %10u %10u\n", 4416228561Snp stats.macInErrs[0], stats.macInErrs[1], stats.macInErrs[2], 4417228561Snp stats.macInErrs[3]); 4418228561Snp sbuf_printf(sb, "hdrInErrs: %10u %10u %10u %10u\n", 4419228561Snp stats.hdrInErrs[0], stats.hdrInErrs[1], stats.hdrInErrs[2], 4420228561Snp stats.hdrInErrs[3]); 4421228561Snp sbuf_printf(sb, "tcpInErrs: %10u %10u %10u %10u\n", 4422228561Snp stats.tcpInErrs[0], stats.tcpInErrs[1], stats.tcpInErrs[2], 4423228561Snp stats.tcpInErrs[3]); 4424228561Snp sbuf_printf(sb, "tcp6InErrs: %10u %10u %10u %10u\n", 4425228561Snp stats.tcp6InErrs[0], stats.tcp6InErrs[1], stats.tcp6InErrs[2], 4426228561Snp stats.tcp6InErrs[3]); 4427228561Snp sbuf_printf(sb, "tnlCongDrops: %10u %10u %10u %10u\n", 4428228561Snp stats.tnlCongDrops[0], stats.tnlCongDrops[1], stats.tnlCongDrops[2], 4429228561Snp stats.tnlCongDrops[3]); 4430228561Snp sbuf_printf(sb, "tnlTxDrops: %10u %10u %10u %10u\n", 4431228561Snp stats.tnlTxDrops[0], stats.tnlTxDrops[1], stats.tnlTxDrops[2], 4432228561Snp stats.tnlTxDrops[3]); 4433228561Snp sbuf_printf(sb, "ofldVlanDrops: %10u %10u %10u %10u\n", 4434228561Snp stats.ofldVlanDrops[0], stats.ofldVlanDrops[1], 4435228561Snp stats.ofldVlanDrops[2], stats.ofldVlanDrops[3]); 4436228561Snp sbuf_printf(sb, "ofldChanDrops: %10u %10u %10u %10u\n\n", 4437228561Snp stats.ofldChanDrops[0], stats.ofldChanDrops[1], 4438228561Snp stats.ofldChanDrops[2], stats.ofldChanDrops[3]); 4439228561Snp sbuf_printf(sb, "ofldNoNeigh: %u\nofldCongDefer: %u", 4440228561Snp stats.ofldNoNeigh, stats.ofldCongDefer); 4441228561Snp 4442228561Snp rc = sbuf_finish(sb); 4443228561Snp sbuf_delete(sb); 4444228561Snp 4445228561Snp return (rc); 4446228561Snp} 4447228561Snp 4448228561Snpstatic int 4449228561Snpsysctl_tx_rate(SYSCTL_HANDLER_ARGS) 4450228561Snp{ 4451228561Snp struct adapter *sc = arg1; 4452228561Snp struct sbuf *sb; 4453228561Snp int rc; 4454228561Snp u64 nrate[NCHAN], orate[NCHAN]; 4455228561Snp 4456228561Snp rc = sysctl_wire_old_buffer(req, 0); 4457228561Snp if (rc != 0) 4458228561Snp return (rc); 4459228561Snp 4460228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4461228561Snp if (sb == NULL) 4462228561Snp return (ENOMEM); 4463228561Snp 4464228561Snp t4_get_chan_txrate(sc, nrate, orate); 4465228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 4466228561Snp "channel 3\n"); 4467228561Snp sbuf_printf(sb, "NIC B/s: %10ju %10ju %10ju %10ju\n", 4468228561Snp nrate[0], nrate[1], nrate[2], nrate[3]); 4469228561Snp sbuf_printf(sb, "Offload B/s: %10ju %10ju %10ju %10ju", 4470228561Snp orate[0], orate[1], orate[2], orate[3]); 4471228561Snp 4472228561Snp rc = sbuf_finish(sb); 4473228561Snp sbuf_delete(sb); 4474228561Snp 4475228561Snp return (rc); 4476228561Snp} 4477231115Snp#endif 4478228561Snp 4479219286Snpstatic inline void 4480219286Snptxq_start(struct ifnet *ifp, struct sge_txq *txq) 4481219286Snp{ 4482219286Snp struct buf_ring *br; 4483219286Snp struct mbuf *m; 4484219286Snp 4485219286Snp TXQ_LOCK_ASSERT_OWNED(txq); 4486219286Snp 4487220873Snp br = txq->br; 4488219286Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 4489219286Snp if (m) 4490219286Snp t4_eth_tx(ifp, txq, m); 4491219286Snp} 4492219286Snp 4493219286Snpvoid 4494228561Snpt4_tx_callout(void *arg) 4495219286Snp{ 4496228561Snp struct sge_eq *eq = arg; 4497228561Snp struct adapter *sc; 4498219286Snp 4499228561Snp if (EQ_TRYLOCK(eq) == 0) 4500228561Snp goto reschedule; 4501228561Snp 4502228561Snp if (eq->flags & EQ_STALLED && !can_resume_tx(eq)) { 4503228561Snp EQ_UNLOCK(eq); 4504228561Snpreschedule: 4505228561Snp if (__predict_true(!(eq->flags && EQ_DOOMED))) 4506228561Snp callout_schedule(&eq->tx_callout, 1); 4507228561Snp return; 4508228561Snp } 4509228561Snp 4510228561Snp EQ_LOCK_ASSERT_OWNED(eq); 4511228561Snp 4512228561Snp if (__predict_true((eq->flags & EQ_DOOMED) == 0)) { 4513228561Snp 4514228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 4515228561Snp struct sge_txq *txq = arg; 4516228561Snp struct port_info *pi = txq->ifp->if_softc; 4517228561Snp 4518228561Snp sc = pi->adapter; 4519228561Snp } else { 4520228561Snp struct sge_wrq *wrq = arg; 4521228561Snp 4522228561Snp sc = wrq->adapter; 4523228561Snp } 4524228561Snp 4525228561Snp taskqueue_enqueue(sc->tq[eq->tx_chan], &eq->tx_task); 4526228561Snp } 4527228561Snp 4528228561Snp EQ_UNLOCK(eq); 4529228561Snp} 4530228561Snp 4531228561Snpvoid 4532228561Snpt4_tx_task(void *arg, int count) 4533228561Snp{ 4534228561Snp struct sge_eq *eq = arg; 4535228561Snp 4536228561Snp EQ_LOCK(eq); 4537228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 4538228561Snp struct sge_txq *txq = arg; 4539220649Snp txq_start(txq->ifp, txq); 4540228561Snp } else { 4541228561Snp struct sge_wrq *wrq = arg; 4542228561Snp t4_wrq_tx_locked(wrq->adapter, wrq, NULL); 4543228561Snp } 4544228561Snp EQ_UNLOCK(eq); 4545219286Snp} 4546219286Snp 4547221474Snpstatic uint32_t 4548221474Snpfconf_to_mode(uint32_t fconf) 4549221474Snp{ 4550221474Snp uint32_t mode; 4551221474Snp 4552221474Snp mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR | 4553221474Snp T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT; 4554221474Snp 4555221474Snp if (fconf & F_FRAGMENTATION) 4556221474Snp mode |= T4_FILTER_IP_FRAGMENT; 4557221474Snp 4558221474Snp if (fconf & F_MPSHITTYPE) 4559221474Snp mode |= T4_FILTER_MPS_HIT_TYPE; 4560221474Snp 4561221474Snp if (fconf & F_MACMATCH) 4562221474Snp mode |= T4_FILTER_MAC_IDX; 4563221474Snp 4564221474Snp if (fconf & F_ETHERTYPE) 4565221474Snp mode |= T4_FILTER_ETH_TYPE; 4566221474Snp 4567221474Snp if (fconf & F_PROTOCOL) 4568221474Snp mode |= T4_FILTER_IP_PROTO; 4569221474Snp 4570221474Snp if (fconf & F_TOS) 4571221474Snp mode |= T4_FILTER_IP_TOS; 4572221474Snp 4573221474Snp if (fconf & F_VLAN) 4574228561Snp mode |= T4_FILTER_VLAN; 4575221474Snp 4576221474Snp if (fconf & F_VNIC_ID) 4577228561Snp mode |= T4_FILTER_VNIC; 4578221474Snp 4579221474Snp if (fconf & F_PORT) 4580221474Snp mode |= T4_FILTER_PORT; 4581221474Snp 4582221474Snp if (fconf & F_FCOE) 4583221474Snp mode |= T4_FILTER_FCoE; 4584221474Snp 4585221474Snp return (mode); 4586221474Snp} 4587221474Snp 4588221474Snpstatic uint32_t 4589221474Snpmode_to_fconf(uint32_t mode) 4590221474Snp{ 4591221474Snp uint32_t fconf = 0; 4592221474Snp 4593221474Snp if (mode & T4_FILTER_IP_FRAGMENT) 4594221474Snp fconf |= F_FRAGMENTATION; 4595221474Snp 4596221474Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 4597221474Snp fconf |= F_MPSHITTYPE; 4598221474Snp 4599221474Snp if (mode & T4_FILTER_MAC_IDX) 4600221474Snp fconf |= F_MACMATCH; 4601221474Snp 4602221474Snp if (mode & T4_FILTER_ETH_TYPE) 4603221474Snp fconf |= F_ETHERTYPE; 4604221474Snp 4605221474Snp if (mode & T4_FILTER_IP_PROTO) 4606221474Snp fconf |= F_PROTOCOL; 4607221474Snp 4608221474Snp if (mode & T4_FILTER_IP_TOS) 4609221474Snp fconf |= F_TOS; 4610221474Snp 4611228561Snp if (mode & T4_FILTER_VLAN) 4612221474Snp fconf |= F_VLAN; 4613221474Snp 4614228561Snp if (mode & T4_FILTER_VNIC) 4615221474Snp fconf |= F_VNIC_ID; 4616221474Snp 4617221474Snp if (mode & T4_FILTER_PORT) 4618221474Snp fconf |= F_PORT; 4619221474Snp 4620221474Snp if (mode & T4_FILTER_FCoE) 4621221474Snp fconf |= F_FCOE; 4622221474Snp 4623221474Snp return (fconf); 4624221474Snp} 4625221474Snp 4626221474Snpstatic uint32_t 4627221474Snpfspec_to_fconf(struct t4_filter_specification *fs) 4628221474Snp{ 4629221474Snp uint32_t fconf = 0; 4630221474Snp 4631221474Snp if (fs->val.frag || fs->mask.frag) 4632221474Snp fconf |= F_FRAGMENTATION; 4633221474Snp 4634221474Snp if (fs->val.matchtype || fs->mask.matchtype) 4635221474Snp fconf |= F_MPSHITTYPE; 4636221474Snp 4637221474Snp if (fs->val.macidx || fs->mask.macidx) 4638221474Snp fconf |= F_MACMATCH; 4639221474Snp 4640221474Snp if (fs->val.ethtype || fs->mask.ethtype) 4641221474Snp fconf |= F_ETHERTYPE; 4642221474Snp 4643221474Snp if (fs->val.proto || fs->mask.proto) 4644221474Snp fconf |= F_PROTOCOL; 4645221474Snp 4646221474Snp if (fs->val.tos || fs->mask.tos) 4647221474Snp fconf |= F_TOS; 4648221474Snp 4649228561Snp if (fs->val.vlan_vld || fs->mask.vlan_vld) 4650221474Snp fconf |= F_VLAN; 4651221474Snp 4652228561Snp if (fs->val.vnic_vld || fs->mask.vnic_vld) 4653221474Snp fconf |= F_VNIC_ID; 4654221474Snp 4655221474Snp if (fs->val.iport || fs->mask.iport) 4656221474Snp fconf |= F_PORT; 4657221474Snp 4658221474Snp if (fs->val.fcoe || fs->mask.fcoe) 4659221474Snp fconf |= F_FCOE; 4660221474Snp 4661221474Snp return (fconf); 4662221474Snp} 4663221474Snp 4664221474Snpstatic int 4665221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode) 4666221474Snp{ 4667245274Snp int rc; 4668221474Snp uint32_t fconf; 4669221474Snp 4670245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 4671245274Snp "t4getfm"); 4672245274Snp if (rc) 4673245274Snp return (rc); 4674245274Snp 4675221474Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1, 4676221474Snp A_TP_VLAN_PRI_MAP); 4677221474Snp 4678228561Snp if (sc->filter_mode != fconf) { 4679228561Snp log(LOG_WARNING, "%s: cached filter mode out of sync %x %x.\n", 4680228561Snp device_get_nameunit(sc->dev), sc->filter_mode, fconf); 4681228561Snp sc->filter_mode = fconf; 4682228561Snp } 4683221474Snp 4684228561Snp *mode = fconf_to_mode(sc->filter_mode); 4685228561Snp 4686245274Snp end_synchronized_op(sc, LOCK_HELD); 4687221474Snp return (0); 4688221474Snp} 4689221474Snp 4690221474Snpstatic int 4691221474Snpset_filter_mode(struct adapter *sc, uint32_t mode) 4692221474Snp{ 4693221474Snp uint32_t fconf; 4694221474Snp int rc; 4695221474Snp 4696221474Snp fconf = mode_to_fconf(mode); 4697221474Snp 4698245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 4699245274Snp "t4setfm"); 4700245274Snp if (rc) 4701245274Snp return (rc); 4702221474Snp 4703221474Snp if (sc->tids.ftids_in_use > 0) { 4704221474Snp rc = EBUSY; 4705221474Snp goto done; 4706221474Snp } 4707221474Snp 4708237263Snp#ifdef TCP_OFFLOAD 4709228561Snp if (sc->offload_map) { 4710228561Snp rc = EBUSY; 4711228561Snp goto done; 4712228561Snp } 4713228561Snp#endif 4714228561Snp 4715228561Snp#ifdef notyet 4716221474Snp rc = -t4_set_filter_mode(sc, fconf); 4717228561Snp if (rc == 0) 4718228561Snp sc->filter_mode = fconf; 4719228561Snp#else 4720228561Snp rc = ENOTSUP; 4721228561Snp#endif 4722228561Snp 4723221474Snpdone: 4724245274Snp end_synchronized_op(sc, LOCK_HELD); 4725221474Snp return (rc); 4726221474Snp} 4727221474Snp 4728222552Snpstatic inline uint64_t 4729222552Snpget_filter_hits(struct adapter *sc, uint32_t fid) 4730222552Snp{ 4731222552Snp uint32_t tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 4732222552Snp uint64_t hits; 4733222552Snp 4734222552Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0), 4735222552Snp tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE); 4736222552Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0)); 4737222552Snp hits = t4_read_reg64(sc, MEMWIN0_BASE + 16); 4738222552Snp 4739222552Snp return (be64toh(hits)); 4740222552Snp} 4741222552Snp 4742221474Snpstatic int 4743221474Snpget_filter(struct adapter *sc, struct t4_filter *t) 4744221474Snp{ 4745245274Snp int i, rc, nfilters = sc->tids.nftids; 4746221474Snp struct filter_entry *f; 4747221474Snp 4748245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK, 4749245274Snp "t4getf"); 4750245274Snp if (rc) 4751245274Snp return (rc); 4752221474Snp 4753221474Snp if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL || 4754221474Snp t->idx >= nfilters) { 4755221474Snp t->idx = 0xffffffff; 4756245274Snp goto done; 4757221474Snp } 4758221474Snp 4759221474Snp f = &sc->tids.ftid_tab[t->idx]; 4760221474Snp for (i = t->idx; i < nfilters; i++, f++) { 4761221474Snp if (f->valid) { 4762221474Snp t->idx = i; 4763222509Snp t->l2tidx = f->l2t ? f->l2t->idx : 0; 4764222509Snp t->smtidx = f->smtidx; 4765222552Snp if (f->fs.hitcnts) 4766222552Snp t->hits = get_filter_hits(sc, t->idx); 4767222552Snp else 4768222552Snp t->hits = UINT64_MAX; 4769221474Snp t->fs = f->fs; 4770221474Snp 4771245274Snp goto done; 4772221474Snp } 4773221474Snp } 4774221474Snp 4775221474Snp t->idx = 0xffffffff; 4776245274Snpdone: 4777245274Snp end_synchronized_op(sc, LOCK_HELD); 4778221474Snp return (0); 4779221474Snp} 4780221474Snp 4781221474Snpstatic int 4782221474Snpset_filter(struct adapter *sc, struct t4_filter *t) 4783221474Snp{ 4784221474Snp unsigned int nfilters, nports; 4785221474Snp struct filter_entry *f; 4786245274Snp int i, rc; 4787221474Snp 4788245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setf"); 4789245274Snp if (rc) 4790245274Snp return (rc); 4791221474Snp 4792221474Snp nfilters = sc->tids.nftids; 4793221474Snp nports = sc->params.nports; 4794221474Snp 4795245274Snp if (nfilters == 0) { 4796245274Snp rc = ENOTSUP; 4797245274Snp goto done; 4798245274Snp } 4799221474Snp 4800245274Snp if (!(sc->flags & FULL_INIT_DONE)) { 4801245274Snp rc = EAGAIN; 4802245274Snp goto done; 4803245274Snp } 4804221474Snp 4805245274Snp if (t->idx >= nfilters) { 4806245274Snp rc = EINVAL; 4807245274Snp goto done; 4808245274Snp } 4809221474Snp 4810221474Snp /* Validate against the global filter mode */ 4811245274Snp if ((sc->filter_mode | fspec_to_fconf(&t->fs)) != sc->filter_mode) { 4812245274Snp rc = E2BIG; 4813245274Snp goto done; 4814245274Snp } 4815221474Snp 4816245274Snp if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) { 4817245274Snp rc = EINVAL; 4818245274Snp goto done; 4819245274Snp } 4820221474Snp 4821245274Snp if (t->fs.val.iport >= nports) { 4822245274Snp rc = EINVAL; 4823245274Snp goto done; 4824245274Snp } 4825221474Snp 4826221474Snp /* Can't specify an iq if not steering to it */ 4827245274Snp if (!t->fs.dirsteer && t->fs.iq) { 4828245274Snp rc = EINVAL; 4829245274Snp goto done; 4830245274Snp } 4831221474Snp 4832221474Snp /* IPv6 filter idx must be 4 aligned */ 4833221474Snp if (t->fs.type == 1 && 4834245274Snp ((t->idx & 0x3) || t->idx + 4 >= nfilters)) { 4835245274Snp rc = EINVAL; 4836245274Snp goto done; 4837245274Snp } 4838221474Snp 4839221474Snp if (sc->tids.ftid_tab == NULL) { 4840221474Snp KASSERT(sc->tids.ftids_in_use == 0, 4841221474Snp ("%s: no memory allocated but filters_in_use > 0", 4842221474Snp __func__)); 4843221474Snp 4844221474Snp sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) * 4845221474Snp nfilters, M_CXGBE, M_NOWAIT | M_ZERO); 4846245274Snp if (sc->tids.ftid_tab == NULL) { 4847245274Snp rc = ENOMEM; 4848245274Snp goto done; 4849245274Snp } 4850245274Snp mtx_init(&sc->tids.ftid_lock, "T4 filters", 0, MTX_DEF); 4851221474Snp } 4852221474Snp 4853221474Snp for (i = 0; i < 4; i++) { 4854221474Snp f = &sc->tids.ftid_tab[t->idx + i]; 4855221474Snp 4856245274Snp if (f->pending || f->valid) { 4857245274Snp rc = EBUSY; 4858245274Snp goto done; 4859245274Snp } 4860245274Snp if (f->locked) { 4861245274Snp rc = EPERM; 4862245274Snp goto done; 4863245274Snp } 4864221474Snp 4865221474Snp if (t->fs.type == 0) 4866221474Snp break; 4867221474Snp } 4868221474Snp 4869221474Snp f = &sc->tids.ftid_tab[t->idx]; 4870221474Snp f->fs = t->fs; 4871221474Snp 4872245274Snp rc = set_filter_wr(sc, t->idx); 4873245274Snpdone: 4874245274Snp end_synchronized_op(sc, 0); 4875245274Snp 4876245274Snp if (rc == 0) { 4877245274Snp mtx_lock(&sc->tids.ftid_lock); 4878245274Snp for (;;) { 4879245274Snp if (f->pending == 0) { 4880245274Snp rc = f->valid ? 0 : EIO; 4881245274Snp break; 4882245274Snp } 4883245274Snp 4884245274Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 4885245274Snp PCATCH, "t4setfw", 0)) { 4886245274Snp rc = EINPROGRESS; 4887245274Snp break; 4888245274Snp } 4889245274Snp } 4890245274Snp mtx_unlock(&sc->tids.ftid_lock); 4891245274Snp } 4892245274Snp return (rc); 4893221474Snp} 4894221474Snp 4895221474Snpstatic int 4896221474Snpdel_filter(struct adapter *sc, struct t4_filter *t) 4897221474Snp{ 4898221474Snp unsigned int nfilters; 4899221474Snp struct filter_entry *f; 4900245274Snp int rc; 4901221474Snp 4902245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4delf"); 4903245274Snp if (rc) 4904245274Snp return (rc); 4905221474Snp 4906221474Snp nfilters = sc->tids.nftids; 4907221474Snp 4908245274Snp if (nfilters == 0) { 4909245274Snp rc = ENOTSUP; 4910245274Snp goto done; 4911245274Snp } 4912221474Snp 4913221474Snp if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 || 4914245274Snp t->idx >= nfilters) { 4915245274Snp rc = EINVAL; 4916245274Snp goto done; 4917245274Snp } 4918221474Snp 4919245274Snp if (!(sc->flags & FULL_INIT_DONE)) { 4920245274Snp rc = EAGAIN; 4921245274Snp goto done; 4922245274Snp } 4923221474Snp 4924221474Snp f = &sc->tids.ftid_tab[t->idx]; 4925221474Snp 4926245274Snp if (f->pending) { 4927245274Snp rc = EBUSY; 4928245274Snp goto done; 4929245274Snp } 4930245274Snp if (f->locked) { 4931245274Snp rc = EPERM; 4932245274Snp goto done; 4933245274Snp } 4934221474Snp 4935221474Snp if (f->valid) { 4936221474Snp t->fs = f->fs; /* extra info for the caller */ 4937245274Snp rc = del_filter_wr(sc, t->idx); 4938221474Snp } 4939221474Snp 4940245274Snpdone: 4941245274Snp end_synchronized_op(sc, 0); 4942245274Snp 4943245274Snp if (rc == 0) { 4944245274Snp mtx_lock(&sc->tids.ftid_lock); 4945245274Snp for (;;) { 4946245274Snp if (f->pending == 0) { 4947245274Snp rc = f->valid ? EIO : 0; 4948245274Snp break; 4949245274Snp } 4950245274Snp 4951245274Snp if (mtx_sleep(&sc->tids.ftid_tab, &sc->tids.ftid_lock, 4952245274Snp PCATCH, "t4delfw", 0)) { 4953245274Snp rc = EINPROGRESS; 4954245274Snp break; 4955245274Snp } 4956245274Snp } 4957245274Snp mtx_unlock(&sc->tids.ftid_lock); 4958245274Snp } 4959245274Snp 4960245274Snp return (rc); 4961221474Snp} 4962221474Snp 4963221474Snpstatic void 4964222509Snpclear_filter(struct filter_entry *f) 4965221474Snp{ 4966222509Snp if (f->l2t) 4967222509Snp t4_l2t_release(f->l2t); 4968222509Snp 4969221474Snp bzero(f, sizeof (*f)); 4970221474Snp} 4971221474Snp 4972221474Snpstatic int 4973221474Snpset_filter_wr(struct adapter *sc, int fidx) 4974221474Snp{ 4975221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 4976237263Snp struct wrqe *wr; 4977221474Snp struct fw_filter_wr *fwr; 4978221474Snp unsigned int ftid; 4979221474Snp 4980245274Snp ASSERT_SYNCHRONIZED_OP(sc); 4981221474Snp 4982222509Snp if (f->fs.newdmac || f->fs.newvlan) { 4983222509Snp /* This filter needs an L2T entry; allocate one. */ 4984222509Snp f->l2t = t4_l2t_alloc_switching(sc->l2t); 4985222509Snp if (f->l2t == NULL) 4986222509Snp return (EAGAIN); 4987222509Snp if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport, 4988222509Snp f->fs.dmac)) { 4989222509Snp t4_l2t_release(f->l2t); 4990222509Snp f->l2t = NULL; 4991222509Snp return (ENOMEM); 4992222509Snp } 4993222509Snp } 4994221474Snp 4995221474Snp ftid = sc->tids.ftid_base + fidx; 4996221474Snp 4997237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 4998237263Snp if (wr == NULL) 4999221474Snp return (ENOMEM); 5000221474Snp 5001237263Snp fwr = wrtod(wr); 5002221474Snp bzero(fwr, sizeof (*fwr)); 5003221474Snp 5004221474Snp fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR)); 5005221474Snp fwr->len16_pkd = htobe32(FW_LEN16(*fwr)); 5006221474Snp fwr->tid_to_iq = 5007221474Snp htobe32(V_FW_FILTER_WR_TID(ftid) | 5008221474Snp V_FW_FILTER_WR_RQTYPE(f->fs.type) | 5009221474Snp V_FW_FILTER_WR_NOREPLY(0) | 5010221474Snp V_FW_FILTER_WR_IQ(f->fs.iq)); 5011221474Snp fwr->del_filter_to_l2tix = 5012221474Snp htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) | 5013221474Snp V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) | 5014221474Snp V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) | 5015221474Snp V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) | 5016221474Snp V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) | 5017221474Snp V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) | 5018221474Snp V_FW_FILTER_WR_DMAC(f->fs.newdmac) | 5019221474Snp V_FW_FILTER_WR_SMAC(f->fs.newsmac) | 5020221474Snp V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT || 5021221474Snp f->fs.newvlan == VLAN_REWRITE) | 5022221474Snp V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE || 5023221474Snp f->fs.newvlan == VLAN_REWRITE) | 5024221474Snp V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) | 5025221474Snp V_FW_FILTER_WR_TXCHAN(f->fs.eport) | 5026221474Snp V_FW_FILTER_WR_PRIO(f->fs.prio) | 5027222509Snp V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0)); 5028221474Snp fwr->ethtype = htobe16(f->fs.val.ethtype); 5029221474Snp fwr->ethtypem = htobe16(f->fs.mask.ethtype); 5030221474Snp fwr->frag_to_ovlan_vldm = 5031221474Snp (V_FW_FILTER_WR_FRAG(f->fs.val.frag) | 5032221474Snp V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) | 5033228561Snp V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) | 5034228561Snp V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.vnic_vld) | 5035228561Snp V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) | 5036228561Snp V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.vnic_vld)); 5037221474Snp fwr->smac_sel = 0; 5038221474Snp fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) | 5039228561Snp V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id)); 5040221474Snp fwr->maci_to_matchtypem = 5041221474Snp htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) | 5042221474Snp V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) | 5043221474Snp V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) | 5044221474Snp V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) | 5045221474Snp V_FW_FILTER_WR_PORT(f->fs.val.iport) | 5046221474Snp V_FW_FILTER_WR_PORTM(f->fs.mask.iport) | 5047221474Snp V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) | 5048221474Snp V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype)); 5049221474Snp fwr->ptcl = f->fs.val.proto; 5050221474Snp fwr->ptclm = f->fs.mask.proto; 5051221474Snp fwr->ttyp = f->fs.val.tos; 5052221474Snp fwr->ttypm = f->fs.mask.tos; 5053228561Snp fwr->ivlan = htobe16(f->fs.val.vlan); 5054228561Snp fwr->ivlanm = htobe16(f->fs.mask.vlan); 5055228561Snp fwr->ovlan = htobe16(f->fs.val.vnic); 5056228561Snp fwr->ovlanm = htobe16(f->fs.mask.vnic); 5057221474Snp bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip)); 5058221474Snp bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm)); 5059221474Snp bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip)); 5060221474Snp bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm)); 5061221474Snp fwr->lp = htobe16(f->fs.val.dport); 5062221474Snp fwr->lpm = htobe16(f->fs.mask.dport); 5063221474Snp fwr->fp = htobe16(f->fs.val.sport); 5064221474Snp fwr->fpm = htobe16(f->fs.mask.sport); 5065221474Snp if (f->fs.newsmac) 5066221474Snp bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma)); 5067221474Snp 5068221474Snp f->pending = 1; 5069221474Snp sc->tids.ftids_in_use++; 5070228561Snp 5071237263Snp t4_wrq_tx(sc, wr); 5072228561Snp return (0); 5073221474Snp} 5074221474Snp 5075221474Snpstatic int 5076221474Snpdel_filter_wr(struct adapter *sc, int fidx) 5077221474Snp{ 5078221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 5079237263Snp struct wrqe *wr; 5080221474Snp struct fw_filter_wr *fwr; 5081228561Snp unsigned int ftid; 5082221474Snp 5083221474Snp ftid = sc->tids.ftid_base + fidx; 5084221474Snp 5085237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 5086237263Snp if (wr == NULL) 5087221474Snp return (ENOMEM); 5088237263Snp fwr = wrtod(wr); 5089221474Snp bzero(fwr, sizeof (*fwr)); 5090221474Snp 5091228561Snp t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id); 5092221474Snp 5093221474Snp f->pending = 1; 5094237263Snp t4_wrq_tx(sc, wr); 5095228561Snp return (0); 5096221474Snp} 5097221474Snp 5098239338Snpint 5099239338Snpt4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 5100221474Snp{ 5101228561Snp struct adapter *sc = iq->adapter; 5102228561Snp const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1); 5103221474Snp unsigned int idx = GET_TID(rpl); 5104221474Snp 5105228561Snp KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__, 5106228561Snp rss->opcode)); 5107228561Snp 5108221474Snp if (idx >= sc->tids.ftid_base && 5109221474Snp (idx -= sc->tids.ftid_base) < sc->tids.nftids) { 5110221474Snp unsigned int rc = G_COOKIE(rpl->cookie); 5111221474Snp struct filter_entry *f = &sc->tids.ftid_tab[idx]; 5112221474Snp 5113245274Snp mtx_lock(&sc->tids.ftid_lock); 5114228561Snp if (rc == FW_FILTER_WR_FLT_ADDED) { 5115245274Snp KASSERT(f->pending, ("%s: filter[%u] isn't pending.", 5116245274Snp __func__, idx)); 5117221474Snp f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff; 5118221474Snp f->pending = 0; /* asynchronous setup completed */ 5119221474Snp f->valid = 1; 5120231120Snp } else { 5121231120Snp if (rc != FW_FILTER_WR_FLT_DELETED) { 5122231120Snp /* Add or delete failed, display an error */ 5123231120Snp log(LOG_ERR, 5124231120Snp "filter %u setup failed with error %u\n", 5125231120Snp idx, rc); 5126231120Snp } 5127228561Snp 5128231120Snp clear_filter(f); 5129231120Snp sc->tids.ftids_in_use--; 5130221474Snp } 5131245274Snp wakeup(&sc->tids.ftid_tab); 5132245274Snp mtx_unlock(&sc->tids.ftid_lock); 5133221474Snp } 5134228561Snp 5135228561Snp return (0); 5136221474Snp} 5137221474Snp 5138222973Snpstatic int 5139222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt) 5140222973Snp{ 5141245274Snp int rc; 5142222973Snp 5143222973Snp if (cntxt->cid > M_CTXTQID) 5144245274Snp return (EINVAL); 5145222973Snp 5146222973Snp if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS && 5147222973Snp cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM) 5148245274Snp return (EINVAL); 5149222973Snp 5150222973Snp if (sc->flags & FW_OK) { 5151245274Snp rc = begin_synchronized_op(sc, NULL, HOLD_LOCK, "t4ctxt"); 5152245274Snp if (rc == 0) { 5153245274Snp rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, 5154245274Snp cntxt->mem_id, &cntxt->data[0]); 5155245274Snp end_synchronized_op(sc, LOCK_HELD); 5156245274Snp if (rc == 0) 5157245274Snp return (0); 5158245274Snp } 5159222973Snp } 5160222973Snp 5161245274Snp /* 5162245274Snp * Read via firmware failed or wasn't even attempted. Read directly via 5163245274Snp * the backdoor. 5164245274Snp */ 5165245274Snp rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id, 5166245274Snp &cntxt->data[0]); 5167245274Snp return (rc); 5168245274Snp} 5169222973Snp 5170245274Snpstatic int 5171245274Snpload_fw(struct adapter *sc, struct t4_data *fw) 5172245274Snp{ 5173245274Snp int rc; 5174245274Snp uint8_t *fw_data; 5175245274Snp 5176245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4ldfw"); 5177245274Snp if (rc) 5178245274Snp return (rc); 5179245274Snp 5180245274Snp if (sc->flags & FULL_INIT_DONE) { 5181245274Snp rc = EBUSY; 5182245274Snp goto done; 5183222973Snp } 5184222973Snp 5185245274Snp fw_data = malloc(fw->len, M_CXGBE, M_WAITOK); 5186245274Snp if (fw_data == NULL) { 5187245274Snp rc = ENOMEM; 5188245274Snp goto done; 5189245274Snp } 5190245274Snp 5191245274Snp rc = copyin(fw->data, fw_data, fw->len); 5192245274Snp if (rc == 0) 5193245274Snp rc = -t4_load_fw(sc, fw_data, fw->len); 5194245274Snp 5195245274Snp free(fw_data, M_CXGBE); 5196245274Snpdone: 5197245274Snp end_synchronized_op(sc, 0); 5198222973Snp return (rc); 5199222973Snp} 5200222973Snp 5201228561Snpstatic int 5202228561Snpread_card_mem(struct adapter *sc, struct t4_mem_range *mr) 5203228561Snp{ 5204228561Snp uint32_t base, size, lo, hi, win, off, remaining, i, n; 5205228561Snp uint32_t *buf, *b; 5206228561Snp int rc; 5207228561Snp 5208228561Snp /* reads are in multiples of 32 bits */ 5209228561Snp if (mr->addr & 3 || mr->len & 3 || mr->len == 0) 5210228561Snp return (EINVAL); 5211228561Snp 5212228561Snp /* 5213228561Snp * We don't want to deal with potential holes so we mandate that the 5214228561Snp * requested region must lie entirely within one of the 3 memories. 5215228561Snp */ 5216228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 5217228561Snp if (lo & F_EDRAM0_ENABLE) { 5218228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 5219228561Snp base = G_EDRAM0_BASE(hi) << 20; 5220228561Snp size = G_EDRAM0_SIZE(hi) << 20; 5221228561Snp if (size > 0 && 5222228561Snp mr->addr >= base && mr->addr < base + size && 5223228561Snp mr->addr + mr->len <= base + size) 5224228561Snp goto proceed; 5225228561Snp } 5226228561Snp if (lo & F_EDRAM1_ENABLE) { 5227228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 5228228561Snp base = G_EDRAM1_BASE(hi) << 20; 5229228561Snp size = G_EDRAM1_SIZE(hi) << 20; 5230228561Snp if (size > 0 && 5231228561Snp mr->addr >= base && mr->addr < base + size && 5232228561Snp mr->addr + mr->len <= base + size) 5233228561Snp goto proceed; 5234228561Snp } 5235228561Snp if (lo & F_EXT_MEM_ENABLE) { 5236228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 5237228561Snp base = G_EXT_MEM_BASE(hi) << 20; 5238228561Snp size = G_EXT_MEM_SIZE(hi) << 20; 5239228561Snp if (size > 0 && 5240228561Snp mr->addr >= base && mr->addr < base + size && 5241228561Snp mr->addr + mr->len <= base + size) 5242228561Snp goto proceed; 5243228561Snp } 5244228561Snp return (ENXIO); 5245228561Snp 5246228561Snpproceed: 5247228561Snp buf = b = malloc(mr->len, M_CXGBE, M_WAITOK); 5248228561Snp 5249228561Snp /* 5250228561Snp * Position the PCIe window (we use memwin2) to the 16B aligned area 5251228561Snp * just at/before the requested region. 5252228561Snp */ 5253228561Snp win = mr->addr & ~0xf; 5254228561Snp off = mr->addr - win; /* offset of the requested region in the win */ 5255228561Snp remaining = mr->len; 5256228561Snp 5257228561Snp while (remaining) { 5258228561Snp t4_write_reg(sc, 5259228561Snp PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2), win); 5260228561Snp t4_read_reg(sc, 5261228561Snp PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2)); 5262228561Snp 5263228561Snp /* number of bytes that we'll copy in the inner loop */ 5264228561Snp n = min(remaining, MEMWIN2_APERTURE - off); 5265228561Snp 5266228561Snp for (i = 0; i < n; i += 4, remaining -= 4) 5267228561Snp *b++ = t4_read_reg(sc, MEMWIN2_BASE + off + i); 5268228561Snp 5269228561Snp win += MEMWIN2_APERTURE; 5270228561Snp off = 0; 5271228561Snp } 5272228561Snp 5273228561Snp rc = copyout(buf, mr->data, mr->len); 5274228561Snp free(buf, M_CXGBE); 5275228561Snp 5276228561Snp return (rc); 5277228561Snp} 5278228561Snp 5279241399Snpstatic int 5280241399Snpread_i2c(struct adapter *sc, struct t4_i2c_data *i2cd) 5281241399Snp{ 5282241399Snp int rc; 5283241399Snp 5284241399Snp if (i2cd->len == 0 || i2cd->port_id >= sc->params.nports) 5285241399Snp return (EINVAL); 5286241399Snp 5287241399Snp if (i2cd->len > 1) { 5288241399Snp /* XXX: need fw support for longer reads in one go */ 5289241399Snp return (ENOTSUP); 5290241399Snp } 5291241399Snp 5292245274Snp rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4i2crd"); 5293245274Snp if (rc) 5294245274Snp return (rc); 5295241399Snp rc = -t4_i2c_rd(sc, sc->mbox, i2cd->port_id, i2cd->dev_addr, 5296241399Snp i2cd->offset, &i2cd->data[0]); 5297245274Snp end_synchronized_op(sc, 0); 5298241399Snp 5299241399Snp return (rc); 5300241399Snp} 5301241399Snp 5302218792Snpint 5303218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap) 5304218792Snp{ 5305222102Snp int i; 5306218792Snp 5307222102Snp return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0); 5308218792Snp} 5309218792Snp 5310218792Snpint 5311218792Snpt4_os_pci_save_state(struct adapter *sc) 5312218792Snp{ 5313218792Snp device_t dev; 5314218792Snp struct pci_devinfo *dinfo; 5315218792Snp 5316218792Snp dev = sc->dev; 5317218792Snp dinfo = device_get_ivars(dev); 5318218792Snp 5319218792Snp pci_cfg_save(dev, dinfo, 0); 5320218792Snp return (0); 5321218792Snp} 5322218792Snp 5323218792Snpint 5324218792Snpt4_os_pci_restore_state(struct adapter *sc) 5325218792Snp{ 5326218792Snp device_t dev; 5327218792Snp struct pci_devinfo *dinfo; 5328218792Snp 5329218792Snp dev = sc->dev; 5330218792Snp dinfo = device_get_ivars(dev); 5331218792Snp 5332218792Snp pci_cfg_restore(dev, dinfo); 5333218792Snp return (0); 5334218792Snp} 5335219299Snp 5336218792Snpvoid 5337218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx) 5338218792Snp{ 5339218792Snp struct port_info *pi = sc->port[idx]; 5340218792Snp static const char *mod_str[] = { 5341220232Snp NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM" 5342218792Snp }; 5343218792Snp 5344218792Snp if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 5345218792Snp if_printf(pi->ifp, "transceiver unplugged.\n"); 5346220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) 5347220232Snp if_printf(pi->ifp, "unknown transceiver inserted.\n"); 5348220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) 5349220232Snp if_printf(pi->ifp, "unsupported transceiver inserted.\n"); 5350240452Snp else if (pi->mod_type > 0 && pi->mod_type < nitems(mod_str)) { 5351218792Snp if_printf(pi->ifp, "%s transceiver inserted.\n", 5352218792Snp mod_str[pi->mod_type]); 5353219299Snp } else { 5354219299Snp if_printf(pi->ifp, "transceiver (type %d) inserted.\n", 5355219299Snp pi->mod_type); 5356219299Snp } 5357218792Snp} 5358218792Snp 5359218792Snpvoid 5360218792Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat) 5361218792Snp{ 5362218792Snp struct port_info *pi = sc->port[idx]; 5363218792Snp struct ifnet *ifp = pi->ifp; 5364218792Snp 5365218792Snp if (link_stat) { 5366218792Snp ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed); 5367218792Snp if_link_state_change(ifp, LINK_STATE_UP); 5368218792Snp } else 5369218792Snp if_link_state_change(ifp, LINK_STATE_DOWN); 5370218792Snp} 5371218792Snp 5372228561Snpvoid 5373228561Snpt4_iterate(void (*func)(struct adapter *, void *), void *arg) 5374228561Snp{ 5375228561Snp struct adapter *sc; 5376228561Snp 5377228561Snp mtx_lock(&t4_list_lock); 5378228561Snp SLIST_FOREACH(sc, &t4_list, link) { 5379228561Snp /* 5380228561Snp * func should not make any assumptions about what state sc is 5381228561Snp * in - the only guarantee is that sc->sc_lock is a valid lock. 5382228561Snp */ 5383228561Snp func(sc, arg); 5384228561Snp } 5385228561Snp mtx_unlock(&t4_list_lock); 5386228561Snp} 5387228561Snp 5388218792Snpstatic int 5389218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td) 5390218792Snp{ 5391218792Snp return (0); 5392218792Snp} 5393218792Snp 5394218792Snpstatic int 5395218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td) 5396218792Snp{ 5397218792Snp return (0); 5398218792Snp} 5399218792Snp 5400218792Snpstatic int 5401218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag, 5402218792Snp struct thread *td) 5403218792Snp{ 5404218792Snp int rc; 5405218792Snp struct adapter *sc = dev->si_drv1; 5406218792Snp 5407218792Snp rc = priv_check(td, PRIV_DRIVER); 5408218792Snp if (rc != 0) 5409218792Snp return (rc); 5410218792Snp 5411218792Snp switch (cmd) { 5412220410Snp case CHELSIO_T4_GETREG: { 5413220410Snp struct t4_reg *edata = (struct t4_reg *)data; 5414220410Snp 5415218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 5416218792Snp return (EFAULT); 5417220410Snp 5418220410Snp if (edata->size == 4) 5419220410Snp edata->val = t4_read_reg(sc, edata->addr); 5420220410Snp else if (edata->size == 8) 5421220410Snp edata->val = t4_read_reg64(sc, edata->addr); 5422220410Snp else 5423220410Snp return (EINVAL); 5424220410Snp 5425218792Snp break; 5426218792Snp } 5427220410Snp case CHELSIO_T4_SETREG: { 5428220410Snp struct t4_reg *edata = (struct t4_reg *)data; 5429220410Snp 5430218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 5431218792Snp return (EFAULT); 5432220410Snp 5433220410Snp if (edata->size == 4) { 5434220410Snp if (edata->val & 0xffffffff00000000) 5435220410Snp return (EINVAL); 5436220410Snp t4_write_reg(sc, edata->addr, (uint32_t) edata->val); 5437220410Snp } else if (edata->size == 8) 5438220410Snp t4_write_reg64(sc, edata->addr, edata->val); 5439220410Snp else 5440220410Snp return (EINVAL); 5441218792Snp break; 5442218792Snp } 5443218792Snp case CHELSIO_T4_REGDUMP: { 5444218792Snp struct t4_regdump *regs = (struct t4_regdump *)data; 5445218792Snp int reglen = T4_REGDUMP_SIZE; 5446218792Snp uint8_t *buf; 5447218792Snp 5448218792Snp if (regs->len < reglen) { 5449218792Snp regs->len = reglen; /* hint to the caller */ 5450218792Snp return (ENOBUFS); 5451218792Snp } 5452218792Snp 5453218792Snp regs->len = reglen; 5454218792Snp buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO); 5455218792Snp t4_get_regs(sc, regs, buf); 5456218792Snp rc = copyout(buf, regs->data, reglen); 5457218792Snp free(buf, M_CXGBE); 5458218792Snp break; 5459218792Snp } 5460221474Snp case CHELSIO_T4_GET_FILTER_MODE: 5461221474Snp rc = get_filter_mode(sc, (uint32_t *)data); 5462221474Snp break; 5463221474Snp case CHELSIO_T4_SET_FILTER_MODE: 5464221474Snp rc = set_filter_mode(sc, *(uint32_t *)data); 5465221474Snp break; 5466221474Snp case CHELSIO_T4_GET_FILTER: 5467221474Snp rc = get_filter(sc, (struct t4_filter *)data); 5468221474Snp break; 5469221474Snp case CHELSIO_T4_SET_FILTER: 5470221474Snp rc = set_filter(sc, (struct t4_filter *)data); 5471221474Snp break; 5472221474Snp case CHELSIO_T4_DEL_FILTER: 5473221474Snp rc = del_filter(sc, (struct t4_filter *)data); 5474221474Snp break; 5475222973Snp case CHELSIO_T4_GET_SGE_CONTEXT: 5476222973Snp rc = get_sge_context(sc, (struct t4_sge_context *)data); 5477222973Snp break; 5478245274Snp case CHELSIO_T4_LOAD_FW: 5479245274Snp rc = load_fw(sc, (struct t4_data *)data); 5480228561Snp break; 5481228561Snp case CHELSIO_T4_GET_MEM: 5482228561Snp rc = read_card_mem(sc, (struct t4_mem_range *)data); 5483228561Snp break; 5484241399Snp case CHELSIO_T4_GET_I2C: 5485241399Snp rc = read_i2c(sc, (struct t4_i2c_data *)data); 5486241399Snp break; 5487241409Snp case CHELSIO_T4_CLEAR_STATS: { 5488241409Snp u_int port_id = *(uint32_t *)data; 5489241409Snp 5490241409Snp if (port_id >= sc->params.nports) 5491241409Snp return (EINVAL); 5492241409Snp 5493241409Snp t4_clr_port_stats(sc, port_id); 5494241409Snp break; 5495241409Snp } 5496218792Snp default: 5497218792Snp rc = EINVAL; 5498218792Snp } 5499218792Snp 5500218792Snp return (rc); 5501218792Snp} 5502218792Snp 5503237263Snp#ifdef TCP_OFFLOAD 5504219392Snpstatic int 5505228561Snptoe_capability(struct port_info *pi, int enable) 5506228561Snp{ 5507228561Snp int rc; 5508228561Snp struct adapter *sc = pi->adapter; 5509228561Snp 5510245274Snp ASSERT_SYNCHRONIZED_OP(sc); 5511228561Snp 5512228561Snp if (!is_offload(sc)) 5513228561Snp return (ENODEV); 5514228561Snp 5515228561Snp if (enable) { 5516237263Snp if (!(sc->flags & FULL_INIT_DONE)) { 5517245274Snp rc = cxgbe_init_synchronized(pi); 5518245274Snp if (rc) 5519245274Snp return (rc); 5520237263Snp } 5521237263Snp 5522228561Snp if (isset(&sc->offload_map, pi->port_id)) 5523228561Snp return (0); 5524228561Snp 5525237263Snp if (!(sc->flags & TOM_INIT_DONE)) { 5526237263Snp rc = t4_activate_uld(sc, ULD_TOM); 5527237263Snp if (rc == EAGAIN) { 5528237263Snp log(LOG_WARNING, 5529237263Snp "You must kldload t4_tom.ko before trying " 5530237263Snp "to enable TOE on a cxgbe interface.\n"); 5531237263Snp } 5532228561Snp if (rc != 0) 5533228561Snp return (rc); 5534237263Snp KASSERT(sc->tom_softc != NULL, 5535237263Snp ("%s: TOM activated but softc NULL", __func__)); 5536237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 5537237263Snp ("%s: TOM activated but flag not set", __func__)); 5538228561Snp } 5539228561Snp 5540228561Snp setbit(&sc->offload_map, pi->port_id); 5541228561Snp } else { 5542228561Snp if (!isset(&sc->offload_map, pi->port_id)) 5543228561Snp return (0); 5544228561Snp 5545237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 5546237263Snp ("%s: TOM never initialized?", __func__)); 5547228561Snp clrbit(&sc->offload_map, pi->port_id); 5548228561Snp } 5549228561Snp 5550228561Snp return (0); 5551228561Snp} 5552228561Snp 5553228561Snp/* 5554228561Snp * Add an upper layer driver to the global list. 5555228561Snp */ 5556228561Snpint 5557228561Snpt4_register_uld(struct uld_info *ui) 5558228561Snp{ 5559228561Snp int rc = 0; 5560228561Snp struct uld_info *u; 5561228561Snp 5562228561Snp mtx_lock(&t4_uld_list_lock); 5563228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 5564228561Snp if (u->uld_id == ui->uld_id) { 5565228561Snp rc = EEXIST; 5566228561Snp goto done; 5567228561Snp } 5568228561Snp } 5569228561Snp 5570228561Snp SLIST_INSERT_HEAD(&t4_uld_list, ui, link); 5571228561Snp ui->refcount = 0; 5572228561Snpdone: 5573228561Snp mtx_unlock(&t4_uld_list_lock); 5574228561Snp return (rc); 5575228561Snp} 5576228561Snp 5577228561Snpint 5578228561Snpt4_unregister_uld(struct uld_info *ui) 5579228561Snp{ 5580228561Snp int rc = EINVAL; 5581228561Snp struct uld_info *u; 5582228561Snp 5583228561Snp mtx_lock(&t4_uld_list_lock); 5584228561Snp 5585228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 5586228561Snp if (u == ui) { 5587228561Snp if (ui->refcount > 0) { 5588228561Snp rc = EBUSY; 5589228561Snp goto done; 5590228561Snp } 5591228561Snp 5592228561Snp SLIST_REMOVE(&t4_uld_list, ui, uld_info, link); 5593228561Snp rc = 0; 5594228561Snp goto done; 5595228561Snp } 5596228561Snp } 5597228561Snpdone: 5598228561Snp mtx_unlock(&t4_uld_list_lock); 5599228561Snp return (rc); 5600228561Snp} 5601228561Snp 5602237263Snpint 5603237263Snpt4_activate_uld(struct adapter *sc, int id) 5604228561Snp{ 5605228561Snp int rc = EAGAIN; 5606228561Snp struct uld_info *ui; 5607228561Snp 5608245274Snp ASSERT_SYNCHRONIZED_OP(sc); 5609245274Snp 5610228561Snp mtx_lock(&t4_uld_list_lock); 5611228561Snp 5612228561Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 5613228561Snp if (ui->uld_id == id) { 5614237263Snp rc = ui->activate(sc); 5615237263Snp if (rc == 0) 5616228561Snp ui->refcount++; 5617228561Snp goto done; 5618228561Snp } 5619228561Snp } 5620228561Snpdone: 5621228561Snp mtx_unlock(&t4_uld_list_lock); 5622228561Snp 5623228561Snp return (rc); 5624228561Snp} 5625228561Snp 5626237263Snpint 5627237263Snpt4_deactivate_uld(struct adapter *sc, int id) 5628228561Snp{ 5629237263Snp int rc = EINVAL; 5630237263Snp struct uld_info *ui; 5631228561Snp 5632245274Snp ASSERT_SYNCHRONIZED_OP(sc); 5633245274Snp 5634228561Snp mtx_lock(&t4_uld_list_lock); 5635228561Snp 5636237263Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 5637237263Snp if (ui->uld_id == id) { 5638237263Snp rc = ui->deactivate(sc); 5639237263Snp if (rc == 0) 5640237263Snp ui->refcount--; 5641237263Snp goto done; 5642237263Snp } 5643228561Snp } 5644228561Snpdone: 5645228561Snp mtx_unlock(&t4_uld_list_lock); 5646228561Snp 5647228561Snp return (rc); 5648228561Snp} 5649228561Snp#endif 5650228561Snp 5651228561Snp/* 5652228561Snp * Come up with reasonable defaults for some of the tunables, provided they're 5653228561Snp * not set by the user (in which case we'll use the values as is). 5654228561Snp */ 5655228561Snpstatic void 5656228561Snptweak_tunables(void) 5657228561Snp{ 5658228561Snp int nc = mp_ncpus; /* our snapshot of the number of CPUs */ 5659228561Snp 5660228561Snp if (t4_ntxq10g < 1) 5661228561Snp t4_ntxq10g = min(nc, NTXQ_10G); 5662228561Snp 5663228561Snp if (t4_ntxq1g < 1) 5664228561Snp t4_ntxq1g = min(nc, NTXQ_1G); 5665228561Snp 5666228561Snp if (t4_nrxq10g < 1) 5667228561Snp t4_nrxq10g = min(nc, NRXQ_10G); 5668228561Snp 5669228561Snp if (t4_nrxq1g < 1) 5670228561Snp t4_nrxq1g = min(nc, NRXQ_1G); 5671228561Snp 5672237263Snp#ifdef TCP_OFFLOAD 5673228561Snp if (t4_nofldtxq10g < 1) 5674228561Snp t4_nofldtxq10g = min(nc, NOFLDTXQ_10G); 5675228561Snp 5676228561Snp if (t4_nofldtxq1g < 1) 5677228561Snp t4_nofldtxq1g = min(nc, NOFLDTXQ_1G); 5678228561Snp 5679228561Snp if (t4_nofldrxq10g < 1) 5680228561Snp t4_nofldrxq10g = min(nc, NOFLDRXQ_10G); 5681228561Snp 5682228561Snp if (t4_nofldrxq1g < 1) 5683228561Snp t4_nofldrxq1g = min(nc, NOFLDRXQ_1G); 5684238028Snp 5685238028Snp if (t4_toecaps_allowed == -1) 5686238028Snp t4_toecaps_allowed = FW_CAPS_CONFIG_TOE; 5687238028Snp#else 5688238028Snp if (t4_toecaps_allowed == -1) 5689238028Snp t4_toecaps_allowed = 0; 5690228561Snp#endif 5691228561Snp 5692228561Snp if (t4_tmr_idx_10g < 0 || t4_tmr_idx_10g >= SGE_NTIMERS) 5693228561Snp t4_tmr_idx_10g = TMR_IDX_10G; 5694228561Snp 5695228561Snp if (t4_pktc_idx_10g < -1 || t4_pktc_idx_10g >= SGE_NCOUNTERS) 5696228561Snp t4_pktc_idx_10g = PKTC_IDX_10G; 5697228561Snp 5698228561Snp if (t4_tmr_idx_1g < 0 || t4_tmr_idx_1g >= SGE_NTIMERS) 5699228561Snp t4_tmr_idx_1g = TMR_IDX_1G; 5700228561Snp 5701228561Snp if (t4_pktc_idx_1g < -1 || t4_pktc_idx_1g >= SGE_NCOUNTERS) 5702228561Snp t4_pktc_idx_1g = PKTC_IDX_1G; 5703228561Snp 5704228561Snp if (t4_qsize_txq < 128) 5705228561Snp t4_qsize_txq = 128; 5706228561Snp 5707228561Snp if (t4_qsize_rxq < 128) 5708228561Snp t4_qsize_rxq = 128; 5709228561Snp while (t4_qsize_rxq & 7) 5710228561Snp t4_qsize_rxq++; 5711228561Snp 5712228561Snp t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX; 5713228561Snp} 5714228561Snp 5715228561Snpstatic int 5716219392Snpt4_mod_event(module_t mod, int cmd, void *arg) 5717219392Snp{ 5718228561Snp int rc = 0; 5719219392Snp 5720228561Snp switch (cmd) { 5721228561Snp case MOD_LOAD: 5722219392Snp t4_sge_modload(); 5723228561Snp mtx_init(&t4_list_lock, "T4 adapters", 0, MTX_DEF); 5724228561Snp SLIST_INIT(&t4_list); 5725237263Snp#ifdef TCP_OFFLOAD 5726228561Snp mtx_init(&t4_uld_list_lock, "T4 ULDs", 0, MTX_DEF); 5727228561Snp SLIST_INIT(&t4_uld_list); 5728228561Snp#endif 5729228561Snp tweak_tunables(); 5730228561Snp break; 5731219392Snp 5732228561Snp case MOD_UNLOAD: 5733237263Snp#ifdef TCP_OFFLOAD 5734228561Snp mtx_lock(&t4_uld_list_lock); 5735228561Snp if (!SLIST_EMPTY(&t4_uld_list)) { 5736228561Snp rc = EBUSY; 5737228561Snp mtx_unlock(&t4_uld_list_lock); 5738228561Snp break; 5739228561Snp } 5740228561Snp mtx_unlock(&t4_uld_list_lock); 5741228561Snp mtx_destroy(&t4_uld_list_lock); 5742228561Snp#endif 5743228561Snp mtx_lock(&t4_list_lock); 5744228561Snp if (!SLIST_EMPTY(&t4_list)) { 5745228561Snp rc = EBUSY; 5746228561Snp mtx_unlock(&t4_list_lock); 5747228561Snp break; 5748228561Snp } 5749228561Snp mtx_unlock(&t4_list_lock); 5750228561Snp mtx_destroy(&t4_list_lock); 5751228561Snp break; 5752228561Snp } 5753228561Snp 5754228561Snp return (rc); 5755219392Snp} 5756219392Snp 5757218792Snpstatic devclass_t t4_devclass; 5758218792Snpstatic devclass_t cxgbe_devclass; 5759218792Snp 5760219392SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, t4_mod_event, 0); 5761218792SnpMODULE_VERSION(t4nex, 1); 5762218792Snp 5763218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0); 5764218792SnpMODULE_VERSION(cxgbe, 1); 5765