t4_main.c revision 239338
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 239338 2012-08-16 20:15:29Z 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_locked(struct port_info *); 288218792Snpstatic int cxgbe_init_synchronized(struct port_info *); 289218792Snpstatic int cxgbe_uninit_locked(struct port_info *); 290218792Snpstatic int cxgbe_uninit_synchronized(struct port_info *); 291228561Snpstatic int adapter_full_init(struct adapter *); 292228561Snpstatic int adapter_full_uninit(struct adapter *); 293228561Snpstatic int port_full_init(struct port_info *); 294228561Snpstatic int port_full_uninit(struct port_info *); 295228561Snpstatic void quiesce_eq(struct adapter *, struct sge_eq *); 296228561Snpstatic void quiesce_iq(struct adapter *, struct sge_iq *); 297228561Snpstatic void quiesce_fl(struct adapter *, struct sge_fl *); 298218792Snpstatic int t4_alloc_irq(struct adapter *, struct irq *, int rid, 299228561Snp driver_intr_t *, void *, char *); 300218792Snpstatic int t4_free_irq(struct adapter *, struct irq *); 301218792Snpstatic void reg_block_dump(struct adapter *, uint8_t *, unsigned int, 302218792Snp unsigned int); 303218792Snpstatic void t4_get_regs(struct adapter *, struct t4_regdump *, uint8_t *); 304218792Snpstatic void cxgbe_tick(void *); 305237263Snpstatic void cxgbe_vlan_config(void *, struct ifnet *, uint16_t); 306228561Snpstatic int cpl_not_handled(struct sge_iq *, const struct rss_header *, 307228561Snp struct mbuf *); 308237263Snpstatic int an_not_handled(struct sge_iq *, const struct rsp_ctrl *); 309239336Snpstatic int fw_msg_not_handled(struct adapter *, const __be64 *); 310218792Snpstatic int t4_sysctls(struct adapter *); 311218792Snpstatic int cxgbe_sysctls(struct port_info *); 312219436Snpstatic int sysctl_int_array(SYSCTL_HANDLER_ARGS); 313228561Snpstatic int sysctl_bitfield(SYSCTL_HANDLER_ARGS); 314218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS); 315218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS); 316218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS); 317218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS); 318218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS); 319231115Snp#ifdef SBUF_DRAIN 320228561Snpstatic int sysctl_cctrl(SYSCTL_HANDLER_ARGS); 321228561Snpstatic int sysctl_cpl_stats(SYSCTL_HANDLER_ARGS); 322228561Snpstatic int sysctl_ddp_stats(SYSCTL_HANDLER_ARGS); 323222551Snpstatic int sysctl_devlog(SYSCTL_HANDLER_ARGS); 324228561Snpstatic int sysctl_fcoe_stats(SYSCTL_HANDLER_ARGS); 325228561Snpstatic int sysctl_hw_sched(SYSCTL_HANDLER_ARGS); 326228561Snpstatic int sysctl_lb_stats(SYSCTL_HANDLER_ARGS); 327228561Snpstatic int sysctl_meminfo(SYSCTL_HANDLER_ARGS); 328228561Snpstatic int sysctl_path_mtus(SYSCTL_HANDLER_ARGS); 329228561Snpstatic int sysctl_pm_stats(SYSCTL_HANDLER_ARGS); 330228561Snpstatic int sysctl_rdma_stats(SYSCTL_HANDLER_ARGS); 331228561Snpstatic int sysctl_tcp_stats(SYSCTL_HANDLER_ARGS); 332228561Snpstatic int sysctl_tids(SYSCTL_HANDLER_ARGS); 333228561Snpstatic int sysctl_tp_err_stats(SYSCTL_HANDLER_ARGS); 334228561Snpstatic int sysctl_tx_rate(SYSCTL_HANDLER_ARGS); 335231115Snp#endif 336219286Snpstatic inline void txq_start(struct ifnet *, struct sge_txq *); 337221474Snpstatic uint32_t fconf_to_mode(uint32_t); 338221474Snpstatic uint32_t mode_to_fconf(uint32_t); 339221474Snpstatic uint32_t fspec_to_fconf(struct t4_filter_specification *); 340221474Snpstatic int get_filter_mode(struct adapter *, uint32_t *); 341221474Snpstatic int set_filter_mode(struct adapter *, uint32_t); 342222552Snpstatic inline uint64_t get_filter_hits(struct adapter *, uint32_t); 343221474Snpstatic int get_filter(struct adapter *, struct t4_filter *); 344221474Snpstatic int set_filter(struct adapter *, struct t4_filter *); 345221474Snpstatic int del_filter(struct adapter *, struct t4_filter *); 346222509Snpstatic void clear_filter(struct filter_entry *); 347221474Snpstatic int set_filter_wr(struct adapter *, int); 348221474Snpstatic int del_filter_wr(struct adapter *, int); 349222973Snpstatic int get_sge_context(struct adapter *, struct t4_sge_context *); 350228561Snpstatic int read_card_mem(struct adapter *, struct t4_mem_range *); 351237263Snp#ifdef TCP_OFFLOAD 352228561Snpstatic int toe_capability(struct port_info *, int); 353228561Snp#endif 354219392Snpstatic int t4_mod_event(module_t, int, void *); 355218792Snp 356218792Snpstruct t4_pciids { 357218792Snp uint16_t device; 358218792Snp char *desc; 359218792Snp} t4_pciids[] = { 360237587Snp {0xa000, "Chelsio Terminator 4 FPGA"}, 361237587Snp {0x4400, "Chelsio T440-dbg"}, 362237587Snp {0x4401, "Chelsio T420-CR"}, 363237587Snp {0x4402, "Chelsio T422-CR"}, 364237587Snp {0x4403, "Chelsio T440-CR"}, 365237587Snp {0x4404, "Chelsio T420-BCH"}, 366237587Snp {0x4405, "Chelsio T440-BCH"}, 367237587Snp {0x4406, "Chelsio T440-CH"}, 368237587Snp {0x4407, "Chelsio T420-SO"}, 369237587Snp {0x4408, "Chelsio T420-CX"}, 370237587Snp {0x4409, "Chelsio T420-BT"}, 371237587Snp {0x440a, "Chelsio T404-BT"}, 372218792Snp}; 373218792Snp 374237263Snp#ifdef TCP_OFFLOAD 375237263Snp/* 376237263Snp * service_iq() has an iq and needs the fl. Offset of fl from the iq should be 377237263Snp * exactly the same for both rxq and ofld_rxq. 378237263Snp */ 379237263SnpCTASSERT(offsetof(struct sge_ofld_rxq, iq) == offsetof(struct sge_rxq, iq)); 380228561SnpCTASSERT(offsetof(struct sge_ofld_rxq, fl) == offsetof(struct sge_rxq, fl)); 381228561Snp#endif 382228561Snp 383239336Snp/* No easy way to include t4_msg.h before adapter.h so we check this way */ 384239336SnpCTASSERT(ARRAY_SIZE(((struct adapter *)0)->cpl_handler) == NUM_CPL_CMDS); 385239336SnpCTASSERT(ARRAY_SIZE(((struct adapter *)0)->fw_msg_handler) == NUM_FW6_TYPES); 386239336Snp 387218792Snpstatic int 388218792Snpt4_probe(device_t dev) 389218792Snp{ 390218792Snp int i; 391218792Snp uint16_t v = pci_get_vendor(dev); 392218792Snp uint16_t d = pci_get_device(dev); 393237587Snp uint8_t f = pci_get_function(dev); 394218792Snp 395218792Snp if (v != PCI_VENDOR_ID_CHELSIO) 396218792Snp return (ENXIO); 397218792Snp 398237587Snp /* Attach only to PF0 of the FPGA */ 399237587Snp if (d == 0xa000 && f != 0) 400237587Snp return (ENXIO); 401237587Snp 402218792Snp for (i = 0; i < ARRAY_SIZE(t4_pciids); i++) { 403237587Snp if (d == t4_pciids[i].device) { 404218792Snp device_set_desc(dev, t4_pciids[i].desc); 405218792Snp return (BUS_PROBE_DEFAULT); 406218792Snp } 407218792Snp } 408218792Snp 409218792Snp return (ENXIO); 410218792Snp} 411218792Snp 412218792Snpstatic int 413218792Snpt4_attach(device_t dev) 414218792Snp{ 415218792Snp struct adapter *sc; 416218792Snp int rc = 0, i, n10g, n1g, rqidx, tqidx; 417218792Snp struct intrs_and_queues iaq; 418218792Snp struct sge *s; 419237263Snp#ifdef TCP_OFFLOAD 420228561Snp int ofld_rqidx, ofld_tqidx; 421228561Snp#endif 422218792Snp 423218792Snp sc = device_get_softc(dev); 424218792Snp sc->dev = dev; 425218792Snp 426218792Snp pci_enable_busmaster(dev); 427222085Snp if (pci_find_cap(dev, PCIY_EXPRESS, &i) == 0) { 428228561Snp uint32_t v; 429228561Snp 430222085Snp pci_set_max_read_req(dev, 4096); 431222085Snp v = pci_read_config(dev, i + PCIR_EXPRESS_DEVICE_CTL, 2); 432222085Snp v |= PCIM_EXP_CTL_RELAXED_ORD_ENABLE; 433222085Snp pci_write_config(dev, i + PCIR_EXPRESS_DEVICE_CTL, v, 2); 434222085Snp } 435222085Snp 436218792Snp snprintf(sc->lockname, sizeof(sc->lockname), "%s", 437218792Snp device_get_nameunit(dev)); 438218792Snp mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF); 439228561Snp mtx_lock(&t4_list_lock); 440228561Snp SLIST_INSERT_HEAD(&t4_list, sc, link); 441228561Snp mtx_unlock(&t4_list_lock); 442218792Snp 443228561Snp mtx_init(&sc->sfl_lock, "starving freelists", 0, MTX_DEF); 444228561Snp TAILQ_INIT(&sc->sfl); 445228561Snp callout_init(&sc->sfl_callout, CALLOUT_MPSAFE); 446228561Snp 447218792Snp rc = map_bars(sc); 448218792Snp if (rc != 0) 449218792Snp goto done; /* error message displayed already */ 450218792Snp 451237587Snp /* 452237587Snp * This is the real PF# to which we're attaching. Works from within PCI 453237587Snp * passthrough environments too, where pci_get_function() could return a 454237587Snp * different PF# depending on the passthrough configuration. We need to 455237587Snp * use the real PF# in all our communication with the firmware. 456237587Snp */ 457237587Snp sc->pf = G_SOURCEPF(t4_read_reg(sc, A_PL_WHOAMI)); 458237587Snp sc->mbox = sc->pf; 459237587Snp 460218792Snp memset(sc->chan_map, 0xff, sizeof(sc->chan_map)); 461237263Snp sc->an_handler = an_not_handled; 462228561Snp for (i = 0; i < ARRAY_SIZE(sc->cpl_handler); i++) 463228561Snp sc->cpl_handler[i] = cpl_not_handled; 464239336Snp for (i = 0; i < ARRAY_SIZE(sc->fw_msg_handler); i++) 465239336Snp sc->fw_msg_handler[i] = fw_msg_not_handled; 466239338Snp t4_register_cpl_handler(sc, CPL_SET_TCB_RPL, t4_filter_rpl); 467218792Snp 468218792Snp /* Prepare the adapter for operation */ 469218792Snp rc = -t4_prep_adapter(sc); 470218792Snp if (rc != 0) { 471218792Snp device_printf(dev, "failed to prepare adapter: %d.\n", rc); 472218792Snp goto done; 473218792Snp } 474218792Snp 475228561Snp /* 476228561Snp * Do this really early, with the memory windows set up even before the 477228561Snp * character device. The userland tool's register i/o and mem read 478228561Snp * will work even in "recovery mode". 479228561Snp */ 480228561Snp setup_memwin(sc); 481218792Snp sc->cdev = make_dev(&t4_cdevsw, device_get_unit(dev), UID_ROOT, 482218792Snp GID_WHEEL, 0600, "%s", device_get_nameunit(dev)); 483218792Snp sc->cdev->si_drv1 = sc; 484218792Snp 485228561Snp /* Go no further if recovery mode has been requested. */ 486228561Snp if (TUNABLE_INT_FETCH("hw.cxgbe.sos", &i) && i != 0) { 487228561Snp device_printf(dev, "recovery mode.\n"); 488228561Snp goto done; 489228561Snp } 490228561Snp 491218792Snp /* Prepare the firmware for operation */ 492218792Snp rc = prep_firmware(sc); 493218792Snp if (rc != 0) 494218792Snp goto done; /* error message displayed already */ 495218792Snp 496228561Snp rc = get_params__pre_init(sc); 497228561Snp if (rc != 0) 498228561Snp goto done; /* error message displayed already */ 499222551Snp 500228561Snp rc = t4_sge_init(sc); 501228561Snp if (rc != 0) 502228561Snp goto done; /* error message displayed already */ 503218792Snp 504228561Snp if (sc->flags & MASTER_PF) { 505228561Snp /* get basic stuff going */ 506228561Snp rc = -t4_fw_initialize(sc, sc->mbox); 507228561Snp if (rc != 0) { 508228561Snp device_printf(dev, "early init failed: %d.\n", rc); 509228561Snp goto done; 510228561Snp } 511218792Snp } 512218792Snp 513228561Snp rc = get_params__post_init(sc); 514228561Snp if (rc != 0) 515228561Snp goto done; /* error message displayed already */ 516218792Snp 517228561Snp if (sc->flags & MASTER_PF) { 518218792Snp 519228561Snp /* final tweaks to some settings */ 520218792Snp 521228561Snp t4_load_mtus(sc, sc->params.mtus, sc->params.a_wnd, 522228561Snp sc->params.b_wnd); 523228561Snp t4_write_reg(sc, A_ULP_RX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12)); 524228561Snp t4_set_reg_field(sc, A_TP_PARA_REG3, F_TUNNELCNGDROP0 | 525239258Snp F_TUNNELCNGDROP1 | F_TUNNELCNGDROP2 | F_TUNNELCNGDROP3, 526239258Snp F_TUNNELCNGDROP0 | F_TUNNELCNGDROP1 | F_TUNNELCNGDROP2 | 527239258Snp F_TUNNELCNGDROP3); 528228561Snp t4_set_reg_field(sc, A_TP_PARA_REG5, 529228561Snp V_INDICATESIZE(M_INDICATESIZE) | 530228561Snp F_REARMDDPOFFSET | F_RESETDDPOFFSET, 531228561Snp V_INDICATESIZE(M_INDICATESIZE) | 532228561Snp F_REARMDDPOFFSET | F_RESETDDPOFFSET); 533228561Snp } else { 534228561Snp /* 535228561Snp * XXX: Verify that we can live with whatever the master driver 536228561Snp * has done so far, and hope that it doesn't change any global 537228561Snp * setting from underneath us in the future. 538228561Snp */ 539218792Snp } 540218792Snp 541228561Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &sc->filter_mode, 1, 542228561Snp A_TP_VLAN_PRI_MAP); 543218792Snp 544228561Snp for (i = 0; i < NCHAN; i++) 545228561Snp sc->params.tp.tx_modq[i] = i; 546218792Snp 547218792Snp rc = t4_create_dma_tag(sc); 548218792Snp if (rc != 0) 549218792Snp goto done; /* error message displayed already */ 550218792Snp 551218792Snp /* 552218792Snp * First pass over all the ports - allocate VIs and initialize some 553218792Snp * basic parameters like mac address, port type, etc. We also figure 554218792Snp * out whether a port is 10G or 1G and use that information when 555218792Snp * calculating how many interrupts to attempt to allocate. 556218792Snp */ 557218792Snp n10g = n1g = 0; 558218792Snp for_each_port(sc, i) { 559218792Snp struct port_info *pi; 560218792Snp 561218792Snp pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK); 562218792Snp sc->port[i] = pi; 563218792Snp 564218792Snp /* These must be set before t4_port_init */ 565218792Snp pi->adapter = sc; 566218792Snp pi->port_id = i; 567218792Snp 568218792Snp /* Allocate the vi and initialize parameters like mac addr */ 569218792Snp rc = -t4_port_init(pi, sc->mbox, sc->pf, 0); 570218792Snp if (rc != 0) { 571218792Snp device_printf(dev, "unable to initialize port %d: %d\n", 572218792Snp i, rc); 573218792Snp free(pi, M_CXGBE); 574222510Snp sc->port[i] = NULL; 575222510Snp goto done; 576218792Snp } 577218792Snp 578218792Snp snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d", 579218792Snp device_get_nameunit(dev), i); 580218792Snp mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF); 581218792Snp 582218792Snp if (is_10G_port(pi)) { 583218792Snp n10g++; 584228561Snp pi->tmr_idx = t4_tmr_idx_10g; 585228561Snp pi->pktc_idx = t4_pktc_idx_10g; 586218792Snp } else { 587218792Snp n1g++; 588228561Snp pi->tmr_idx = t4_tmr_idx_1g; 589228561Snp pi->pktc_idx = t4_pktc_idx_1g; 590218792Snp } 591218792Snp 592218792Snp pi->xact_addr_filt = -1; 593218792Snp 594228561Snp pi->qsize_rxq = t4_qsize_rxq; 595228561Snp pi->qsize_txq = t4_qsize_txq; 596218792Snp 597218792Snp pi->dev = device_add_child(dev, "cxgbe", -1); 598218792Snp if (pi->dev == NULL) { 599218792Snp device_printf(dev, 600218792Snp "failed to add device for port %d.\n", i); 601218792Snp rc = ENXIO; 602218792Snp goto done; 603218792Snp } 604218792Snp device_set_softc(pi->dev, pi); 605218792Snp } 606218792Snp 607218792Snp /* 608218792Snp * Interrupt type, # of interrupts, # of rx/tx queues, etc. 609218792Snp */ 610218792Snp rc = cfg_itype_and_nqueues(sc, n10g, n1g, &iaq); 611218792Snp if (rc != 0) 612218792Snp goto done; /* error message displayed already */ 613218792Snp 614218792Snp sc->intr_type = iaq.intr_type; 615218792Snp sc->intr_count = iaq.nirq; 616228561Snp sc->flags |= iaq.intr_flags; 617218792Snp 618218792Snp s = &sc->sge; 619218792Snp s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g; 620218792Snp s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g; 621220873Snp s->neq = s->ntxq + s->nrxq; /* the free list in an rxq is an eq */ 622228561Snp s->neq += sc->params.nports + 1;/* ctrl queues: 1 per port + 1 mgmt */ 623218792Snp s->niq = s->nrxq + 1; /* 1 extra for firmware event queue */ 624222510Snp 625237263Snp#ifdef TCP_OFFLOAD 626228561Snp if (is_offload(sc)) { 627228561Snp 628228561Snp s->nofldrxq = n10g * iaq.nofldrxq10g + n1g * iaq.nofldrxq1g; 629228561Snp s->nofldtxq = n10g * iaq.nofldtxq10g + n1g * iaq.nofldtxq1g; 630228561Snp s->neq += s->nofldtxq + s->nofldrxq; 631228561Snp s->niq += s->nofldrxq; 632228561Snp 633228561Snp s->ofld_rxq = malloc(s->nofldrxq * sizeof(struct sge_ofld_rxq), 634228561Snp M_CXGBE, M_ZERO | M_WAITOK); 635228561Snp s->ofld_txq = malloc(s->nofldtxq * sizeof(struct sge_wrq), 636228561Snp M_CXGBE, M_ZERO | M_WAITOK); 637228561Snp } 638228561Snp#endif 639228561Snp 640228561Snp s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_wrq), M_CXGBE, 641220873Snp M_ZERO | M_WAITOK); 642218792Snp s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE, 643218792Snp M_ZERO | M_WAITOK); 644218792Snp s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE, 645218792Snp M_ZERO | M_WAITOK); 646218792Snp s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE, 647218792Snp M_ZERO | M_WAITOK); 648218792Snp s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE, 649218792Snp M_ZERO | M_WAITOK); 650218792Snp 651218792Snp sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE, 652218792Snp M_ZERO | M_WAITOK); 653218792Snp 654228561Snp t4_init_l2t(sc, M_WAITOK); 655222509Snp 656218792Snp /* 657218792Snp * Second pass over the ports. This time we know the number of rx and 658218792Snp * tx queues that each port should get. 659218792Snp */ 660218792Snp rqidx = tqidx = 0; 661237263Snp#ifdef TCP_OFFLOAD 662228561Snp ofld_rqidx = ofld_tqidx = 0; 663228561Snp#endif 664218792Snp for_each_port(sc, i) { 665218792Snp struct port_info *pi = sc->port[i]; 666218792Snp 667218792Snp if (pi == NULL) 668218792Snp continue; 669218792Snp 670218792Snp pi->first_rxq = rqidx; 671218792Snp pi->first_txq = tqidx; 672228561Snp if (is_10G_port(pi)) { 673228561Snp pi->nrxq = iaq.nrxq10g; 674228561Snp pi->ntxq = iaq.ntxq10g; 675228561Snp } else { 676228561Snp pi->nrxq = iaq.nrxq1g; 677228561Snp pi->ntxq = iaq.ntxq1g; 678228561Snp } 679218792Snp 680218792Snp rqidx += pi->nrxq; 681218792Snp tqidx += pi->ntxq; 682228561Snp 683237263Snp#ifdef TCP_OFFLOAD 684228561Snp if (is_offload(sc)) { 685228561Snp pi->first_ofld_rxq = ofld_rqidx; 686228561Snp pi->first_ofld_txq = ofld_tqidx; 687228561Snp if (is_10G_port(pi)) { 688228561Snp pi->nofldrxq = iaq.nofldrxq10g; 689228561Snp pi->nofldtxq = iaq.nofldtxq10g; 690228561Snp } else { 691228561Snp pi->nofldrxq = iaq.nofldrxq1g; 692228561Snp pi->nofldtxq = iaq.nofldtxq1g; 693228561Snp } 694228561Snp ofld_rqidx += pi->nofldrxq; 695228561Snp ofld_tqidx += pi->nofldtxq; 696228561Snp } 697228561Snp#endif 698218792Snp } 699218792Snp 700218792Snp rc = bus_generic_attach(dev); 701218792Snp if (rc != 0) { 702218792Snp device_printf(dev, 703218792Snp "failed to attach all child ports: %d\n", rc); 704218792Snp goto done; 705218792Snp } 706218792Snp 707218792Snp device_printf(dev, 708228561Snp "PCIe x%d, %d ports, %d %s interrupt%s, %d eq, %d iq\n", 709228561Snp sc->params.pci.width, sc->params.nports, sc->intr_count, 710228561Snp sc->intr_type == INTR_MSIX ? "MSI-X" : 711228561Snp (sc->intr_type == INTR_MSI ? "MSI" : "INTx"), 712228561Snp sc->intr_count > 1 ? "s" : "", sc->sge.neq, sc->sge.niq); 713228561Snp 714218792Snp t4_set_desc(sc); 715218792Snp 716218792Snpdone: 717228561Snp if (rc != 0 && sc->cdev) { 718228561Snp /* cdev was created and so cxgbetool works; recover that way. */ 719228561Snp device_printf(dev, 720228561Snp "error during attach, adapter is now in recovery mode.\n"); 721228561Snp rc = 0; 722228561Snp } 723228561Snp 724218792Snp if (rc != 0) 725218792Snp t4_detach(dev); 726228561Snp else 727228561Snp t4_sysctls(sc); 728218792Snp 729218792Snp return (rc); 730218792Snp} 731218792Snp 732218792Snp/* 733218792Snp * Idempotent 734218792Snp */ 735218792Snpstatic int 736218792Snpt4_detach(device_t dev) 737218792Snp{ 738218792Snp struct adapter *sc; 739218792Snp struct port_info *pi; 740228561Snp int i, rc; 741218792Snp 742218792Snp sc = device_get_softc(dev); 743218792Snp 744228561Snp if (sc->flags & FULL_INIT_DONE) 745228561Snp t4_intr_disable(sc); 746228561Snp 747228561Snp if (sc->cdev) { 748218792Snp destroy_dev(sc->cdev); 749228561Snp sc->cdev = NULL; 750228561Snp } 751218792Snp 752228561Snp rc = bus_generic_detach(dev); 753228561Snp if (rc) { 754228561Snp device_printf(dev, 755228561Snp "failed to detach child devices: %d\n", rc); 756228561Snp return (rc); 757228561Snp } 758228561Snp 759218792Snp for (i = 0; i < MAX_NPORTS; i++) { 760218792Snp pi = sc->port[i]; 761218792Snp if (pi) { 762218792Snp t4_free_vi(pi->adapter, sc->mbox, sc->pf, 0, pi->viid); 763218792Snp if (pi->dev) 764218792Snp device_delete_child(dev, pi->dev); 765218792Snp 766218792Snp mtx_destroy(&pi->pi_lock); 767218792Snp free(pi, M_CXGBE); 768218792Snp } 769218792Snp } 770218792Snp 771228561Snp if (sc->flags & FULL_INIT_DONE) 772228561Snp adapter_full_uninit(sc); 773228561Snp 774218792Snp if (sc->flags & FW_OK) 775218792Snp t4_fw_bye(sc, sc->mbox); 776218792Snp 777219944Snp if (sc->intr_type == INTR_MSI || sc->intr_type == INTR_MSIX) 778218792Snp pci_release_msi(dev); 779218792Snp 780218792Snp if (sc->regs_res) 781218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid, 782218792Snp sc->regs_res); 783218792Snp 784218792Snp if (sc->msix_res) 785218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid, 786218792Snp sc->msix_res); 787218792Snp 788222509Snp if (sc->l2t) 789222509Snp t4_free_l2t(sc->l2t); 790222509Snp 791237263Snp#ifdef TCP_OFFLOAD 792228561Snp free(sc->sge.ofld_rxq, M_CXGBE); 793228561Snp free(sc->sge.ofld_txq, M_CXGBE); 794228561Snp#endif 795218792Snp free(sc->irq, M_CXGBE); 796218792Snp free(sc->sge.rxq, M_CXGBE); 797218792Snp free(sc->sge.txq, M_CXGBE); 798220873Snp free(sc->sge.ctrlq, M_CXGBE); 799218792Snp free(sc->sge.iqmap, M_CXGBE); 800218792Snp free(sc->sge.eqmap, M_CXGBE); 801221474Snp free(sc->tids.ftid_tab, M_CXGBE); 802218792Snp t4_destroy_dma_tag(sc); 803228561Snp if (mtx_initialized(&sc->sc_lock)) { 804228561Snp mtx_lock(&t4_list_lock); 805228561Snp SLIST_REMOVE(&t4_list, sc, adapter, link); 806228561Snp mtx_unlock(&t4_list_lock); 807228561Snp mtx_destroy(&sc->sc_lock); 808228561Snp } 809218792Snp 810228561Snp if (mtx_initialized(&sc->sfl_lock)) 811228561Snp mtx_destroy(&sc->sfl_lock); 812228561Snp 813218792Snp bzero(sc, sizeof(*sc)); 814218792Snp 815218792Snp return (0); 816218792Snp} 817218792Snp 818218792Snp 819218792Snpstatic int 820218792Snpcxgbe_probe(device_t dev) 821218792Snp{ 822218792Snp char buf[128]; 823218792Snp struct port_info *pi = device_get_softc(dev); 824218792Snp 825228561Snp snprintf(buf, sizeof(buf), "port %d", pi->port_id); 826218792Snp device_set_desc_copy(dev, buf); 827218792Snp 828218792Snp return (BUS_PROBE_DEFAULT); 829218792Snp} 830218792Snp 831218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \ 832218792Snp IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \ 833237831Snp IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6) 834237819Snp#define T4_CAP_ENABLE (T4_CAP) 835218792Snp 836218792Snpstatic int 837218792Snpcxgbe_attach(device_t dev) 838218792Snp{ 839218792Snp struct port_info *pi = device_get_softc(dev); 840218792Snp struct ifnet *ifp; 841218792Snp 842218792Snp /* Allocate an ifnet and set it up */ 843218792Snp ifp = if_alloc(IFT_ETHER); 844218792Snp if (ifp == NULL) { 845218792Snp device_printf(dev, "Cannot allocate ifnet\n"); 846218792Snp return (ENOMEM); 847218792Snp } 848218792Snp pi->ifp = ifp; 849218792Snp ifp->if_softc = pi; 850218792Snp 851218792Snp callout_init(&pi->tick, CALLOUT_MPSAFE); 852218792Snp 853218792Snp if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 854218792Snp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 855218792Snp 856218792Snp ifp->if_init = cxgbe_init; 857218792Snp ifp->if_ioctl = cxgbe_ioctl; 858218792Snp ifp->if_transmit = cxgbe_transmit; 859218792Snp ifp->if_qflush = cxgbe_qflush; 860218792Snp 861218792Snp ifp->if_capabilities = T4_CAP; 862237263Snp#ifdef TCP_OFFLOAD 863228561Snp if (is_offload(pi->adapter)) 864228561Snp ifp->if_capabilities |= IFCAP_TOE4; 865228561Snp#endif 866218792Snp ifp->if_capenable = T4_CAP_ENABLE; 867237799Snp ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO | 868237799Snp CSUM_UDP_IPV6 | CSUM_TCP_IPV6; 869218792Snp 870218792Snp /* Initialize ifmedia for this port */ 871218792Snp ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change, 872218792Snp cxgbe_media_status); 873218792Snp build_medialist(pi); 874218792Snp 875237263Snp pi->vlan_c = EVENTHANDLER_REGISTER(vlan_config, cxgbe_vlan_config, ifp, 876237263Snp EVENTHANDLER_PRI_ANY); 877237263Snp 878218792Snp ether_ifattach(ifp, pi->hw_addr); 879218792Snp 880237263Snp#ifdef TCP_OFFLOAD 881228561Snp if (is_offload(pi->adapter)) { 882228561Snp device_printf(dev, 883228561Snp "%d txq, %d rxq (NIC); %d txq, %d rxq (TOE)\n", 884228561Snp pi->ntxq, pi->nrxq, pi->nofldtxq, pi->nofldrxq); 885228561Snp } else 886218792Snp#endif 887228561Snp device_printf(dev, "%d txq, %d rxq\n", pi->ntxq, pi->nrxq); 888218792Snp 889218792Snp cxgbe_sysctls(pi); 890218792Snp 891218792Snp return (0); 892218792Snp} 893218792Snp 894218792Snpstatic int 895218792Snpcxgbe_detach(device_t dev) 896218792Snp{ 897218792Snp struct port_info *pi = device_get_softc(dev); 898218792Snp struct adapter *sc = pi->adapter; 899228561Snp struct ifnet *ifp = pi->ifp; 900218792Snp 901218792Snp /* Tell if_ioctl and if_init that the port is going away */ 902218792Snp ADAPTER_LOCK(sc); 903218792Snp SET_DOOMED(pi); 904218792Snp wakeup(&sc->flags); 905218792Snp while (IS_BUSY(sc)) 906218792Snp mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0); 907218792Snp SET_BUSY(sc); 908218792Snp ADAPTER_UNLOCK(sc); 909218792Snp 910237263Snp if (pi->vlan_c) 911237263Snp EVENTHANDLER_DEREGISTER(vlan_config, pi->vlan_c); 912237263Snp 913228561Snp PORT_LOCK(pi); 914228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 915228561Snp callout_stop(&pi->tick); 916228561Snp PORT_UNLOCK(pi); 917228561Snp callout_drain(&pi->tick); 918218792Snp 919228561Snp /* Let detach proceed even if these fail. */ 920228561Snp cxgbe_uninit_synchronized(pi); 921228561Snp port_full_uninit(pi); 922219286Snp 923218792Snp ifmedia_removeall(&pi->media); 924218792Snp ether_ifdetach(pi->ifp); 925218792Snp if_free(pi->ifp); 926218792Snp 927218792Snp ADAPTER_LOCK(sc); 928218792Snp CLR_BUSY(sc); 929218792Snp wakeup_one(&sc->flags); 930218792Snp ADAPTER_UNLOCK(sc); 931218792Snp 932218792Snp return (0); 933218792Snp} 934218792Snp 935218792Snpstatic void 936218792Snpcxgbe_init(void *arg) 937218792Snp{ 938218792Snp struct port_info *pi = arg; 939218792Snp struct adapter *sc = pi->adapter; 940218792Snp 941218792Snp ADAPTER_LOCK(sc); 942218792Snp cxgbe_init_locked(pi); /* releases adapter lock */ 943218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 944218792Snp} 945218792Snp 946218792Snpstatic int 947218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) 948218792Snp{ 949218792Snp int rc = 0, mtu, flags; 950218792Snp struct port_info *pi = ifp->if_softc; 951218792Snp struct adapter *sc = pi->adapter; 952218792Snp struct ifreq *ifr = (struct ifreq *)data; 953218792Snp uint32_t mask; 954218792Snp 955218792Snp switch (cmd) { 956218792Snp case SIOCSIFMTU: 957218792Snp ADAPTER_LOCK(sc); 958218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 959218792Snp if (rc) { 960218792Snpfail: 961218792Snp ADAPTER_UNLOCK(sc); 962218792Snp return (rc); 963218792Snp } 964218792Snp 965218792Snp mtu = ifr->ifr_mtu; 966218792Snp if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) { 967218792Snp rc = EINVAL; 968218792Snp } else { 969218792Snp ifp->if_mtu = mtu; 970218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 971218792Snp t4_update_fl_bufsize(ifp); 972218792Snp PORT_LOCK(pi); 973218792Snp rc = update_mac_settings(pi, XGMAC_MTU); 974218792Snp PORT_UNLOCK(pi); 975218792Snp } 976218792Snp } 977218792Snp ADAPTER_UNLOCK(sc); 978218792Snp break; 979218792Snp 980218792Snp case SIOCSIFFLAGS: 981218792Snp ADAPTER_LOCK(sc); 982218792Snp if (IS_DOOMED(pi)) { 983218792Snp rc = ENXIO; 984218792Snp goto fail; 985218792Snp } 986218792Snp if (ifp->if_flags & IFF_UP) { 987218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 988218792Snp flags = pi->if_flags; 989218792Snp if ((ifp->if_flags ^ flags) & 990218792Snp (IFF_PROMISC | IFF_ALLMULTI)) { 991218792Snp if (IS_BUSY(sc)) { 992218792Snp rc = EBUSY; 993218792Snp goto fail; 994218792Snp } 995218792Snp PORT_LOCK(pi); 996218792Snp rc = update_mac_settings(pi, 997218792Snp XGMAC_PROMISC | XGMAC_ALLMULTI); 998218792Snp PORT_UNLOCK(pi); 999218792Snp } 1000218792Snp ADAPTER_UNLOCK(sc); 1001218792Snp } else 1002218792Snp rc = cxgbe_init_locked(pi); 1003218792Snp pi->if_flags = ifp->if_flags; 1004218792Snp } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1005218792Snp rc = cxgbe_uninit_locked(pi); 1006218792Snp else 1007218792Snp ADAPTER_UNLOCK(sc); 1008218792Snp 1009218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 1010218792Snp break; 1011218792Snp 1012218792Snp case SIOCADDMULTI: 1013218792Snp case SIOCDELMULTI: /* these two can be called with a mutex held :-( */ 1014218792Snp ADAPTER_LOCK(sc); 1015218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 1016218792Snp if (rc) 1017218792Snp goto fail; 1018218792Snp 1019218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1020218792Snp PORT_LOCK(pi); 1021218792Snp rc = update_mac_settings(pi, XGMAC_MCADDRS); 1022218792Snp PORT_UNLOCK(pi); 1023218792Snp } 1024218792Snp ADAPTER_UNLOCK(sc); 1025218792Snp break; 1026218792Snp 1027218792Snp case SIOCSIFCAP: 1028218792Snp ADAPTER_LOCK(sc); 1029218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 1030218792Snp if (rc) 1031218792Snp goto fail; 1032218792Snp 1033218792Snp mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1034218792Snp if (mask & IFCAP_TXCSUM) { 1035218792Snp ifp->if_capenable ^= IFCAP_TXCSUM; 1036218792Snp ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 1037218792Snp 1038237831Snp if (IFCAP_TSO4 & ifp->if_capenable && 1039218792Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1040237799Snp ifp->if_capenable &= ~IFCAP_TSO4; 1041218792Snp if_printf(ifp, 1042237831Snp "tso4 disabled due to -txcsum.\n"); 1043218792Snp } 1044218792Snp } 1045237799Snp if (mask & IFCAP_TXCSUM_IPV6) { 1046237799Snp ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 1047237799Snp ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); 1048237799Snp 1049237799Snp if (IFCAP_TSO6 & ifp->if_capenable && 1050237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1051237799Snp ifp->if_capenable &= ~IFCAP_TSO6; 1052237799Snp if_printf(ifp, 1053237799Snp "tso6 disabled due to -txcsum6.\n"); 1054237799Snp } 1055237799Snp } 1056218792Snp if (mask & IFCAP_RXCSUM) 1057218792Snp ifp->if_capenable ^= IFCAP_RXCSUM; 1058237799Snp if (mask & IFCAP_RXCSUM_IPV6) 1059237799Snp ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 1060237799Snp 1061237799Snp /* 1062237799Snp * Note that we leave CSUM_TSO alone (it is always set). The 1063237799Snp * kernel takes both IFCAP_TSOx and CSUM_TSO into account before 1064237799Snp * sending a TSO request our way, so it's sufficient to toggle 1065237799Snp * IFCAP_TSOx only. 1066237799Snp */ 1067218792Snp if (mask & IFCAP_TSO4) { 1068237799Snp if (!(IFCAP_TSO4 & ifp->if_capenable) && 1069237799Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1070237799Snp if_printf(ifp, "enable txcsum first.\n"); 1071237799Snp rc = EAGAIN; 1072237799Snp goto fail; 1073237799Snp } 1074218792Snp ifp->if_capenable ^= IFCAP_TSO4; 1075218792Snp } 1076237799Snp if (mask & IFCAP_TSO6) { 1077237799Snp if (!(IFCAP_TSO6 & ifp->if_capenable) && 1078237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1079237799Snp if_printf(ifp, "enable txcsum6 first.\n"); 1080237799Snp rc = EAGAIN; 1081237799Snp goto fail; 1082237799Snp } 1083237799Snp ifp->if_capenable ^= IFCAP_TSO6; 1084237799Snp } 1085218792Snp if (mask & IFCAP_LRO) { 1086237819Snp#if defined(INET) || defined(INET6) 1087218792Snp int i; 1088218792Snp struct sge_rxq *rxq; 1089218792Snp 1090218792Snp ifp->if_capenable ^= IFCAP_LRO; 1091218792Snp for_each_rxq(pi, i, rxq) { 1092218792Snp if (ifp->if_capenable & IFCAP_LRO) 1093228561Snp rxq->iq.flags |= IQ_LRO_ENABLED; 1094218792Snp else 1095228561Snp rxq->iq.flags &= ~IQ_LRO_ENABLED; 1096218792Snp } 1097218792Snp#endif 1098218792Snp } 1099237263Snp#ifdef TCP_OFFLOAD 1100228561Snp if (mask & IFCAP_TOE) { 1101228561Snp int enable = (ifp->if_capenable ^ mask) & IFCAP_TOE; 1102228561Snp 1103228561Snp rc = toe_capability(pi, enable); 1104228561Snp if (rc != 0) 1105228561Snp goto fail; 1106228561Snp 1107228561Snp ifp->if_capenable ^= mask; 1108218792Snp } 1109218792Snp#endif 1110218792Snp if (mask & IFCAP_VLAN_HWTAGGING) { 1111218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1112218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1113218792Snp PORT_LOCK(pi); 1114218792Snp rc = update_mac_settings(pi, XGMAC_VLANEX); 1115218792Snp PORT_UNLOCK(pi); 1116218792Snp } 1117218792Snp } 1118218792Snp if (mask & IFCAP_VLAN_MTU) { 1119218792Snp ifp->if_capenable ^= IFCAP_VLAN_MTU; 1120218792Snp 1121218792Snp /* Need to find out how to disable auto-mtu-inflation */ 1122218792Snp } 1123218792Snp if (mask & IFCAP_VLAN_HWTSO) 1124218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1125218792Snp if (mask & IFCAP_VLAN_HWCSUM) 1126218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 1127218792Snp 1128218792Snp#ifdef VLAN_CAPABILITIES 1129218792Snp VLAN_CAPABILITIES(ifp); 1130218792Snp#endif 1131218792Snp ADAPTER_UNLOCK(sc); 1132218792Snp break; 1133218792Snp 1134218792Snp case SIOCSIFMEDIA: 1135218792Snp case SIOCGIFMEDIA: 1136218792Snp ifmedia_ioctl(ifp, ifr, &pi->media, cmd); 1137218792Snp break; 1138218792Snp 1139218792Snp default: 1140218792Snp rc = ether_ioctl(ifp, cmd, data); 1141218792Snp } 1142218792Snp 1143218792Snp return (rc); 1144218792Snp} 1145218792Snp 1146218792Snpstatic int 1147218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m) 1148218792Snp{ 1149218792Snp struct port_info *pi = ifp->if_softc; 1150218792Snp struct adapter *sc = pi->adapter; 1151218792Snp struct sge_txq *txq = &sc->sge.txq[pi->first_txq]; 1152218792Snp struct buf_ring *br; 1153218792Snp int rc; 1154218792Snp 1155218792Snp M_ASSERTPKTHDR(m); 1156218792Snp 1157228561Snp if (__predict_false(pi->link_cfg.link_ok == 0)) { 1158218792Snp m_freem(m); 1159228561Snp return (ENETDOWN); 1160218792Snp } 1161218792Snp 1162218792Snp if (m->m_flags & M_FLOWID) 1163218792Snp txq += (m->m_pkthdr.flowid % pi->ntxq); 1164220873Snp br = txq->br; 1165218792Snp 1166218792Snp if (TXQ_TRYLOCK(txq) == 0) { 1167228561Snp struct sge_eq *eq = &txq->eq; 1168228561Snp 1169218792Snp /* 1170228561Snp * It is possible that t4_eth_tx finishes up and releases the 1171228561Snp * lock between the TRYLOCK above and the drbr_enqueue here. We 1172228561Snp * need to make sure that this mbuf doesn't just sit there in 1173228561Snp * the drbr. 1174218792Snp */ 1175218792Snp 1176228561Snp rc = drbr_enqueue(ifp, br, m); 1177228561Snp if (rc == 0 && callout_pending(&eq->tx_callout) == 0 && 1178228561Snp !(eq->flags & EQ_DOOMED)) 1179228561Snp callout_reset(&eq->tx_callout, 1, t4_tx_callout, eq); 1180228561Snp return (rc); 1181218792Snp } 1182218792Snp 1183218792Snp /* 1184218792Snp * txq->m is the mbuf that is held up due to a temporary shortage of 1185218792Snp * resources and it should be put on the wire first. Then what's in 1186218792Snp * drbr and finally the mbuf that was just passed in to us. 1187218792Snp * 1188218792Snp * Return code should indicate the fate of the mbuf that was passed in 1189218792Snp * this time. 1190218792Snp */ 1191218792Snp 1192218792Snp TXQ_LOCK_ASSERT_OWNED(txq); 1193218792Snp if (drbr_needs_enqueue(ifp, br) || txq->m) { 1194218792Snp 1195218792Snp /* Queued for transmission. */ 1196218792Snp 1197218792Snp rc = drbr_enqueue(ifp, br, m); 1198218792Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 1199218792Snp (void) t4_eth_tx(ifp, txq, m); 1200218792Snp TXQ_UNLOCK(txq); 1201218792Snp return (rc); 1202218792Snp } 1203218792Snp 1204218792Snp /* Direct transmission. */ 1205218792Snp rc = t4_eth_tx(ifp, txq, m); 1206218792Snp if (rc != 0 && txq->m) 1207218792Snp rc = 0; /* held, will be transmitted soon (hopefully) */ 1208218792Snp 1209218792Snp TXQ_UNLOCK(txq); 1210218792Snp return (rc); 1211218792Snp} 1212218792Snp 1213218792Snpstatic void 1214218792Snpcxgbe_qflush(struct ifnet *ifp) 1215218792Snp{ 1216218792Snp struct port_info *pi = ifp->if_softc; 1217220649Snp struct sge_txq *txq; 1218220649Snp int i; 1219220649Snp struct mbuf *m; 1220218792Snp 1221228561Snp /* queues do not exist if !PORT_INIT_DONE. */ 1222228561Snp if (pi->flags & PORT_INIT_DONE) { 1223220649Snp for_each_txq(pi, i, txq) { 1224220649Snp TXQ_LOCK(txq); 1225220649Snp m_freem(txq->m); 1226228561Snp txq->m = NULL; 1227220873Snp while ((m = buf_ring_dequeue_sc(txq->br)) != NULL) 1228220649Snp m_freem(m); 1229220649Snp TXQ_UNLOCK(txq); 1230220649Snp } 1231220649Snp } 1232220649Snp if_qflush(ifp); 1233218792Snp} 1234218792Snp 1235218792Snpstatic int 1236218792Snpcxgbe_media_change(struct ifnet *ifp) 1237218792Snp{ 1238218792Snp struct port_info *pi = ifp->if_softc; 1239218792Snp 1240218792Snp device_printf(pi->dev, "%s unimplemented.\n", __func__); 1241218792Snp 1242218792Snp return (EOPNOTSUPP); 1243218792Snp} 1244218792Snp 1245218792Snpstatic void 1246218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1247218792Snp{ 1248218792Snp struct port_info *pi = ifp->if_softc; 1249218792Snp struct ifmedia_entry *cur = pi->media.ifm_cur; 1250218792Snp int speed = pi->link_cfg.speed; 1251218792Snp int data = (pi->port_type << 8) | pi->mod_type; 1252218792Snp 1253218792Snp if (cur->ifm_data != data) { 1254218792Snp build_medialist(pi); 1255218792Snp cur = pi->media.ifm_cur; 1256218792Snp } 1257218792Snp 1258218792Snp ifmr->ifm_status = IFM_AVALID; 1259218792Snp if (!pi->link_cfg.link_ok) 1260218792Snp return; 1261218792Snp 1262218792Snp ifmr->ifm_status |= IFM_ACTIVE; 1263218792Snp 1264218792Snp /* active and current will differ iff current media is autoselect. */ 1265218792Snp if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO) 1266218792Snp return; 1267218792Snp 1268218792Snp ifmr->ifm_active = IFM_ETHER | IFM_FDX; 1269218792Snp if (speed == SPEED_10000) 1270218792Snp ifmr->ifm_active |= IFM_10G_T; 1271218792Snp else if (speed == SPEED_1000) 1272218792Snp ifmr->ifm_active |= IFM_1000_T; 1273218792Snp else if (speed == SPEED_100) 1274218792Snp ifmr->ifm_active |= IFM_100_TX; 1275218792Snp else if (speed == SPEED_10) 1276218792Snp ifmr->ifm_active |= IFM_10_T; 1277218792Snp else 1278218792Snp KASSERT(0, ("%s: link up but speed unknown (%u)", __func__, 1279218792Snp speed)); 1280218792Snp} 1281218792Snp 1282218792Snpvoid 1283218792Snpt4_fatal_err(struct adapter *sc) 1284218792Snp{ 1285218792Snp t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0); 1286218792Snp t4_intr_disable(sc); 1287218792Snp log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n", 1288218792Snp device_get_nameunit(sc->dev)); 1289218792Snp} 1290218792Snp 1291218792Snpstatic int 1292218792Snpmap_bars(struct adapter *sc) 1293218792Snp{ 1294218792Snp sc->regs_rid = PCIR_BAR(0); 1295218792Snp sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1296218792Snp &sc->regs_rid, RF_ACTIVE); 1297218792Snp if (sc->regs_res == NULL) { 1298218792Snp device_printf(sc->dev, "cannot map registers.\n"); 1299218792Snp return (ENXIO); 1300218792Snp } 1301218792Snp sc->bt = rman_get_bustag(sc->regs_res); 1302218792Snp sc->bh = rman_get_bushandle(sc->regs_res); 1303218792Snp sc->mmio_len = rman_get_size(sc->regs_res); 1304218792Snp 1305218792Snp sc->msix_rid = PCIR_BAR(4); 1306218792Snp sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1307218792Snp &sc->msix_rid, RF_ACTIVE); 1308218792Snp if (sc->msix_res == NULL) { 1309218792Snp device_printf(sc->dev, "cannot map MSI-X BAR.\n"); 1310218792Snp return (ENXIO); 1311218792Snp } 1312218792Snp 1313218792Snp return (0); 1314218792Snp} 1315218792Snp 1316218792Snpstatic void 1317218792Snpsetup_memwin(struct adapter *sc) 1318218792Snp{ 1319237587Snp uint32_t bar0; 1320218792Snp 1321237587Snp /* 1322237587Snp * Read low 32b of bar0 indirectly via the hardware backdoor mechanism. 1323237587Snp * Works from within PCI passthrough environments too, where 1324237587Snp * rman_get_start() can return a different value. We need to program 1325237587Snp * the memory window decoders with the actual addresses that will be 1326237587Snp * coming across the PCIe link. 1327237587Snp */ 1328237587Snp bar0 = t4_hw_pci_read_cfg4(sc, PCIR_BAR(0)); 1329237587Snp bar0 &= (uint32_t) PCIM_BAR_MEM_BASE; 1330218792Snp 1331218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 0), 1332218792Snp (bar0 + MEMWIN0_BASE) | V_BIR(0) | 1333218792Snp V_WINDOW(ilog2(MEMWIN0_APERTURE) - 10)); 1334218792Snp 1335218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 1), 1336218792Snp (bar0 + MEMWIN1_BASE) | V_BIR(0) | 1337218792Snp V_WINDOW(ilog2(MEMWIN1_APERTURE) - 10)); 1338218792Snp 1339218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2), 1340218792Snp (bar0 + MEMWIN2_BASE) | V_BIR(0) | 1341218792Snp V_WINDOW(ilog2(MEMWIN2_APERTURE) - 10)); 1342237587Snp 1343237587Snp /* flush */ 1344237587Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2)); 1345218792Snp} 1346218792Snp 1347218792Snpstatic int 1348218792Snpcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g, 1349218792Snp struct intrs_and_queues *iaq) 1350218792Snp{ 1351228561Snp int rc, itype, navail, nrxq10g, nrxq1g, n; 1352228561Snp int nofldrxq10g = 0, nofldrxq1g = 0; 1353218792Snp 1354218792Snp bzero(iaq, sizeof(*iaq)); 1355218792Snp 1356228561Snp iaq->ntxq10g = t4_ntxq10g; 1357228561Snp iaq->ntxq1g = t4_ntxq1g; 1358228561Snp iaq->nrxq10g = nrxq10g = t4_nrxq10g; 1359228561Snp iaq->nrxq1g = nrxq1g = t4_nrxq1g; 1360237263Snp#ifdef TCP_OFFLOAD 1361237463Snp if (is_offload(sc)) { 1362237463Snp iaq->nofldtxq10g = t4_nofldtxq10g; 1363237463Snp iaq->nofldtxq1g = t4_nofldtxq1g; 1364237463Snp iaq->nofldrxq10g = nofldrxq10g = t4_nofldrxq10g; 1365237463Snp iaq->nofldrxq1g = nofldrxq1g = t4_nofldrxq1g; 1366237463Snp } 1367228561Snp#endif 1368228561Snp 1369219944Snp for (itype = INTR_MSIX; itype; itype >>= 1) { 1370218792Snp 1371228561Snp if ((itype & t4_intr_types) == 0) 1372218792Snp continue; /* not allowed */ 1373218792Snp 1374219944Snp if (itype == INTR_MSIX) 1375218792Snp navail = pci_msix_count(sc->dev); 1376219944Snp else if (itype == INTR_MSI) 1377218792Snp navail = pci_msi_count(sc->dev); 1378218792Snp else 1379218792Snp navail = 1; 1380228561Snprestart: 1381218792Snp if (navail == 0) 1382218792Snp continue; 1383218792Snp 1384218792Snp iaq->intr_type = itype; 1385228561Snp iaq->intr_flags = 0; 1386218792Snp 1387228561Snp /* 1388228561Snp * Best option: an interrupt vector for errors, one for the 1389228561Snp * firmware event queue, and one each for each rxq (NIC as well 1390228561Snp * as offload). 1391228561Snp */ 1392228561Snp iaq->nirq = T4_EXTRA_INTR; 1393228561Snp iaq->nirq += n10g * (nrxq10g + nofldrxq10g); 1394228561Snp iaq->nirq += n1g * (nrxq1g + nofldrxq1g); 1395228561Snp if (iaq->nirq <= navail && 1396228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) { 1397228561Snp iaq->intr_flags |= INTR_DIRECT; 1398228561Snp goto allocate; 1399228561Snp } 1400218792Snp 1401228561Snp /* 1402228561Snp * Second best option: an interrupt vector for errors, one for 1403228561Snp * the firmware event queue, and one each for either NIC or 1404228561Snp * offload rxq's. 1405228561Snp */ 1406228561Snp iaq->nirq = T4_EXTRA_INTR; 1407228561Snp iaq->nirq += n10g * max(nrxq10g, nofldrxq10g); 1408228561Snp iaq->nirq += n1g * max(nrxq1g, nofldrxq1g); 1409228561Snp if (iaq->nirq <= navail && 1410228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) 1411228561Snp goto allocate; 1412218792Snp 1413228561Snp /* 1414228561Snp * Next best option: an interrupt vector for errors, one for the 1415228561Snp * firmware event queue, and at least one per port. At this 1416228561Snp * point we know we'll have to downsize nrxq or nofldrxq to fit 1417228561Snp * what's available to us. 1418228561Snp */ 1419228561Snp iaq->nirq = T4_EXTRA_INTR; 1420228561Snp iaq->nirq += n10g + n1g; 1421228561Snp if (iaq->nirq <= navail) { 1422228561Snp int leftover = navail - iaq->nirq; 1423218792Snp 1424228561Snp if (n10g > 0) { 1425228561Snp int target = max(nrxq10g, nofldrxq10g); 1426219944Snp 1427228561Snp n = 1; 1428228561Snp while (n < target && leftover >= n10g) { 1429228561Snp leftover -= n10g; 1430228561Snp iaq->nirq += n10g; 1431228561Snp n++; 1432228561Snp } 1433228561Snp iaq->nrxq10g = min(n, nrxq10g); 1434237263Snp#ifdef TCP_OFFLOAD 1435237463Snp if (is_offload(sc)) 1436237463Snp iaq->nofldrxq10g = min(n, nofldrxq10g); 1437228561Snp#endif 1438228561Snp } 1439218792Snp 1440228561Snp if (n1g > 0) { 1441228561Snp int target = max(nrxq1g, nofldrxq1g); 1442219944Snp 1443228561Snp n = 1; 1444228561Snp while (n < target && leftover >= n1g) { 1445228561Snp leftover -= n1g; 1446228561Snp iaq->nirq += n1g; 1447228561Snp n++; 1448219944Snp } 1449228561Snp iaq->nrxq1g = min(n, nrxq1g); 1450237263Snp#ifdef TCP_OFFLOAD 1451237463Snp if (is_offload(sc)) 1452237463Snp iaq->nofldrxq1g = min(n, nofldrxq1g); 1453228561Snp#endif 1454219944Snp } 1455219944Snp 1456228561Snp if (itype != INTR_MSI || powerof2(iaq->nirq)) 1457228561Snp goto allocate; 1458218792Snp } 1459218792Snp 1460228561Snp /* 1461228561Snp * Least desirable option: one interrupt vector for everything. 1462228561Snp */ 1463228561Snp iaq->nirq = iaq->nrxq10g = iaq->nrxq1g = 1; 1464237263Snp#ifdef TCP_OFFLOAD 1465237463Snp if (is_offload(sc)) 1466237463Snp iaq->nofldrxq10g = iaq->nofldrxq1g = 1; 1467228561Snp#endif 1468228561Snp 1469228561Snpallocate: 1470218792Snp navail = iaq->nirq; 1471218792Snp rc = 0; 1472219944Snp if (itype == INTR_MSIX) 1473218792Snp rc = pci_alloc_msix(sc->dev, &navail); 1474219944Snp else if (itype == INTR_MSI) 1475218792Snp rc = pci_alloc_msi(sc->dev, &navail); 1476218792Snp 1477218792Snp if (rc == 0) { 1478218792Snp if (navail == iaq->nirq) 1479218792Snp return (0); 1480218792Snp 1481218792Snp /* 1482218792Snp * Didn't get the number requested. Use whatever number 1483218792Snp * the kernel is willing to allocate (it's in navail). 1484218792Snp */ 1485228561Snp device_printf(sc->dev, "fewer vectors than requested, " 1486228561Snp "type=%d, req=%d, rcvd=%d; will downshift req.\n", 1487228561Snp itype, iaq->nirq, navail); 1488218792Snp pci_release_msi(sc->dev); 1489228561Snp goto restart; 1490218792Snp } 1491218792Snp 1492218792Snp device_printf(sc->dev, 1493218792Snp "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n", 1494218792Snp itype, rc, iaq->nirq, navail); 1495218792Snp } 1496218792Snp 1497218792Snp device_printf(sc->dev, 1498218792Snp "failed to find a usable interrupt type. " 1499228561Snp "allowed=%d, msi-x=%d, msi=%d, intx=1", t4_intr_types, 1500218792Snp pci_msix_count(sc->dev), pci_msi_count(sc->dev)); 1501218792Snp 1502218792Snp return (ENXIO); 1503218792Snp} 1504218792Snp 1505218792Snp/* 1506228561Snp * Install a compatible firmware (if required), establish contact with it (by 1507228561Snp * saying hello), and reset the device. If we end up as the master driver, 1508228561Snp * partition adapter resources by providing a configuration file to the 1509228561Snp * firmware. 1510218792Snp */ 1511218792Snpstatic int 1512218792Snpprep_firmware(struct adapter *sc) 1513218792Snp{ 1514228561Snp const struct firmware *fw = NULL, *cfg = NULL, *default_cfg; 1515218792Snp int rc; 1516218792Snp enum dev_state state; 1517218792Snp 1518228561Snp default_cfg = firmware_get(T4_CFGNAME); 1519228561Snp 1520218792Snp /* Check firmware version and install a different one if necessary */ 1521218792Snp rc = t4_check_fw_version(sc); 1522234831Snp snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u", 1523234831Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1524234831Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1525234831Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1526234831Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 1527228561Snp if (rc != 0) { 1528219287Snp uint32_t v = 0; 1529218792Snp 1530218792Snp fw = firmware_get(T4_FWNAME); 1531219287Snp if (fw != NULL) { 1532219287Snp const struct fw_hdr *hdr = (const void *)fw->data; 1533219287Snp 1534219287Snp v = ntohl(hdr->fw_ver); 1535219287Snp 1536219287Snp /* 1537219287Snp * The firmware module will not be used if it isn't the 1538219287Snp * same major version as what the driver was compiled 1539228561Snp * with. 1540219287Snp */ 1541219287Snp if (G_FW_HDR_FW_VER_MAJOR(v) != FW_VERSION_MAJOR) { 1542219287Snp device_printf(sc->dev, 1543219287Snp "Found firmware image but version %d " 1544219287Snp "can not be used with this driver (%d)\n", 1545219287Snp G_FW_HDR_FW_VER_MAJOR(v), FW_VERSION_MAJOR); 1546219287Snp 1547219287Snp firmware_put(fw, FIRMWARE_UNLOAD); 1548219287Snp fw = NULL; 1549219287Snp } 1550218792Snp } 1551218792Snp 1552228561Snp if (fw == NULL && rc < 0) { 1553219287Snp device_printf(sc->dev, "No usable firmware. " 1554228561Snp "card has %d.%d.%d, driver compiled with %d.%d.%d", 1555219287Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1556219287Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1557219287Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1558219287Snp FW_VERSION_MAJOR, FW_VERSION_MINOR, 1559228561Snp FW_VERSION_MICRO); 1560228561Snp rc = EAGAIN; 1561228561Snp goto done; 1562219287Snp } 1563219287Snp 1564219287Snp /* 1565219287Snp * Always upgrade, even for minor/micro/build mismatches. 1566219287Snp * Downgrade only for a major version mismatch or if 1567219287Snp * force_firmware_install was specified. 1568219287Snp */ 1569228561Snp if (fw != NULL && (rc < 0 || v > sc->params.fw_vers)) { 1570218792Snp device_printf(sc->dev, 1571219287Snp "installing firmware %d.%d.%d.%d on card.\n", 1572219287Snp G_FW_HDR_FW_VER_MAJOR(v), G_FW_HDR_FW_VER_MINOR(v), 1573219287Snp G_FW_HDR_FW_VER_MICRO(v), G_FW_HDR_FW_VER_BUILD(v)); 1574219287Snp 1575219287Snp rc = -t4_load_fw(sc, fw->data, fw->datasize); 1576219287Snp if (rc != 0) { 1577219287Snp device_printf(sc->dev, 1578219287Snp "failed to install firmware: %d\n", rc); 1579228561Snp goto done; 1580219287Snp } else { 1581219287Snp /* refresh */ 1582219287Snp (void) t4_check_fw_version(sc); 1583234831Snp snprintf(sc->fw_version, 1584234831Snp sizeof(sc->fw_version), "%u.%u.%u.%u", 1585234831Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1586234831Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1587234831Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1588234831Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 1589219287Snp } 1590218792Snp } 1591218792Snp } 1592218792Snp 1593228561Snp /* Contact firmware. */ 1594228561Snp rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state); 1595218792Snp if (rc < 0) { 1596218792Snp rc = -rc; 1597218792Snp device_printf(sc->dev, 1598218792Snp "failed to connect to the firmware: %d.\n", rc); 1599228561Snp goto done; 1600218792Snp } 1601228561Snp if (rc == sc->mbox) 1602228561Snp sc->flags |= MASTER_PF; 1603218792Snp 1604218792Snp /* Reset device */ 1605218792Snp rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST); 1606218792Snp if (rc != 0) { 1607218792Snp device_printf(sc->dev, "firmware reset failed: %d.\n", rc); 1608218792Snp if (rc != ETIMEDOUT && rc != EIO) 1609218792Snp t4_fw_bye(sc, sc->mbox); 1610228561Snp goto done; 1611218792Snp } 1612218792Snp 1613228561Snp /* Partition adapter resources as specified in the config file. */ 1614228561Snp if (sc->flags & MASTER_PF) { 1615228561Snp if (strncmp(t4_cfg_file, "default", sizeof(t4_cfg_file))) { 1616228561Snp char s[32]; 1617228561Snp 1618228561Snp snprintf(s, sizeof(s), "t4fw_cfg_%s", t4_cfg_file); 1619228561Snp cfg = firmware_get(s); 1620228561Snp if (cfg == NULL) { 1621228561Snp device_printf(sc->dev, 1622228561Snp "unable to locate %s module, " 1623228561Snp "will use default config file.\n", s); 1624228561Snp } 1625228561Snp } 1626228561Snp 1627228561Snp rc = partition_resources(sc, cfg ? cfg : default_cfg); 1628228561Snp if (rc != 0) 1629228561Snp goto done; /* error message displayed already */ 1630228561Snp } 1631228561Snp 1632218792Snp sc->flags |= FW_OK; 1633218792Snp 1634228561Snpdone: 1635228561Snp if (fw != NULL) 1636228561Snp firmware_put(fw, FIRMWARE_UNLOAD); 1637228561Snp if (cfg != NULL) 1638228561Snp firmware_put(cfg, FIRMWARE_UNLOAD); 1639228561Snp if (default_cfg != NULL) 1640228561Snp firmware_put(default_cfg, FIRMWARE_UNLOAD); 1641228561Snp 1642228561Snp return (rc); 1643218792Snp} 1644218792Snp 1645228561Snp#define FW_PARAM_DEV(param) \ 1646228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ 1647228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) 1648228561Snp#define FW_PARAM_PFVF(param) \ 1649228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ 1650228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)) 1651228561Snp 1652228561Snp/* 1653228561Snp * Upload configuration file to card's memory. 1654228561Snp */ 1655218792Snpstatic int 1656228561Snpupload_config_file(struct adapter *sc, const struct firmware *fw, uint32_t *mt, 1657228561Snp uint32_t *ma) 1658222551Snp{ 1659228561Snp int rc, i; 1660228561Snp uint32_t param, val, mtype, maddr, bar, off, win, remaining; 1661228561Snp const uint32_t *b; 1662222551Snp 1663228561Snp /* Figure out where the firmware wants us to upload it. */ 1664228561Snp param = FW_PARAM_DEV(CF); 1665228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 1666222551Snp if (rc != 0) { 1667228561Snp /* Firmwares without config file support will fail this way */ 1668222551Snp device_printf(sc->dev, 1669228561Snp "failed to query config file location: %d.\n", rc); 1670222551Snp return (rc); 1671222551Snp } 1672228561Snp *mt = mtype = G_FW_PARAMS_PARAM_Y(val); 1673228561Snp *ma = maddr = G_FW_PARAMS_PARAM_Z(val) << 16; 1674222551Snp 1675228561Snp if (maddr & 3) { 1676228561Snp device_printf(sc->dev, 1677228561Snp "cannot upload config file (type %u, addr %x).\n", 1678228561Snp mtype, maddr); 1679228561Snp return (EFAULT); 1680228561Snp } 1681222551Snp 1682228561Snp /* Translate mtype/maddr to an address suitable for the PCIe window */ 1683228561Snp val = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 1684228561Snp val &= F_EDRAM0_ENABLE | F_EDRAM1_ENABLE | F_EXT_MEM_ENABLE; 1685228561Snp switch (mtype) { 1686228561Snp case FW_MEMTYPE_CF_EDC0: 1687228561Snp if (!(val & F_EDRAM0_ENABLE)) 1688228561Snp goto err; 1689228561Snp bar = t4_read_reg(sc, A_MA_EDRAM0_BAR); 1690228561Snp maddr += G_EDRAM0_BASE(bar) << 20; 1691228561Snp break; 1692228561Snp 1693228561Snp case FW_MEMTYPE_CF_EDC1: 1694228561Snp if (!(val & F_EDRAM1_ENABLE)) 1695228561Snp goto err; 1696228561Snp bar = t4_read_reg(sc, A_MA_EDRAM1_BAR); 1697228561Snp maddr += G_EDRAM1_BASE(bar) << 20; 1698228561Snp break; 1699228561Snp 1700228561Snp case FW_MEMTYPE_CF_EXTMEM: 1701228561Snp if (!(val & F_EXT_MEM_ENABLE)) 1702228561Snp goto err; 1703228561Snp bar = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 1704228561Snp maddr += G_EXT_MEM_BASE(bar) << 20; 1705228561Snp break; 1706228561Snp 1707228561Snp default: 1708228561Snperr: 1709228561Snp device_printf(sc->dev, 1710228561Snp "cannot upload config file (type %u, enabled %u).\n", 1711228561Snp mtype, val); 1712228561Snp return (EFAULT); 1713228561Snp } 1714228561Snp 1715228561Snp /* 1716228561Snp * Position the PCIe window (we use memwin2) to the 16B aligned area 1717228561Snp * just at/before the upload location. 1718228561Snp */ 1719228561Snp win = maddr & ~0xf; 1720228561Snp off = maddr - win; /* offset from the start of the window. */ 1721228561Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2), win); 1722228561Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2)); 1723228561Snp 1724228561Snp remaining = fw->datasize; 1725228561Snp if (remaining > FLASH_CFG_MAX_SIZE || 1726228561Snp remaining > MEMWIN2_APERTURE - off) { 1727228561Snp device_printf(sc->dev, "cannot upload config file all at once " 1728228561Snp "(size %u, max %u, room %u).\n", 1729228561Snp remaining, FLASH_CFG_MAX_SIZE, MEMWIN2_APERTURE - off); 1730228561Snp return (EFBIG); 1731228561Snp } 1732228561Snp 1733228561Snp /* 1734228561Snp * XXX: sheer laziness. We deliberately added 4 bytes of useless 1735228561Snp * stuffing/comments at the end of the config file so it's ok to simply 1736228561Snp * throw away the last remaining bytes when the config file is not an 1737228561Snp * exact multiple of 4. 1738228561Snp */ 1739228561Snp b = fw->data; 1740228561Snp for (i = 0; remaining >= 4; i += 4, remaining -= 4) 1741228561Snp t4_write_reg(sc, MEMWIN2_BASE + off + i, *b++); 1742228561Snp 1743228561Snp return (rc); 1744222551Snp} 1745222551Snp 1746228561Snp/* 1747228561Snp * Partition chip resources for use between various PFs, VFs, etc. This is done 1748228561Snp * by uploading the firmware configuration file to the adapter and instructing 1749228561Snp * the firmware to process it. 1750228561Snp */ 1751222551Snpstatic int 1752228561Snppartition_resources(struct adapter *sc, const struct firmware *cfg) 1753218792Snp{ 1754218792Snp int rc; 1755228561Snp struct fw_caps_config_cmd caps; 1756228561Snp uint32_t mtype, maddr, finicsum, cfcsum; 1757218792Snp 1758228561Snp rc = cfg ? upload_config_file(sc, cfg, &mtype, &maddr) : ENOENT; 1759228561Snp if (rc != 0) { 1760228561Snp mtype = FW_MEMTYPE_CF_FLASH; 1761228561Snp maddr = t4_flash_cfg_addr(sc); 1762228561Snp } 1763228561Snp 1764228561Snp bzero(&caps, sizeof(caps)); 1765228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1766218792Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1767228561Snp caps.cfvalid_to_len16 = htobe32(F_FW_CAPS_CONFIG_CMD_CFVALID | 1768228561Snp V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) | 1769228561Snp V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(maddr >> 16) | FW_LEN16(caps)); 1770228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 1771228561Snp if (rc != 0) { 1772228561Snp device_printf(sc->dev, 1773228561Snp "failed to pre-process config file: %d.\n", rc); 1774218792Snp return (rc); 1775228561Snp } 1776218792Snp 1777228561Snp finicsum = be32toh(caps.finicsum); 1778228561Snp cfcsum = be32toh(caps.cfcsum); 1779228561Snp if (finicsum != cfcsum) { 1780228561Snp device_printf(sc->dev, 1781228561Snp "WARNING: config file checksum mismatch: %08x %08x\n", 1782228561Snp finicsum, cfcsum); 1783228561Snp } 1784228561Snp sc->cfcsum = cfcsum; 1785218792Snp 1786228561Snp#define LIMIT_CAPS(x) do { \ 1787228561Snp caps.x &= htobe16(t4_##x##_allowed); \ 1788228561Snp sc->x = htobe16(caps.x); \ 1789228561Snp} while (0) 1790228561Snp 1791228561Snp /* 1792228561Snp * Let the firmware know what features will (not) be used so it can tune 1793228561Snp * things accordingly. 1794228561Snp */ 1795228561Snp LIMIT_CAPS(linkcaps); 1796228561Snp LIMIT_CAPS(niccaps); 1797228561Snp LIMIT_CAPS(toecaps); 1798228561Snp LIMIT_CAPS(rdmacaps); 1799228561Snp LIMIT_CAPS(iscsicaps); 1800228561Snp LIMIT_CAPS(fcoecaps); 1801228561Snp#undef LIMIT_CAPS 1802228561Snp 1803228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1804218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE); 1805228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 1806228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), NULL); 1807228561Snp if (rc != 0) { 1808228561Snp device_printf(sc->dev, 1809228561Snp "failed to process config file: %d.\n", rc); 1810228561Snp return (rc); 1811228561Snp } 1812218792Snp 1813228561Snp return (0); 1814218792Snp} 1815218792Snp 1816228561Snp/* 1817228561Snp * Retrieve parameters that are needed (or nice to have) prior to calling 1818228561Snp * t4_sge_init and t4_fw_initialize. 1819228561Snp */ 1820218792Snpstatic int 1821228561Snpget_params__pre_init(struct adapter *sc) 1822218792Snp{ 1823218792Snp int rc; 1824228561Snp uint32_t param[2], val[2]; 1825228561Snp struct fw_devlog_cmd cmd; 1826228561Snp struct devlog_params *dlog = &sc->params.devlog; 1827218792Snp 1828228561Snp param[0] = FW_PARAM_DEV(PORTVEC); 1829228561Snp param[1] = FW_PARAM_DEV(CCLK); 1830228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 1831218792Snp if (rc != 0) { 1832218792Snp device_printf(sc->dev, 1833228561Snp "failed to query parameters (pre_init): %d.\n", rc); 1834228561Snp return (rc); 1835218792Snp } 1836218792Snp 1837218792Snp sc->params.portvec = val[0]; 1838218792Snp sc->params.nports = 0; 1839218792Snp while (val[0]) { 1840218792Snp sc->params.nports++; 1841218792Snp val[0] &= val[0] - 1; 1842218792Snp } 1843218792Snp 1844228561Snp sc->params.vpd.cclk = val[1]; 1845218792Snp 1846228561Snp /* Read device log parameters. */ 1847228561Snp bzero(&cmd, sizeof(cmd)); 1848228561Snp cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) | 1849228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1850228561Snp cmd.retval_len16 = htobe32(FW_LEN16(cmd)); 1851228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &cmd, sizeof(cmd), &cmd); 1852228561Snp if (rc != 0) { 1853228561Snp device_printf(sc->dev, 1854228561Snp "failed to get devlog parameters: %d.\n", rc); 1855228561Snp bzero(dlog, sizeof (*dlog)); 1856228561Snp rc = 0; /* devlog isn't critical for device operation */ 1857228561Snp } else { 1858228561Snp val[0] = be32toh(cmd.memtype_devlog_memaddr16_devlog); 1859228561Snp dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(val[0]); 1860228561Snp dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(val[0]) << 4; 1861228561Snp dlog->size = be32toh(cmd.memsize_devlog); 1862228561Snp } 1863228561Snp 1864228561Snp return (rc); 1865228561Snp} 1866228561Snp 1867228561Snp/* 1868228561Snp * Retrieve various parameters that are of interest to the driver. The device 1869228561Snp * has been initialized by the firmware at this point. 1870228561Snp */ 1871228561Snpstatic int 1872228561Snpget_params__post_init(struct adapter *sc) 1873228561Snp{ 1874228561Snp int rc; 1875228561Snp uint32_t param[7], val[7]; 1876228561Snp struct fw_caps_config_cmd caps; 1877228561Snp 1878228561Snp param[0] = FW_PARAM_PFVF(IQFLINT_START); 1879228561Snp param[1] = FW_PARAM_PFVF(EQ_START); 1880228561Snp param[2] = FW_PARAM_PFVF(FILTER_START); 1881228561Snp param[3] = FW_PARAM_PFVF(FILTER_END); 1882228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 4, param, val); 1883228561Snp if (rc != 0) { 1884228561Snp device_printf(sc->dev, 1885228561Snp "failed to query parameters (post_init): %d.\n", rc); 1886228561Snp return (rc); 1887228561Snp } 1888228561Snp 1889228561Snp sc->sge.iq_start = val[0]; 1890228561Snp sc->sge.eq_start = val[1]; 1891228561Snp sc->tids.ftid_base = val[2]; 1892228561Snp sc->tids.nftids = val[3] - val[2] + 1; 1893228561Snp 1894228561Snp /* get capabilites */ 1895228561Snp bzero(&caps, sizeof(caps)); 1896228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1897228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1898228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 1899228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 1900228561Snp if (rc != 0) { 1901228561Snp device_printf(sc->dev, 1902228561Snp "failed to get card capabilities: %d.\n", rc); 1903228561Snp return (rc); 1904228561Snp } 1905228561Snp 1906228561Snp if (caps.toecaps) { 1907218792Snp /* query offload-related parameters */ 1908228561Snp param[0] = FW_PARAM_DEV(NTID); 1909228561Snp param[1] = FW_PARAM_PFVF(SERVER_START); 1910228561Snp param[2] = FW_PARAM_PFVF(SERVER_END); 1911228561Snp param[3] = FW_PARAM_PFVF(TDDP_START); 1912228561Snp param[4] = FW_PARAM_PFVF(TDDP_END); 1913228561Snp param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 1914228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 1915218792Snp if (rc != 0) { 1916218792Snp device_printf(sc->dev, 1917218792Snp "failed to query TOE parameters: %d.\n", rc); 1918228561Snp return (rc); 1919218792Snp } 1920218792Snp sc->tids.ntids = val[0]; 1921218792Snp sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS); 1922218792Snp sc->tids.stid_base = val[1]; 1923218792Snp sc->tids.nstids = val[2] - val[1] + 1; 1924218792Snp sc->vres.ddp.start = val[3]; 1925218792Snp sc->vres.ddp.size = val[4] - val[3] + 1; 1926218792Snp sc->params.ofldq_wr_cred = val[5]; 1927218792Snp sc->params.offload = 1; 1928218792Snp } 1929228561Snp if (caps.rdmacaps) { 1930228561Snp param[0] = FW_PARAM_PFVF(STAG_START); 1931228561Snp param[1] = FW_PARAM_PFVF(STAG_END); 1932228561Snp param[2] = FW_PARAM_PFVF(RQ_START); 1933228561Snp param[3] = FW_PARAM_PFVF(RQ_END); 1934228561Snp param[4] = FW_PARAM_PFVF(PBL_START); 1935228561Snp param[5] = FW_PARAM_PFVF(PBL_END); 1936228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 1937218792Snp if (rc != 0) { 1938218792Snp device_printf(sc->dev, 1939228561Snp "failed to query RDMA parameters(1): %d.\n", rc); 1940228561Snp return (rc); 1941218792Snp } 1942218792Snp sc->vres.stag.start = val[0]; 1943218792Snp sc->vres.stag.size = val[1] - val[0] + 1; 1944218792Snp sc->vres.rq.start = val[2]; 1945218792Snp sc->vres.rq.size = val[3] - val[2] + 1; 1946218792Snp sc->vres.pbl.start = val[4]; 1947218792Snp sc->vres.pbl.size = val[5] - val[4] + 1; 1948228561Snp 1949228561Snp param[0] = FW_PARAM_PFVF(SQRQ_START); 1950228561Snp param[1] = FW_PARAM_PFVF(SQRQ_END); 1951228561Snp param[2] = FW_PARAM_PFVF(CQ_START); 1952228561Snp param[3] = FW_PARAM_PFVF(CQ_END); 1953228561Snp param[4] = FW_PARAM_PFVF(OCQ_START); 1954228561Snp param[5] = FW_PARAM_PFVF(OCQ_END); 1955228561Snp rc = -t4_query_params(sc, 0, 0, 0, 6, param, val); 1956228561Snp if (rc != 0) { 1957228561Snp device_printf(sc->dev, 1958228561Snp "failed to query RDMA parameters(2): %d.\n", rc); 1959228561Snp return (rc); 1960228561Snp } 1961228561Snp sc->vres.qp.start = val[0]; 1962228561Snp sc->vres.qp.size = val[1] - val[0] + 1; 1963228561Snp sc->vres.cq.start = val[2]; 1964228561Snp sc->vres.cq.size = val[3] - val[2] + 1; 1965228561Snp sc->vres.ocq.start = val[4]; 1966228561Snp sc->vres.ocq.size = val[5] - val[4] + 1; 1967218792Snp } 1968228561Snp if (caps.iscsicaps) { 1969228561Snp param[0] = FW_PARAM_PFVF(ISCSI_START); 1970228561Snp param[1] = FW_PARAM_PFVF(ISCSI_END); 1971228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 1972218792Snp if (rc != 0) { 1973218792Snp device_printf(sc->dev, 1974218792Snp "failed to query iSCSI parameters: %d.\n", rc); 1975228561Snp return (rc); 1976218792Snp } 1977218792Snp sc->vres.iscsi.start = val[0]; 1978218792Snp sc->vres.iscsi.size = val[1] - val[0] + 1; 1979218792Snp } 1980218792Snp 1981228561Snp /* These are finalized by FW initialization, load their values now */ 1982228561Snp val[0] = t4_read_reg(sc, A_TP_TIMER_RESOLUTION); 1983228561Snp sc->params.tp.tre = G_TIMERRESOLUTION(val[0]); 1984228561Snp sc->params.tp.dack_re = G_DELAYEDACKRESOLUTION(val[0]); 1985228561Snp t4_read_mtu_tbl(sc, sc->params.mtus, NULL); 1986228561Snp 1987218792Snp return (rc); 1988218792Snp} 1989218792Snp 1990228561Snp#undef FW_PARAM_PFVF 1991228561Snp#undef FW_PARAM_DEV 1992228561Snp 1993218792Snpstatic void 1994218792Snpt4_set_desc(struct adapter *sc) 1995218792Snp{ 1996218792Snp char buf[128]; 1997218792Snp struct adapter_params *p = &sc->params; 1998218792Snp 1999228561Snp snprintf(buf, sizeof(buf), "Chelsio %s %sNIC (rev %d), S/N:%s, E/C:%s", 2000228561Snp p->vpd.id, is_offload(sc) ? "R" : "", p->rev, p->vpd.sn, p->vpd.ec); 2001218792Snp 2002218792Snp device_set_desc_copy(sc->dev, buf); 2003218792Snp} 2004218792Snp 2005218792Snpstatic void 2006218792Snpbuild_medialist(struct port_info *pi) 2007218792Snp{ 2008218792Snp struct ifmedia *media = &pi->media; 2009218792Snp int data, m; 2010218792Snp 2011218792Snp PORT_LOCK(pi); 2012218792Snp 2013218792Snp ifmedia_removeall(media); 2014218792Snp 2015218792Snp m = IFM_ETHER | IFM_FDX; 2016218792Snp data = (pi->port_type << 8) | pi->mod_type; 2017218792Snp 2018218792Snp switch(pi->port_type) { 2019218792Snp case FW_PORT_TYPE_BT_XFI: 2020218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2021218792Snp break; 2022218792Snp 2023218792Snp case FW_PORT_TYPE_BT_XAUI: 2024218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2025218792Snp /* fall through */ 2026218792Snp 2027218792Snp case FW_PORT_TYPE_BT_SGMII: 2028218792Snp ifmedia_add(media, m | IFM_1000_T, data, NULL); 2029218792Snp ifmedia_add(media, m | IFM_100_TX, data, NULL); 2030218792Snp ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL); 2031218792Snp ifmedia_set(media, IFM_ETHER | IFM_AUTO); 2032218792Snp break; 2033218792Snp 2034218792Snp case FW_PORT_TYPE_CX4: 2035218792Snp ifmedia_add(media, m | IFM_10G_CX4, data, NULL); 2036218792Snp ifmedia_set(media, m | IFM_10G_CX4); 2037218792Snp break; 2038218792Snp 2039218792Snp case FW_PORT_TYPE_SFP: 2040218792Snp case FW_PORT_TYPE_FIBER_XFI: 2041218792Snp case FW_PORT_TYPE_FIBER_XAUI: 2042218792Snp switch (pi->mod_type) { 2043218792Snp 2044218792Snp case FW_PORT_MOD_TYPE_LR: 2045218792Snp ifmedia_add(media, m | IFM_10G_LR, data, NULL); 2046218792Snp ifmedia_set(media, m | IFM_10G_LR); 2047218792Snp break; 2048218792Snp 2049218792Snp case FW_PORT_MOD_TYPE_SR: 2050218792Snp ifmedia_add(media, m | IFM_10G_SR, data, NULL); 2051218792Snp ifmedia_set(media, m | IFM_10G_SR); 2052218792Snp break; 2053218792Snp 2054218792Snp case FW_PORT_MOD_TYPE_LRM: 2055218792Snp ifmedia_add(media, m | IFM_10G_LRM, data, NULL); 2056218792Snp ifmedia_set(media, m | IFM_10G_LRM); 2057218792Snp break; 2058218792Snp 2059218792Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2060218792Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2061218792Snp ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL); 2062218792Snp ifmedia_set(media, m | IFM_10G_TWINAX); 2063218792Snp break; 2064218792Snp 2065218792Snp case FW_PORT_MOD_TYPE_NONE: 2066218792Snp m &= ~IFM_FDX; 2067218792Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2068218792Snp ifmedia_set(media, m | IFM_NONE); 2069218792Snp break; 2070218792Snp 2071218792Snp case FW_PORT_MOD_TYPE_NA: 2072218792Snp case FW_PORT_MOD_TYPE_ER: 2073218792Snp default: 2074218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2075218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2076218792Snp break; 2077218792Snp } 2078218792Snp break; 2079218792Snp 2080218792Snp case FW_PORT_TYPE_KX4: 2081218792Snp case FW_PORT_TYPE_KX: 2082218792Snp case FW_PORT_TYPE_KR: 2083218792Snp default: 2084218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2085218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2086218792Snp break; 2087218792Snp } 2088218792Snp 2089218792Snp PORT_UNLOCK(pi); 2090218792Snp} 2091218792Snp 2092231172Snp#define FW_MAC_EXACT_CHUNK 7 2093231172Snp 2094218792Snp/* 2095218792Snp * Program the port's XGMAC based on parameters in ifnet. The caller also 2096218792Snp * indicates which parameters should be programmed (the rest are left alone). 2097218792Snp */ 2098218792Snpstatic int 2099218792Snpupdate_mac_settings(struct port_info *pi, int flags) 2100218792Snp{ 2101218792Snp int rc; 2102218792Snp struct ifnet *ifp = pi->ifp; 2103218792Snp struct adapter *sc = pi->adapter; 2104218792Snp int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1; 2105218792Snp 2106218792Snp PORT_LOCK_ASSERT_OWNED(pi); 2107218792Snp KASSERT(flags, ("%s: not told what to update.", __func__)); 2108218792Snp 2109218792Snp if (flags & XGMAC_MTU) 2110218792Snp mtu = ifp->if_mtu; 2111218792Snp 2112218792Snp if (flags & XGMAC_PROMISC) 2113218792Snp promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0; 2114218792Snp 2115218792Snp if (flags & XGMAC_ALLMULTI) 2116218792Snp allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0; 2117218792Snp 2118218792Snp if (flags & XGMAC_VLANEX) 2119218792Snp vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0; 2120218792Snp 2121218792Snp rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, mtu, promisc, allmulti, 1, 2122218792Snp vlanex, false); 2123218792Snp if (rc) { 2124218792Snp if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, rc); 2125218792Snp return (rc); 2126218792Snp } 2127218792Snp 2128218792Snp if (flags & XGMAC_UCADDR) { 2129218792Snp uint8_t ucaddr[ETHER_ADDR_LEN]; 2130218792Snp 2131218792Snp bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr)); 2132218792Snp rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, 2133218792Snp ucaddr, true, true); 2134218792Snp if (rc < 0) { 2135218792Snp rc = -rc; 2136218792Snp if_printf(ifp, "change_mac failed: %d\n", rc); 2137218792Snp return (rc); 2138218792Snp } else { 2139218792Snp pi->xact_addr_filt = rc; 2140218792Snp rc = 0; 2141218792Snp } 2142218792Snp } 2143218792Snp 2144218792Snp if (flags & XGMAC_MCADDRS) { 2145231172Snp const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK]; 2146218792Snp int del = 1; 2147218792Snp uint64_t hash = 0; 2148218792Snp struct ifmultiaddr *ifma; 2149231172Snp int i = 0, j; 2150218792Snp 2151218792Snp if_maddr_rlock(ifp); 2152218792Snp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2153238054Snp if (ifma->ifma_addr->sa_family != AF_LINK) 2154218792Snp continue; 2155231172Snp mcaddr[i++] = 2156231172Snp LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 2157218792Snp 2158231172Snp if (i == FW_MAC_EXACT_CHUNK) { 2159231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2160231172Snp del, i, mcaddr, NULL, &hash, 0); 2161231172Snp if (rc < 0) { 2162231172Snp rc = -rc; 2163231172Snp for (j = 0; j < i; j++) { 2164231172Snp if_printf(ifp, 2165231172Snp "failed to add mc address" 2166231172Snp " %02x:%02x:%02x:" 2167231172Snp "%02x:%02x:%02x rc=%d\n", 2168231172Snp mcaddr[j][0], mcaddr[j][1], 2169231172Snp mcaddr[j][2], mcaddr[j][3], 2170231172Snp mcaddr[j][4], mcaddr[j][5], 2171231172Snp rc); 2172231172Snp } 2173231172Snp goto mcfail; 2174231172Snp } 2175231172Snp del = 0; 2176231172Snp i = 0; 2177231172Snp } 2178231172Snp } 2179231172Snp if (i > 0) { 2180231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2181231172Snp del, i, mcaddr, NULL, &hash, 0); 2182218792Snp if (rc < 0) { 2183218792Snp rc = -rc; 2184231172Snp for (j = 0; j < i; j++) { 2185231172Snp if_printf(ifp, 2186231172Snp "failed to add mc address" 2187231172Snp " %02x:%02x:%02x:" 2188231172Snp "%02x:%02x:%02x rc=%d\n", 2189231172Snp mcaddr[j][0], mcaddr[j][1], 2190231172Snp mcaddr[j][2], mcaddr[j][3], 2191231172Snp mcaddr[j][4], mcaddr[j][5], 2192231172Snp rc); 2193231172Snp } 2194218792Snp goto mcfail; 2195218792Snp } 2196218792Snp } 2197218792Snp 2198218792Snp rc = -t4_set_addr_hash(sc, sc->mbox, pi->viid, 0, hash, 0); 2199218792Snp if (rc != 0) 2200218792Snp if_printf(ifp, "failed to set mc address hash: %d", rc); 2201218792Snpmcfail: 2202218792Snp if_maddr_runlock(ifp); 2203218792Snp } 2204218792Snp 2205218792Snp return (rc); 2206218792Snp} 2207218792Snp 2208218792Snpstatic int 2209218792Snpcxgbe_init_locked(struct port_info *pi) 2210218792Snp{ 2211218792Snp struct adapter *sc = pi->adapter; 2212218792Snp int rc = 0; 2213218792Snp 2214218792Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 2215218792Snp 2216218792Snp while (!IS_DOOMED(pi) && IS_BUSY(sc)) { 2217218792Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4init", 0)) { 2218218792Snp rc = EINTR; 2219218792Snp goto done; 2220218792Snp } 2221218792Snp } 2222218792Snp if (IS_DOOMED(pi)) { 2223218792Snp rc = ENXIO; 2224218792Snp goto done; 2225218792Snp } 2226218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 2227218792Snp 2228218792Snp /* Give up the adapter lock, port init code can sleep. */ 2229218792Snp SET_BUSY(sc); 2230218792Snp ADAPTER_UNLOCK(sc); 2231218792Snp 2232218792Snp rc = cxgbe_init_synchronized(pi); 2233218792Snp 2234218792Snpdone: 2235218792Snp ADAPTER_LOCK(sc); 2236218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 2237218792Snp CLR_BUSY(sc); 2238218792Snp wakeup_one(&sc->flags); 2239218792Snp ADAPTER_UNLOCK(sc); 2240218792Snp return (rc); 2241218792Snp} 2242218792Snp 2243218792Snpstatic int 2244218792Snpcxgbe_init_synchronized(struct port_info *pi) 2245218792Snp{ 2246218792Snp struct adapter *sc = pi->adapter; 2247218792Snp struct ifnet *ifp = pi->ifp; 2248228561Snp int rc = 0; 2249218792Snp 2250218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2251218792Snp 2252218792Snp if (isset(&sc->open_device_map, pi->port_id)) { 2253218792Snp KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, 2254218792Snp ("mismatch between open_device_map and if_drv_flags")); 2255218792Snp return (0); /* already running */ 2256218792Snp } 2257218792Snp 2258228561Snp if (!(sc->flags & FULL_INIT_DONE) && 2259228561Snp ((rc = adapter_full_init(sc)) != 0)) 2260218792Snp return (rc); /* error message displayed already */ 2261218792Snp 2262228561Snp if (!(pi->flags & PORT_INIT_DONE) && 2263228561Snp ((rc = port_full_init(pi)) != 0)) 2264228561Snp return (rc); /* error message displayed already */ 2265218792Snp 2266218792Snp PORT_LOCK(pi); 2267218792Snp rc = update_mac_settings(pi, XGMAC_ALL); 2268218792Snp PORT_UNLOCK(pi); 2269218792Snp if (rc) 2270218792Snp goto done; /* error message displayed already */ 2271218792Snp 2272218792Snp rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg); 2273218792Snp if (rc != 0) { 2274218792Snp if_printf(ifp, "start_link failed: %d\n", rc); 2275218792Snp goto done; 2276218792Snp } 2277218792Snp 2278218792Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true); 2279218792Snp if (rc != 0) { 2280218792Snp if_printf(ifp, "enable_vi failed: %d\n", rc); 2281218792Snp goto done; 2282218792Snp } 2283218792Snp 2284218792Snp /* all ok */ 2285218792Snp setbit(&sc->open_device_map, pi->port_id); 2286218792Snp ifp->if_drv_flags |= IFF_DRV_RUNNING; 2287218792Snp 2288218792Snp callout_reset(&pi->tick, hz, cxgbe_tick, pi); 2289218792Snpdone: 2290218792Snp if (rc != 0) 2291218792Snp cxgbe_uninit_synchronized(pi); 2292218792Snp 2293218792Snp return (rc); 2294218792Snp} 2295218792Snp 2296218792Snpstatic int 2297218792Snpcxgbe_uninit_locked(struct port_info *pi) 2298218792Snp{ 2299218792Snp struct adapter *sc = pi->adapter; 2300218792Snp int rc; 2301218792Snp 2302218792Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 2303218792Snp 2304218792Snp while (!IS_DOOMED(pi) && IS_BUSY(sc)) { 2305218792Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4uninit", 0)) { 2306218792Snp rc = EINTR; 2307218792Snp goto done; 2308218792Snp } 2309218792Snp } 2310218792Snp if (IS_DOOMED(pi)) { 2311218792Snp rc = ENXIO; 2312218792Snp goto done; 2313218792Snp } 2314218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 2315218792Snp SET_BUSY(sc); 2316218792Snp ADAPTER_UNLOCK(sc); 2317218792Snp 2318218792Snp rc = cxgbe_uninit_synchronized(pi); 2319218792Snp 2320218792Snp ADAPTER_LOCK(sc); 2321218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 2322218792Snp CLR_BUSY(sc); 2323218792Snp wakeup_one(&sc->flags); 2324218792Snpdone: 2325218792Snp ADAPTER_UNLOCK(sc); 2326218792Snp return (rc); 2327218792Snp} 2328218792Snp 2329218792Snp/* 2330218792Snp * Idempotent. 2331218792Snp */ 2332218792Snpstatic int 2333218792Snpcxgbe_uninit_synchronized(struct port_info *pi) 2334218792Snp{ 2335218792Snp struct adapter *sc = pi->adapter; 2336218792Snp struct ifnet *ifp = pi->ifp; 2337218792Snp int rc; 2338218792Snp 2339218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2340218792Snp 2341218792Snp /* 2342228561Snp * Disable the VI so that all its data in either direction is discarded 2343228561Snp * by the MPS. Leave everything else (the queues, interrupts, and 1Hz 2344228561Snp * tick) intact as the TP can deliver negative advice or data that it's 2345228561Snp * holding in its RAM (for an offloaded connection) even after the VI is 2346228561Snp * disabled. 2347218792Snp */ 2348228561Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false); 2349228561Snp if (rc) { 2350228561Snp if_printf(ifp, "disable_vi failed: %d\n", rc); 2351228561Snp return (rc); 2352228561Snp } 2353228561Snp 2354218792Snp clrbit(&sc->open_device_map, pi->port_id); 2355228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2356218792Snp 2357218792Snp pi->link_cfg.link_ok = 0; 2358218792Snp pi->link_cfg.speed = 0; 2359218792Snp t4_os_link_changed(sc, pi->port_id, 0); 2360218792Snp 2361218792Snp return (0); 2362218792Snp} 2363218792Snp 2364222510Snp#define T4_ALLOC_IRQ(sc, irq, rid, handler, arg, name) do { \ 2365222510Snp rc = t4_alloc_irq(sc, irq, rid, handler, arg, name); \ 2366218792Snp if (rc != 0) \ 2367218792Snp goto done; \ 2368218792Snp} while (0) 2369228561Snp 2370218792Snpstatic int 2371228561Snpadapter_full_init(struct adapter *sc) 2372218792Snp{ 2373222510Snp int rc, i, rid, p, q; 2374222510Snp char s[8]; 2375222510Snp struct irq *irq; 2376228561Snp struct port_info *pi; 2377228561Snp struct sge_rxq *rxq; 2378237263Snp#ifdef TCP_OFFLOAD 2379228561Snp struct sge_ofld_rxq *ofld_rxq; 2380228561Snp#endif 2381218792Snp 2382218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2383228561Snp KASSERT((sc->flags & FULL_INIT_DONE) == 0, 2384228561Snp ("%s: FULL_INIT_DONE already", __func__)); 2385218792Snp 2386218792Snp /* 2387220873Snp * queues that belong to the adapter (not any particular port). 2388218792Snp */ 2389220873Snp rc = t4_setup_adapter_queues(sc); 2390218792Snp if (rc != 0) 2391218792Snp goto done; 2392218792Snp 2393228561Snp for (i = 0; i < ARRAY_SIZE(sc->tq); i++) { 2394228561Snp sc->tq[i] = taskqueue_create("t4 taskq", M_NOWAIT, 2395228561Snp taskqueue_thread_enqueue, &sc->tq[i]); 2396228561Snp if (sc->tq[i] == NULL) { 2397228561Snp device_printf(sc->dev, 2398228561Snp "failed to allocate task queue %d\n", i); 2399228561Snp rc = ENOMEM; 2400228561Snp goto done; 2401228561Snp } 2402228561Snp taskqueue_start_threads(&sc->tq[i], 1, PI_NET, "%s tq%d", 2403228561Snp device_get_nameunit(sc->dev), i); 2404228561Snp } 2405228561Snp 2406218792Snp /* 2407218792Snp * Setup interrupts. 2408218792Snp */ 2409222510Snp irq = &sc->irq[0]; 2410222510Snp rid = sc->intr_type == INTR_INTX ? 0 : 1; 2411218792Snp if (sc->intr_count == 1) { 2412228561Snp KASSERT(!(sc->flags & INTR_DIRECT), 2413228561Snp ("%s: single interrupt && INTR_DIRECT?", __func__)); 2414222510Snp 2415222510Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr_all, sc, "all"); 2416218792Snp } else { 2417228561Snp /* Multiple interrupts. */ 2418228561Snp KASSERT(sc->intr_count >= T4_EXTRA_INTR + sc->params.nports, 2419228561Snp ("%s: too few intr.", __func__)); 2420228561Snp 2421228561Snp /* The first one is always error intr */ 2422222510Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr_err, sc, "err"); 2423222510Snp irq++; 2424222510Snp rid++; 2425218792Snp 2426228561Snp /* The second one is always the firmware event queue */ 2427228561Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr_evt, &sc->sge.fwq, "evt"); 2428228561Snp irq++; 2429228561Snp rid++; 2430222510Snp 2431228561Snp /* 2432228561Snp * Note that if INTR_DIRECT is not set then either the NIC rx 2433228561Snp * queues or (exclusive or) the TOE rx queueus will be taking 2434228561Snp * direct interrupts. 2435228561Snp * 2436228561Snp * There is no need to check for is_offload(sc) as nofldrxq 2437228561Snp * will be 0 if offload is disabled. 2438228561Snp */ 2439228561Snp for_each_port(sc, p) { 2440228561Snp pi = sc->port[p]; 2441222510Snp 2442237263Snp#ifdef TCP_OFFLOAD 2443228561Snp /* 2444228561Snp * Skip over the NIC queues if they aren't taking direct 2445228561Snp * interrupts. 2446228561Snp */ 2447228561Snp if (!(sc->flags & INTR_DIRECT) && 2448228561Snp pi->nofldrxq > pi->nrxq) 2449228561Snp goto ofld_queues; 2450228561Snp#endif 2451228561Snp rxq = &sc->sge.rxq[pi->first_rxq]; 2452228561Snp for (q = 0; q < pi->nrxq; q++, rxq++) { 2453228561Snp snprintf(s, sizeof(s), "%d.%d", p, q); 2454228561Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr, rxq, s); 2455222510Snp irq++; 2456222510Snp rid++; 2457218792Snp } 2458218792Snp 2459237263Snp#ifdef TCP_OFFLOAD 2460228561Snp /* 2461228561Snp * Skip over the offload queues if they aren't taking 2462228561Snp * direct interrupts. 2463228561Snp */ 2464228561Snp if (!(sc->flags & INTR_DIRECT)) 2465228561Snp continue; 2466228561Snpofld_queues: 2467228561Snp ofld_rxq = &sc->sge.ofld_rxq[pi->first_ofld_rxq]; 2468228561Snp for (q = 0; q < pi->nofldrxq; q++, ofld_rxq++) { 2469228561Snp snprintf(s, sizeof(s), "%d,%d", p, q); 2470228561Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr, ofld_rxq, s); 2471228561Snp irq++; 2472228561Snp rid++; 2473218792Snp } 2474228561Snp#endif 2475218792Snp } 2476218792Snp } 2477218792Snp 2478218792Snp t4_intr_enable(sc); 2479218792Snp sc->flags |= FULL_INIT_DONE; 2480218792Snpdone: 2481218792Snp if (rc != 0) 2482228561Snp adapter_full_uninit(sc); 2483218792Snp 2484218792Snp return (rc); 2485218792Snp} 2486218792Snp#undef T4_ALLOC_IRQ 2487218792Snp 2488218792Snpstatic int 2489228561Snpadapter_full_uninit(struct adapter *sc) 2490218792Snp{ 2491218792Snp int i; 2492218792Snp 2493218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2494218792Snp 2495220873Snp t4_teardown_adapter_queues(sc); 2496218792Snp 2497218792Snp for (i = 0; i < sc->intr_count; i++) 2498218792Snp t4_free_irq(sc, &sc->irq[i]); 2499218792Snp 2500228561Snp for (i = 0; i < ARRAY_SIZE(sc->tq) && sc->tq[i]; i++) { 2501228561Snp taskqueue_free(sc->tq[i]); 2502228561Snp sc->tq[i] = NULL; 2503228561Snp } 2504228561Snp 2505218792Snp sc->flags &= ~FULL_INIT_DONE; 2506218792Snp 2507218792Snp return (0); 2508218792Snp} 2509218792Snp 2510218792Snpstatic int 2511228561Snpport_full_init(struct port_info *pi) 2512228561Snp{ 2513228561Snp struct adapter *sc = pi->adapter; 2514228561Snp struct ifnet *ifp = pi->ifp; 2515228561Snp uint16_t *rss; 2516228561Snp struct sge_rxq *rxq; 2517228561Snp int rc, i; 2518228561Snp 2519228561Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2520228561Snp KASSERT((pi->flags & PORT_INIT_DONE) == 0, 2521228561Snp ("%s: PORT_INIT_DONE already", __func__)); 2522228561Snp 2523228561Snp sysctl_ctx_init(&pi->ctx); 2524228561Snp pi->flags |= PORT_SYSCTL_CTX; 2525228561Snp 2526228561Snp /* 2527228561Snp * Allocate tx/rx/fl queues for this port. 2528228561Snp */ 2529228561Snp rc = t4_setup_port_queues(pi); 2530228561Snp if (rc != 0) 2531228561Snp goto done; /* error message displayed already */ 2532228561Snp 2533228561Snp /* 2534228561Snp * Setup RSS for this port. 2535228561Snp */ 2536228561Snp rss = malloc(pi->nrxq * sizeof (*rss), M_CXGBE, 2537228561Snp M_ZERO | M_WAITOK); 2538228561Snp for_each_rxq(pi, i, rxq) { 2539228561Snp rss[i] = rxq->iq.abs_id; 2540228561Snp } 2541228561Snp rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, 2542228561Snp pi->rss_size, rss, pi->nrxq); 2543228561Snp free(rss, M_CXGBE); 2544228561Snp if (rc != 0) { 2545228561Snp if_printf(ifp, "rss_config failed: %d\n", rc); 2546228561Snp goto done; 2547228561Snp } 2548228561Snp 2549228561Snp pi->flags |= PORT_INIT_DONE; 2550228561Snpdone: 2551228561Snp if (rc != 0) 2552228561Snp port_full_uninit(pi); 2553228561Snp 2554228561Snp return (rc); 2555228561Snp} 2556228561Snp 2557228561Snp/* 2558228561Snp * Idempotent. 2559228561Snp */ 2560228561Snpstatic int 2561228561Snpport_full_uninit(struct port_info *pi) 2562228561Snp{ 2563228561Snp struct adapter *sc = pi->adapter; 2564228561Snp int i; 2565228561Snp struct sge_rxq *rxq; 2566228561Snp struct sge_txq *txq; 2567237263Snp#ifdef TCP_OFFLOAD 2568228561Snp struct sge_ofld_rxq *ofld_rxq; 2569228561Snp struct sge_wrq *ofld_txq; 2570228561Snp#endif 2571228561Snp 2572228561Snp if (pi->flags & PORT_INIT_DONE) { 2573228561Snp 2574228561Snp /* Need to quiesce queues. XXX: ctrl queues? */ 2575228561Snp 2576228561Snp for_each_txq(pi, i, txq) { 2577228561Snp quiesce_eq(sc, &txq->eq); 2578228561Snp } 2579228561Snp 2580237263Snp#ifdef TCP_OFFLOAD 2581228561Snp for_each_ofld_txq(pi, i, ofld_txq) { 2582228561Snp quiesce_eq(sc, &ofld_txq->eq); 2583228561Snp } 2584228561Snp#endif 2585228561Snp 2586228561Snp for_each_rxq(pi, i, rxq) { 2587228561Snp quiesce_iq(sc, &rxq->iq); 2588228561Snp quiesce_fl(sc, &rxq->fl); 2589228561Snp } 2590228561Snp 2591237263Snp#ifdef TCP_OFFLOAD 2592228561Snp for_each_ofld_rxq(pi, i, ofld_rxq) { 2593228561Snp quiesce_iq(sc, &ofld_rxq->iq); 2594228561Snp quiesce_fl(sc, &ofld_rxq->fl); 2595228561Snp } 2596228561Snp#endif 2597228561Snp } 2598228561Snp 2599228561Snp t4_teardown_port_queues(pi); 2600228561Snp pi->flags &= ~PORT_INIT_DONE; 2601228561Snp 2602228561Snp return (0); 2603228561Snp} 2604228561Snp 2605228561Snpstatic void 2606228561Snpquiesce_eq(struct adapter *sc, struct sge_eq *eq) 2607228561Snp{ 2608228561Snp EQ_LOCK(eq); 2609228561Snp eq->flags |= EQ_DOOMED; 2610228561Snp 2611228561Snp /* 2612228561Snp * Wait for the response to a credit flush if one's 2613228561Snp * pending. 2614228561Snp */ 2615228561Snp while (eq->flags & EQ_CRFLUSHED) 2616228561Snp mtx_sleep(eq, &eq->eq_lock, 0, "crflush", 0); 2617228561Snp EQ_UNLOCK(eq); 2618228561Snp 2619228561Snp callout_drain(&eq->tx_callout); /* XXX: iffy */ 2620228561Snp pause("callout", 10); /* Still iffy */ 2621228561Snp 2622228561Snp taskqueue_drain(sc->tq[eq->tx_chan], &eq->tx_task); 2623228561Snp} 2624228561Snp 2625228561Snpstatic void 2626228561Snpquiesce_iq(struct adapter *sc, struct sge_iq *iq) 2627228561Snp{ 2628228561Snp (void) sc; /* unused */ 2629228561Snp 2630228561Snp /* Synchronize with the interrupt handler */ 2631228561Snp while (!atomic_cmpset_int(&iq->state, IQS_IDLE, IQS_DISABLED)) 2632228561Snp pause("iqfree", 1); 2633228561Snp} 2634228561Snp 2635228561Snpstatic void 2636228561Snpquiesce_fl(struct adapter *sc, struct sge_fl *fl) 2637228561Snp{ 2638228561Snp mtx_lock(&sc->sfl_lock); 2639228561Snp FL_LOCK(fl); 2640228561Snp fl->flags |= FL_DOOMED; 2641228561Snp FL_UNLOCK(fl); 2642228561Snp mtx_unlock(&sc->sfl_lock); 2643228561Snp 2644228561Snp callout_drain(&sc->sfl_callout); 2645228561Snp KASSERT((fl->flags & FL_STARVING) == 0, 2646228561Snp ("%s: still starving", __func__)); 2647228561Snp} 2648228561Snp 2649228561Snpstatic int 2650218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid, 2651228561Snp driver_intr_t *handler, void *arg, char *name) 2652218792Snp{ 2653218792Snp int rc; 2654218792Snp 2655218792Snp irq->rid = rid; 2656218792Snp irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid, 2657218792Snp RF_SHAREABLE | RF_ACTIVE); 2658218792Snp if (irq->res == NULL) { 2659218792Snp device_printf(sc->dev, 2660218792Snp "failed to allocate IRQ for rid %d, name %s.\n", rid, name); 2661218792Snp return (ENOMEM); 2662218792Snp } 2663218792Snp 2664218792Snp rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET, 2665218792Snp NULL, handler, arg, &irq->tag); 2666218792Snp if (rc != 0) { 2667218792Snp device_printf(sc->dev, 2668218792Snp "failed to setup interrupt for rid %d, name %s: %d\n", 2669218792Snp rid, name, rc); 2670218792Snp } else if (name) 2671218792Snp bus_describe_intr(sc->dev, irq->res, irq->tag, name); 2672218792Snp 2673218792Snp return (rc); 2674218792Snp} 2675218792Snp 2676218792Snpstatic int 2677218792Snpt4_free_irq(struct adapter *sc, struct irq *irq) 2678218792Snp{ 2679218792Snp if (irq->tag) 2680218792Snp bus_teardown_intr(sc->dev, irq->res, irq->tag); 2681218792Snp if (irq->res) 2682218792Snp bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res); 2683218792Snp 2684218792Snp bzero(irq, sizeof(*irq)); 2685218792Snp 2686218792Snp return (0); 2687218792Snp} 2688218792Snp 2689218792Snpstatic void 2690218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start, 2691218792Snp unsigned int end) 2692218792Snp{ 2693218792Snp uint32_t *p = (uint32_t *)(buf + start); 2694218792Snp 2695218792Snp for ( ; start <= end; start += sizeof(uint32_t)) 2696218792Snp *p++ = t4_read_reg(sc, start); 2697218792Snp} 2698218792Snp 2699218792Snpstatic void 2700218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf) 2701218792Snp{ 2702218792Snp int i; 2703218792Snp static const unsigned int reg_ranges[] = { 2704218792Snp 0x1008, 0x1108, 2705218792Snp 0x1180, 0x11b4, 2706218792Snp 0x11fc, 0x123c, 2707218792Snp 0x1300, 0x173c, 2708218792Snp 0x1800, 0x18fc, 2709218792Snp 0x3000, 0x30d8, 2710218792Snp 0x30e0, 0x5924, 2711218792Snp 0x5960, 0x59d4, 2712218792Snp 0x5a00, 0x5af8, 2713218792Snp 0x6000, 0x6098, 2714218792Snp 0x6100, 0x6150, 2715218792Snp 0x6200, 0x6208, 2716218792Snp 0x6240, 0x6248, 2717218792Snp 0x6280, 0x6338, 2718218792Snp 0x6370, 0x638c, 2719218792Snp 0x6400, 0x643c, 2720218792Snp 0x6500, 0x6524, 2721218792Snp 0x6a00, 0x6a38, 2722218792Snp 0x6a60, 0x6a78, 2723218792Snp 0x6b00, 0x6b84, 2724218792Snp 0x6bf0, 0x6c84, 2725218792Snp 0x6cf0, 0x6d84, 2726218792Snp 0x6df0, 0x6e84, 2727218792Snp 0x6ef0, 0x6f84, 2728218792Snp 0x6ff0, 0x7084, 2729218792Snp 0x70f0, 0x7184, 2730218792Snp 0x71f0, 0x7284, 2731218792Snp 0x72f0, 0x7384, 2732218792Snp 0x73f0, 0x7450, 2733218792Snp 0x7500, 0x7530, 2734218792Snp 0x7600, 0x761c, 2735218792Snp 0x7680, 0x76cc, 2736218792Snp 0x7700, 0x7798, 2737218792Snp 0x77c0, 0x77fc, 2738218792Snp 0x7900, 0x79fc, 2739218792Snp 0x7b00, 0x7c38, 2740218792Snp 0x7d00, 0x7efc, 2741218792Snp 0x8dc0, 0x8e1c, 2742218792Snp 0x8e30, 0x8e78, 2743218792Snp 0x8ea0, 0x8f6c, 2744218792Snp 0x8fc0, 0x9074, 2745218792Snp 0x90fc, 0x90fc, 2746218792Snp 0x9400, 0x9458, 2747218792Snp 0x9600, 0x96bc, 2748218792Snp 0x9800, 0x9808, 2749218792Snp 0x9820, 0x983c, 2750218792Snp 0x9850, 0x9864, 2751218792Snp 0x9c00, 0x9c6c, 2752218792Snp 0x9c80, 0x9cec, 2753218792Snp 0x9d00, 0x9d6c, 2754218792Snp 0x9d80, 0x9dec, 2755218792Snp 0x9e00, 0x9e6c, 2756218792Snp 0x9e80, 0x9eec, 2757218792Snp 0x9f00, 0x9f6c, 2758218792Snp 0x9f80, 0x9fec, 2759218792Snp 0xd004, 0xd03c, 2760218792Snp 0xdfc0, 0xdfe0, 2761218792Snp 0xe000, 0xea7c, 2762218792Snp 0xf000, 0x11190, 2763237439Snp 0x19040, 0x1906c, 2764237439Snp 0x19078, 0x19080, 2765237439Snp 0x1908c, 0x19124, 2766218792Snp 0x19150, 0x191b0, 2767218792Snp 0x191d0, 0x191e8, 2768218792Snp 0x19238, 0x1924c, 2769218792Snp 0x193f8, 0x19474, 2770218792Snp 0x19490, 0x194f8, 2771218792Snp 0x19800, 0x19f30, 2772218792Snp 0x1a000, 0x1a06c, 2773218792Snp 0x1a0b0, 0x1a120, 2774218792Snp 0x1a128, 0x1a138, 2775218792Snp 0x1a190, 0x1a1c4, 2776218792Snp 0x1a1fc, 0x1a1fc, 2777218792Snp 0x1e040, 0x1e04c, 2778237439Snp 0x1e284, 0x1e28c, 2779218792Snp 0x1e2c0, 0x1e2c0, 2780218792Snp 0x1e2e0, 0x1e2e0, 2781218792Snp 0x1e300, 0x1e384, 2782218792Snp 0x1e3c0, 0x1e3c8, 2783218792Snp 0x1e440, 0x1e44c, 2784237439Snp 0x1e684, 0x1e68c, 2785218792Snp 0x1e6c0, 0x1e6c0, 2786218792Snp 0x1e6e0, 0x1e6e0, 2787218792Snp 0x1e700, 0x1e784, 2788218792Snp 0x1e7c0, 0x1e7c8, 2789218792Snp 0x1e840, 0x1e84c, 2790237439Snp 0x1ea84, 0x1ea8c, 2791218792Snp 0x1eac0, 0x1eac0, 2792218792Snp 0x1eae0, 0x1eae0, 2793218792Snp 0x1eb00, 0x1eb84, 2794218792Snp 0x1ebc0, 0x1ebc8, 2795218792Snp 0x1ec40, 0x1ec4c, 2796237439Snp 0x1ee84, 0x1ee8c, 2797218792Snp 0x1eec0, 0x1eec0, 2798218792Snp 0x1eee0, 0x1eee0, 2799218792Snp 0x1ef00, 0x1ef84, 2800218792Snp 0x1efc0, 0x1efc8, 2801218792Snp 0x1f040, 0x1f04c, 2802237439Snp 0x1f284, 0x1f28c, 2803218792Snp 0x1f2c0, 0x1f2c0, 2804218792Snp 0x1f2e0, 0x1f2e0, 2805218792Snp 0x1f300, 0x1f384, 2806218792Snp 0x1f3c0, 0x1f3c8, 2807218792Snp 0x1f440, 0x1f44c, 2808237439Snp 0x1f684, 0x1f68c, 2809218792Snp 0x1f6c0, 0x1f6c0, 2810218792Snp 0x1f6e0, 0x1f6e0, 2811218792Snp 0x1f700, 0x1f784, 2812218792Snp 0x1f7c0, 0x1f7c8, 2813218792Snp 0x1f840, 0x1f84c, 2814237439Snp 0x1fa84, 0x1fa8c, 2815218792Snp 0x1fac0, 0x1fac0, 2816218792Snp 0x1fae0, 0x1fae0, 2817218792Snp 0x1fb00, 0x1fb84, 2818218792Snp 0x1fbc0, 0x1fbc8, 2819218792Snp 0x1fc40, 0x1fc4c, 2820237439Snp 0x1fe84, 0x1fe8c, 2821218792Snp 0x1fec0, 0x1fec0, 2822218792Snp 0x1fee0, 0x1fee0, 2823218792Snp 0x1ff00, 0x1ff84, 2824218792Snp 0x1ffc0, 0x1ffc8, 2825218792Snp 0x20000, 0x2002c, 2826218792Snp 0x20100, 0x2013c, 2827218792Snp 0x20190, 0x201c8, 2828218792Snp 0x20200, 0x20318, 2829218792Snp 0x20400, 0x20528, 2830218792Snp 0x20540, 0x20614, 2831218792Snp 0x21000, 0x21040, 2832218792Snp 0x2104c, 0x21060, 2833218792Snp 0x210c0, 0x210ec, 2834218792Snp 0x21200, 0x21268, 2835218792Snp 0x21270, 0x21284, 2836218792Snp 0x212fc, 0x21388, 2837218792Snp 0x21400, 0x21404, 2838218792Snp 0x21500, 0x21518, 2839218792Snp 0x2152c, 0x2153c, 2840218792Snp 0x21550, 0x21554, 2841218792Snp 0x21600, 0x21600, 2842218792Snp 0x21608, 0x21628, 2843218792Snp 0x21630, 0x2163c, 2844218792Snp 0x21700, 0x2171c, 2845218792Snp 0x21780, 0x2178c, 2846218792Snp 0x21800, 0x21c38, 2847218792Snp 0x21c80, 0x21d7c, 2848218792Snp 0x21e00, 0x21e04, 2849218792Snp 0x22000, 0x2202c, 2850218792Snp 0x22100, 0x2213c, 2851218792Snp 0x22190, 0x221c8, 2852218792Snp 0x22200, 0x22318, 2853218792Snp 0x22400, 0x22528, 2854218792Snp 0x22540, 0x22614, 2855218792Snp 0x23000, 0x23040, 2856218792Snp 0x2304c, 0x23060, 2857218792Snp 0x230c0, 0x230ec, 2858218792Snp 0x23200, 0x23268, 2859218792Snp 0x23270, 0x23284, 2860218792Snp 0x232fc, 0x23388, 2861218792Snp 0x23400, 0x23404, 2862218792Snp 0x23500, 0x23518, 2863218792Snp 0x2352c, 0x2353c, 2864218792Snp 0x23550, 0x23554, 2865218792Snp 0x23600, 0x23600, 2866218792Snp 0x23608, 0x23628, 2867218792Snp 0x23630, 0x2363c, 2868218792Snp 0x23700, 0x2371c, 2869218792Snp 0x23780, 0x2378c, 2870218792Snp 0x23800, 0x23c38, 2871218792Snp 0x23c80, 0x23d7c, 2872218792Snp 0x23e00, 0x23e04, 2873218792Snp 0x24000, 0x2402c, 2874218792Snp 0x24100, 0x2413c, 2875218792Snp 0x24190, 0x241c8, 2876218792Snp 0x24200, 0x24318, 2877218792Snp 0x24400, 0x24528, 2878218792Snp 0x24540, 0x24614, 2879218792Snp 0x25000, 0x25040, 2880218792Snp 0x2504c, 0x25060, 2881218792Snp 0x250c0, 0x250ec, 2882218792Snp 0x25200, 0x25268, 2883218792Snp 0x25270, 0x25284, 2884218792Snp 0x252fc, 0x25388, 2885218792Snp 0x25400, 0x25404, 2886218792Snp 0x25500, 0x25518, 2887218792Snp 0x2552c, 0x2553c, 2888218792Snp 0x25550, 0x25554, 2889218792Snp 0x25600, 0x25600, 2890218792Snp 0x25608, 0x25628, 2891218792Snp 0x25630, 0x2563c, 2892218792Snp 0x25700, 0x2571c, 2893218792Snp 0x25780, 0x2578c, 2894218792Snp 0x25800, 0x25c38, 2895218792Snp 0x25c80, 0x25d7c, 2896218792Snp 0x25e00, 0x25e04, 2897218792Snp 0x26000, 0x2602c, 2898218792Snp 0x26100, 0x2613c, 2899218792Snp 0x26190, 0x261c8, 2900218792Snp 0x26200, 0x26318, 2901218792Snp 0x26400, 0x26528, 2902218792Snp 0x26540, 0x26614, 2903218792Snp 0x27000, 0x27040, 2904218792Snp 0x2704c, 0x27060, 2905218792Snp 0x270c0, 0x270ec, 2906218792Snp 0x27200, 0x27268, 2907218792Snp 0x27270, 0x27284, 2908218792Snp 0x272fc, 0x27388, 2909218792Snp 0x27400, 0x27404, 2910218792Snp 0x27500, 0x27518, 2911218792Snp 0x2752c, 0x2753c, 2912218792Snp 0x27550, 0x27554, 2913218792Snp 0x27600, 0x27600, 2914218792Snp 0x27608, 0x27628, 2915218792Snp 0x27630, 0x2763c, 2916218792Snp 0x27700, 0x2771c, 2917218792Snp 0x27780, 0x2778c, 2918218792Snp 0x27800, 0x27c38, 2919218792Snp 0x27c80, 0x27d7c, 2920218792Snp 0x27e00, 0x27e04 2921218792Snp }; 2922218792Snp 2923218792Snp regs->version = 4 | (sc->params.rev << 10); 2924218792Snp for (i = 0; i < ARRAY_SIZE(reg_ranges); i += 2) 2925218792Snp reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]); 2926218792Snp} 2927218792Snp 2928218792Snpstatic void 2929218792Snpcxgbe_tick(void *arg) 2930218792Snp{ 2931218792Snp struct port_info *pi = arg; 2932218792Snp struct ifnet *ifp = pi->ifp; 2933218792Snp struct sge_txq *txq; 2934218792Snp int i, drops; 2935218792Snp struct port_stats *s = &pi->stats; 2936218792Snp 2937218792Snp PORT_LOCK(pi); 2938218792Snp if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2939218792Snp PORT_UNLOCK(pi); 2940218792Snp return; /* without scheduling another callout */ 2941218792Snp } 2942218792Snp 2943218792Snp t4_get_port_stats(pi->adapter, pi->tx_chan, s); 2944218792Snp 2945228561Snp ifp->if_opackets = s->tx_frames - s->tx_pause; 2946228561Snp ifp->if_ipackets = s->rx_frames - s->rx_pause; 2947228561Snp ifp->if_obytes = s->tx_octets - s->tx_pause * 64; 2948228561Snp ifp->if_ibytes = s->rx_octets - s->rx_pause * 64; 2949228561Snp ifp->if_omcasts = s->tx_mcast_frames - s->tx_pause; 2950228561Snp ifp->if_imcasts = s->rx_mcast_frames - s->rx_pause; 2951218792Snp ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 + 2952239259Snp s->rx_ovflow3 + s->rx_trunc0 + s->rx_trunc1 + s->rx_trunc2 + 2953239259Snp s->rx_trunc3; 2954218792Snp 2955218792Snp drops = s->tx_drop; 2956218792Snp for_each_txq(pi, i, txq) 2957220873Snp drops += txq->br->br_drops; 2958218792Snp ifp->if_snd.ifq_drops = drops; 2959218792Snp 2960218792Snp ifp->if_oerrors = s->tx_error_frames; 2961218792Snp ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long + 2962218792Snp s->rx_fcs_err + s->rx_len_err; 2963218792Snp 2964218792Snp callout_schedule(&pi->tick, hz); 2965218792Snp PORT_UNLOCK(pi); 2966218792Snp} 2967218792Snp 2968237263Snpstatic void 2969237263Snpcxgbe_vlan_config(void *arg, struct ifnet *ifp, uint16_t vid) 2970237263Snp{ 2971237263Snp struct ifnet *vlan; 2972237263Snp 2973237263Snp if (arg != ifp) 2974237263Snp return; 2975237263Snp 2976237263Snp vlan = VLAN_DEVAT(ifp, vid); 2977237263Snp VLAN_SETCOOKIE(vlan, ifp); 2978237263Snp} 2979237263Snp 2980218792Snpstatic int 2981228561Snpcpl_not_handled(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 2982228561Snp{ 2983237263Snp 2984228561Snp#ifdef INVARIANTS 2985237263Snp panic("%s: opcode 0x%02x on iq %p with payload %p", 2986228561Snp __func__, rss->opcode, iq, m); 2987228561Snp#else 2988239336Snp log(LOG_ERR, "%s: opcode 0x%02x on iq %p with payload %p\n", 2989228561Snp __func__, rss->opcode, iq, m); 2990228561Snp m_freem(m); 2991228561Snp#endif 2992228561Snp return (EDOOFUS); 2993228561Snp} 2994228561Snp 2995228561Snpint 2996228561Snpt4_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h) 2997228561Snp{ 2998228561Snp uintptr_t *loc, new; 2999228561Snp 3000228561Snp if (opcode >= ARRAY_SIZE(sc->cpl_handler)) 3001228561Snp return (EINVAL); 3002228561Snp 3003228561Snp new = h ? (uintptr_t)h : (uintptr_t)cpl_not_handled; 3004228561Snp loc = (uintptr_t *) &sc->cpl_handler[opcode]; 3005228561Snp atomic_store_rel_ptr(loc, new); 3006228561Snp 3007228561Snp return (0); 3008228561Snp} 3009228561Snp 3010228561Snpstatic int 3011237263Snpan_not_handled(struct sge_iq *iq, const struct rsp_ctrl *ctrl) 3012237263Snp{ 3013237263Snp 3014237263Snp#ifdef INVARIANTS 3015237263Snp panic("%s: async notification on iq %p (ctrl %p)", __func__, iq, ctrl); 3016237263Snp#else 3017239336Snp log(LOG_ERR, "%s: async notification on iq %p (ctrl %p)\n", 3018237263Snp __func__, iq, ctrl); 3019237263Snp#endif 3020237263Snp return (EDOOFUS); 3021237263Snp} 3022237263Snp 3023237263Snpint 3024237263Snpt4_register_an_handler(struct adapter *sc, an_handler_t h) 3025237263Snp{ 3026237263Snp uintptr_t *loc, new; 3027237263Snp 3028237263Snp new = h ? (uintptr_t)h : (uintptr_t)an_not_handled; 3029237263Snp loc = (uintptr_t *) &sc->an_handler; 3030237263Snp atomic_store_rel_ptr(loc, new); 3031237263Snp 3032237263Snp return (0); 3033237263Snp} 3034237263Snp 3035237263Snpstatic int 3036239336Snpfw_msg_not_handled(struct adapter *sc, const __be64 *rpl) 3037239336Snp{ 3038239336Snp __be64 *r = __DECONST(__be64 *, rpl); 3039239336Snp struct cpl_fw6_msg *cpl = member2struct(cpl_fw6_msg, data, r); 3040239336Snp 3041239336Snp#ifdef INVARIANTS 3042239336Snp panic("%s: fw_msg type %d", __func__, cpl->type); 3043239336Snp#else 3044239336Snp log(LOG_ERR, "%s: fw_msg type %d\n", __func__, cpl->type); 3045239336Snp#endif 3046239336Snp return (EDOOFUS); 3047239336Snp} 3048239336Snp 3049239336Snpint 3050239336Snpt4_register_fw_msg_handler(struct adapter *sc, int type, fw_msg_handler_t h) 3051239336Snp{ 3052239336Snp uintptr_t *loc, new; 3053239336Snp 3054239336Snp if (type >= ARRAY_SIZE(sc->fw_msg_handler)) 3055239336Snp return (EINVAL); 3056239336Snp 3057239336Snp new = h ? (uintptr_t)h : (uintptr_t)fw_msg_not_handled; 3058239336Snp loc = (uintptr_t *) &sc->fw_msg_handler[type]; 3059239336Snp atomic_store_rel_ptr(loc, new); 3060239336Snp 3061239336Snp return (0); 3062239336Snp} 3063239336Snp 3064239336Snpstatic int 3065218792Snpt4_sysctls(struct adapter *sc) 3066218792Snp{ 3067218792Snp struct sysctl_ctx_list *ctx; 3068218792Snp struct sysctl_oid *oid; 3069228561Snp struct sysctl_oid_list *children, *c0; 3070228561Snp static char *caps[] = { 3071228561Snp "\20\1PPP\2QFC\3DCBX", /* caps[0] linkcaps */ 3072228561Snp "\20\1NIC\2VM\3IDS\4UM\5UM_ISGL", /* caps[1] niccaps */ 3073228561Snp "\20\1TOE", /* caps[2] toecaps */ 3074228561Snp "\20\1RDDP\2RDMAC", /* caps[3] rdmacaps */ 3075228561Snp "\20\1INITIATOR_PDU\2TARGET_PDU" /* caps[4] iscsicaps */ 3076228561Snp "\3INITIATOR_CNXOFLD\4TARGET_CNXOFLD" 3077228561Snp "\5INITIATOR_SSNOFLD\6TARGET_SSNOFLD", 3078228561Snp "\20\1INITIATOR\2TARGET\3CTRL_OFLD" /* caps[5] fcoecaps */ 3079228561Snp }; 3080218792Snp 3081218792Snp ctx = device_get_sysctl_ctx(sc->dev); 3082228561Snp 3083228561Snp /* 3084228561Snp * dev.t4nex.X. 3085228561Snp */ 3086218792Snp oid = device_get_sysctl_tree(sc->dev); 3087228561Snp c0 = children = SYSCTL_CHILDREN(oid); 3088218792Snp 3089218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, 3090218792Snp &sc->params.nports, 0, "# of ports"); 3091218792Snp 3092218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD, 3093218792Snp &sc->params.rev, 0, "chip hardware revision"); 3094218792Snp 3095218792Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 3096218792Snp CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 3097218792Snp 3098228561Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "cf", 3099228561Snp CTLFLAG_RD, &t4_cfg_file, 0, "configuration file"); 3100218792Snp 3101228561Snp SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cfcsum", CTLFLAG_RD, 3102228561Snp &sc->cfcsum, 0, "config file checksum"); 3103228561Snp 3104228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkcaps", 3105228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[0], sc->linkcaps, 3106228561Snp sysctl_bitfield, "A", "available link capabilities"); 3107228561Snp 3108228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "niccaps", 3109228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[1], sc->niccaps, 3110228561Snp sysctl_bitfield, "A", "available NIC capabilities"); 3111228561Snp 3112228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "toecaps", 3113228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[2], sc->toecaps, 3114228561Snp sysctl_bitfield, "A", "available TCP offload capabilities"); 3115228561Snp 3116228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdmacaps", 3117228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[3], sc->rdmacaps, 3118228561Snp sysctl_bitfield, "A", "available RDMA capabilities"); 3119228561Snp 3120228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "iscsicaps", 3121228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[4], sc->iscsicaps, 3122228561Snp sysctl_bitfield, "A", "available iSCSI capabilities"); 3123228561Snp 3124228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoecaps", 3125228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[5], sc->fcoecaps, 3126228561Snp sysctl_bitfield, "A", "available FCoE capabilities"); 3127228561Snp 3128218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, 3129218792Snp &sc->params.vpd.cclk, 0, "core clock frequency (in KHz)"); 3130218792Snp 3131219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers", 3132228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.timer_val, 3133228561Snp sizeof(sc->sge.timer_val), sysctl_int_array, "A", 3134228561Snp "interrupt holdoff timer values (us)"); 3135218792Snp 3136219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts", 3137228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.counter_val, 3138228561Snp sizeof(sc->sge.counter_val), sysctl_int_array, "A", 3139228561Snp "interrupt holdoff packet counter values"); 3140218792Snp 3141231115Snp#ifdef SBUF_DRAIN 3142228561Snp /* 3143228561Snp * dev.t4nex.X.misc. Marked CTLFLAG_SKIP to avoid information overload. 3144228561Snp */ 3145228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "misc", 3146228561Snp CTLFLAG_RD | CTLFLAG_SKIP, NULL, 3147228561Snp "logs and miscellaneous information"); 3148228561Snp children = SYSCTL_CHILDREN(oid); 3149228561Snp 3150228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cctrl", 3151228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3152228561Snp sysctl_cctrl, "A", "congestion control"); 3153228561Snp 3154228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats", 3155228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3156228561Snp sysctl_cpl_stats, "A", "CPL statistics"); 3157228561Snp 3158228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ddp_stats", 3159228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3160228561Snp sysctl_ddp_stats, "A", "DDP statistics"); 3161228561Snp 3162222551Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog", 3163222551Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3164228561Snp sysctl_devlog, "A", "firmware's device log"); 3165222551Snp 3166228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoe_stats", 3167228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3168228561Snp sysctl_fcoe_stats, "A", "FCoE statistics"); 3169228561Snp 3170228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hw_sched", 3171228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3172228561Snp sysctl_hw_sched, "A", "hardware scheduler "); 3173228561Snp 3174228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "l2t", 3175228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3176228561Snp sysctl_l2t, "A", "hardware L2 table"); 3177228561Snp 3178228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats", 3179228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3180228561Snp sysctl_lb_stats, "A", "loopback statistics"); 3181228561Snp 3182228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "meminfo", 3183228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3184228561Snp sysctl_meminfo, "A", "memory regions"); 3185228561Snp 3186228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "path_mtus", 3187228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3188228561Snp sysctl_path_mtus, "A", "path MTUs"); 3189228561Snp 3190228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pm_stats", 3191228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3192228561Snp sysctl_pm_stats, "A", "PM statistics"); 3193228561Snp 3194228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_stats", 3195228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3196228561Snp sysctl_rdma_stats, "A", "RDMA statistics"); 3197228561Snp 3198228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tcp_stats", 3199228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3200228561Snp sysctl_tcp_stats, "A", "TCP statistics"); 3201228561Snp 3202228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tids", 3203228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3204228561Snp sysctl_tids, "A", "TID information"); 3205228561Snp 3206228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_err_stats", 3207228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3208228561Snp sysctl_tp_err_stats, "A", "TP error statistics"); 3209228561Snp 3210228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_rate", 3211228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3212228561Snp sysctl_tx_rate, "A", "Tx rate"); 3213231115Snp#endif 3214228561Snp 3215237263Snp#ifdef TCP_OFFLOAD 3216228561Snp if (is_offload(sc)) { 3217228561Snp /* 3218228561Snp * dev.t4nex.X.toe. 3219228561Snp */ 3220228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "toe", CTLFLAG_RD, 3221228561Snp NULL, "TOE parameters"); 3222228561Snp children = SYSCTL_CHILDREN(oid); 3223228561Snp 3224228561Snp sc->tt.sndbuf = 256 * 1024; 3225228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "sndbuf", CTLFLAG_RW, 3226228561Snp &sc->tt.sndbuf, 0, "max hardware send buffer size"); 3227228561Snp 3228228561Snp sc->tt.ddp = 0; 3229228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp", CTLFLAG_RW, 3230228561Snp &sc->tt.ddp, 0, "DDP allowed"); 3231228561Snp sc->tt.indsz = M_INDICATESIZE; 3232228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "indsz", CTLFLAG_RW, 3233228561Snp &sc->tt.indsz, 0, "DDP max indicate size allowed"); 3234228561Snp sc->tt.ddp_thres = 3*4096; 3235228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp_thres", CTLFLAG_RW, 3236228561Snp &sc->tt.ddp_thres, 0, "DDP threshold"); 3237228561Snp } 3238228561Snp#endif 3239228561Snp 3240228561Snp 3241218792Snp return (0); 3242218792Snp} 3243218792Snp 3244218792Snpstatic int 3245218792Snpcxgbe_sysctls(struct port_info *pi) 3246218792Snp{ 3247218792Snp struct sysctl_ctx_list *ctx; 3248218792Snp struct sysctl_oid *oid; 3249218792Snp struct sysctl_oid_list *children; 3250218792Snp 3251218792Snp ctx = device_get_sysctl_ctx(pi->dev); 3252218792Snp 3253218792Snp /* 3254218792Snp * dev.cxgbe.X. 3255218792Snp */ 3256218792Snp oid = device_get_sysctl_tree(pi->dev); 3257218792Snp children = SYSCTL_CHILDREN(oid); 3258218792Snp 3259218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD, 3260218792Snp &pi->nrxq, 0, "# of rx queues"); 3261218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD, 3262218792Snp &pi->ntxq, 0, "# of tx queues"); 3263218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD, 3264218792Snp &pi->first_rxq, 0, "index of first rx queue"); 3265218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD, 3266218792Snp &pi->first_txq, 0, "index of first tx queue"); 3267218792Snp 3268237263Snp#ifdef TCP_OFFLOAD 3269228561Snp if (is_offload(pi->adapter)) { 3270228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldrxq", CTLFLAG_RD, 3271228561Snp &pi->nofldrxq, 0, 3272228561Snp "# of rx queues for offloaded TCP connections"); 3273228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldtxq", CTLFLAG_RD, 3274228561Snp &pi->nofldtxq, 0, 3275228561Snp "# of tx queues for offloaded TCP connections"); 3276228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_rxq", 3277228561Snp CTLFLAG_RD, &pi->first_ofld_rxq, 0, 3278228561Snp "index of first TOE rx queue"); 3279228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_txq", 3280228561Snp CTLFLAG_RD, &pi->first_ofld_txq, 0, 3281228561Snp "index of first TOE tx queue"); 3282228561Snp } 3283228561Snp#endif 3284228561Snp 3285218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx", 3286218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I", 3287218792Snp "holdoff timer index"); 3288218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx", 3289218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I", 3290218792Snp "holdoff packet counter index"); 3291218792Snp 3292218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq", 3293218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I", 3294218792Snp "rx queue size"); 3295218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq", 3296218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I", 3297218792Snp "tx queue size"); 3298218792Snp 3299218792Snp /* 3300218792Snp * dev.cxgbe.X.stats. 3301218792Snp */ 3302218792Snp oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, 3303218792Snp NULL, "port statistics"); 3304218792Snp children = SYSCTL_CHILDREN(oid); 3305218792Snp 3306218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \ 3307218792Snp SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \ 3308218792Snp CTLTYPE_U64 | CTLFLAG_RD, pi->adapter, reg, \ 3309218792Snp sysctl_handle_t4_reg64, "QU", desc) 3310218792Snp 3311218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames", 3312218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L)); 3313218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames", 3314218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L)); 3315218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames", 3316218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L)); 3317218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames", 3318218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L)); 3319218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames", 3320218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L)); 3321218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames", 3322218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L)); 3323218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_64", 3324218792Snp "# of tx frames in this range", 3325218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L)); 3326218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127", 3327218792Snp "# of tx frames in this range", 3328218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L)); 3329218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255", 3330218792Snp "# of tx frames in this range", 3331218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L)); 3332218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511", 3333218792Snp "# of tx frames in this range", 3334218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L)); 3335218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023", 3336218792Snp "# of tx frames in this range", 3337218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L)); 3338218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518", 3339218792Snp "# of tx frames in this range", 3340218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L)); 3341218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max", 3342218792Snp "# of tx frames in this range", 3343218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L)); 3344218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames", 3345218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L)); 3346218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted", 3347218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L)); 3348218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted", 3349218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L)); 3350218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted", 3351218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L)); 3352218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted", 3353218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L)); 3354218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted", 3355218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L)); 3356218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted", 3357218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L)); 3358218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted", 3359218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L)); 3360218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted", 3361218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L)); 3362218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted", 3363218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L)); 3364218792Snp 3365218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames", 3366218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L)); 3367218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames", 3368218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L)); 3369218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames", 3370218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L)); 3371218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames", 3372218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L)); 3373218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames", 3374218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L)); 3375218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU", 3376218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L)); 3377218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames", 3378218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L)); 3379218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err", 3380218792Snp "# of frames received with bad FCS", 3381218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L)); 3382218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_len_err", 3383218792Snp "# of frames received with length error", 3384218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L)); 3385218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors", 3386218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L)); 3387218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received", 3388218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L)); 3389218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_64", 3390218792Snp "# of rx frames in this range", 3391218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L)); 3392218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127", 3393218792Snp "# of rx frames in this range", 3394218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L)); 3395218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255", 3396218792Snp "# of rx frames in this range", 3397218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L)); 3398218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511", 3399218792Snp "# of rx frames in this range", 3400218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L)); 3401218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023", 3402218792Snp "# of rx frames in this range", 3403218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L)); 3404218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518", 3405218792Snp "# of rx frames in this range", 3406218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L)); 3407218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max", 3408218792Snp "# of rx frames in this range", 3409218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L)); 3410218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received", 3411218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L)); 3412218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received", 3413218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L)); 3414218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received", 3415218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L)); 3416218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received", 3417218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L)); 3418218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received", 3419218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L)); 3420218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received", 3421218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L)); 3422218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received", 3423218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L)); 3424218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received", 3425218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L)); 3426218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received", 3427218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L)); 3428218792Snp 3429218792Snp#undef SYSCTL_ADD_T4_REG64 3430218792Snp 3431218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \ 3432218792Snp SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \ 3433218792Snp &pi->stats.name, desc) 3434218792Snp 3435218792Snp /* We get these from port_stats and they may be stale by upto 1s */ 3436218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0, 3437218792Snp "# drops due to buffer-group 0 overflows"); 3438218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1, 3439218792Snp "# drops due to buffer-group 1 overflows"); 3440218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2, 3441218792Snp "# drops due to buffer-group 2 overflows"); 3442218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3, 3443218792Snp "# drops due to buffer-group 3 overflows"); 3444218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc0, 3445218792Snp "# of buffer-group 0 truncated packets"); 3446218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc1, 3447218792Snp "# of buffer-group 1 truncated packets"); 3448218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc2, 3449218792Snp "# of buffer-group 2 truncated packets"); 3450218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc3, 3451218792Snp "# of buffer-group 3 truncated packets"); 3452218792Snp 3453218792Snp#undef SYSCTL_ADD_T4_PORTSTAT 3454218792Snp 3455218792Snp return (0); 3456218792Snp} 3457218792Snp 3458218792Snpstatic int 3459219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS) 3460219436Snp{ 3461219436Snp int rc, *i; 3462219436Snp struct sbuf sb; 3463219436Snp 3464219436Snp sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); 3465219436Snp for (i = arg1; arg2; arg2 -= sizeof(int), i++) 3466219436Snp sbuf_printf(&sb, "%d ", *i); 3467219436Snp sbuf_trim(&sb); 3468219436Snp sbuf_finish(&sb); 3469219436Snp rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 3470219436Snp sbuf_delete(&sb); 3471219436Snp return (rc); 3472219436Snp} 3473219436Snp 3474219436Snpstatic int 3475228561Snpsysctl_bitfield(SYSCTL_HANDLER_ARGS) 3476228561Snp{ 3477228561Snp int rc; 3478228561Snp struct sbuf *sb; 3479228561Snp 3480228561Snp rc = sysctl_wire_old_buffer(req, 0); 3481228561Snp if (rc != 0) 3482228561Snp return(rc); 3483228561Snp 3484228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 3485228561Snp if (sb == NULL) 3486228561Snp return (ENOMEM); 3487228561Snp 3488228561Snp sbuf_printf(sb, "%b", (int)arg2, (char *)arg1); 3489228561Snp rc = sbuf_finish(sb); 3490228561Snp sbuf_delete(sb); 3491228561Snp 3492228561Snp return (rc); 3493228561Snp} 3494228561Snp 3495228561Snpstatic int 3496218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS) 3497218792Snp{ 3498218792Snp struct port_info *pi = arg1; 3499218792Snp struct adapter *sc = pi->adapter; 3500218792Snp int idx, rc, i; 3501218792Snp 3502218792Snp idx = pi->tmr_idx; 3503218792Snp 3504218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 3505218792Snp if (rc != 0 || req->newptr == NULL) 3506218792Snp return (rc); 3507218792Snp 3508218792Snp if (idx < 0 || idx >= SGE_NTIMERS) 3509218792Snp return (EINVAL); 3510218792Snp 3511218792Snp ADAPTER_LOCK(sc); 3512218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3513218792Snp if (rc == 0) { 3514228561Snp struct sge_rxq *rxq; 3515228561Snp uint8_t v; 3516228561Snp 3517228561Snp v = V_QINTR_TIMER_IDX(idx) | V_QINTR_CNT_EN(pi->pktc_idx != -1); 3518218792Snp for_each_rxq(pi, i, rxq) { 3519228561Snp#ifdef atomic_store_rel_8 3520228561Snp atomic_store_rel_8(&rxq->iq.intr_params, v); 3521228561Snp#else 3522228561Snp rxq->iq.intr_params = v; 3523228561Snp#endif 3524218792Snp } 3525218792Snp pi->tmr_idx = idx; 3526218792Snp } 3527218792Snp 3528218792Snp ADAPTER_UNLOCK(sc); 3529218792Snp return (rc); 3530218792Snp} 3531218792Snp 3532218792Snpstatic int 3533218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS) 3534218792Snp{ 3535218792Snp struct port_info *pi = arg1; 3536218792Snp struct adapter *sc = pi->adapter; 3537218792Snp int idx, rc; 3538218792Snp 3539218792Snp idx = pi->pktc_idx; 3540218792Snp 3541218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 3542218792Snp if (rc != 0 || req->newptr == NULL) 3543218792Snp return (rc); 3544218792Snp 3545218792Snp if (idx < -1 || idx >= SGE_NCOUNTERS) 3546218792Snp return (EINVAL); 3547218792Snp 3548218792Snp ADAPTER_LOCK(sc); 3549218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3550228561Snp if (rc == 0 && pi->flags & PORT_INIT_DONE) 3551228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 3552218792Snp 3553218792Snp if (rc == 0) 3554218792Snp pi->pktc_idx = idx; 3555218792Snp 3556218792Snp ADAPTER_UNLOCK(sc); 3557218792Snp return (rc); 3558218792Snp} 3559218792Snp 3560218792Snpstatic int 3561218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS) 3562218792Snp{ 3563218792Snp struct port_info *pi = arg1; 3564218792Snp struct adapter *sc = pi->adapter; 3565218792Snp int qsize, rc; 3566218792Snp 3567218792Snp qsize = pi->qsize_rxq; 3568218792Snp 3569218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 3570218792Snp if (rc != 0 || req->newptr == NULL) 3571218792Snp return (rc); 3572218792Snp 3573218792Snp if (qsize < 128 || (qsize & 7)) 3574218792Snp return (EINVAL); 3575218792Snp 3576218792Snp ADAPTER_LOCK(sc); 3577218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3578228561Snp if (rc == 0 && pi->flags & PORT_INIT_DONE) 3579228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 3580218792Snp 3581218792Snp if (rc == 0) 3582218792Snp pi->qsize_rxq = qsize; 3583218792Snp 3584218792Snp ADAPTER_UNLOCK(sc); 3585218792Snp return (rc); 3586218792Snp} 3587218792Snp 3588218792Snpstatic int 3589218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS) 3590218792Snp{ 3591218792Snp struct port_info *pi = arg1; 3592218792Snp struct adapter *sc = pi->adapter; 3593218792Snp int qsize, rc; 3594218792Snp 3595218792Snp qsize = pi->qsize_txq; 3596218792Snp 3597218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 3598218792Snp if (rc != 0 || req->newptr == NULL) 3599218792Snp return (rc); 3600218792Snp 3601218792Snp if (qsize < 128) 3602218792Snp return (EINVAL); 3603218792Snp 3604218792Snp ADAPTER_LOCK(sc); 3605218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3606228561Snp if (rc == 0 && pi->flags & PORT_INIT_DONE) 3607228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 3608218792Snp 3609218792Snp if (rc == 0) 3610218792Snp pi->qsize_txq = qsize; 3611218792Snp 3612218792Snp ADAPTER_UNLOCK(sc); 3613218792Snp return (rc); 3614218792Snp} 3615218792Snp 3616218792Snpstatic int 3617218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS) 3618218792Snp{ 3619218792Snp struct adapter *sc = arg1; 3620218792Snp int reg = arg2; 3621218792Snp uint64_t val; 3622218792Snp 3623218792Snp val = t4_read_reg64(sc, reg); 3624218792Snp 3625218792Snp return (sysctl_handle_64(oidp, &val, 0, req)); 3626218792Snp} 3627218792Snp 3628231115Snp#ifdef SBUF_DRAIN 3629228561Snpstatic int 3630228561Snpsysctl_cctrl(SYSCTL_HANDLER_ARGS) 3631228561Snp{ 3632228561Snp struct adapter *sc = arg1; 3633228561Snp struct sbuf *sb; 3634228561Snp int rc, i; 3635228561Snp uint16_t incr[NMTUS][NCCTRL_WIN]; 3636228561Snp static const char *dec_fac[] = { 3637228561Snp "0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875", 3638228561Snp "0.9375" 3639228561Snp }; 3640228561Snp 3641228561Snp rc = sysctl_wire_old_buffer(req, 0); 3642228561Snp if (rc != 0) 3643228561Snp return (rc); 3644228561Snp 3645228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3646228561Snp if (sb == NULL) 3647228561Snp return (ENOMEM); 3648228561Snp 3649228561Snp t4_read_cong_tbl(sc, incr); 3650228561Snp 3651228561Snp for (i = 0; i < NCCTRL_WIN; ++i) { 3652228561Snp sbuf_printf(sb, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i, 3653228561Snp incr[0][i], incr[1][i], incr[2][i], incr[3][i], incr[4][i], 3654228561Snp incr[5][i], incr[6][i], incr[7][i]); 3655228561Snp sbuf_printf(sb, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n", 3656228561Snp incr[8][i], incr[9][i], incr[10][i], incr[11][i], 3657228561Snp incr[12][i], incr[13][i], incr[14][i], incr[15][i], 3658228561Snp sc->params.a_wnd[i], dec_fac[sc->params.b_wnd[i]]); 3659228561Snp } 3660228561Snp 3661228561Snp rc = sbuf_finish(sb); 3662228561Snp sbuf_delete(sb); 3663228561Snp 3664228561Snp return (rc); 3665228561Snp} 3666228561Snp 3667228561Snpstatic int 3668228561Snpsysctl_cpl_stats(SYSCTL_HANDLER_ARGS) 3669228561Snp{ 3670228561Snp struct adapter *sc = arg1; 3671228561Snp struct sbuf *sb; 3672228561Snp int rc; 3673228561Snp struct tp_cpl_stats stats; 3674228561Snp 3675228561Snp rc = sysctl_wire_old_buffer(req, 0); 3676228561Snp if (rc != 0) 3677228561Snp return (rc); 3678228561Snp 3679228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3680228561Snp if (sb == NULL) 3681228561Snp return (ENOMEM); 3682228561Snp 3683228561Snp t4_tp_get_cpl_stats(sc, &stats); 3684228561Snp 3685228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 3686228561Snp "channel 3\n"); 3687228561Snp sbuf_printf(sb, "CPL requests: %10u %10u %10u %10u\n", 3688228561Snp stats.req[0], stats.req[1], stats.req[2], stats.req[3]); 3689228561Snp sbuf_printf(sb, "CPL responses: %10u %10u %10u %10u", 3690228561Snp stats.rsp[0], stats.rsp[1], stats.rsp[2], stats.rsp[3]); 3691228561Snp 3692228561Snp rc = sbuf_finish(sb); 3693228561Snp sbuf_delete(sb); 3694228561Snp 3695228561Snp return (rc); 3696228561Snp} 3697228561Snp 3698228561Snpstatic int 3699228561Snpsysctl_ddp_stats(SYSCTL_HANDLER_ARGS) 3700228561Snp{ 3701228561Snp struct adapter *sc = arg1; 3702228561Snp struct sbuf *sb; 3703228561Snp int rc; 3704228561Snp struct tp_usm_stats stats; 3705228561Snp 3706228561Snp rc = sysctl_wire_old_buffer(req, 0); 3707228561Snp if (rc != 0) 3708228561Snp return(rc); 3709228561Snp 3710228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3711228561Snp if (sb == NULL) 3712228561Snp return (ENOMEM); 3713228561Snp 3714228561Snp t4_get_usm_stats(sc, &stats); 3715228561Snp 3716228561Snp sbuf_printf(sb, "Frames: %u\n", stats.frames); 3717228561Snp sbuf_printf(sb, "Octets: %ju\n", stats.octets); 3718228561Snp sbuf_printf(sb, "Drops: %u", stats.drops); 3719228561Snp 3720228561Snp rc = sbuf_finish(sb); 3721228561Snp sbuf_delete(sb); 3722228561Snp 3723228561Snp return (rc); 3724228561Snp} 3725228561Snp 3726222551Snpconst char *devlog_level_strings[] = { 3727222551Snp [FW_DEVLOG_LEVEL_EMERG] = "EMERG", 3728222551Snp [FW_DEVLOG_LEVEL_CRIT] = "CRIT", 3729222551Snp [FW_DEVLOG_LEVEL_ERR] = "ERR", 3730222551Snp [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", 3731222551Snp [FW_DEVLOG_LEVEL_INFO] = "INFO", 3732222551Snp [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" 3733222551Snp}; 3734222551Snp 3735222551Snpconst char *devlog_facility_strings[] = { 3736222551Snp [FW_DEVLOG_FACILITY_CORE] = "CORE", 3737222551Snp [FW_DEVLOG_FACILITY_SCHED] = "SCHED", 3738222551Snp [FW_DEVLOG_FACILITY_TIMER] = "TIMER", 3739222551Snp [FW_DEVLOG_FACILITY_RES] = "RES", 3740222551Snp [FW_DEVLOG_FACILITY_HW] = "HW", 3741222551Snp [FW_DEVLOG_FACILITY_FLR] = "FLR", 3742222551Snp [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", 3743222551Snp [FW_DEVLOG_FACILITY_PHY] = "PHY", 3744222551Snp [FW_DEVLOG_FACILITY_MAC] = "MAC", 3745222551Snp [FW_DEVLOG_FACILITY_PORT] = "PORT", 3746222551Snp [FW_DEVLOG_FACILITY_VI] = "VI", 3747222551Snp [FW_DEVLOG_FACILITY_FILTER] = "FILTER", 3748222551Snp [FW_DEVLOG_FACILITY_ACL] = "ACL", 3749222551Snp [FW_DEVLOG_FACILITY_TM] = "TM", 3750222551Snp [FW_DEVLOG_FACILITY_QFC] = "QFC", 3751222551Snp [FW_DEVLOG_FACILITY_DCB] = "DCB", 3752222551Snp [FW_DEVLOG_FACILITY_ETH] = "ETH", 3753222551Snp [FW_DEVLOG_FACILITY_OFLD] = "OFLD", 3754222551Snp [FW_DEVLOG_FACILITY_RI] = "RI", 3755222551Snp [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", 3756222551Snp [FW_DEVLOG_FACILITY_FCOE] = "FCOE", 3757222551Snp [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", 3758222551Snp [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE" 3759222551Snp}; 3760222551Snp 3761222551Snpstatic int 3762222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS) 3763222551Snp{ 3764222551Snp struct adapter *sc = arg1; 3765222551Snp struct devlog_params *dparams = &sc->params.devlog; 3766222551Snp struct fw_devlog_e *buf, *e; 3767222551Snp int i, j, rc, nentries, first = 0; 3768222551Snp struct sbuf *sb; 3769222551Snp uint64_t ftstamp = UINT64_MAX; 3770222551Snp 3771222551Snp if (dparams->start == 0) 3772222551Snp return (ENXIO); 3773222551Snp 3774222551Snp nentries = dparams->size / sizeof(struct fw_devlog_e); 3775222551Snp 3776222551Snp buf = malloc(dparams->size, M_CXGBE, M_NOWAIT); 3777222551Snp if (buf == NULL) 3778222551Snp return (ENOMEM); 3779222551Snp 3780222551Snp rc = -t4_mem_read(sc, dparams->memtype, dparams->start, dparams->size, 3781222551Snp (void *)buf); 3782222551Snp if (rc != 0) 3783222551Snp goto done; 3784222551Snp 3785222551Snp for (i = 0; i < nentries; i++) { 3786222551Snp e = &buf[i]; 3787222551Snp 3788222551Snp if (e->timestamp == 0) 3789222551Snp break; /* end */ 3790222551Snp 3791222551Snp e->timestamp = be64toh(e->timestamp); 3792222551Snp e->seqno = be32toh(e->seqno); 3793222551Snp for (j = 0; j < 8; j++) 3794222551Snp e->params[j] = be32toh(e->params[j]); 3795222551Snp 3796222551Snp if (e->timestamp < ftstamp) { 3797222551Snp ftstamp = e->timestamp; 3798222551Snp first = i; 3799222551Snp } 3800222551Snp } 3801222551Snp 3802222551Snp if (buf[first].timestamp == 0) 3803222551Snp goto done; /* nothing in the log */ 3804222551Snp 3805222551Snp rc = sysctl_wire_old_buffer(req, 0); 3806222551Snp if (rc != 0) 3807222551Snp goto done; 3808222551Snp 3809222551Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3810228561Snp if (sb == NULL) { 3811228561Snp rc = ENOMEM; 3812228561Snp goto done; 3813228561Snp } 3814228561Snp sbuf_printf(sb, "%10s %15s %8s %8s %s\n", 3815222551Snp "Seq#", "Tstamp", "Level", "Facility", "Message"); 3816222551Snp 3817222551Snp i = first; 3818222551Snp do { 3819222551Snp e = &buf[i]; 3820222551Snp if (e->timestamp == 0) 3821222551Snp break; /* end */ 3822222551Snp 3823222551Snp sbuf_printf(sb, "%10d %15ju %8s %8s ", 3824222551Snp e->seqno, e->timestamp, 3825222551Snp (e->level < ARRAY_SIZE(devlog_level_strings) ? 3826222551Snp devlog_level_strings[e->level] : "UNKNOWN"), 3827222551Snp (e->facility < ARRAY_SIZE(devlog_facility_strings) ? 3828222551Snp devlog_facility_strings[e->facility] : "UNKNOWN")); 3829222551Snp sbuf_printf(sb, e->fmt, e->params[0], e->params[1], 3830222551Snp e->params[2], e->params[3], e->params[4], 3831222551Snp e->params[5], e->params[6], e->params[7]); 3832222551Snp 3833222551Snp if (++i == nentries) 3834222551Snp i = 0; 3835222551Snp } while (i != first); 3836222551Snp 3837222551Snp rc = sbuf_finish(sb); 3838222551Snp sbuf_delete(sb); 3839222551Snpdone: 3840222551Snp free(buf, M_CXGBE); 3841222551Snp return (rc); 3842222551Snp} 3843222551Snp 3844228561Snpstatic int 3845228561Snpsysctl_fcoe_stats(SYSCTL_HANDLER_ARGS) 3846228561Snp{ 3847228561Snp struct adapter *sc = arg1; 3848228561Snp struct sbuf *sb; 3849228561Snp int rc; 3850228561Snp struct tp_fcoe_stats stats[4]; 3851228561Snp 3852228561Snp rc = sysctl_wire_old_buffer(req, 0); 3853228561Snp if (rc != 0) 3854228561Snp return (rc); 3855228561Snp 3856228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3857228561Snp if (sb == NULL) 3858228561Snp return (ENOMEM); 3859228561Snp 3860228561Snp t4_get_fcoe_stats(sc, 0, &stats[0]); 3861228561Snp t4_get_fcoe_stats(sc, 1, &stats[1]); 3862228561Snp t4_get_fcoe_stats(sc, 2, &stats[2]); 3863228561Snp t4_get_fcoe_stats(sc, 3, &stats[3]); 3864228561Snp 3865228561Snp sbuf_printf(sb, " channel 0 channel 1 " 3866228561Snp "channel 2 channel 3\n"); 3867228561Snp sbuf_printf(sb, "octetsDDP: %16ju %16ju %16ju %16ju\n", 3868228561Snp stats[0].octetsDDP, stats[1].octetsDDP, stats[2].octetsDDP, 3869228561Snp stats[3].octetsDDP); 3870228561Snp sbuf_printf(sb, "framesDDP: %16u %16u %16u %16u\n", stats[0].framesDDP, 3871228561Snp stats[1].framesDDP, stats[2].framesDDP, stats[3].framesDDP); 3872228561Snp sbuf_printf(sb, "framesDrop: %16u %16u %16u %16u", 3873228561Snp stats[0].framesDrop, stats[1].framesDrop, stats[2].framesDrop, 3874228561Snp stats[3].framesDrop); 3875228561Snp 3876228561Snp rc = sbuf_finish(sb); 3877228561Snp sbuf_delete(sb); 3878228561Snp 3879228561Snp return (rc); 3880228561Snp} 3881228561Snp 3882228561Snpstatic int 3883228561Snpsysctl_hw_sched(SYSCTL_HANDLER_ARGS) 3884228561Snp{ 3885228561Snp struct adapter *sc = arg1; 3886228561Snp struct sbuf *sb; 3887228561Snp int rc, i; 3888228561Snp unsigned int map, kbps, ipg, mode; 3889228561Snp unsigned int pace_tab[NTX_SCHED]; 3890228561Snp 3891228561Snp rc = sysctl_wire_old_buffer(req, 0); 3892228561Snp if (rc != 0) 3893228561Snp return (rc); 3894228561Snp 3895228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3896228561Snp if (sb == NULL) 3897228561Snp return (ENOMEM); 3898228561Snp 3899228561Snp map = t4_read_reg(sc, A_TP_TX_MOD_QUEUE_REQ_MAP); 3900228561Snp mode = G_TIMERMODE(t4_read_reg(sc, A_TP_MOD_CONFIG)); 3901228561Snp t4_read_pace_tbl(sc, pace_tab); 3902228561Snp 3903228561Snp sbuf_printf(sb, "Scheduler Mode Channel Rate (Kbps) " 3904228561Snp "Class IPG (0.1 ns) Flow IPG (us)"); 3905228561Snp 3906228561Snp for (i = 0; i < NTX_SCHED; ++i, map >>= 2) { 3907228561Snp t4_get_tx_sched(sc, i, &kbps, &ipg); 3908228561Snp sbuf_printf(sb, "\n %u %-5s %u ", i, 3909228561Snp (mode & (1 << i)) ? "flow" : "class", map & 3); 3910228561Snp if (kbps) 3911228561Snp sbuf_printf(sb, "%9u ", kbps); 3912228561Snp else 3913228561Snp sbuf_printf(sb, " disabled "); 3914228561Snp 3915228561Snp if (ipg) 3916228561Snp sbuf_printf(sb, "%13u ", ipg); 3917228561Snp else 3918228561Snp sbuf_printf(sb, " disabled "); 3919228561Snp 3920228561Snp if (pace_tab[i]) 3921228561Snp sbuf_printf(sb, "%10u", pace_tab[i]); 3922228561Snp else 3923228561Snp sbuf_printf(sb, " disabled"); 3924228561Snp } 3925228561Snp 3926228561Snp rc = sbuf_finish(sb); 3927228561Snp sbuf_delete(sb); 3928228561Snp 3929228561Snp return (rc); 3930228561Snp} 3931228561Snp 3932228561Snpstatic int 3933228561Snpsysctl_lb_stats(SYSCTL_HANDLER_ARGS) 3934228561Snp{ 3935228561Snp struct adapter *sc = arg1; 3936228561Snp struct sbuf *sb; 3937228561Snp int rc, i, j; 3938228561Snp uint64_t *p0, *p1; 3939228561Snp struct lb_port_stats s[2]; 3940228561Snp static const char *stat_name[] = { 3941228561Snp "OctetsOK:", "FramesOK:", "BcastFrames:", "McastFrames:", 3942228561Snp "UcastFrames:", "ErrorFrames:", "Frames64:", "Frames65To127:", 3943228561Snp "Frames128To255:", "Frames256To511:", "Frames512To1023:", 3944228561Snp "Frames1024To1518:", "Frames1519ToMax:", "FramesDropped:", 3945228561Snp "BG0FramesDropped:", "BG1FramesDropped:", "BG2FramesDropped:", 3946228561Snp "BG3FramesDropped:", "BG0FramesTrunc:", "BG1FramesTrunc:", 3947228561Snp "BG2FramesTrunc:", "BG3FramesTrunc:" 3948228561Snp }; 3949228561Snp 3950228561Snp rc = sysctl_wire_old_buffer(req, 0); 3951228561Snp if (rc != 0) 3952228561Snp return (rc); 3953228561Snp 3954228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3955228561Snp if (sb == NULL) 3956228561Snp return (ENOMEM); 3957228561Snp 3958228561Snp memset(s, 0, sizeof(s)); 3959228561Snp 3960228561Snp for (i = 0; i < 4; i += 2) { 3961228561Snp t4_get_lb_stats(sc, i, &s[0]); 3962228561Snp t4_get_lb_stats(sc, i + 1, &s[1]); 3963228561Snp 3964228561Snp p0 = &s[0].octets; 3965228561Snp p1 = &s[1].octets; 3966228561Snp sbuf_printf(sb, "%s Loopback %u" 3967228561Snp " Loopback %u", i == 0 ? "" : "\n", i, i + 1); 3968228561Snp 3969228561Snp for (j = 0; j < ARRAY_SIZE(stat_name); j++) 3970228561Snp sbuf_printf(sb, "\n%-17s %20ju %20ju", stat_name[j], 3971228561Snp *p0++, *p1++); 3972228561Snp } 3973228561Snp 3974228561Snp rc = sbuf_finish(sb); 3975228561Snp sbuf_delete(sb); 3976228561Snp 3977228561Snp return (rc); 3978228561Snp} 3979228561Snp 3980228561Snpstruct mem_desc { 3981228561Snp unsigned int base; 3982228561Snp unsigned int limit; 3983228561Snp unsigned int idx; 3984228561Snp}; 3985228561Snp 3986228561Snpstatic int 3987228561Snpmem_desc_cmp(const void *a, const void *b) 3988228561Snp{ 3989228561Snp return ((const struct mem_desc *)a)->base - 3990228561Snp ((const struct mem_desc *)b)->base; 3991228561Snp} 3992228561Snp 3993228561Snpstatic void 3994228561Snpmem_region_show(struct sbuf *sb, const char *name, unsigned int from, 3995228561Snp unsigned int to) 3996228561Snp{ 3997228561Snp unsigned int size; 3998228561Snp 3999228561Snp size = to - from + 1; 4000228561Snp if (size == 0) 4001228561Snp return; 4002228561Snp 4003228561Snp /* XXX: need humanize_number(3) in libkern for a more readable 'size' */ 4004228561Snp sbuf_printf(sb, "%-15s %#x-%#x [%u]\n", name, from, to, size); 4005228561Snp} 4006228561Snp 4007228561Snpstatic int 4008228561Snpsysctl_meminfo(SYSCTL_HANDLER_ARGS) 4009228561Snp{ 4010228561Snp struct adapter *sc = arg1; 4011228561Snp struct sbuf *sb; 4012228561Snp int rc, i, n; 4013228561Snp uint32_t lo, hi; 4014228561Snp static const char *memory[] = { "EDC0:", "EDC1:", "MC:" }; 4015228561Snp static const char *region[] = { 4016228561Snp "DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:", 4017228561Snp "Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:", 4018228561Snp "Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:", 4019228561Snp "TDDP region:", "TPT region:", "STAG region:", "RQ region:", 4020228561Snp "RQUDP region:", "PBL region:", "TXPBL region:", "ULPRX state:", 4021228561Snp "ULPTX state:", "On-chip queues:" 4022228561Snp }; 4023228561Snp struct mem_desc avail[3]; 4024228561Snp struct mem_desc mem[ARRAY_SIZE(region) + 3]; /* up to 3 holes */ 4025228561Snp struct mem_desc *md = mem; 4026228561Snp 4027228561Snp rc = sysctl_wire_old_buffer(req, 0); 4028228561Snp if (rc != 0) 4029228561Snp return (rc); 4030228561Snp 4031228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 4032228561Snp if (sb == NULL) 4033228561Snp return (ENOMEM); 4034228561Snp 4035228561Snp for (i = 0; i < ARRAY_SIZE(mem); i++) { 4036228561Snp mem[i].limit = 0; 4037228561Snp mem[i].idx = i; 4038228561Snp } 4039228561Snp 4040228561Snp /* Find and sort the populated memory ranges */ 4041228561Snp i = 0; 4042228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 4043228561Snp if (lo & F_EDRAM0_ENABLE) { 4044228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 4045228561Snp avail[i].base = G_EDRAM0_BASE(hi) << 20; 4046228561Snp avail[i].limit = avail[i].base + (G_EDRAM0_SIZE(hi) << 20); 4047228561Snp avail[i].idx = 0; 4048228561Snp i++; 4049228561Snp } 4050228561Snp if (lo & F_EDRAM1_ENABLE) { 4051228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 4052228561Snp avail[i].base = G_EDRAM1_BASE(hi) << 20; 4053228561Snp avail[i].limit = avail[i].base + (G_EDRAM1_SIZE(hi) << 20); 4054228561Snp avail[i].idx = 1; 4055228561Snp i++; 4056228561Snp } 4057228561Snp if (lo & F_EXT_MEM_ENABLE) { 4058228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 4059228561Snp avail[i].base = G_EXT_MEM_BASE(hi) << 20; 4060228561Snp avail[i].limit = avail[i].base + (G_EXT_MEM_SIZE(hi) << 20); 4061228561Snp avail[i].idx = 2; 4062228561Snp i++; 4063228561Snp } 4064228561Snp if (!i) /* no memory available */ 4065228561Snp return 0; 4066228561Snp qsort(avail, i, sizeof(struct mem_desc), mem_desc_cmp); 4067228561Snp 4068228561Snp (md++)->base = t4_read_reg(sc, A_SGE_DBQ_CTXT_BADDR); 4069228561Snp (md++)->base = t4_read_reg(sc, A_SGE_IMSG_CTXT_BADDR); 4070228561Snp (md++)->base = t4_read_reg(sc, A_SGE_FLM_CACHE_BADDR); 4071228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 4072228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_BASE); 4073228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TIMER_BASE); 4074228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_RX_FLST_BASE); 4075228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_TX_FLST_BASE); 4076228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_PS_FLST_BASE); 4077228561Snp 4078228561Snp /* the next few have explicit upper bounds */ 4079228561Snp md->base = t4_read_reg(sc, A_TP_PMM_TX_BASE); 4080228561Snp md->limit = md->base - 1 + 4081228561Snp t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE) * 4082228561Snp G_PMTXMAXPAGE(t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE)); 4083228561Snp md++; 4084228561Snp 4085228561Snp md->base = t4_read_reg(sc, A_TP_PMM_RX_BASE); 4086228561Snp md->limit = md->base - 1 + 4087228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) * 4088228561Snp G_PMRXMAXPAGE(t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE)); 4089228561Snp md++; 4090228561Snp 4091228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 4092228561Snp hi = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4; 4093228561Snp md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE); 4094228561Snp md->limit = (sc->tids.ntids - hi) * 16 + md->base - 1; 4095228561Snp } else { 4096228561Snp md->base = 0; 4097228561Snp md->idx = ARRAY_SIZE(region); /* hide it */ 4098228561Snp } 4099228561Snp md++; 4100228561Snp 4101228561Snp#define ulp_region(reg) \ 4102228561Snp md->base = t4_read_reg(sc, A_ULP_ ## reg ## _LLIMIT);\ 4103228561Snp (md++)->limit = t4_read_reg(sc, A_ULP_ ## reg ## _ULIMIT) 4104228561Snp 4105228561Snp ulp_region(RX_ISCSI); 4106228561Snp ulp_region(RX_TDDP); 4107228561Snp ulp_region(TX_TPT); 4108228561Snp ulp_region(RX_STAG); 4109228561Snp ulp_region(RX_RQ); 4110228561Snp ulp_region(RX_RQUDP); 4111228561Snp ulp_region(RX_PBL); 4112228561Snp ulp_region(TX_PBL); 4113228561Snp#undef ulp_region 4114228561Snp 4115228561Snp md->base = t4_read_reg(sc, A_ULP_RX_CTX_BASE); 4116228561Snp md->limit = md->base + sc->tids.ntids - 1; 4117228561Snp md++; 4118228561Snp md->base = t4_read_reg(sc, A_ULP_TX_ERR_TABLE_BASE); 4119228561Snp md->limit = md->base + sc->tids.ntids - 1; 4120228561Snp md++; 4121228561Snp 4122228561Snp md->base = sc->vres.ocq.start; 4123228561Snp if (sc->vres.ocq.size) 4124228561Snp md->limit = md->base + sc->vres.ocq.size - 1; 4125228561Snp else 4126228561Snp md->idx = ARRAY_SIZE(region); /* hide it */ 4127228561Snp md++; 4128228561Snp 4129228561Snp /* add any address-space holes, there can be up to 3 */ 4130228561Snp for (n = 0; n < i - 1; n++) 4131228561Snp if (avail[n].limit < avail[n + 1].base) 4132228561Snp (md++)->base = avail[n].limit; 4133228561Snp if (avail[n].limit) 4134228561Snp (md++)->base = avail[n].limit; 4135228561Snp 4136228561Snp n = md - mem; 4137228561Snp qsort(mem, n, sizeof(struct mem_desc), mem_desc_cmp); 4138228561Snp 4139228561Snp for (lo = 0; lo < i; lo++) 4140228561Snp mem_region_show(sb, memory[avail[lo].idx], avail[lo].base, 4141228561Snp avail[lo].limit - 1); 4142228561Snp 4143228561Snp sbuf_printf(sb, "\n"); 4144228561Snp for (i = 0; i < n; i++) { 4145228561Snp if (mem[i].idx >= ARRAY_SIZE(region)) 4146228561Snp continue; /* skip holes */ 4147228561Snp if (!mem[i].limit) 4148228561Snp mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0; 4149228561Snp mem_region_show(sb, region[mem[i].idx], mem[i].base, 4150228561Snp mem[i].limit); 4151228561Snp } 4152228561Snp 4153228561Snp sbuf_printf(sb, "\n"); 4154228561Snp lo = t4_read_reg(sc, A_CIM_SDRAM_BASE_ADDR); 4155228561Snp hi = t4_read_reg(sc, A_CIM_SDRAM_ADDR_SIZE) + lo - 1; 4156228561Snp mem_region_show(sb, "uP RAM:", lo, hi); 4157228561Snp 4158228561Snp lo = t4_read_reg(sc, A_CIM_EXTMEM2_BASE_ADDR); 4159228561Snp hi = t4_read_reg(sc, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1; 4160228561Snp mem_region_show(sb, "uP Extmem2:", lo, hi); 4161228561Snp 4162228561Snp lo = t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE); 4163228561Snp sbuf_printf(sb, "\n%u Rx pages of size %uKiB for %u channels\n", 4164228561Snp G_PMRXMAXPAGE(lo), 4165228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) >> 10, 4166228561Snp (lo & F_PMRXNUMCHN) ? 2 : 1); 4167228561Snp 4168228561Snp lo = t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE); 4169228561Snp hi = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE); 4170228561Snp sbuf_printf(sb, "%u Tx pages of size %u%ciB for %u channels\n", 4171228561Snp G_PMTXMAXPAGE(lo), 4172228561Snp hi >= (1 << 20) ? (hi >> 20) : (hi >> 10), 4173228561Snp hi >= (1 << 20) ? 'M' : 'K', 1 << G_PMTXNUMCHN(lo)); 4174228561Snp sbuf_printf(sb, "%u p-structs\n", 4175228561Snp t4_read_reg(sc, A_TP_CMM_MM_MAX_PSTRUCT)); 4176228561Snp 4177228561Snp for (i = 0; i < 4; i++) { 4178228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV0 + i * 4); 4179228561Snp sbuf_printf(sb, "\nPort %d using %u pages out of %u allocated", 4180228561Snp i, G_USED(lo), G_ALLOC(lo)); 4181228561Snp } 4182228561Snp for (i = 0; i < 4; i++) { 4183228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV4 + i * 4); 4184228561Snp sbuf_printf(sb, 4185228561Snp "\nLoopback %d using %u pages out of %u allocated", 4186228561Snp i, G_USED(lo), G_ALLOC(lo)); 4187228561Snp } 4188228561Snp 4189228561Snp rc = sbuf_finish(sb); 4190228561Snp sbuf_delete(sb); 4191228561Snp 4192228561Snp return (rc); 4193228561Snp} 4194228561Snp 4195228561Snpstatic int 4196228561Snpsysctl_path_mtus(SYSCTL_HANDLER_ARGS) 4197228561Snp{ 4198228561Snp struct adapter *sc = arg1; 4199228561Snp struct sbuf *sb; 4200228561Snp int rc; 4201228561Snp uint16_t mtus[NMTUS]; 4202228561Snp 4203228561Snp rc = sysctl_wire_old_buffer(req, 0); 4204228561Snp if (rc != 0) 4205228561Snp return (rc); 4206228561Snp 4207228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4208228561Snp if (sb == NULL) 4209228561Snp return (ENOMEM); 4210228561Snp 4211228561Snp t4_read_mtu_tbl(sc, mtus, NULL); 4212228561Snp 4213228561Snp sbuf_printf(sb, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", 4214228561Snp mtus[0], mtus[1], mtus[2], mtus[3], mtus[4], mtus[5], mtus[6], 4215228561Snp mtus[7], mtus[8], mtus[9], mtus[10], mtus[11], mtus[12], mtus[13], 4216228561Snp mtus[14], mtus[15]); 4217228561Snp 4218228561Snp rc = sbuf_finish(sb); 4219228561Snp sbuf_delete(sb); 4220228561Snp 4221228561Snp return (rc); 4222228561Snp} 4223228561Snp 4224228561Snpstatic int 4225228561Snpsysctl_pm_stats(SYSCTL_HANDLER_ARGS) 4226228561Snp{ 4227228561Snp struct adapter *sc = arg1; 4228228561Snp struct sbuf *sb; 4229228561Snp int rc, i; 4230228561Snp uint32_t tx_cnt[PM_NSTATS], rx_cnt[PM_NSTATS]; 4231228561Snp uint64_t tx_cyc[PM_NSTATS], rx_cyc[PM_NSTATS]; 4232228561Snp static const char *pm_stats[] = { 4233228561Snp "Read:", "Write bypass:", "Write mem:", "Flush:", "FIFO wait:" 4234228561Snp }; 4235228561Snp 4236228561Snp rc = sysctl_wire_old_buffer(req, 0); 4237228561Snp if (rc != 0) 4238228561Snp return (rc); 4239228561Snp 4240228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4241228561Snp if (sb == NULL) 4242228561Snp return (ENOMEM); 4243228561Snp 4244228561Snp t4_pmtx_get_stats(sc, tx_cnt, tx_cyc); 4245228561Snp t4_pmrx_get_stats(sc, rx_cnt, rx_cyc); 4246228561Snp 4247228561Snp sbuf_printf(sb, " Tx count Tx cycles " 4248228561Snp "Rx count Rx cycles"); 4249228561Snp for (i = 0; i < PM_NSTATS; i++) 4250228561Snp sbuf_printf(sb, "\n%-13s %10u %20ju %10u %20ju", 4251228561Snp pm_stats[i], tx_cnt[i], tx_cyc[i], rx_cnt[i], rx_cyc[i]); 4252228561Snp 4253228561Snp rc = sbuf_finish(sb); 4254228561Snp sbuf_delete(sb); 4255228561Snp 4256228561Snp return (rc); 4257228561Snp} 4258228561Snp 4259228561Snpstatic int 4260228561Snpsysctl_rdma_stats(SYSCTL_HANDLER_ARGS) 4261228561Snp{ 4262228561Snp struct adapter *sc = arg1; 4263228561Snp struct sbuf *sb; 4264228561Snp int rc; 4265228561Snp struct tp_rdma_stats stats; 4266228561Snp 4267228561Snp rc = sysctl_wire_old_buffer(req, 0); 4268228561Snp if (rc != 0) 4269228561Snp return (rc); 4270228561Snp 4271228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4272228561Snp if (sb == NULL) 4273228561Snp return (ENOMEM); 4274228561Snp 4275228561Snp t4_tp_get_rdma_stats(sc, &stats); 4276228561Snp sbuf_printf(sb, "NoRQEModDefferals: %u\n", stats.rqe_dfr_mod); 4277228561Snp sbuf_printf(sb, "NoRQEPktDefferals: %u", stats.rqe_dfr_pkt); 4278228561Snp 4279228561Snp rc = sbuf_finish(sb); 4280228561Snp sbuf_delete(sb); 4281228561Snp 4282228561Snp return (rc); 4283228561Snp} 4284228561Snp 4285228561Snpstatic int 4286228561Snpsysctl_tcp_stats(SYSCTL_HANDLER_ARGS) 4287228561Snp{ 4288228561Snp struct adapter *sc = arg1; 4289228561Snp struct sbuf *sb; 4290228561Snp int rc; 4291228561Snp struct tp_tcp_stats v4, v6; 4292228561Snp 4293228561Snp rc = sysctl_wire_old_buffer(req, 0); 4294228561Snp if (rc != 0) 4295228561Snp return (rc); 4296228561Snp 4297228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4298228561Snp if (sb == NULL) 4299228561Snp return (ENOMEM); 4300228561Snp 4301228561Snp t4_tp_get_tcp_stats(sc, &v4, &v6); 4302228561Snp sbuf_printf(sb, 4303228561Snp " IP IPv6\n"); 4304228561Snp sbuf_printf(sb, "OutRsts: %20u %20u\n", 4305228561Snp v4.tcpOutRsts, v6.tcpOutRsts); 4306228561Snp sbuf_printf(sb, "InSegs: %20ju %20ju\n", 4307228561Snp v4.tcpInSegs, v6.tcpInSegs); 4308228561Snp sbuf_printf(sb, "OutSegs: %20ju %20ju\n", 4309228561Snp v4.tcpOutSegs, v6.tcpOutSegs); 4310228561Snp sbuf_printf(sb, "RetransSegs: %20ju %20ju", 4311228561Snp v4.tcpRetransSegs, v6.tcpRetransSegs); 4312228561Snp 4313228561Snp rc = sbuf_finish(sb); 4314228561Snp sbuf_delete(sb); 4315228561Snp 4316228561Snp return (rc); 4317228561Snp} 4318228561Snp 4319228561Snpstatic int 4320228561Snpsysctl_tids(SYSCTL_HANDLER_ARGS) 4321228561Snp{ 4322228561Snp struct adapter *sc = arg1; 4323228561Snp struct sbuf *sb; 4324228561Snp int rc; 4325228561Snp struct tid_info *t = &sc->tids; 4326228561Snp 4327228561Snp rc = sysctl_wire_old_buffer(req, 0); 4328228561Snp if (rc != 0) 4329228561Snp return (rc); 4330228561Snp 4331228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4332228561Snp if (sb == NULL) 4333228561Snp return (ENOMEM); 4334228561Snp 4335228561Snp if (t->natids) { 4336228561Snp sbuf_printf(sb, "ATID range: 0-%u, in use: %u\n", t->natids - 1, 4337228561Snp t->atids_in_use); 4338228561Snp } 4339228561Snp 4340228561Snp if (t->ntids) { 4341228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 4342228561Snp uint32_t b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4; 4343228561Snp 4344228561Snp if (b) { 4345228561Snp sbuf_printf(sb, "TID range: 0-%u, %u-%u", b - 1, 4346228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 4347228561Snp t->ntids - 1); 4348228561Snp } else { 4349228561Snp sbuf_printf(sb, "TID range: %u-%u", 4350228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 4351228561Snp t->ntids - 1); 4352228561Snp } 4353228561Snp } else 4354228561Snp sbuf_printf(sb, "TID range: 0-%u", t->ntids - 1); 4355228561Snp sbuf_printf(sb, ", in use: %u\n", 4356228561Snp atomic_load_acq_int(&t->tids_in_use)); 4357228561Snp } 4358228561Snp 4359228561Snp if (t->nstids) { 4360228561Snp sbuf_printf(sb, "STID range: %u-%u, in use: %u\n", t->stid_base, 4361228561Snp t->stid_base + t->nstids - 1, t->stids_in_use); 4362228561Snp } 4363228561Snp 4364228561Snp if (t->nftids) { 4365228561Snp sbuf_printf(sb, "FTID range: %u-%u\n", t->ftid_base, 4366228561Snp t->ftid_base + t->nftids - 1); 4367228561Snp } 4368228561Snp 4369228561Snp sbuf_printf(sb, "HW TID usage: %u IP users, %u IPv6 users", 4370228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV4), 4371228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV6)); 4372228561Snp 4373228561Snp rc = sbuf_finish(sb); 4374228561Snp sbuf_delete(sb); 4375228561Snp 4376228561Snp return (rc); 4377228561Snp} 4378228561Snp 4379228561Snpstatic int 4380228561Snpsysctl_tp_err_stats(SYSCTL_HANDLER_ARGS) 4381228561Snp{ 4382228561Snp struct adapter *sc = arg1; 4383228561Snp struct sbuf *sb; 4384228561Snp int rc; 4385228561Snp struct tp_err_stats stats; 4386228561Snp 4387228561Snp rc = sysctl_wire_old_buffer(req, 0); 4388228561Snp if (rc != 0) 4389228561Snp return (rc); 4390228561Snp 4391228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4392228561Snp if (sb == NULL) 4393228561Snp return (ENOMEM); 4394228561Snp 4395228561Snp t4_tp_get_err_stats(sc, &stats); 4396228561Snp 4397228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 4398228561Snp "channel 3\n"); 4399228561Snp sbuf_printf(sb, "macInErrs: %10u %10u %10u %10u\n", 4400228561Snp stats.macInErrs[0], stats.macInErrs[1], stats.macInErrs[2], 4401228561Snp stats.macInErrs[3]); 4402228561Snp sbuf_printf(sb, "hdrInErrs: %10u %10u %10u %10u\n", 4403228561Snp stats.hdrInErrs[0], stats.hdrInErrs[1], stats.hdrInErrs[2], 4404228561Snp stats.hdrInErrs[3]); 4405228561Snp sbuf_printf(sb, "tcpInErrs: %10u %10u %10u %10u\n", 4406228561Snp stats.tcpInErrs[0], stats.tcpInErrs[1], stats.tcpInErrs[2], 4407228561Snp stats.tcpInErrs[3]); 4408228561Snp sbuf_printf(sb, "tcp6InErrs: %10u %10u %10u %10u\n", 4409228561Snp stats.tcp6InErrs[0], stats.tcp6InErrs[1], stats.tcp6InErrs[2], 4410228561Snp stats.tcp6InErrs[3]); 4411228561Snp sbuf_printf(sb, "tnlCongDrops: %10u %10u %10u %10u\n", 4412228561Snp stats.tnlCongDrops[0], stats.tnlCongDrops[1], stats.tnlCongDrops[2], 4413228561Snp stats.tnlCongDrops[3]); 4414228561Snp sbuf_printf(sb, "tnlTxDrops: %10u %10u %10u %10u\n", 4415228561Snp stats.tnlTxDrops[0], stats.tnlTxDrops[1], stats.tnlTxDrops[2], 4416228561Snp stats.tnlTxDrops[3]); 4417228561Snp sbuf_printf(sb, "ofldVlanDrops: %10u %10u %10u %10u\n", 4418228561Snp stats.ofldVlanDrops[0], stats.ofldVlanDrops[1], 4419228561Snp stats.ofldVlanDrops[2], stats.ofldVlanDrops[3]); 4420228561Snp sbuf_printf(sb, "ofldChanDrops: %10u %10u %10u %10u\n\n", 4421228561Snp stats.ofldChanDrops[0], stats.ofldChanDrops[1], 4422228561Snp stats.ofldChanDrops[2], stats.ofldChanDrops[3]); 4423228561Snp sbuf_printf(sb, "ofldNoNeigh: %u\nofldCongDefer: %u", 4424228561Snp stats.ofldNoNeigh, stats.ofldCongDefer); 4425228561Snp 4426228561Snp rc = sbuf_finish(sb); 4427228561Snp sbuf_delete(sb); 4428228561Snp 4429228561Snp return (rc); 4430228561Snp} 4431228561Snp 4432228561Snpstatic int 4433228561Snpsysctl_tx_rate(SYSCTL_HANDLER_ARGS) 4434228561Snp{ 4435228561Snp struct adapter *sc = arg1; 4436228561Snp struct sbuf *sb; 4437228561Snp int rc; 4438228561Snp u64 nrate[NCHAN], orate[NCHAN]; 4439228561Snp 4440228561Snp rc = sysctl_wire_old_buffer(req, 0); 4441228561Snp if (rc != 0) 4442228561Snp return (rc); 4443228561Snp 4444228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4445228561Snp if (sb == NULL) 4446228561Snp return (ENOMEM); 4447228561Snp 4448228561Snp t4_get_chan_txrate(sc, nrate, orate); 4449228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 4450228561Snp "channel 3\n"); 4451228561Snp sbuf_printf(sb, "NIC B/s: %10ju %10ju %10ju %10ju\n", 4452228561Snp nrate[0], nrate[1], nrate[2], nrate[3]); 4453228561Snp sbuf_printf(sb, "Offload B/s: %10ju %10ju %10ju %10ju", 4454228561Snp orate[0], orate[1], orate[2], orate[3]); 4455228561Snp 4456228561Snp rc = sbuf_finish(sb); 4457228561Snp sbuf_delete(sb); 4458228561Snp 4459228561Snp return (rc); 4460228561Snp} 4461231115Snp#endif 4462228561Snp 4463219286Snpstatic inline void 4464219286Snptxq_start(struct ifnet *ifp, struct sge_txq *txq) 4465219286Snp{ 4466219286Snp struct buf_ring *br; 4467219286Snp struct mbuf *m; 4468219286Snp 4469219286Snp TXQ_LOCK_ASSERT_OWNED(txq); 4470219286Snp 4471220873Snp br = txq->br; 4472219286Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 4473219286Snp if (m) 4474219286Snp t4_eth_tx(ifp, txq, m); 4475219286Snp} 4476219286Snp 4477219286Snpvoid 4478228561Snpt4_tx_callout(void *arg) 4479219286Snp{ 4480228561Snp struct sge_eq *eq = arg; 4481228561Snp struct adapter *sc; 4482219286Snp 4483228561Snp if (EQ_TRYLOCK(eq) == 0) 4484228561Snp goto reschedule; 4485228561Snp 4486228561Snp if (eq->flags & EQ_STALLED && !can_resume_tx(eq)) { 4487228561Snp EQ_UNLOCK(eq); 4488228561Snpreschedule: 4489228561Snp if (__predict_true(!(eq->flags && EQ_DOOMED))) 4490228561Snp callout_schedule(&eq->tx_callout, 1); 4491228561Snp return; 4492228561Snp } 4493228561Snp 4494228561Snp EQ_LOCK_ASSERT_OWNED(eq); 4495228561Snp 4496228561Snp if (__predict_true((eq->flags & EQ_DOOMED) == 0)) { 4497228561Snp 4498228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 4499228561Snp struct sge_txq *txq = arg; 4500228561Snp struct port_info *pi = txq->ifp->if_softc; 4501228561Snp 4502228561Snp sc = pi->adapter; 4503228561Snp } else { 4504228561Snp struct sge_wrq *wrq = arg; 4505228561Snp 4506228561Snp sc = wrq->adapter; 4507228561Snp } 4508228561Snp 4509228561Snp taskqueue_enqueue(sc->tq[eq->tx_chan], &eq->tx_task); 4510228561Snp } 4511228561Snp 4512228561Snp EQ_UNLOCK(eq); 4513228561Snp} 4514228561Snp 4515228561Snpvoid 4516228561Snpt4_tx_task(void *arg, int count) 4517228561Snp{ 4518228561Snp struct sge_eq *eq = arg; 4519228561Snp 4520228561Snp EQ_LOCK(eq); 4521228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 4522228561Snp struct sge_txq *txq = arg; 4523220649Snp txq_start(txq->ifp, txq); 4524228561Snp } else { 4525228561Snp struct sge_wrq *wrq = arg; 4526228561Snp t4_wrq_tx_locked(wrq->adapter, wrq, NULL); 4527228561Snp } 4528228561Snp EQ_UNLOCK(eq); 4529219286Snp} 4530219286Snp 4531221474Snpstatic uint32_t 4532221474Snpfconf_to_mode(uint32_t fconf) 4533221474Snp{ 4534221474Snp uint32_t mode; 4535221474Snp 4536221474Snp mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR | 4537221474Snp T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT; 4538221474Snp 4539221474Snp if (fconf & F_FRAGMENTATION) 4540221474Snp mode |= T4_FILTER_IP_FRAGMENT; 4541221474Snp 4542221474Snp if (fconf & F_MPSHITTYPE) 4543221474Snp mode |= T4_FILTER_MPS_HIT_TYPE; 4544221474Snp 4545221474Snp if (fconf & F_MACMATCH) 4546221474Snp mode |= T4_FILTER_MAC_IDX; 4547221474Snp 4548221474Snp if (fconf & F_ETHERTYPE) 4549221474Snp mode |= T4_FILTER_ETH_TYPE; 4550221474Snp 4551221474Snp if (fconf & F_PROTOCOL) 4552221474Snp mode |= T4_FILTER_IP_PROTO; 4553221474Snp 4554221474Snp if (fconf & F_TOS) 4555221474Snp mode |= T4_FILTER_IP_TOS; 4556221474Snp 4557221474Snp if (fconf & F_VLAN) 4558228561Snp mode |= T4_FILTER_VLAN; 4559221474Snp 4560221474Snp if (fconf & F_VNIC_ID) 4561228561Snp mode |= T4_FILTER_VNIC; 4562221474Snp 4563221474Snp if (fconf & F_PORT) 4564221474Snp mode |= T4_FILTER_PORT; 4565221474Snp 4566221474Snp if (fconf & F_FCOE) 4567221474Snp mode |= T4_FILTER_FCoE; 4568221474Snp 4569221474Snp return (mode); 4570221474Snp} 4571221474Snp 4572221474Snpstatic uint32_t 4573221474Snpmode_to_fconf(uint32_t mode) 4574221474Snp{ 4575221474Snp uint32_t fconf = 0; 4576221474Snp 4577221474Snp if (mode & T4_FILTER_IP_FRAGMENT) 4578221474Snp fconf |= F_FRAGMENTATION; 4579221474Snp 4580221474Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 4581221474Snp fconf |= F_MPSHITTYPE; 4582221474Snp 4583221474Snp if (mode & T4_FILTER_MAC_IDX) 4584221474Snp fconf |= F_MACMATCH; 4585221474Snp 4586221474Snp if (mode & T4_FILTER_ETH_TYPE) 4587221474Snp fconf |= F_ETHERTYPE; 4588221474Snp 4589221474Snp if (mode & T4_FILTER_IP_PROTO) 4590221474Snp fconf |= F_PROTOCOL; 4591221474Snp 4592221474Snp if (mode & T4_FILTER_IP_TOS) 4593221474Snp fconf |= F_TOS; 4594221474Snp 4595228561Snp if (mode & T4_FILTER_VLAN) 4596221474Snp fconf |= F_VLAN; 4597221474Snp 4598228561Snp if (mode & T4_FILTER_VNIC) 4599221474Snp fconf |= F_VNIC_ID; 4600221474Snp 4601221474Snp if (mode & T4_FILTER_PORT) 4602221474Snp fconf |= F_PORT; 4603221474Snp 4604221474Snp if (mode & T4_FILTER_FCoE) 4605221474Snp fconf |= F_FCOE; 4606221474Snp 4607221474Snp return (fconf); 4608221474Snp} 4609221474Snp 4610221474Snpstatic uint32_t 4611221474Snpfspec_to_fconf(struct t4_filter_specification *fs) 4612221474Snp{ 4613221474Snp uint32_t fconf = 0; 4614221474Snp 4615221474Snp if (fs->val.frag || fs->mask.frag) 4616221474Snp fconf |= F_FRAGMENTATION; 4617221474Snp 4618221474Snp if (fs->val.matchtype || fs->mask.matchtype) 4619221474Snp fconf |= F_MPSHITTYPE; 4620221474Snp 4621221474Snp if (fs->val.macidx || fs->mask.macidx) 4622221474Snp fconf |= F_MACMATCH; 4623221474Snp 4624221474Snp if (fs->val.ethtype || fs->mask.ethtype) 4625221474Snp fconf |= F_ETHERTYPE; 4626221474Snp 4627221474Snp if (fs->val.proto || fs->mask.proto) 4628221474Snp fconf |= F_PROTOCOL; 4629221474Snp 4630221474Snp if (fs->val.tos || fs->mask.tos) 4631221474Snp fconf |= F_TOS; 4632221474Snp 4633228561Snp if (fs->val.vlan_vld || fs->mask.vlan_vld) 4634221474Snp fconf |= F_VLAN; 4635221474Snp 4636228561Snp if (fs->val.vnic_vld || fs->mask.vnic_vld) 4637221474Snp fconf |= F_VNIC_ID; 4638221474Snp 4639221474Snp if (fs->val.iport || fs->mask.iport) 4640221474Snp fconf |= F_PORT; 4641221474Snp 4642221474Snp if (fs->val.fcoe || fs->mask.fcoe) 4643221474Snp fconf |= F_FCOE; 4644221474Snp 4645221474Snp return (fconf); 4646221474Snp} 4647221474Snp 4648221474Snpstatic int 4649221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode) 4650221474Snp{ 4651221474Snp uint32_t fconf; 4652221474Snp 4653221474Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1, 4654221474Snp A_TP_VLAN_PRI_MAP); 4655221474Snp 4656228561Snp if (sc->filter_mode != fconf) { 4657228561Snp log(LOG_WARNING, "%s: cached filter mode out of sync %x %x.\n", 4658228561Snp device_get_nameunit(sc->dev), sc->filter_mode, fconf); 4659228561Snp sc->filter_mode = fconf; 4660228561Snp } 4661221474Snp 4662228561Snp *mode = fconf_to_mode(sc->filter_mode); 4663228561Snp 4664221474Snp return (0); 4665221474Snp} 4666221474Snp 4667221474Snpstatic int 4668221474Snpset_filter_mode(struct adapter *sc, uint32_t mode) 4669221474Snp{ 4670221474Snp uint32_t fconf; 4671221474Snp int rc; 4672221474Snp 4673221474Snp fconf = mode_to_fconf(mode); 4674221474Snp 4675221474Snp ADAPTER_LOCK(sc); 4676221474Snp if (IS_BUSY(sc)) { 4677221474Snp rc = EAGAIN; 4678221474Snp goto done; 4679221474Snp } 4680221474Snp 4681221474Snp if (sc->tids.ftids_in_use > 0) { 4682221474Snp rc = EBUSY; 4683221474Snp goto done; 4684221474Snp } 4685221474Snp 4686237263Snp#ifdef TCP_OFFLOAD 4687228561Snp if (sc->offload_map) { 4688228561Snp rc = EBUSY; 4689228561Snp goto done; 4690228561Snp } 4691228561Snp#endif 4692228561Snp 4693228561Snp#ifdef notyet 4694221474Snp rc = -t4_set_filter_mode(sc, fconf); 4695228561Snp if (rc == 0) 4696228561Snp sc->filter_mode = fconf; 4697228561Snp#else 4698228561Snp rc = ENOTSUP; 4699228561Snp#endif 4700228561Snp 4701221474Snpdone: 4702221474Snp ADAPTER_UNLOCK(sc); 4703221474Snp return (rc); 4704221474Snp} 4705221474Snp 4706222552Snpstatic inline uint64_t 4707222552Snpget_filter_hits(struct adapter *sc, uint32_t fid) 4708222552Snp{ 4709222552Snp uint32_t tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 4710222552Snp uint64_t hits; 4711222552Snp 4712222552Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0), 4713222552Snp tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE); 4714222552Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0)); 4715222552Snp hits = t4_read_reg64(sc, MEMWIN0_BASE + 16); 4716222552Snp 4717222552Snp return (be64toh(hits)); 4718222552Snp} 4719222552Snp 4720221474Snpstatic int 4721221474Snpget_filter(struct adapter *sc, struct t4_filter *t) 4722221474Snp{ 4723221474Snp int i, nfilters = sc->tids.nftids; 4724221474Snp struct filter_entry *f; 4725221474Snp 4726221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4727221474Snp 4728221474Snp if (IS_BUSY(sc)) 4729221474Snp return (EAGAIN); 4730221474Snp 4731221474Snp if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL || 4732221474Snp t->idx >= nfilters) { 4733221474Snp t->idx = 0xffffffff; 4734221474Snp return (0); 4735221474Snp } 4736221474Snp 4737221474Snp f = &sc->tids.ftid_tab[t->idx]; 4738221474Snp for (i = t->idx; i < nfilters; i++, f++) { 4739221474Snp if (f->valid) { 4740221474Snp t->idx = i; 4741222509Snp t->l2tidx = f->l2t ? f->l2t->idx : 0; 4742222509Snp t->smtidx = f->smtidx; 4743222552Snp if (f->fs.hitcnts) 4744222552Snp t->hits = get_filter_hits(sc, t->idx); 4745222552Snp else 4746222552Snp t->hits = UINT64_MAX; 4747221474Snp t->fs = f->fs; 4748221474Snp 4749221474Snp return (0); 4750221474Snp } 4751221474Snp } 4752221474Snp 4753221474Snp t->idx = 0xffffffff; 4754221474Snp return (0); 4755221474Snp} 4756221474Snp 4757221474Snpstatic int 4758221474Snpset_filter(struct adapter *sc, struct t4_filter *t) 4759221474Snp{ 4760221474Snp unsigned int nfilters, nports; 4761221474Snp struct filter_entry *f; 4762221474Snp int i; 4763221474Snp 4764221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4765221474Snp 4766221474Snp nfilters = sc->tids.nftids; 4767221474Snp nports = sc->params.nports; 4768221474Snp 4769221474Snp if (nfilters == 0) 4770221474Snp return (ENOTSUP); 4771221474Snp 4772221474Snp if (!(sc->flags & FULL_INIT_DONE)) 4773221474Snp return (EAGAIN); 4774221474Snp 4775221474Snp if (t->idx >= nfilters) 4776221474Snp return (EINVAL); 4777221474Snp 4778221474Snp /* Validate against the global filter mode */ 4779228561Snp if ((sc->filter_mode | fspec_to_fconf(&t->fs)) != sc->filter_mode) 4780221474Snp return (E2BIG); 4781221474Snp 4782221474Snp if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) 4783221474Snp return (EINVAL); 4784221474Snp 4785221474Snp if (t->fs.val.iport >= nports) 4786221474Snp return (EINVAL); 4787221474Snp 4788221474Snp /* Can't specify an iq if not steering to it */ 4789221474Snp if (!t->fs.dirsteer && t->fs.iq) 4790221474Snp return (EINVAL); 4791221474Snp 4792221474Snp /* IPv6 filter idx must be 4 aligned */ 4793221474Snp if (t->fs.type == 1 && 4794221474Snp ((t->idx & 0x3) || t->idx + 4 >= nfilters)) 4795221474Snp return (EINVAL); 4796221474Snp 4797221474Snp if (sc->tids.ftid_tab == NULL) { 4798221474Snp KASSERT(sc->tids.ftids_in_use == 0, 4799221474Snp ("%s: no memory allocated but filters_in_use > 0", 4800221474Snp __func__)); 4801221474Snp 4802221474Snp sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) * 4803221474Snp nfilters, M_CXGBE, M_NOWAIT | M_ZERO); 4804221474Snp if (sc->tids.ftid_tab == NULL) 4805221474Snp return (ENOMEM); 4806221474Snp } 4807221474Snp 4808221474Snp for (i = 0; i < 4; i++) { 4809221474Snp f = &sc->tids.ftid_tab[t->idx + i]; 4810221474Snp 4811221474Snp if (f->pending || f->valid) 4812221474Snp return (EBUSY); 4813221474Snp if (f->locked) 4814221474Snp return (EPERM); 4815221474Snp 4816221474Snp if (t->fs.type == 0) 4817221474Snp break; 4818221474Snp } 4819221474Snp 4820221474Snp f = &sc->tids.ftid_tab[t->idx]; 4821221474Snp f->fs = t->fs; 4822221474Snp 4823221474Snp return set_filter_wr(sc, t->idx); 4824221474Snp} 4825221474Snp 4826221474Snpstatic int 4827221474Snpdel_filter(struct adapter *sc, struct t4_filter *t) 4828221474Snp{ 4829221474Snp unsigned int nfilters; 4830221474Snp struct filter_entry *f; 4831221474Snp 4832221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4833221474Snp 4834221474Snp if (IS_BUSY(sc)) 4835221474Snp return (EAGAIN); 4836221474Snp 4837221474Snp nfilters = sc->tids.nftids; 4838221474Snp 4839221474Snp if (nfilters == 0) 4840221474Snp return (ENOTSUP); 4841221474Snp 4842221474Snp if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 || 4843221474Snp t->idx >= nfilters) 4844221474Snp return (EINVAL); 4845221474Snp 4846221474Snp if (!(sc->flags & FULL_INIT_DONE)) 4847221474Snp return (EAGAIN); 4848221474Snp 4849221474Snp f = &sc->tids.ftid_tab[t->idx]; 4850221474Snp 4851221474Snp if (f->pending) 4852221474Snp return (EBUSY); 4853221474Snp if (f->locked) 4854221474Snp return (EPERM); 4855221474Snp 4856221474Snp if (f->valid) { 4857221474Snp t->fs = f->fs; /* extra info for the caller */ 4858221474Snp return del_filter_wr(sc, t->idx); 4859221474Snp } 4860221474Snp 4861221474Snp return (0); 4862221474Snp} 4863221474Snp 4864221474Snpstatic void 4865222509Snpclear_filter(struct filter_entry *f) 4866221474Snp{ 4867222509Snp if (f->l2t) 4868222509Snp t4_l2t_release(f->l2t); 4869222509Snp 4870221474Snp bzero(f, sizeof (*f)); 4871221474Snp} 4872221474Snp 4873221474Snpstatic int 4874221474Snpset_filter_wr(struct adapter *sc, int fidx) 4875221474Snp{ 4876221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 4877237263Snp struct wrqe *wr; 4878221474Snp struct fw_filter_wr *fwr; 4879221474Snp unsigned int ftid; 4880221474Snp 4881221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4882221474Snp 4883222509Snp if (f->fs.newdmac || f->fs.newvlan) { 4884222509Snp /* This filter needs an L2T entry; allocate one. */ 4885222509Snp f->l2t = t4_l2t_alloc_switching(sc->l2t); 4886222509Snp if (f->l2t == NULL) 4887222509Snp return (EAGAIN); 4888222509Snp if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport, 4889222509Snp f->fs.dmac)) { 4890222509Snp t4_l2t_release(f->l2t); 4891222509Snp f->l2t = NULL; 4892222509Snp return (ENOMEM); 4893222509Snp } 4894222509Snp } 4895221474Snp 4896221474Snp ftid = sc->tids.ftid_base + fidx; 4897221474Snp 4898237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 4899237263Snp if (wr == NULL) 4900221474Snp return (ENOMEM); 4901221474Snp 4902237263Snp fwr = wrtod(wr); 4903221474Snp bzero(fwr, sizeof (*fwr)); 4904221474Snp 4905221474Snp fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR)); 4906221474Snp fwr->len16_pkd = htobe32(FW_LEN16(*fwr)); 4907221474Snp fwr->tid_to_iq = 4908221474Snp htobe32(V_FW_FILTER_WR_TID(ftid) | 4909221474Snp V_FW_FILTER_WR_RQTYPE(f->fs.type) | 4910221474Snp V_FW_FILTER_WR_NOREPLY(0) | 4911221474Snp V_FW_FILTER_WR_IQ(f->fs.iq)); 4912221474Snp fwr->del_filter_to_l2tix = 4913221474Snp htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) | 4914221474Snp V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) | 4915221474Snp V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) | 4916221474Snp V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) | 4917221474Snp V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) | 4918221474Snp V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) | 4919221474Snp V_FW_FILTER_WR_DMAC(f->fs.newdmac) | 4920221474Snp V_FW_FILTER_WR_SMAC(f->fs.newsmac) | 4921221474Snp V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT || 4922221474Snp f->fs.newvlan == VLAN_REWRITE) | 4923221474Snp V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE || 4924221474Snp f->fs.newvlan == VLAN_REWRITE) | 4925221474Snp V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) | 4926221474Snp V_FW_FILTER_WR_TXCHAN(f->fs.eport) | 4927221474Snp V_FW_FILTER_WR_PRIO(f->fs.prio) | 4928222509Snp V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0)); 4929221474Snp fwr->ethtype = htobe16(f->fs.val.ethtype); 4930221474Snp fwr->ethtypem = htobe16(f->fs.mask.ethtype); 4931221474Snp fwr->frag_to_ovlan_vldm = 4932221474Snp (V_FW_FILTER_WR_FRAG(f->fs.val.frag) | 4933221474Snp V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) | 4934228561Snp V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) | 4935228561Snp V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.vnic_vld) | 4936228561Snp V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) | 4937228561Snp V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.vnic_vld)); 4938221474Snp fwr->smac_sel = 0; 4939221474Snp fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) | 4940228561Snp V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id)); 4941221474Snp fwr->maci_to_matchtypem = 4942221474Snp htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) | 4943221474Snp V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) | 4944221474Snp V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) | 4945221474Snp V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) | 4946221474Snp V_FW_FILTER_WR_PORT(f->fs.val.iport) | 4947221474Snp V_FW_FILTER_WR_PORTM(f->fs.mask.iport) | 4948221474Snp V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) | 4949221474Snp V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype)); 4950221474Snp fwr->ptcl = f->fs.val.proto; 4951221474Snp fwr->ptclm = f->fs.mask.proto; 4952221474Snp fwr->ttyp = f->fs.val.tos; 4953221474Snp fwr->ttypm = f->fs.mask.tos; 4954228561Snp fwr->ivlan = htobe16(f->fs.val.vlan); 4955228561Snp fwr->ivlanm = htobe16(f->fs.mask.vlan); 4956228561Snp fwr->ovlan = htobe16(f->fs.val.vnic); 4957228561Snp fwr->ovlanm = htobe16(f->fs.mask.vnic); 4958221474Snp bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip)); 4959221474Snp bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm)); 4960221474Snp bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip)); 4961221474Snp bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm)); 4962221474Snp fwr->lp = htobe16(f->fs.val.dport); 4963221474Snp fwr->lpm = htobe16(f->fs.mask.dport); 4964221474Snp fwr->fp = htobe16(f->fs.val.sport); 4965221474Snp fwr->fpm = htobe16(f->fs.mask.sport); 4966221474Snp if (f->fs.newsmac) 4967221474Snp bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma)); 4968221474Snp 4969221474Snp f->pending = 1; 4970221474Snp sc->tids.ftids_in_use++; 4971228561Snp 4972237263Snp t4_wrq_tx(sc, wr); 4973228561Snp return (0); 4974221474Snp} 4975221474Snp 4976221474Snpstatic int 4977221474Snpdel_filter_wr(struct adapter *sc, int fidx) 4978221474Snp{ 4979221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 4980237263Snp struct wrqe *wr; 4981221474Snp struct fw_filter_wr *fwr; 4982228561Snp unsigned int ftid; 4983221474Snp 4984221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4985221474Snp 4986221474Snp ftid = sc->tids.ftid_base + fidx; 4987221474Snp 4988237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 4989237263Snp if (wr == NULL) 4990221474Snp return (ENOMEM); 4991237263Snp fwr = wrtod(wr); 4992221474Snp bzero(fwr, sizeof (*fwr)); 4993221474Snp 4994228561Snp t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id); 4995221474Snp 4996221474Snp f->pending = 1; 4997237263Snp t4_wrq_tx(sc, wr); 4998228561Snp return (0); 4999221474Snp} 5000221474Snp 5001239338Snpint 5002239338Snpt4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 5003221474Snp{ 5004228561Snp struct adapter *sc = iq->adapter; 5005228561Snp const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1); 5006221474Snp unsigned int idx = GET_TID(rpl); 5007221474Snp 5008228561Snp KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__, 5009228561Snp rss->opcode)); 5010228561Snp 5011221474Snp if (idx >= sc->tids.ftid_base && 5012221474Snp (idx -= sc->tids.ftid_base) < sc->tids.nftids) { 5013221474Snp unsigned int rc = G_COOKIE(rpl->cookie); 5014221474Snp struct filter_entry *f = &sc->tids.ftid_tab[idx]; 5015221474Snp 5016231120Snp ADAPTER_LOCK(sc); 5017228561Snp if (rc == FW_FILTER_WR_FLT_ADDED) { 5018221474Snp f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff; 5019221474Snp f->pending = 0; /* asynchronous setup completed */ 5020221474Snp f->valid = 1; 5021231120Snp } else { 5022231120Snp if (rc != FW_FILTER_WR_FLT_DELETED) { 5023231120Snp /* Add or delete failed, display an error */ 5024231120Snp log(LOG_ERR, 5025231120Snp "filter %u setup failed with error %u\n", 5026231120Snp idx, rc); 5027231120Snp } 5028228561Snp 5029231120Snp clear_filter(f); 5030231120Snp sc->tids.ftids_in_use--; 5031221474Snp } 5032228561Snp ADAPTER_UNLOCK(sc); 5033221474Snp } 5034228561Snp 5035228561Snp return (0); 5036221474Snp} 5037221474Snp 5038222973Snpstatic int 5039222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt) 5040222973Snp{ 5041222973Snp int rc = EINVAL; 5042222973Snp 5043222973Snp if (cntxt->cid > M_CTXTQID) 5044222973Snp return (rc); 5045222973Snp 5046222973Snp if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS && 5047222973Snp cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM) 5048222973Snp return (rc); 5049222973Snp 5050222973Snp if (sc->flags & FW_OK) { 5051222973Snp ADAPTER_LOCK(sc); /* Avoid parallel t4_wr_mbox */ 5052222973Snp rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id, 5053222973Snp &cntxt->data[0]); 5054222973Snp ADAPTER_UNLOCK(sc); 5055222973Snp } 5056222973Snp 5057222973Snp if (rc != 0) { 5058222973Snp /* Read via firmware failed or wasn't even attempted */ 5059222973Snp 5060222973Snp rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id, 5061222973Snp &cntxt->data[0]); 5062222973Snp } 5063222973Snp 5064222973Snp return (rc); 5065222973Snp} 5066222973Snp 5067228561Snpstatic int 5068228561Snpread_card_mem(struct adapter *sc, struct t4_mem_range *mr) 5069228561Snp{ 5070228561Snp uint32_t base, size, lo, hi, win, off, remaining, i, n; 5071228561Snp uint32_t *buf, *b; 5072228561Snp int rc; 5073228561Snp 5074228561Snp /* reads are in multiples of 32 bits */ 5075228561Snp if (mr->addr & 3 || mr->len & 3 || mr->len == 0) 5076228561Snp return (EINVAL); 5077228561Snp 5078228561Snp /* 5079228561Snp * We don't want to deal with potential holes so we mandate that the 5080228561Snp * requested region must lie entirely within one of the 3 memories. 5081228561Snp */ 5082228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 5083228561Snp if (lo & F_EDRAM0_ENABLE) { 5084228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 5085228561Snp base = G_EDRAM0_BASE(hi) << 20; 5086228561Snp size = G_EDRAM0_SIZE(hi) << 20; 5087228561Snp if (size > 0 && 5088228561Snp mr->addr >= base && mr->addr < base + size && 5089228561Snp mr->addr + mr->len <= base + size) 5090228561Snp goto proceed; 5091228561Snp } 5092228561Snp if (lo & F_EDRAM1_ENABLE) { 5093228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 5094228561Snp base = G_EDRAM1_BASE(hi) << 20; 5095228561Snp size = G_EDRAM1_SIZE(hi) << 20; 5096228561Snp if (size > 0 && 5097228561Snp mr->addr >= base && mr->addr < base + size && 5098228561Snp mr->addr + mr->len <= base + size) 5099228561Snp goto proceed; 5100228561Snp } 5101228561Snp if (lo & F_EXT_MEM_ENABLE) { 5102228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 5103228561Snp base = G_EXT_MEM_BASE(hi) << 20; 5104228561Snp size = G_EXT_MEM_SIZE(hi) << 20; 5105228561Snp if (size > 0 && 5106228561Snp mr->addr >= base && mr->addr < base + size && 5107228561Snp mr->addr + mr->len <= base + size) 5108228561Snp goto proceed; 5109228561Snp } 5110228561Snp return (ENXIO); 5111228561Snp 5112228561Snpproceed: 5113228561Snp buf = b = malloc(mr->len, M_CXGBE, M_WAITOK); 5114228561Snp 5115228561Snp /* 5116228561Snp * Position the PCIe window (we use memwin2) to the 16B aligned area 5117228561Snp * just at/before the requested region. 5118228561Snp */ 5119228561Snp win = mr->addr & ~0xf; 5120228561Snp off = mr->addr - win; /* offset of the requested region in the win */ 5121228561Snp remaining = mr->len; 5122228561Snp 5123228561Snp while (remaining) { 5124228561Snp t4_write_reg(sc, 5125228561Snp PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2), win); 5126228561Snp t4_read_reg(sc, 5127228561Snp PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2)); 5128228561Snp 5129228561Snp /* number of bytes that we'll copy in the inner loop */ 5130228561Snp n = min(remaining, MEMWIN2_APERTURE - off); 5131228561Snp 5132228561Snp for (i = 0; i < n; i += 4, remaining -= 4) 5133228561Snp *b++ = t4_read_reg(sc, MEMWIN2_BASE + off + i); 5134228561Snp 5135228561Snp win += MEMWIN2_APERTURE; 5136228561Snp off = 0; 5137228561Snp } 5138228561Snp 5139228561Snp rc = copyout(buf, mr->data, mr->len); 5140228561Snp free(buf, M_CXGBE); 5141228561Snp 5142228561Snp return (rc); 5143228561Snp} 5144228561Snp 5145218792Snpint 5146218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap) 5147218792Snp{ 5148222102Snp int i; 5149218792Snp 5150222102Snp return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0); 5151218792Snp} 5152218792Snp 5153218792Snpint 5154218792Snpt4_os_pci_save_state(struct adapter *sc) 5155218792Snp{ 5156218792Snp device_t dev; 5157218792Snp struct pci_devinfo *dinfo; 5158218792Snp 5159218792Snp dev = sc->dev; 5160218792Snp dinfo = device_get_ivars(dev); 5161218792Snp 5162218792Snp pci_cfg_save(dev, dinfo, 0); 5163218792Snp return (0); 5164218792Snp} 5165218792Snp 5166218792Snpint 5167218792Snpt4_os_pci_restore_state(struct adapter *sc) 5168218792Snp{ 5169218792Snp device_t dev; 5170218792Snp struct pci_devinfo *dinfo; 5171218792Snp 5172218792Snp dev = sc->dev; 5173218792Snp dinfo = device_get_ivars(dev); 5174218792Snp 5175218792Snp pci_cfg_restore(dev, dinfo); 5176218792Snp return (0); 5177218792Snp} 5178219299Snp 5179218792Snpvoid 5180218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx) 5181218792Snp{ 5182218792Snp struct port_info *pi = sc->port[idx]; 5183218792Snp static const char *mod_str[] = { 5184220232Snp NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM" 5185218792Snp }; 5186218792Snp 5187218792Snp if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 5188218792Snp if_printf(pi->ifp, "transceiver unplugged.\n"); 5189220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) 5190220232Snp if_printf(pi->ifp, "unknown transceiver inserted.\n"); 5191220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) 5192220232Snp if_printf(pi->ifp, "unsupported transceiver inserted.\n"); 5193219299Snp else if (pi->mod_type > 0 && pi->mod_type < ARRAY_SIZE(mod_str)) { 5194218792Snp if_printf(pi->ifp, "%s transceiver inserted.\n", 5195218792Snp mod_str[pi->mod_type]); 5196219299Snp } else { 5197219299Snp if_printf(pi->ifp, "transceiver (type %d) inserted.\n", 5198219299Snp pi->mod_type); 5199219299Snp } 5200218792Snp} 5201218792Snp 5202218792Snpvoid 5203218792Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat) 5204218792Snp{ 5205218792Snp struct port_info *pi = sc->port[idx]; 5206218792Snp struct ifnet *ifp = pi->ifp; 5207218792Snp 5208218792Snp if (link_stat) { 5209218792Snp ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed); 5210218792Snp if_link_state_change(ifp, LINK_STATE_UP); 5211218792Snp } else 5212218792Snp if_link_state_change(ifp, LINK_STATE_DOWN); 5213218792Snp} 5214218792Snp 5215228561Snpvoid 5216228561Snpt4_iterate(void (*func)(struct adapter *, void *), void *arg) 5217228561Snp{ 5218228561Snp struct adapter *sc; 5219228561Snp 5220228561Snp mtx_lock(&t4_list_lock); 5221228561Snp SLIST_FOREACH(sc, &t4_list, link) { 5222228561Snp /* 5223228561Snp * func should not make any assumptions about what state sc is 5224228561Snp * in - the only guarantee is that sc->sc_lock is a valid lock. 5225228561Snp */ 5226228561Snp func(sc, arg); 5227228561Snp } 5228228561Snp mtx_unlock(&t4_list_lock); 5229228561Snp} 5230228561Snp 5231218792Snpstatic int 5232218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td) 5233218792Snp{ 5234218792Snp return (0); 5235218792Snp} 5236218792Snp 5237218792Snpstatic int 5238218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td) 5239218792Snp{ 5240218792Snp return (0); 5241218792Snp} 5242218792Snp 5243218792Snpstatic int 5244218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag, 5245218792Snp struct thread *td) 5246218792Snp{ 5247218792Snp int rc; 5248218792Snp struct adapter *sc = dev->si_drv1; 5249218792Snp 5250218792Snp rc = priv_check(td, PRIV_DRIVER); 5251218792Snp if (rc != 0) 5252218792Snp return (rc); 5253218792Snp 5254218792Snp switch (cmd) { 5255220410Snp case CHELSIO_T4_GETREG: { 5256220410Snp struct t4_reg *edata = (struct t4_reg *)data; 5257220410Snp 5258218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 5259218792Snp return (EFAULT); 5260220410Snp 5261220410Snp if (edata->size == 4) 5262220410Snp edata->val = t4_read_reg(sc, edata->addr); 5263220410Snp else if (edata->size == 8) 5264220410Snp edata->val = t4_read_reg64(sc, edata->addr); 5265220410Snp else 5266220410Snp return (EINVAL); 5267220410Snp 5268218792Snp break; 5269218792Snp } 5270220410Snp case CHELSIO_T4_SETREG: { 5271220410Snp struct t4_reg *edata = (struct t4_reg *)data; 5272220410Snp 5273218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 5274218792Snp return (EFAULT); 5275220410Snp 5276220410Snp if (edata->size == 4) { 5277220410Snp if (edata->val & 0xffffffff00000000) 5278220410Snp return (EINVAL); 5279220410Snp t4_write_reg(sc, edata->addr, (uint32_t) edata->val); 5280220410Snp } else if (edata->size == 8) 5281220410Snp t4_write_reg64(sc, edata->addr, edata->val); 5282220410Snp else 5283220410Snp return (EINVAL); 5284218792Snp break; 5285218792Snp } 5286218792Snp case CHELSIO_T4_REGDUMP: { 5287218792Snp struct t4_regdump *regs = (struct t4_regdump *)data; 5288218792Snp int reglen = T4_REGDUMP_SIZE; 5289218792Snp uint8_t *buf; 5290218792Snp 5291218792Snp if (regs->len < reglen) { 5292218792Snp regs->len = reglen; /* hint to the caller */ 5293218792Snp return (ENOBUFS); 5294218792Snp } 5295218792Snp 5296218792Snp regs->len = reglen; 5297218792Snp buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO); 5298218792Snp t4_get_regs(sc, regs, buf); 5299218792Snp rc = copyout(buf, regs->data, reglen); 5300218792Snp free(buf, M_CXGBE); 5301218792Snp break; 5302218792Snp } 5303221474Snp case CHELSIO_T4_GET_FILTER_MODE: 5304221474Snp rc = get_filter_mode(sc, (uint32_t *)data); 5305221474Snp break; 5306221474Snp case CHELSIO_T4_SET_FILTER_MODE: 5307221474Snp rc = set_filter_mode(sc, *(uint32_t *)data); 5308221474Snp break; 5309221474Snp case CHELSIO_T4_GET_FILTER: 5310221474Snp ADAPTER_LOCK(sc); 5311221474Snp rc = get_filter(sc, (struct t4_filter *)data); 5312221474Snp ADAPTER_UNLOCK(sc); 5313221474Snp break; 5314221474Snp case CHELSIO_T4_SET_FILTER: 5315221474Snp ADAPTER_LOCK(sc); 5316221474Snp rc = set_filter(sc, (struct t4_filter *)data); 5317221474Snp ADAPTER_UNLOCK(sc); 5318221474Snp break; 5319221474Snp case CHELSIO_T4_DEL_FILTER: 5320221474Snp ADAPTER_LOCK(sc); 5321221474Snp rc = del_filter(sc, (struct t4_filter *)data); 5322221474Snp ADAPTER_UNLOCK(sc); 5323221474Snp break; 5324222973Snp case CHELSIO_T4_GET_SGE_CONTEXT: 5325222973Snp rc = get_sge_context(sc, (struct t4_sge_context *)data); 5326222973Snp break; 5327228561Snp case CHELSIO_T4_LOAD_FW: { 5328228561Snp struct t4_data *fw = (struct t4_data *)data; 5329228561Snp uint8_t *fw_data; 5330228561Snp 5331228561Snp if (sc->flags & FULL_INIT_DONE) 5332228561Snp return (EBUSY); 5333228561Snp 5334228561Snp fw_data = malloc(fw->len, M_CXGBE, M_NOWAIT); 5335228561Snp if (fw_data == NULL) 5336228561Snp return (ENOMEM); 5337228561Snp 5338228561Snp rc = copyin(fw->data, fw_data, fw->len); 5339228561Snp if (rc == 0) 5340228561Snp rc = -t4_load_fw(sc, fw_data, fw->len); 5341228561Snp 5342228561Snp free(fw_data, M_CXGBE); 5343228561Snp break; 5344228561Snp } 5345228561Snp case CHELSIO_T4_GET_MEM: 5346228561Snp rc = read_card_mem(sc, (struct t4_mem_range *)data); 5347228561Snp break; 5348218792Snp default: 5349218792Snp rc = EINVAL; 5350218792Snp } 5351218792Snp 5352218792Snp return (rc); 5353218792Snp} 5354218792Snp 5355237263Snp#ifdef TCP_OFFLOAD 5356219392Snpstatic int 5357228561Snptoe_capability(struct port_info *pi, int enable) 5358228561Snp{ 5359228561Snp int rc; 5360228561Snp struct adapter *sc = pi->adapter; 5361228561Snp 5362228561Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 5363228561Snp 5364228561Snp if (!is_offload(sc)) 5365228561Snp return (ENODEV); 5366228561Snp 5367228561Snp if (enable) { 5368237263Snp if (!(sc->flags & FULL_INIT_DONE)) { 5369237263Snp log(LOG_WARNING, 5370237263Snp "You must enable a cxgbe interface first\n"); 5371237263Snp return (EAGAIN); 5372237263Snp } 5373237263Snp 5374228561Snp if (isset(&sc->offload_map, pi->port_id)) 5375228561Snp return (0); 5376228561Snp 5377237263Snp if (!(sc->flags & TOM_INIT_DONE)) { 5378237263Snp rc = t4_activate_uld(sc, ULD_TOM); 5379237263Snp if (rc == EAGAIN) { 5380237263Snp log(LOG_WARNING, 5381237263Snp "You must kldload t4_tom.ko before trying " 5382237263Snp "to enable TOE on a cxgbe interface.\n"); 5383237263Snp } 5384228561Snp if (rc != 0) 5385228561Snp return (rc); 5386237263Snp KASSERT(sc->tom_softc != NULL, 5387237263Snp ("%s: TOM activated but softc NULL", __func__)); 5388237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 5389237263Snp ("%s: TOM activated but flag not set", __func__)); 5390228561Snp } 5391228561Snp 5392228561Snp setbit(&sc->offload_map, pi->port_id); 5393228561Snp } else { 5394228561Snp if (!isset(&sc->offload_map, pi->port_id)) 5395228561Snp return (0); 5396228561Snp 5397237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 5398237263Snp ("%s: TOM never initialized?", __func__)); 5399228561Snp clrbit(&sc->offload_map, pi->port_id); 5400228561Snp } 5401228561Snp 5402228561Snp return (0); 5403228561Snp} 5404228561Snp 5405228561Snp/* 5406228561Snp * Add an upper layer driver to the global list. 5407228561Snp */ 5408228561Snpint 5409228561Snpt4_register_uld(struct uld_info *ui) 5410228561Snp{ 5411228561Snp int rc = 0; 5412228561Snp struct uld_info *u; 5413228561Snp 5414228561Snp mtx_lock(&t4_uld_list_lock); 5415228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 5416228561Snp if (u->uld_id == ui->uld_id) { 5417228561Snp rc = EEXIST; 5418228561Snp goto done; 5419228561Snp } 5420228561Snp } 5421228561Snp 5422228561Snp SLIST_INSERT_HEAD(&t4_uld_list, ui, link); 5423228561Snp ui->refcount = 0; 5424228561Snpdone: 5425228561Snp mtx_unlock(&t4_uld_list_lock); 5426228561Snp return (rc); 5427228561Snp} 5428228561Snp 5429228561Snpint 5430228561Snpt4_unregister_uld(struct uld_info *ui) 5431228561Snp{ 5432228561Snp int rc = EINVAL; 5433228561Snp struct uld_info *u; 5434228561Snp 5435228561Snp mtx_lock(&t4_uld_list_lock); 5436228561Snp 5437228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 5438228561Snp if (u == ui) { 5439228561Snp if (ui->refcount > 0) { 5440228561Snp rc = EBUSY; 5441228561Snp goto done; 5442228561Snp } 5443228561Snp 5444228561Snp SLIST_REMOVE(&t4_uld_list, ui, uld_info, link); 5445228561Snp rc = 0; 5446228561Snp goto done; 5447228561Snp } 5448228561Snp } 5449228561Snpdone: 5450228561Snp mtx_unlock(&t4_uld_list_lock); 5451228561Snp return (rc); 5452228561Snp} 5453228561Snp 5454237263Snpint 5455237263Snpt4_activate_uld(struct adapter *sc, int id) 5456228561Snp{ 5457228561Snp int rc = EAGAIN; 5458228561Snp struct uld_info *ui; 5459228561Snp 5460228561Snp mtx_lock(&t4_uld_list_lock); 5461228561Snp 5462228561Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 5463228561Snp if (ui->uld_id == id) { 5464237263Snp rc = ui->activate(sc); 5465237263Snp if (rc == 0) 5466228561Snp ui->refcount++; 5467228561Snp goto done; 5468228561Snp } 5469228561Snp } 5470228561Snpdone: 5471228561Snp mtx_unlock(&t4_uld_list_lock); 5472228561Snp 5473228561Snp return (rc); 5474228561Snp} 5475228561Snp 5476237263Snpint 5477237263Snpt4_deactivate_uld(struct adapter *sc, int id) 5478228561Snp{ 5479237263Snp int rc = EINVAL; 5480237263Snp struct uld_info *ui; 5481228561Snp 5482228561Snp mtx_lock(&t4_uld_list_lock); 5483228561Snp 5484237263Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 5485237263Snp if (ui->uld_id == id) { 5486237263Snp rc = ui->deactivate(sc); 5487237263Snp if (rc == 0) 5488237263Snp ui->refcount--; 5489237263Snp goto done; 5490237263Snp } 5491228561Snp } 5492228561Snpdone: 5493228561Snp mtx_unlock(&t4_uld_list_lock); 5494228561Snp 5495228561Snp return (rc); 5496228561Snp} 5497228561Snp#endif 5498228561Snp 5499228561Snp/* 5500228561Snp * Come up with reasonable defaults for some of the tunables, provided they're 5501228561Snp * not set by the user (in which case we'll use the values as is). 5502228561Snp */ 5503228561Snpstatic void 5504228561Snptweak_tunables(void) 5505228561Snp{ 5506228561Snp int nc = mp_ncpus; /* our snapshot of the number of CPUs */ 5507228561Snp 5508228561Snp if (t4_ntxq10g < 1) 5509228561Snp t4_ntxq10g = min(nc, NTXQ_10G); 5510228561Snp 5511228561Snp if (t4_ntxq1g < 1) 5512228561Snp t4_ntxq1g = min(nc, NTXQ_1G); 5513228561Snp 5514228561Snp if (t4_nrxq10g < 1) 5515228561Snp t4_nrxq10g = min(nc, NRXQ_10G); 5516228561Snp 5517228561Snp if (t4_nrxq1g < 1) 5518228561Snp t4_nrxq1g = min(nc, NRXQ_1G); 5519228561Snp 5520237263Snp#ifdef TCP_OFFLOAD 5521228561Snp if (t4_nofldtxq10g < 1) 5522228561Snp t4_nofldtxq10g = min(nc, NOFLDTXQ_10G); 5523228561Snp 5524228561Snp if (t4_nofldtxq1g < 1) 5525228561Snp t4_nofldtxq1g = min(nc, NOFLDTXQ_1G); 5526228561Snp 5527228561Snp if (t4_nofldrxq10g < 1) 5528228561Snp t4_nofldrxq10g = min(nc, NOFLDRXQ_10G); 5529228561Snp 5530228561Snp if (t4_nofldrxq1g < 1) 5531228561Snp t4_nofldrxq1g = min(nc, NOFLDRXQ_1G); 5532238028Snp 5533238028Snp if (t4_toecaps_allowed == -1) 5534238028Snp t4_toecaps_allowed = FW_CAPS_CONFIG_TOE; 5535238028Snp#else 5536238028Snp if (t4_toecaps_allowed == -1) 5537238028Snp t4_toecaps_allowed = 0; 5538228561Snp#endif 5539228561Snp 5540228561Snp if (t4_tmr_idx_10g < 0 || t4_tmr_idx_10g >= SGE_NTIMERS) 5541228561Snp t4_tmr_idx_10g = TMR_IDX_10G; 5542228561Snp 5543228561Snp if (t4_pktc_idx_10g < -1 || t4_pktc_idx_10g >= SGE_NCOUNTERS) 5544228561Snp t4_pktc_idx_10g = PKTC_IDX_10G; 5545228561Snp 5546228561Snp if (t4_tmr_idx_1g < 0 || t4_tmr_idx_1g >= SGE_NTIMERS) 5547228561Snp t4_tmr_idx_1g = TMR_IDX_1G; 5548228561Snp 5549228561Snp if (t4_pktc_idx_1g < -1 || t4_pktc_idx_1g >= SGE_NCOUNTERS) 5550228561Snp t4_pktc_idx_1g = PKTC_IDX_1G; 5551228561Snp 5552228561Snp if (t4_qsize_txq < 128) 5553228561Snp t4_qsize_txq = 128; 5554228561Snp 5555228561Snp if (t4_qsize_rxq < 128) 5556228561Snp t4_qsize_rxq = 128; 5557228561Snp while (t4_qsize_rxq & 7) 5558228561Snp t4_qsize_rxq++; 5559228561Snp 5560228561Snp t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX; 5561228561Snp} 5562228561Snp 5563228561Snpstatic int 5564219392Snpt4_mod_event(module_t mod, int cmd, void *arg) 5565219392Snp{ 5566228561Snp int rc = 0; 5567219392Snp 5568228561Snp switch (cmd) { 5569228561Snp case MOD_LOAD: 5570219392Snp t4_sge_modload(); 5571228561Snp mtx_init(&t4_list_lock, "T4 adapters", 0, MTX_DEF); 5572228561Snp SLIST_INIT(&t4_list); 5573237263Snp#ifdef TCP_OFFLOAD 5574228561Snp mtx_init(&t4_uld_list_lock, "T4 ULDs", 0, MTX_DEF); 5575228561Snp SLIST_INIT(&t4_uld_list); 5576228561Snp#endif 5577228561Snp tweak_tunables(); 5578228561Snp break; 5579219392Snp 5580228561Snp case MOD_UNLOAD: 5581237263Snp#ifdef TCP_OFFLOAD 5582228561Snp mtx_lock(&t4_uld_list_lock); 5583228561Snp if (!SLIST_EMPTY(&t4_uld_list)) { 5584228561Snp rc = EBUSY; 5585228561Snp mtx_unlock(&t4_uld_list_lock); 5586228561Snp break; 5587228561Snp } 5588228561Snp mtx_unlock(&t4_uld_list_lock); 5589228561Snp mtx_destroy(&t4_uld_list_lock); 5590228561Snp#endif 5591228561Snp mtx_lock(&t4_list_lock); 5592228561Snp if (!SLIST_EMPTY(&t4_list)) { 5593228561Snp rc = EBUSY; 5594228561Snp mtx_unlock(&t4_list_lock); 5595228561Snp break; 5596228561Snp } 5597228561Snp mtx_unlock(&t4_list_lock); 5598228561Snp mtx_destroy(&t4_list_lock); 5599228561Snp break; 5600228561Snp } 5601228561Snp 5602228561Snp return (rc); 5603219392Snp} 5604219392Snp 5605218792Snpstatic devclass_t t4_devclass; 5606218792Snpstatic devclass_t cxgbe_devclass; 5607218792Snp 5608219392SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, t4_mod_event, 0); 5609218792SnpMODULE_VERSION(t4nex, 1); 5610218792Snp 5611218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0); 5612218792SnpMODULE_VERSION(cxgbe, 1); 5613