t4_main.c revision 240452
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 240452 2012-09-13 09:10:10Z 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 */ 384240452SnpCTASSERT(nitems(((struct adapter *)0)->cpl_handler) == NUM_CPL_CMDS); 385240452SnpCTASSERT(nitems(((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 402240452Snp for (i = 0; i < nitems(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; 462240452Snp for (i = 0; i < nitems(sc->cpl_handler); i++) 463228561Snp sc->cpl_handler[i] = cpl_not_handled; 464240452Snp for (i = 0; i < nitems(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) { 518239341Snp uint16_t indsz = min(RX_COPY_THRESHOLD - 1, M_INDICATESIZE); 519218792Snp 520228561Snp /* final tweaks to some settings */ 521218792Snp 522228561Snp t4_load_mtus(sc, sc->params.mtus, sc->params.a_wnd, 523228561Snp sc->params.b_wnd); 524239341Snp /* 4K, 16K, 64K, 256K DDP "page sizes" */ 525239341Snp t4_write_reg(sc, A_ULP_RX_TDDP_PSZ, V_HPZ0(0) | V_HPZ1(2) | 526239341Snp V_HPZ2(4) | V_HPZ3(6)); 527239341Snp t4_set_reg_field(sc, A_ULP_RX_CTL, F_TDDPTAGTCB, F_TDDPTAGTCB); 528228561Snp t4_set_reg_field(sc, A_TP_PARA_REG3, F_TUNNELCNGDROP0 | 529239258Snp F_TUNNELCNGDROP1 | F_TUNNELCNGDROP2 | F_TUNNELCNGDROP3, 530239258Snp F_TUNNELCNGDROP0 | F_TUNNELCNGDROP1 | F_TUNNELCNGDROP2 | 531239258Snp F_TUNNELCNGDROP3); 532228561Snp t4_set_reg_field(sc, A_TP_PARA_REG5, 533228561Snp V_INDICATESIZE(M_INDICATESIZE) | 534228561Snp F_REARMDDPOFFSET | F_RESETDDPOFFSET, 535239341Snp V_INDICATESIZE(indsz) | 536228561Snp F_REARMDDPOFFSET | F_RESETDDPOFFSET); 537228561Snp } else { 538228561Snp /* 539228561Snp * XXX: Verify that we can live with whatever the master driver 540228561Snp * has done so far, and hope that it doesn't change any global 541228561Snp * setting from underneath us in the future. 542228561Snp */ 543218792Snp } 544218792Snp 545228561Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &sc->filter_mode, 1, 546228561Snp A_TP_VLAN_PRI_MAP); 547218792Snp 548228561Snp for (i = 0; i < NCHAN; i++) 549228561Snp sc->params.tp.tx_modq[i] = i; 550218792Snp 551218792Snp rc = t4_create_dma_tag(sc); 552218792Snp if (rc != 0) 553218792Snp goto done; /* error message displayed already */ 554218792Snp 555218792Snp /* 556218792Snp * First pass over all the ports - allocate VIs and initialize some 557218792Snp * basic parameters like mac address, port type, etc. We also figure 558218792Snp * out whether a port is 10G or 1G and use that information when 559218792Snp * calculating how many interrupts to attempt to allocate. 560218792Snp */ 561218792Snp n10g = n1g = 0; 562218792Snp for_each_port(sc, i) { 563218792Snp struct port_info *pi; 564218792Snp 565218792Snp pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK); 566218792Snp sc->port[i] = pi; 567218792Snp 568218792Snp /* These must be set before t4_port_init */ 569218792Snp pi->adapter = sc; 570218792Snp pi->port_id = i; 571218792Snp 572218792Snp /* Allocate the vi and initialize parameters like mac addr */ 573218792Snp rc = -t4_port_init(pi, sc->mbox, sc->pf, 0); 574218792Snp if (rc != 0) { 575218792Snp device_printf(dev, "unable to initialize port %d: %d\n", 576218792Snp i, rc); 577218792Snp free(pi, M_CXGBE); 578222510Snp sc->port[i] = NULL; 579222510Snp goto done; 580218792Snp } 581218792Snp 582218792Snp snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d", 583218792Snp device_get_nameunit(dev), i); 584218792Snp mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF); 585218792Snp 586218792Snp if (is_10G_port(pi)) { 587218792Snp n10g++; 588228561Snp pi->tmr_idx = t4_tmr_idx_10g; 589228561Snp pi->pktc_idx = t4_pktc_idx_10g; 590218792Snp } else { 591218792Snp n1g++; 592228561Snp pi->tmr_idx = t4_tmr_idx_1g; 593228561Snp pi->pktc_idx = t4_pktc_idx_1g; 594218792Snp } 595218792Snp 596218792Snp pi->xact_addr_filt = -1; 597218792Snp 598228561Snp pi->qsize_rxq = t4_qsize_rxq; 599228561Snp pi->qsize_txq = t4_qsize_txq; 600218792Snp 601218792Snp pi->dev = device_add_child(dev, "cxgbe", -1); 602218792Snp if (pi->dev == NULL) { 603218792Snp device_printf(dev, 604218792Snp "failed to add device for port %d.\n", i); 605218792Snp rc = ENXIO; 606218792Snp goto done; 607218792Snp } 608218792Snp device_set_softc(pi->dev, pi); 609218792Snp } 610218792Snp 611218792Snp /* 612218792Snp * Interrupt type, # of interrupts, # of rx/tx queues, etc. 613218792Snp */ 614218792Snp rc = cfg_itype_and_nqueues(sc, n10g, n1g, &iaq); 615218792Snp if (rc != 0) 616218792Snp goto done; /* error message displayed already */ 617218792Snp 618218792Snp sc->intr_type = iaq.intr_type; 619218792Snp sc->intr_count = iaq.nirq; 620228561Snp sc->flags |= iaq.intr_flags; 621218792Snp 622218792Snp s = &sc->sge; 623218792Snp s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g; 624218792Snp s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g; 625220873Snp s->neq = s->ntxq + s->nrxq; /* the free list in an rxq is an eq */ 626228561Snp s->neq += sc->params.nports + 1;/* ctrl queues: 1 per port + 1 mgmt */ 627218792Snp s->niq = s->nrxq + 1; /* 1 extra for firmware event queue */ 628222510Snp 629237263Snp#ifdef TCP_OFFLOAD 630228561Snp if (is_offload(sc)) { 631228561Snp 632228561Snp s->nofldrxq = n10g * iaq.nofldrxq10g + n1g * iaq.nofldrxq1g; 633228561Snp s->nofldtxq = n10g * iaq.nofldtxq10g + n1g * iaq.nofldtxq1g; 634228561Snp s->neq += s->nofldtxq + s->nofldrxq; 635228561Snp s->niq += s->nofldrxq; 636228561Snp 637228561Snp s->ofld_rxq = malloc(s->nofldrxq * sizeof(struct sge_ofld_rxq), 638228561Snp M_CXGBE, M_ZERO | M_WAITOK); 639228561Snp s->ofld_txq = malloc(s->nofldtxq * sizeof(struct sge_wrq), 640228561Snp M_CXGBE, M_ZERO | M_WAITOK); 641228561Snp } 642228561Snp#endif 643228561Snp 644228561Snp s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_wrq), M_CXGBE, 645220873Snp M_ZERO | M_WAITOK); 646218792Snp s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE, 647218792Snp M_ZERO | M_WAITOK); 648218792Snp s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE, 649218792Snp M_ZERO | M_WAITOK); 650218792Snp s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE, 651218792Snp M_ZERO | M_WAITOK); 652218792Snp s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE, 653218792Snp M_ZERO | M_WAITOK); 654218792Snp 655218792Snp sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE, 656218792Snp M_ZERO | M_WAITOK); 657218792Snp 658228561Snp t4_init_l2t(sc, M_WAITOK); 659222509Snp 660218792Snp /* 661218792Snp * Second pass over the ports. This time we know the number of rx and 662218792Snp * tx queues that each port should get. 663218792Snp */ 664218792Snp rqidx = tqidx = 0; 665237263Snp#ifdef TCP_OFFLOAD 666228561Snp ofld_rqidx = ofld_tqidx = 0; 667228561Snp#endif 668218792Snp for_each_port(sc, i) { 669218792Snp struct port_info *pi = sc->port[i]; 670218792Snp 671218792Snp if (pi == NULL) 672218792Snp continue; 673218792Snp 674218792Snp pi->first_rxq = rqidx; 675218792Snp pi->first_txq = tqidx; 676228561Snp if (is_10G_port(pi)) { 677228561Snp pi->nrxq = iaq.nrxq10g; 678228561Snp pi->ntxq = iaq.ntxq10g; 679228561Snp } else { 680228561Snp pi->nrxq = iaq.nrxq1g; 681228561Snp pi->ntxq = iaq.ntxq1g; 682228561Snp } 683218792Snp 684218792Snp rqidx += pi->nrxq; 685218792Snp tqidx += pi->ntxq; 686228561Snp 687237263Snp#ifdef TCP_OFFLOAD 688228561Snp if (is_offload(sc)) { 689228561Snp pi->first_ofld_rxq = ofld_rqidx; 690228561Snp pi->first_ofld_txq = ofld_tqidx; 691228561Snp if (is_10G_port(pi)) { 692228561Snp pi->nofldrxq = iaq.nofldrxq10g; 693228561Snp pi->nofldtxq = iaq.nofldtxq10g; 694228561Snp } else { 695228561Snp pi->nofldrxq = iaq.nofldrxq1g; 696228561Snp pi->nofldtxq = iaq.nofldtxq1g; 697228561Snp } 698228561Snp ofld_rqidx += pi->nofldrxq; 699228561Snp ofld_tqidx += pi->nofldtxq; 700228561Snp } 701228561Snp#endif 702218792Snp } 703218792Snp 704218792Snp rc = bus_generic_attach(dev); 705218792Snp if (rc != 0) { 706218792Snp device_printf(dev, 707218792Snp "failed to attach all child ports: %d\n", rc); 708218792Snp goto done; 709218792Snp } 710218792Snp 711218792Snp device_printf(dev, 712228561Snp "PCIe x%d, %d ports, %d %s interrupt%s, %d eq, %d iq\n", 713228561Snp sc->params.pci.width, sc->params.nports, sc->intr_count, 714228561Snp sc->intr_type == INTR_MSIX ? "MSI-X" : 715228561Snp (sc->intr_type == INTR_MSI ? "MSI" : "INTx"), 716228561Snp sc->intr_count > 1 ? "s" : "", sc->sge.neq, sc->sge.niq); 717228561Snp 718218792Snp t4_set_desc(sc); 719218792Snp 720218792Snpdone: 721228561Snp if (rc != 0 && sc->cdev) { 722228561Snp /* cdev was created and so cxgbetool works; recover that way. */ 723228561Snp device_printf(dev, 724228561Snp "error during attach, adapter is now in recovery mode.\n"); 725228561Snp rc = 0; 726228561Snp } 727228561Snp 728218792Snp if (rc != 0) 729218792Snp t4_detach(dev); 730228561Snp else 731228561Snp t4_sysctls(sc); 732218792Snp 733218792Snp return (rc); 734218792Snp} 735218792Snp 736218792Snp/* 737218792Snp * Idempotent 738218792Snp */ 739218792Snpstatic int 740218792Snpt4_detach(device_t dev) 741218792Snp{ 742218792Snp struct adapter *sc; 743218792Snp struct port_info *pi; 744228561Snp int i, rc; 745218792Snp 746218792Snp sc = device_get_softc(dev); 747218792Snp 748228561Snp if (sc->flags & FULL_INIT_DONE) 749228561Snp t4_intr_disable(sc); 750228561Snp 751228561Snp if (sc->cdev) { 752218792Snp destroy_dev(sc->cdev); 753228561Snp sc->cdev = NULL; 754228561Snp } 755218792Snp 756228561Snp rc = bus_generic_detach(dev); 757228561Snp if (rc) { 758228561Snp device_printf(dev, 759228561Snp "failed to detach child devices: %d\n", rc); 760228561Snp return (rc); 761228561Snp } 762228561Snp 763218792Snp for (i = 0; i < MAX_NPORTS; i++) { 764218792Snp pi = sc->port[i]; 765218792Snp if (pi) { 766218792Snp t4_free_vi(pi->adapter, sc->mbox, sc->pf, 0, pi->viid); 767218792Snp if (pi->dev) 768218792Snp device_delete_child(dev, pi->dev); 769218792Snp 770218792Snp mtx_destroy(&pi->pi_lock); 771218792Snp free(pi, M_CXGBE); 772218792Snp } 773218792Snp } 774218792Snp 775228561Snp if (sc->flags & FULL_INIT_DONE) 776228561Snp adapter_full_uninit(sc); 777228561Snp 778218792Snp if (sc->flags & FW_OK) 779218792Snp t4_fw_bye(sc, sc->mbox); 780218792Snp 781219944Snp if (sc->intr_type == INTR_MSI || sc->intr_type == INTR_MSIX) 782218792Snp pci_release_msi(dev); 783218792Snp 784218792Snp if (sc->regs_res) 785218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid, 786218792Snp sc->regs_res); 787218792Snp 788218792Snp if (sc->msix_res) 789218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid, 790218792Snp sc->msix_res); 791218792Snp 792222509Snp if (sc->l2t) 793222509Snp t4_free_l2t(sc->l2t); 794222509Snp 795237263Snp#ifdef TCP_OFFLOAD 796228561Snp free(sc->sge.ofld_rxq, M_CXGBE); 797228561Snp free(sc->sge.ofld_txq, M_CXGBE); 798228561Snp#endif 799218792Snp free(sc->irq, M_CXGBE); 800218792Snp free(sc->sge.rxq, M_CXGBE); 801218792Snp free(sc->sge.txq, M_CXGBE); 802220873Snp free(sc->sge.ctrlq, M_CXGBE); 803218792Snp free(sc->sge.iqmap, M_CXGBE); 804218792Snp free(sc->sge.eqmap, M_CXGBE); 805221474Snp free(sc->tids.ftid_tab, M_CXGBE); 806218792Snp t4_destroy_dma_tag(sc); 807228561Snp if (mtx_initialized(&sc->sc_lock)) { 808228561Snp mtx_lock(&t4_list_lock); 809228561Snp SLIST_REMOVE(&t4_list, sc, adapter, link); 810228561Snp mtx_unlock(&t4_list_lock); 811228561Snp mtx_destroy(&sc->sc_lock); 812228561Snp } 813218792Snp 814228561Snp if (mtx_initialized(&sc->sfl_lock)) 815228561Snp mtx_destroy(&sc->sfl_lock); 816228561Snp 817218792Snp bzero(sc, sizeof(*sc)); 818218792Snp 819218792Snp return (0); 820218792Snp} 821218792Snp 822218792Snp 823218792Snpstatic int 824218792Snpcxgbe_probe(device_t dev) 825218792Snp{ 826218792Snp char buf[128]; 827218792Snp struct port_info *pi = device_get_softc(dev); 828218792Snp 829228561Snp snprintf(buf, sizeof(buf), "port %d", pi->port_id); 830218792Snp device_set_desc_copy(dev, buf); 831218792Snp 832218792Snp return (BUS_PROBE_DEFAULT); 833218792Snp} 834218792Snp 835218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \ 836218792Snp IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \ 837237831Snp IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6) 838237819Snp#define T4_CAP_ENABLE (T4_CAP) 839218792Snp 840218792Snpstatic int 841218792Snpcxgbe_attach(device_t dev) 842218792Snp{ 843218792Snp struct port_info *pi = device_get_softc(dev); 844218792Snp struct ifnet *ifp; 845218792Snp 846218792Snp /* Allocate an ifnet and set it up */ 847218792Snp ifp = if_alloc(IFT_ETHER); 848218792Snp if (ifp == NULL) { 849218792Snp device_printf(dev, "Cannot allocate ifnet\n"); 850218792Snp return (ENOMEM); 851218792Snp } 852218792Snp pi->ifp = ifp; 853218792Snp ifp->if_softc = pi; 854218792Snp 855218792Snp callout_init(&pi->tick, CALLOUT_MPSAFE); 856218792Snp 857218792Snp if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 858218792Snp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 859218792Snp 860218792Snp ifp->if_init = cxgbe_init; 861218792Snp ifp->if_ioctl = cxgbe_ioctl; 862218792Snp ifp->if_transmit = cxgbe_transmit; 863218792Snp ifp->if_qflush = cxgbe_qflush; 864218792Snp 865218792Snp ifp->if_capabilities = T4_CAP; 866237263Snp#ifdef TCP_OFFLOAD 867228561Snp if (is_offload(pi->adapter)) 868228561Snp ifp->if_capabilities |= IFCAP_TOE4; 869228561Snp#endif 870218792Snp ifp->if_capenable = T4_CAP_ENABLE; 871237799Snp ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO | 872237799Snp CSUM_UDP_IPV6 | CSUM_TCP_IPV6; 873218792Snp 874218792Snp /* Initialize ifmedia for this port */ 875218792Snp ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change, 876218792Snp cxgbe_media_status); 877218792Snp build_medialist(pi); 878218792Snp 879237263Snp pi->vlan_c = EVENTHANDLER_REGISTER(vlan_config, cxgbe_vlan_config, ifp, 880237263Snp EVENTHANDLER_PRI_ANY); 881237263Snp 882218792Snp ether_ifattach(ifp, pi->hw_addr); 883218792Snp 884237263Snp#ifdef TCP_OFFLOAD 885228561Snp if (is_offload(pi->adapter)) { 886228561Snp device_printf(dev, 887228561Snp "%d txq, %d rxq (NIC); %d txq, %d rxq (TOE)\n", 888228561Snp pi->ntxq, pi->nrxq, pi->nofldtxq, pi->nofldrxq); 889228561Snp } else 890218792Snp#endif 891228561Snp device_printf(dev, "%d txq, %d rxq\n", pi->ntxq, pi->nrxq); 892218792Snp 893218792Snp cxgbe_sysctls(pi); 894218792Snp 895218792Snp return (0); 896218792Snp} 897218792Snp 898218792Snpstatic int 899218792Snpcxgbe_detach(device_t dev) 900218792Snp{ 901218792Snp struct port_info *pi = device_get_softc(dev); 902218792Snp struct adapter *sc = pi->adapter; 903228561Snp struct ifnet *ifp = pi->ifp; 904218792Snp 905218792Snp /* Tell if_ioctl and if_init that the port is going away */ 906218792Snp ADAPTER_LOCK(sc); 907218792Snp SET_DOOMED(pi); 908218792Snp wakeup(&sc->flags); 909218792Snp while (IS_BUSY(sc)) 910218792Snp mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0); 911218792Snp SET_BUSY(sc); 912218792Snp ADAPTER_UNLOCK(sc); 913218792Snp 914237263Snp if (pi->vlan_c) 915237263Snp EVENTHANDLER_DEREGISTER(vlan_config, pi->vlan_c); 916237263Snp 917228561Snp PORT_LOCK(pi); 918228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 919228561Snp callout_stop(&pi->tick); 920228561Snp PORT_UNLOCK(pi); 921228561Snp callout_drain(&pi->tick); 922218792Snp 923228561Snp /* Let detach proceed even if these fail. */ 924228561Snp cxgbe_uninit_synchronized(pi); 925228561Snp port_full_uninit(pi); 926219286Snp 927218792Snp ifmedia_removeall(&pi->media); 928218792Snp ether_ifdetach(pi->ifp); 929218792Snp if_free(pi->ifp); 930218792Snp 931218792Snp ADAPTER_LOCK(sc); 932218792Snp CLR_BUSY(sc); 933218792Snp wakeup_one(&sc->flags); 934218792Snp ADAPTER_UNLOCK(sc); 935218792Snp 936218792Snp return (0); 937218792Snp} 938218792Snp 939218792Snpstatic void 940218792Snpcxgbe_init(void *arg) 941218792Snp{ 942218792Snp struct port_info *pi = arg; 943218792Snp struct adapter *sc = pi->adapter; 944218792Snp 945218792Snp ADAPTER_LOCK(sc); 946218792Snp cxgbe_init_locked(pi); /* releases adapter lock */ 947218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 948218792Snp} 949218792Snp 950218792Snpstatic int 951218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) 952218792Snp{ 953218792Snp int rc = 0, mtu, flags; 954218792Snp struct port_info *pi = ifp->if_softc; 955218792Snp struct adapter *sc = pi->adapter; 956218792Snp struct ifreq *ifr = (struct ifreq *)data; 957218792Snp uint32_t mask; 958218792Snp 959218792Snp switch (cmd) { 960218792Snp case SIOCSIFMTU: 961218792Snp ADAPTER_LOCK(sc); 962218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 963218792Snp if (rc) { 964218792Snpfail: 965218792Snp ADAPTER_UNLOCK(sc); 966218792Snp return (rc); 967218792Snp } 968218792Snp 969218792Snp mtu = ifr->ifr_mtu; 970218792Snp if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) { 971218792Snp rc = EINVAL; 972218792Snp } else { 973218792Snp ifp->if_mtu = mtu; 974218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 975218792Snp t4_update_fl_bufsize(ifp); 976218792Snp PORT_LOCK(pi); 977218792Snp rc = update_mac_settings(pi, XGMAC_MTU); 978218792Snp PORT_UNLOCK(pi); 979218792Snp } 980218792Snp } 981218792Snp ADAPTER_UNLOCK(sc); 982218792Snp break; 983218792Snp 984218792Snp case SIOCSIFFLAGS: 985218792Snp ADAPTER_LOCK(sc); 986218792Snp if (IS_DOOMED(pi)) { 987218792Snp rc = ENXIO; 988218792Snp goto fail; 989218792Snp } 990218792Snp if (ifp->if_flags & IFF_UP) { 991218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 992218792Snp flags = pi->if_flags; 993218792Snp if ((ifp->if_flags ^ flags) & 994218792Snp (IFF_PROMISC | IFF_ALLMULTI)) { 995218792Snp if (IS_BUSY(sc)) { 996218792Snp rc = EBUSY; 997218792Snp goto fail; 998218792Snp } 999218792Snp PORT_LOCK(pi); 1000218792Snp rc = update_mac_settings(pi, 1001218792Snp XGMAC_PROMISC | XGMAC_ALLMULTI); 1002218792Snp PORT_UNLOCK(pi); 1003218792Snp } 1004218792Snp ADAPTER_UNLOCK(sc); 1005218792Snp } else 1006218792Snp rc = cxgbe_init_locked(pi); 1007218792Snp pi->if_flags = ifp->if_flags; 1008218792Snp } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1009218792Snp rc = cxgbe_uninit_locked(pi); 1010218792Snp else 1011218792Snp ADAPTER_UNLOCK(sc); 1012218792Snp 1013218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 1014218792Snp break; 1015218792Snp 1016218792Snp case SIOCADDMULTI: 1017218792Snp case SIOCDELMULTI: /* these two can be called with a mutex held :-( */ 1018218792Snp ADAPTER_LOCK(sc); 1019218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 1020218792Snp if (rc) 1021218792Snp goto fail; 1022218792Snp 1023218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1024218792Snp PORT_LOCK(pi); 1025218792Snp rc = update_mac_settings(pi, XGMAC_MCADDRS); 1026218792Snp PORT_UNLOCK(pi); 1027218792Snp } 1028218792Snp ADAPTER_UNLOCK(sc); 1029218792Snp break; 1030218792Snp 1031218792Snp case SIOCSIFCAP: 1032218792Snp ADAPTER_LOCK(sc); 1033218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 1034218792Snp if (rc) 1035218792Snp goto fail; 1036218792Snp 1037218792Snp mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1038218792Snp if (mask & IFCAP_TXCSUM) { 1039218792Snp ifp->if_capenable ^= IFCAP_TXCSUM; 1040218792Snp ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 1041218792Snp 1042237831Snp if (IFCAP_TSO4 & ifp->if_capenable && 1043218792Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1044237799Snp ifp->if_capenable &= ~IFCAP_TSO4; 1045218792Snp if_printf(ifp, 1046237831Snp "tso4 disabled due to -txcsum.\n"); 1047218792Snp } 1048218792Snp } 1049237799Snp if (mask & IFCAP_TXCSUM_IPV6) { 1050237799Snp ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 1051237799Snp ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); 1052237799Snp 1053237799Snp if (IFCAP_TSO6 & ifp->if_capenable && 1054237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1055237799Snp ifp->if_capenable &= ~IFCAP_TSO6; 1056237799Snp if_printf(ifp, 1057237799Snp "tso6 disabled due to -txcsum6.\n"); 1058237799Snp } 1059237799Snp } 1060218792Snp if (mask & IFCAP_RXCSUM) 1061218792Snp ifp->if_capenable ^= IFCAP_RXCSUM; 1062237799Snp if (mask & IFCAP_RXCSUM_IPV6) 1063237799Snp ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 1064237799Snp 1065237799Snp /* 1066237799Snp * Note that we leave CSUM_TSO alone (it is always set). The 1067237799Snp * kernel takes both IFCAP_TSOx and CSUM_TSO into account before 1068237799Snp * sending a TSO request our way, so it's sufficient to toggle 1069237799Snp * IFCAP_TSOx only. 1070237799Snp */ 1071218792Snp if (mask & IFCAP_TSO4) { 1072237799Snp if (!(IFCAP_TSO4 & ifp->if_capenable) && 1073237799Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1074237799Snp if_printf(ifp, "enable txcsum first.\n"); 1075237799Snp rc = EAGAIN; 1076237799Snp goto fail; 1077237799Snp } 1078218792Snp ifp->if_capenable ^= IFCAP_TSO4; 1079218792Snp } 1080237799Snp if (mask & IFCAP_TSO6) { 1081237799Snp if (!(IFCAP_TSO6 & ifp->if_capenable) && 1082237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1083237799Snp if_printf(ifp, "enable txcsum6 first.\n"); 1084237799Snp rc = EAGAIN; 1085237799Snp goto fail; 1086237799Snp } 1087237799Snp ifp->if_capenable ^= IFCAP_TSO6; 1088237799Snp } 1089218792Snp if (mask & IFCAP_LRO) { 1090237819Snp#if defined(INET) || defined(INET6) 1091218792Snp int i; 1092218792Snp struct sge_rxq *rxq; 1093218792Snp 1094218792Snp ifp->if_capenable ^= IFCAP_LRO; 1095218792Snp for_each_rxq(pi, i, rxq) { 1096218792Snp if (ifp->if_capenable & IFCAP_LRO) 1097228561Snp rxq->iq.flags |= IQ_LRO_ENABLED; 1098218792Snp else 1099228561Snp rxq->iq.flags &= ~IQ_LRO_ENABLED; 1100218792Snp } 1101218792Snp#endif 1102218792Snp } 1103237263Snp#ifdef TCP_OFFLOAD 1104228561Snp if (mask & IFCAP_TOE) { 1105228561Snp int enable = (ifp->if_capenable ^ mask) & IFCAP_TOE; 1106228561Snp 1107228561Snp rc = toe_capability(pi, enable); 1108228561Snp if (rc != 0) 1109228561Snp goto fail; 1110228561Snp 1111228561Snp ifp->if_capenable ^= mask; 1112218792Snp } 1113218792Snp#endif 1114218792Snp if (mask & IFCAP_VLAN_HWTAGGING) { 1115218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1116218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1117218792Snp PORT_LOCK(pi); 1118218792Snp rc = update_mac_settings(pi, XGMAC_VLANEX); 1119218792Snp PORT_UNLOCK(pi); 1120218792Snp } 1121218792Snp } 1122218792Snp if (mask & IFCAP_VLAN_MTU) { 1123218792Snp ifp->if_capenable ^= IFCAP_VLAN_MTU; 1124218792Snp 1125218792Snp /* Need to find out how to disable auto-mtu-inflation */ 1126218792Snp } 1127218792Snp if (mask & IFCAP_VLAN_HWTSO) 1128218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1129218792Snp if (mask & IFCAP_VLAN_HWCSUM) 1130218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 1131218792Snp 1132218792Snp#ifdef VLAN_CAPABILITIES 1133218792Snp VLAN_CAPABILITIES(ifp); 1134218792Snp#endif 1135218792Snp ADAPTER_UNLOCK(sc); 1136218792Snp break; 1137218792Snp 1138218792Snp case SIOCSIFMEDIA: 1139218792Snp case SIOCGIFMEDIA: 1140218792Snp ifmedia_ioctl(ifp, ifr, &pi->media, cmd); 1141218792Snp break; 1142218792Snp 1143218792Snp default: 1144218792Snp rc = ether_ioctl(ifp, cmd, data); 1145218792Snp } 1146218792Snp 1147218792Snp return (rc); 1148218792Snp} 1149218792Snp 1150218792Snpstatic int 1151218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m) 1152218792Snp{ 1153218792Snp struct port_info *pi = ifp->if_softc; 1154218792Snp struct adapter *sc = pi->adapter; 1155218792Snp struct sge_txq *txq = &sc->sge.txq[pi->first_txq]; 1156218792Snp struct buf_ring *br; 1157218792Snp int rc; 1158218792Snp 1159218792Snp M_ASSERTPKTHDR(m); 1160218792Snp 1161228561Snp if (__predict_false(pi->link_cfg.link_ok == 0)) { 1162218792Snp m_freem(m); 1163228561Snp return (ENETDOWN); 1164218792Snp } 1165218792Snp 1166218792Snp if (m->m_flags & M_FLOWID) 1167218792Snp txq += (m->m_pkthdr.flowid % pi->ntxq); 1168220873Snp br = txq->br; 1169218792Snp 1170218792Snp if (TXQ_TRYLOCK(txq) == 0) { 1171228561Snp struct sge_eq *eq = &txq->eq; 1172228561Snp 1173218792Snp /* 1174228561Snp * It is possible that t4_eth_tx finishes up and releases the 1175228561Snp * lock between the TRYLOCK above and the drbr_enqueue here. We 1176228561Snp * need to make sure that this mbuf doesn't just sit there in 1177228561Snp * the drbr. 1178218792Snp */ 1179218792Snp 1180228561Snp rc = drbr_enqueue(ifp, br, m); 1181228561Snp if (rc == 0 && callout_pending(&eq->tx_callout) == 0 && 1182228561Snp !(eq->flags & EQ_DOOMED)) 1183228561Snp callout_reset(&eq->tx_callout, 1, t4_tx_callout, eq); 1184228561Snp return (rc); 1185218792Snp } 1186218792Snp 1187218792Snp /* 1188218792Snp * txq->m is the mbuf that is held up due to a temporary shortage of 1189218792Snp * resources and it should be put on the wire first. Then what's in 1190218792Snp * drbr and finally the mbuf that was just passed in to us. 1191218792Snp * 1192218792Snp * Return code should indicate the fate of the mbuf that was passed in 1193218792Snp * this time. 1194218792Snp */ 1195218792Snp 1196218792Snp TXQ_LOCK_ASSERT_OWNED(txq); 1197218792Snp if (drbr_needs_enqueue(ifp, br) || txq->m) { 1198218792Snp 1199218792Snp /* Queued for transmission. */ 1200218792Snp 1201218792Snp rc = drbr_enqueue(ifp, br, m); 1202218792Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 1203218792Snp (void) t4_eth_tx(ifp, txq, m); 1204218792Snp TXQ_UNLOCK(txq); 1205218792Snp return (rc); 1206218792Snp } 1207218792Snp 1208218792Snp /* Direct transmission. */ 1209218792Snp rc = t4_eth_tx(ifp, txq, m); 1210218792Snp if (rc != 0 && txq->m) 1211218792Snp rc = 0; /* held, will be transmitted soon (hopefully) */ 1212218792Snp 1213218792Snp TXQ_UNLOCK(txq); 1214218792Snp return (rc); 1215218792Snp} 1216218792Snp 1217218792Snpstatic void 1218218792Snpcxgbe_qflush(struct ifnet *ifp) 1219218792Snp{ 1220218792Snp struct port_info *pi = ifp->if_softc; 1221220649Snp struct sge_txq *txq; 1222220649Snp int i; 1223220649Snp struct mbuf *m; 1224218792Snp 1225228561Snp /* queues do not exist if !PORT_INIT_DONE. */ 1226228561Snp if (pi->flags & PORT_INIT_DONE) { 1227220649Snp for_each_txq(pi, i, txq) { 1228220649Snp TXQ_LOCK(txq); 1229220649Snp m_freem(txq->m); 1230228561Snp txq->m = NULL; 1231220873Snp while ((m = buf_ring_dequeue_sc(txq->br)) != NULL) 1232220649Snp m_freem(m); 1233220649Snp TXQ_UNLOCK(txq); 1234220649Snp } 1235220649Snp } 1236220649Snp if_qflush(ifp); 1237218792Snp} 1238218792Snp 1239218792Snpstatic int 1240218792Snpcxgbe_media_change(struct ifnet *ifp) 1241218792Snp{ 1242218792Snp struct port_info *pi = ifp->if_softc; 1243218792Snp 1244218792Snp device_printf(pi->dev, "%s unimplemented.\n", __func__); 1245218792Snp 1246218792Snp return (EOPNOTSUPP); 1247218792Snp} 1248218792Snp 1249218792Snpstatic void 1250218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1251218792Snp{ 1252218792Snp struct port_info *pi = ifp->if_softc; 1253218792Snp struct ifmedia_entry *cur = pi->media.ifm_cur; 1254218792Snp int speed = pi->link_cfg.speed; 1255218792Snp int data = (pi->port_type << 8) | pi->mod_type; 1256218792Snp 1257218792Snp if (cur->ifm_data != data) { 1258218792Snp build_medialist(pi); 1259218792Snp cur = pi->media.ifm_cur; 1260218792Snp } 1261218792Snp 1262218792Snp ifmr->ifm_status = IFM_AVALID; 1263218792Snp if (!pi->link_cfg.link_ok) 1264218792Snp return; 1265218792Snp 1266218792Snp ifmr->ifm_status |= IFM_ACTIVE; 1267218792Snp 1268218792Snp /* active and current will differ iff current media is autoselect. */ 1269218792Snp if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO) 1270218792Snp return; 1271218792Snp 1272218792Snp ifmr->ifm_active = IFM_ETHER | IFM_FDX; 1273218792Snp if (speed == SPEED_10000) 1274218792Snp ifmr->ifm_active |= IFM_10G_T; 1275218792Snp else if (speed == SPEED_1000) 1276218792Snp ifmr->ifm_active |= IFM_1000_T; 1277218792Snp else if (speed == SPEED_100) 1278218792Snp ifmr->ifm_active |= IFM_100_TX; 1279218792Snp else if (speed == SPEED_10) 1280218792Snp ifmr->ifm_active |= IFM_10_T; 1281218792Snp else 1282218792Snp KASSERT(0, ("%s: link up but speed unknown (%u)", __func__, 1283218792Snp speed)); 1284218792Snp} 1285218792Snp 1286218792Snpvoid 1287218792Snpt4_fatal_err(struct adapter *sc) 1288218792Snp{ 1289218792Snp t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0); 1290218792Snp t4_intr_disable(sc); 1291218792Snp log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n", 1292218792Snp device_get_nameunit(sc->dev)); 1293218792Snp} 1294218792Snp 1295218792Snpstatic int 1296218792Snpmap_bars(struct adapter *sc) 1297218792Snp{ 1298218792Snp sc->regs_rid = PCIR_BAR(0); 1299218792Snp sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1300218792Snp &sc->regs_rid, RF_ACTIVE); 1301218792Snp if (sc->regs_res == NULL) { 1302218792Snp device_printf(sc->dev, "cannot map registers.\n"); 1303218792Snp return (ENXIO); 1304218792Snp } 1305218792Snp sc->bt = rman_get_bustag(sc->regs_res); 1306218792Snp sc->bh = rman_get_bushandle(sc->regs_res); 1307218792Snp sc->mmio_len = rman_get_size(sc->regs_res); 1308218792Snp 1309218792Snp sc->msix_rid = PCIR_BAR(4); 1310218792Snp sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1311218792Snp &sc->msix_rid, RF_ACTIVE); 1312218792Snp if (sc->msix_res == NULL) { 1313218792Snp device_printf(sc->dev, "cannot map MSI-X BAR.\n"); 1314218792Snp return (ENXIO); 1315218792Snp } 1316218792Snp 1317218792Snp return (0); 1318218792Snp} 1319218792Snp 1320218792Snpstatic void 1321218792Snpsetup_memwin(struct adapter *sc) 1322218792Snp{ 1323237587Snp uint32_t bar0; 1324218792Snp 1325237587Snp /* 1326237587Snp * Read low 32b of bar0 indirectly via the hardware backdoor mechanism. 1327237587Snp * Works from within PCI passthrough environments too, where 1328237587Snp * rman_get_start() can return a different value. We need to program 1329237587Snp * the memory window decoders with the actual addresses that will be 1330237587Snp * coming across the PCIe link. 1331237587Snp */ 1332237587Snp bar0 = t4_hw_pci_read_cfg4(sc, PCIR_BAR(0)); 1333237587Snp bar0 &= (uint32_t) PCIM_BAR_MEM_BASE; 1334218792Snp 1335218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 0), 1336218792Snp (bar0 + MEMWIN0_BASE) | V_BIR(0) | 1337218792Snp V_WINDOW(ilog2(MEMWIN0_APERTURE) - 10)); 1338218792Snp 1339218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 1), 1340218792Snp (bar0 + MEMWIN1_BASE) | V_BIR(0) | 1341218792Snp V_WINDOW(ilog2(MEMWIN1_APERTURE) - 10)); 1342218792Snp 1343218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2), 1344218792Snp (bar0 + MEMWIN2_BASE) | V_BIR(0) | 1345218792Snp V_WINDOW(ilog2(MEMWIN2_APERTURE) - 10)); 1346237587Snp 1347237587Snp /* flush */ 1348237587Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2)); 1349218792Snp} 1350218792Snp 1351218792Snpstatic int 1352218792Snpcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g, 1353218792Snp struct intrs_and_queues *iaq) 1354218792Snp{ 1355228561Snp int rc, itype, navail, nrxq10g, nrxq1g, n; 1356228561Snp int nofldrxq10g = 0, nofldrxq1g = 0; 1357218792Snp 1358218792Snp bzero(iaq, sizeof(*iaq)); 1359218792Snp 1360228561Snp iaq->ntxq10g = t4_ntxq10g; 1361228561Snp iaq->ntxq1g = t4_ntxq1g; 1362228561Snp iaq->nrxq10g = nrxq10g = t4_nrxq10g; 1363228561Snp iaq->nrxq1g = nrxq1g = t4_nrxq1g; 1364237263Snp#ifdef TCP_OFFLOAD 1365237463Snp if (is_offload(sc)) { 1366237463Snp iaq->nofldtxq10g = t4_nofldtxq10g; 1367237463Snp iaq->nofldtxq1g = t4_nofldtxq1g; 1368237463Snp iaq->nofldrxq10g = nofldrxq10g = t4_nofldrxq10g; 1369237463Snp iaq->nofldrxq1g = nofldrxq1g = t4_nofldrxq1g; 1370237463Snp } 1371228561Snp#endif 1372228561Snp 1373219944Snp for (itype = INTR_MSIX; itype; itype >>= 1) { 1374218792Snp 1375228561Snp if ((itype & t4_intr_types) == 0) 1376218792Snp continue; /* not allowed */ 1377218792Snp 1378219944Snp if (itype == INTR_MSIX) 1379218792Snp navail = pci_msix_count(sc->dev); 1380219944Snp else if (itype == INTR_MSI) 1381218792Snp navail = pci_msi_count(sc->dev); 1382218792Snp else 1383218792Snp navail = 1; 1384228561Snprestart: 1385218792Snp if (navail == 0) 1386218792Snp continue; 1387218792Snp 1388218792Snp iaq->intr_type = itype; 1389228561Snp iaq->intr_flags = 0; 1390218792Snp 1391228561Snp /* 1392228561Snp * Best option: an interrupt vector for errors, one for the 1393228561Snp * firmware event queue, and one each for each rxq (NIC as well 1394228561Snp * as offload). 1395228561Snp */ 1396228561Snp iaq->nirq = T4_EXTRA_INTR; 1397228561Snp iaq->nirq += n10g * (nrxq10g + nofldrxq10g); 1398228561Snp iaq->nirq += n1g * (nrxq1g + nofldrxq1g); 1399228561Snp if (iaq->nirq <= navail && 1400228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) { 1401228561Snp iaq->intr_flags |= INTR_DIRECT; 1402228561Snp goto allocate; 1403228561Snp } 1404218792Snp 1405228561Snp /* 1406228561Snp * Second best option: an interrupt vector for errors, one for 1407228561Snp * the firmware event queue, and one each for either NIC or 1408228561Snp * offload rxq's. 1409228561Snp */ 1410228561Snp iaq->nirq = T4_EXTRA_INTR; 1411228561Snp iaq->nirq += n10g * max(nrxq10g, nofldrxq10g); 1412228561Snp iaq->nirq += n1g * max(nrxq1g, nofldrxq1g); 1413228561Snp if (iaq->nirq <= navail && 1414228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) 1415228561Snp goto allocate; 1416218792Snp 1417228561Snp /* 1418228561Snp * Next best option: an interrupt vector for errors, one for the 1419228561Snp * firmware event queue, and at least one per port. At this 1420228561Snp * point we know we'll have to downsize nrxq or nofldrxq to fit 1421228561Snp * what's available to us. 1422228561Snp */ 1423228561Snp iaq->nirq = T4_EXTRA_INTR; 1424228561Snp iaq->nirq += n10g + n1g; 1425228561Snp if (iaq->nirq <= navail) { 1426228561Snp int leftover = navail - iaq->nirq; 1427218792Snp 1428228561Snp if (n10g > 0) { 1429228561Snp int target = max(nrxq10g, nofldrxq10g); 1430219944Snp 1431228561Snp n = 1; 1432228561Snp while (n < target && leftover >= n10g) { 1433228561Snp leftover -= n10g; 1434228561Snp iaq->nirq += n10g; 1435228561Snp n++; 1436228561Snp } 1437228561Snp iaq->nrxq10g = min(n, nrxq10g); 1438237263Snp#ifdef TCP_OFFLOAD 1439237463Snp if (is_offload(sc)) 1440237463Snp iaq->nofldrxq10g = min(n, nofldrxq10g); 1441228561Snp#endif 1442228561Snp } 1443218792Snp 1444228561Snp if (n1g > 0) { 1445228561Snp int target = max(nrxq1g, nofldrxq1g); 1446219944Snp 1447228561Snp n = 1; 1448228561Snp while (n < target && leftover >= n1g) { 1449228561Snp leftover -= n1g; 1450228561Snp iaq->nirq += n1g; 1451228561Snp n++; 1452219944Snp } 1453228561Snp iaq->nrxq1g = min(n, nrxq1g); 1454237263Snp#ifdef TCP_OFFLOAD 1455237463Snp if (is_offload(sc)) 1456237463Snp iaq->nofldrxq1g = min(n, nofldrxq1g); 1457228561Snp#endif 1458219944Snp } 1459219944Snp 1460228561Snp if (itype != INTR_MSI || powerof2(iaq->nirq)) 1461228561Snp goto allocate; 1462218792Snp } 1463218792Snp 1464228561Snp /* 1465228561Snp * Least desirable option: one interrupt vector for everything. 1466228561Snp */ 1467228561Snp iaq->nirq = iaq->nrxq10g = iaq->nrxq1g = 1; 1468237263Snp#ifdef TCP_OFFLOAD 1469237463Snp if (is_offload(sc)) 1470237463Snp iaq->nofldrxq10g = iaq->nofldrxq1g = 1; 1471228561Snp#endif 1472228561Snp 1473228561Snpallocate: 1474218792Snp navail = iaq->nirq; 1475218792Snp rc = 0; 1476219944Snp if (itype == INTR_MSIX) 1477218792Snp rc = pci_alloc_msix(sc->dev, &navail); 1478219944Snp else if (itype == INTR_MSI) 1479218792Snp rc = pci_alloc_msi(sc->dev, &navail); 1480218792Snp 1481218792Snp if (rc == 0) { 1482218792Snp if (navail == iaq->nirq) 1483218792Snp return (0); 1484218792Snp 1485218792Snp /* 1486218792Snp * Didn't get the number requested. Use whatever number 1487218792Snp * the kernel is willing to allocate (it's in navail). 1488218792Snp */ 1489228561Snp device_printf(sc->dev, "fewer vectors than requested, " 1490228561Snp "type=%d, req=%d, rcvd=%d; will downshift req.\n", 1491228561Snp itype, iaq->nirq, navail); 1492218792Snp pci_release_msi(sc->dev); 1493228561Snp goto restart; 1494218792Snp } 1495218792Snp 1496218792Snp device_printf(sc->dev, 1497218792Snp "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n", 1498218792Snp itype, rc, iaq->nirq, navail); 1499218792Snp } 1500218792Snp 1501218792Snp device_printf(sc->dev, 1502218792Snp "failed to find a usable interrupt type. " 1503228561Snp "allowed=%d, msi-x=%d, msi=%d, intx=1", t4_intr_types, 1504218792Snp pci_msix_count(sc->dev), pci_msi_count(sc->dev)); 1505218792Snp 1506218792Snp return (ENXIO); 1507218792Snp} 1508218792Snp 1509218792Snp/* 1510228561Snp * Install a compatible firmware (if required), establish contact with it (by 1511228561Snp * saying hello), and reset the device. If we end up as the master driver, 1512228561Snp * partition adapter resources by providing a configuration file to the 1513228561Snp * firmware. 1514218792Snp */ 1515218792Snpstatic int 1516218792Snpprep_firmware(struct adapter *sc) 1517218792Snp{ 1518228561Snp const struct firmware *fw = NULL, *cfg = NULL, *default_cfg; 1519218792Snp int rc; 1520218792Snp enum dev_state state; 1521218792Snp 1522228561Snp default_cfg = firmware_get(T4_CFGNAME); 1523228561Snp 1524218792Snp /* Check firmware version and install a different one if necessary */ 1525218792Snp rc = t4_check_fw_version(sc); 1526234831Snp snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u", 1527234831Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1528234831Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1529234831Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1530234831Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 1531228561Snp if (rc != 0) { 1532219287Snp uint32_t v = 0; 1533218792Snp 1534218792Snp fw = firmware_get(T4_FWNAME); 1535219287Snp if (fw != NULL) { 1536219287Snp const struct fw_hdr *hdr = (const void *)fw->data; 1537219287Snp 1538219287Snp v = ntohl(hdr->fw_ver); 1539219287Snp 1540219287Snp /* 1541219287Snp * The firmware module will not be used if it isn't the 1542219287Snp * same major version as what the driver was compiled 1543228561Snp * with. 1544219287Snp */ 1545219287Snp if (G_FW_HDR_FW_VER_MAJOR(v) != FW_VERSION_MAJOR) { 1546219287Snp device_printf(sc->dev, 1547219287Snp "Found firmware image but version %d " 1548219287Snp "can not be used with this driver (%d)\n", 1549219287Snp G_FW_HDR_FW_VER_MAJOR(v), FW_VERSION_MAJOR); 1550219287Snp 1551219287Snp firmware_put(fw, FIRMWARE_UNLOAD); 1552219287Snp fw = NULL; 1553219287Snp } 1554218792Snp } 1555218792Snp 1556228561Snp if (fw == NULL && rc < 0) { 1557219287Snp device_printf(sc->dev, "No usable firmware. " 1558228561Snp "card has %d.%d.%d, driver compiled with %d.%d.%d", 1559219287Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1560219287Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1561219287Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1562219287Snp FW_VERSION_MAJOR, FW_VERSION_MINOR, 1563228561Snp FW_VERSION_MICRO); 1564228561Snp rc = EAGAIN; 1565228561Snp goto done; 1566219287Snp } 1567219287Snp 1568219287Snp /* 1569219287Snp * Always upgrade, even for minor/micro/build mismatches. 1570219287Snp * Downgrade only for a major version mismatch or if 1571219287Snp * force_firmware_install was specified. 1572219287Snp */ 1573228561Snp if (fw != NULL && (rc < 0 || v > sc->params.fw_vers)) { 1574218792Snp device_printf(sc->dev, 1575219287Snp "installing firmware %d.%d.%d.%d on card.\n", 1576219287Snp G_FW_HDR_FW_VER_MAJOR(v), G_FW_HDR_FW_VER_MINOR(v), 1577219287Snp G_FW_HDR_FW_VER_MICRO(v), G_FW_HDR_FW_VER_BUILD(v)); 1578219287Snp 1579219287Snp rc = -t4_load_fw(sc, fw->data, fw->datasize); 1580219287Snp if (rc != 0) { 1581219287Snp device_printf(sc->dev, 1582219287Snp "failed to install firmware: %d\n", rc); 1583228561Snp goto done; 1584219287Snp } else { 1585219287Snp /* refresh */ 1586219287Snp (void) t4_check_fw_version(sc); 1587234831Snp snprintf(sc->fw_version, 1588234831Snp sizeof(sc->fw_version), "%u.%u.%u.%u", 1589234831Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1590234831Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1591234831Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1592234831Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 1593219287Snp } 1594218792Snp } 1595218792Snp } 1596218792Snp 1597228561Snp /* Contact firmware. */ 1598228561Snp rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state); 1599218792Snp if (rc < 0) { 1600218792Snp rc = -rc; 1601218792Snp device_printf(sc->dev, 1602218792Snp "failed to connect to the firmware: %d.\n", rc); 1603228561Snp goto done; 1604218792Snp } 1605228561Snp if (rc == sc->mbox) 1606228561Snp sc->flags |= MASTER_PF; 1607218792Snp 1608218792Snp /* Reset device */ 1609218792Snp rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST); 1610218792Snp if (rc != 0) { 1611218792Snp device_printf(sc->dev, "firmware reset failed: %d.\n", rc); 1612218792Snp if (rc != ETIMEDOUT && rc != EIO) 1613218792Snp t4_fw_bye(sc, sc->mbox); 1614228561Snp goto done; 1615218792Snp } 1616218792Snp 1617228561Snp /* Partition adapter resources as specified in the config file. */ 1618228561Snp if (sc->flags & MASTER_PF) { 1619228561Snp if (strncmp(t4_cfg_file, "default", sizeof(t4_cfg_file))) { 1620228561Snp char s[32]; 1621228561Snp 1622228561Snp snprintf(s, sizeof(s), "t4fw_cfg_%s", t4_cfg_file); 1623228561Snp cfg = firmware_get(s); 1624228561Snp if (cfg == NULL) { 1625228561Snp device_printf(sc->dev, 1626228561Snp "unable to locate %s module, " 1627228561Snp "will use default config file.\n", s); 1628228561Snp } 1629228561Snp } 1630228561Snp 1631228561Snp rc = partition_resources(sc, cfg ? cfg : default_cfg); 1632228561Snp if (rc != 0) 1633228561Snp goto done; /* error message displayed already */ 1634228561Snp } 1635228561Snp 1636218792Snp sc->flags |= FW_OK; 1637218792Snp 1638228561Snpdone: 1639228561Snp if (fw != NULL) 1640228561Snp firmware_put(fw, FIRMWARE_UNLOAD); 1641228561Snp if (cfg != NULL) 1642228561Snp firmware_put(cfg, FIRMWARE_UNLOAD); 1643228561Snp if (default_cfg != NULL) 1644228561Snp firmware_put(default_cfg, FIRMWARE_UNLOAD); 1645228561Snp 1646228561Snp return (rc); 1647218792Snp} 1648218792Snp 1649228561Snp#define FW_PARAM_DEV(param) \ 1650228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ 1651228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) 1652228561Snp#define FW_PARAM_PFVF(param) \ 1653228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ 1654228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)) 1655228561Snp 1656228561Snp/* 1657228561Snp * Upload configuration file to card's memory. 1658228561Snp */ 1659218792Snpstatic int 1660228561Snpupload_config_file(struct adapter *sc, const struct firmware *fw, uint32_t *mt, 1661228561Snp uint32_t *ma) 1662222551Snp{ 1663228561Snp int rc, i; 1664228561Snp uint32_t param, val, mtype, maddr, bar, off, win, remaining; 1665228561Snp const uint32_t *b; 1666222551Snp 1667228561Snp /* Figure out where the firmware wants us to upload it. */ 1668228561Snp param = FW_PARAM_DEV(CF); 1669228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 1670222551Snp if (rc != 0) { 1671228561Snp /* Firmwares without config file support will fail this way */ 1672222551Snp device_printf(sc->dev, 1673228561Snp "failed to query config file location: %d.\n", rc); 1674222551Snp return (rc); 1675222551Snp } 1676228561Snp *mt = mtype = G_FW_PARAMS_PARAM_Y(val); 1677228561Snp *ma = maddr = G_FW_PARAMS_PARAM_Z(val) << 16; 1678222551Snp 1679228561Snp if (maddr & 3) { 1680228561Snp device_printf(sc->dev, 1681228561Snp "cannot upload config file (type %u, addr %x).\n", 1682228561Snp mtype, maddr); 1683228561Snp return (EFAULT); 1684228561Snp } 1685222551Snp 1686228561Snp /* Translate mtype/maddr to an address suitable for the PCIe window */ 1687228561Snp val = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 1688228561Snp val &= F_EDRAM0_ENABLE | F_EDRAM1_ENABLE | F_EXT_MEM_ENABLE; 1689228561Snp switch (mtype) { 1690228561Snp case FW_MEMTYPE_CF_EDC0: 1691228561Snp if (!(val & F_EDRAM0_ENABLE)) 1692228561Snp goto err; 1693228561Snp bar = t4_read_reg(sc, A_MA_EDRAM0_BAR); 1694228561Snp maddr += G_EDRAM0_BASE(bar) << 20; 1695228561Snp break; 1696228561Snp 1697228561Snp case FW_MEMTYPE_CF_EDC1: 1698228561Snp if (!(val & F_EDRAM1_ENABLE)) 1699228561Snp goto err; 1700228561Snp bar = t4_read_reg(sc, A_MA_EDRAM1_BAR); 1701228561Snp maddr += G_EDRAM1_BASE(bar) << 20; 1702228561Snp break; 1703228561Snp 1704228561Snp case FW_MEMTYPE_CF_EXTMEM: 1705228561Snp if (!(val & F_EXT_MEM_ENABLE)) 1706228561Snp goto err; 1707228561Snp bar = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 1708228561Snp maddr += G_EXT_MEM_BASE(bar) << 20; 1709228561Snp break; 1710228561Snp 1711228561Snp default: 1712228561Snperr: 1713228561Snp device_printf(sc->dev, 1714228561Snp "cannot upload config file (type %u, enabled %u).\n", 1715228561Snp mtype, val); 1716228561Snp return (EFAULT); 1717228561Snp } 1718228561Snp 1719228561Snp /* 1720228561Snp * Position the PCIe window (we use memwin2) to the 16B aligned area 1721228561Snp * just at/before the upload location. 1722228561Snp */ 1723228561Snp win = maddr & ~0xf; 1724228561Snp off = maddr - win; /* offset from the start of the window. */ 1725228561Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2), win); 1726228561Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2)); 1727228561Snp 1728228561Snp remaining = fw->datasize; 1729228561Snp if (remaining > FLASH_CFG_MAX_SIZE || 1730228561Snp remaining > MEMWIN2_APERTURE - off) { 1731228561Snp device_printf(sc->dev, "cannot upload config file all at once " 1732228561Snp "(size %u, max %u, room %u).\n", 1733228561Snp remaining, FLASH_CFG_MAX_SIZE, MEMWIN2_APERTURE - off); 1734228561Snp return (EFBIG); 1735228561Snp } 1736228561Snp 1737228561Snp /* 1738228561Snp * XXX: sheer laziness. We deliberately added 4 bytes of useless 1739228561Snp * stuffing/comments at the end of the config file so it's ok to simply 1740228561Snp * throw away the last remaining bytes when the config file is not an 1741228561Snp * exact multiple of 4. 1742228561Snp */ 1743228561Snp b = fw->data; 1744228561Snp for (i = 0; remaining >= 4; i += 4, remaining -= 4) 1745228561Snp t4_write_reg(sc, MEMWIN2_BASE + off + i, *b++); 1746228561Snp 1747228561Snp return (rc); 1748222551Snp} 1749222551Snp 1750228561Snp/* 1751228561Snp * Partition chip resources for use between various PFs, VFs, etc. This is done 1752228561Snp * by uploading the firmware configuration file to the adapter and instructing 1753228561Snp * the firmware to process it. 1754228561Snp */ 1755222551Snpstatic int 1756228561Snppartition_resources(struct adapter *sc, const struct firmware *cfg) 1757218792Snp{ 1758218792Snp int rc; 1759228561Snp struct fw_caps_config_cmd caps; 1760228561Snp uint32_t mtype, maddr, finicsum, cfcsum; 1761218792Snp 1762228561Snp rc = cfg ? upload_config_file(sc, cfg, &mtype, &maddr) : ENOENT; 1763228561Snp if (rc != 0) { 1764228561Snp mtype = FW_MEMTYPE_CF_FLASH; 1765228561Snp maddr = t4_flash_cfg_addr(sc); 1766228561Snp } 1767228561Snp 1768228561Snp bzero(&caps, sizeof(caps)); 1769228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1770218792Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1771228561Snp caps.cfvalid_to_len16 = htobe32(F_FW_CAPS_CONFIG_CMD_CFVALID | 1772228561Snp V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) | 1773228561Snp V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(maddr >> 16) | FW_LEN16(caps)); 1774228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 1775228561Snp if (rc != 0) { 1776228561Snp device_printf(sc->dev, 1777228561Snp "failed to pre-process config file: %d.\n", rc); 1778218792Snp return (rc); 1779228561Snp } 1780218792Snp 1781228561Snp finicsum = be32toh(caps.finicsum); 1782228561Snp cfcsum = be32toh(caps.cfcsum); 1783228561Snp if (finicsum != cfcsum) { 1784228561Snp device_printf(sc->dev, 1785228561Snp "WARNING: config file checksum mismatch: %08x %08x\n", 1786228561Snp finicsum, cfcsum); 1787228561Snp } 1788228561Snp sc->cfcsum = cfcsum; 1789218792Snp 1790228561Snp#define LIMIT_CAPS(x) do { \ 1791228561Snp caps.x &= htobe16(t4_##x##_allowed); \ 1792228561Snp sc->x = htobe16(caps.x); \ 1793228561Snp} while (0) 1794228561Snp 1795228561Snp /* 1796228561Snp * Let the firmware know what features will (not) be used so it can tune 1797228561Snp * things accordingly. 1798228561Snp */ 1799228561Snp LIMIT_CAPS(linkcaps); 1800228561Snp LIMIT_CAPS(niccaps); 1801228561Snp LIMIT_CAPS(toecaps); 1802228561Snp LIMIT_CAPS(rdmacaps); 1803228561Snp LIMIT_CAPS(iscsicaps); 1804228561Snp LIMIT_CAPS(fcoecaps); 1805228561Snp#undef LIMIT_CAPS 1806228561Snp 1807228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1808218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE); 1809228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 1810228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), NULL); 1811228561Snp if (rc != 0) { 1812228561Snp device_printf(sc->dev, 1813228561Snp "failed to process config file: %d.\n", rc); 1814228561Snp return (rc); 1815228561Snp } 1816218792Snp 1817228561Snp return (0); 1818218792Snp} 1819218792Snp 1820228561Snp/* 1821228561Snp * Retrieve parameters that are needed (or nice to have) prior to calling 1822228561Snp * t4_sge_init and t4_fw_initialize. 1823228561Snp */ 1824218792Snpstatic int 1825228561Snpget_params__pre_init(struct adapter *sc) 1826218792Snp{ 1827218792Snp int rc; 1828228561Snp uint32_t param[2], val[2]; 1829228561Snp struct fw_devlog_cmd cmd; 1830228561Snp struct devlog_params *dlog = &sc->params.devlog; 1831218792Snp 1832228561Snp param[0] = FW_PARAM_DEV(PORTVEC); 1833228561Snp param[1] = FW_PARAM_DEV(CCLK); 1834228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 1835218792Snp if (rc != 0) { 1836218792Snp device_printf(sc->dev, 1837228561Snp "failed to query parameters (pre_init): %d.\n", rc); 1838228561Snp return (rc); 1839218792Snp } 1840218792Snp 1841218792Snp sc->params.portvec = val[0]; 1842240452Snp sc->params.nports = bitcount32(val[0]); 1843228561Snp sc->params.vpd.cclk = val[1]; 1844218792Snp 1845228561Snp /* Read device log parameters. */ 1846228561Snp bzero(&cmd, sizeof(cmd)); 1847228561Snp cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) | 1848228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1849228561Snp cmd.retval_len16 = htobe32(FW_LEN16(cmd)); 1850228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &cmd, sizeof(cmd), &cmd); 1851228561Snp if (rc != 0) { 1852228561Snp device_printf(sc->dev, 1853228561Snp "failed to get devlog parameters: %d.\n", rc); 1854228561Snp bzero(dlog, sizeof (*dlog)); 1855228561Snp rc = 0; /* devlog isn't critical for device operation */ 1856228561Snp } else { 1857228561Snp val[0] = be32toh(cmd.memtype_devlog_memaddr16_devlog); 1858228561Snp dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(val[0]); 1859228561Snp dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(val[0]) << 4; 1860228561Snp dlog->size = be32toh(cmd.memsize_devlog); 1861228561Snp } 1862228561Snp 1863228561Snp return (rc); 1864228561Snp} 1865228561Snp 1866228561Snp/* 1867228561Snp * Retrieve various parameters that are of interest to the driver. The device 1868228561Snp * has been initialized by the firmware at this point. 1869228561Snp */ 1870228561Snpstatic int 1871228561Snpget_params__post_init(struct adapter *sc) 1872228561Snp{ 1873228561Snp int rc; 1874228561Snp uint32_t param[7], val[7]; 1875228561Snp struct fw_caps_config_cmd caps; 1876228561Snp 1877228561Snp param[0] = FW_PARAM_PFVF(IQFLINT_START); 1878228561Snp param[1] = FW_PARAM_PFVF(EQ_START); 1879228561Snp param[2] = FW_PARAM_PFVF(FILTER_START); 1880228561Snp param[3] = FW_PARAM_PFVF(FILTER_END); 1881228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 4, param, val); 1882228561Snp if (rc != 0) { 1883228561Snp device_printf(sc->dev, 1884228561Snp "failed to query parameters (post_init): %d.\n", rc); 1885228561Snp return (rc); 1886228561Snp } 1887228561Snp 1888228561Snp sc->sge.iq_start = val[0]; 1889228561Snp sc->sge.eq_start = val[1]; 1890228561Snp sc->tids.ftid_base = val[2]; 1891228561Snp sc->tids.nftids = val[3] - val[2] + 1; 1892228561Snp 1893228561Snp /* get capabilites */ 1894228561Snp bzero(&caps, sizeof(caps)); 1895228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1896228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1897228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 1898228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 1899228561Snp if (rc != 0) { 1900228561Snp device_printf(sc->dev, 1901228561Snp "failed to get card capabilities: %d.\n", rc); 1902228561Snp return (rc); 1903228561Snp } 1904228561Snp 1905228561Snp if (caps.toecaps) { 1906218792Snp /* query offload-related parameters */ 1907228561Snp param[0] = FW_PARAM_DEV(NTID); 1908228561Snp param[1] = FW_PARAM_PFVF(SERVER_START); 1909228561Snp param[2] = FW_PARAM_PFVF(SERVER_END); 1910228561Snp param[3] = FW_PARAM_PFVF(TDDP_START); 1911228561Snp param[4] = FW_PARAM_PFVF(TDDP_END); 1912228561Snp param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 1913228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 1914218792Snp if (rc != 0) { 1915218792Snp device_printf(sc->dev, 1916218792Snp "failed to query TOE parameters: %d.\n", rc); 1917228561Snp return (rc); 1918218792Snp } 1919218792Snp sc->tids.ntids = val[0]; 1920218792Snp sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS); 1921218792Snp sc->tids.stid_base = val[1]; 1922218792Snp sc->tids.nstids = val[2] - val[1] + 1; 1923218792Snp sc->vres.ddp.start = val[3]; 1924218792Snp sc->vres.ddp.size = val[4] - val[3] + 1; 1925218792Snp sc->params.ofldq_wr_cred = val[5]; 1926218792Snp sc->params.offload = 1; 1927218792Snp } 1928228561Snp if (caps.rdmacaps) { 1929228561Snp param[0] = FW_PARAM_PFVF(STAG_START); 1930228561Snp param[1] = FW_PARAM_PFVF(STAG_END); 1931228561Snp param[2] = FW_PARAM_PFVF(RQ_START); 1932228561Snp param[3] = FW_PARAM_PFVF(RQ_END); 1933228561Snp param[4] = FW_PARAM_PFVF(PBL_START); 1934228561Snp param[5] = FW_PARAM_PFVF(PBL_END); 1935228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 1936218792Snp if (rc != 0) { 1937218792Snp device_printf(sc->dev, 1938228561Snp "failed to query RDMA parameters(1): %d.\n", rc); 1939228561Snp return (rc); 1940218792Snp } 1941218792Snp sc->vres.stag.start = val[0]; 1942218792Snp sc->vres.stag.size = val[1] - val[0] + 1; 1943218792Snp sc->vres.rq.start = val[2]; 1944218792Snp sc->vres.rq.size = val[3] - val[2] + 1; 1945218792Snp sc->vres.pbl.start = val[4]; 1946218792Snp sc->vres.pbl.size = val[5] - val[4] + 1; 1947228561Snp 1948228561Snp param[0] = FW_PARAM_PFVF(SQRQ_START); 1949228561Snp param[1] = FW_PARAM_PFVF(SQRQ_END); 1950228561Snp param[2] = FW_PARAM_PFVF(CQ_START); 1951228561Snp param[3] = FW_PARAM_PFVF(CQ_END); 1952228561Snp param[4] = FW_PARAM_PFVF(OCQ_START); 1953228561Snp param[5] = FW_PARAM_PFVF(OCQ_END); 1954228561Snp rc = -t4_query_params(sc, 0, 0, 0, 6, param, val); 1955228561Snp if (rc != 0) { 1956228561Snp device_printf(sc->dev, 1957228561Snp "failed to query RDMA parameters(2): %d.\n", rc); 1958228561Snp return (rc); 1959228561Snp } 1960228561Snp sc->vres.qp.start = val[0]; 1961228561Snp sc->vres.qp.size = val[1] - val[0] + 1; 1962228561Snp sc->vres.cq.start = val[2]; 1963228561Snp sc->vres.cq.size = val[3] - val[2] + 1; 1964228561Snp sc->vres.ocq.start = val[4]; 1965228561Snp sc->vres.ocq.size = val[5] - val[4] + 1; 1966218792Snp } 1967228561Snp if (caps.iscsicaps) { 1968228561Snp param[0] = FW_PARAM_PFVF(ISCSI_START); 1969228561Snp param[1] = FW_PARAM_PFVF(ISCSI_END); 1970228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 1971218792Snp if (rc != 0) { 1972218792Snp device_printf(sc->dev, 1973218792Snp "failed to query iSCSI parameters: %d.\n", rc); 1974228561Snp return (rc); 1975218792Snp } 1976218792Snp sc->vres.iscsi.start = val[0]; 1977218792Snp sc->vres.iscsi.size = val[1] - val[0] + 1; 1978218792Snp } 1979218792Snp 1980228561Snp /* These are finalized by FW initialization, load their values now */ 1981228561Snp val[0] = t4_read_reg(sc, A_TP_TIMER_RESOLUTION); 1982228561Snp sc->params.tp.tre = G_TIMERRESOLUTION(val[0]); 1983228561Snp sc->params.tp.dack_re = G_DELAYEDACKRESOLUTION(val[0]); 1984228561Snp t4_read_mtu_tbl(sc, sc->params.mtus, NULL); 1985228561Snp 1986218792Snp return (rc); 1987218792Snp} 1988218792Snp 1989228561Snp#undef FW_PARAM_PFVF 1990228561Snp#undef FW_PARAM_DEV 1991228561Snp 1992218792Snpstatic void 1993218792Snpt4_set_desc(struct adapter *sc) 1994218792Snp{ 1995218792Snp char buf[128]; 1996218792Snp struct adapter_params *p = &sc->params; 1997218792Snp 1998228561Snp snprintf(buf, sizeof(buf), "Chelsio %s %sNIC (rev %d), S/N:%s, E/C:%s", 1999228561Snp p->vpd.id, is_offload(sc) ? "R" : "", p->rev, p->vpd.sn, p->vpd.ec); 2000218792Snp 2001218792Snp device_set_desc_copy(sc->dev, buf); 2002218792Snp} 2003218792Snp 2004218792Snpstatic void 2005218792Snpbuild_medialist(struct port_info *pi) 2006218792Snp{ 2007218792Snp struct ifmedia *media = &pi->media; 2008218792Snp int data, m; 2009218792Snp 2010218792Snp PORT_LOCK(pi); 2011218792Snp 2012218792Snp ifmedia_removeall(media); 2013218792Snp 2014218792Snp m = IFM_ETHER | IFM_FDX; 2015218792Snp data = (pi->port_type << 8) | pi->mod_type; 2016218792Snp 2017218792Snp switch(pi->port_type) { 2018218792Snp case FW_PORT_TYPE_BT_XFI: 2019218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2020218792Snp break; 2021218792Snp 2022218792Snp case FW_PORT_TYPE_BT_XAUI: 2023218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2024218792Snp /* fall through */ 2025218792Snp 2026218792Snp case FW_PORT_TYPE_BT_SGMII: 2027218792Snp ifmedia_add(media, m | IFM_1000_T, data, NULL); 2028218792Snp ifmedia_add(media, m | IFM_100_TX, data, NULL); 2029218792Snp ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL); 2030218792Snp ifmedia_set(media, IFM_ETHER | IFM_AUTO); 2031218792Snp break; 2032218792Snp 2033218792Snp case FW_PORT_TYPE_CX4: 2034218792Snp ifmedia_add(media, m | IFM_10G_CX4, data, NULL); 2035218792Snp ifmedia_set(media, m | IFM_10G_CX4); 2036218792Snp break; 2037218792Snp 2038218792Snp case FW_PORT_TYPE_SFP: 2039218792Snp case FW_PORT_TYPE_FIBER_XFI: 2040218792Snp case FW_PORT_TYPE_FIBER_XAUI: 2041218792Snp switch (pi->mod_type) { 2042218792Snp 2043218792Snp case FW_PORT_MOD_TYPE_LR: 2044218792Snp ifmedia_add(media, m | IFM_10G_LR, data, NULL); 2045218792Snp ifmedia_set(media, m | IFM_10G_LR); 2046218792Snp break; 2047218792Snp 2048218792Snp case FW_PORT_MOD_TYPE_SR: 2049218792Snp ifmedia_add(media, m | IFM_10G_SR, data, NULL); 2050218792Snp ifmedia_set(media, m | IFM_10G_SR); 2051218792Snp break; 2052218792Snp 2053218792Snp case FW_PORT_MOD_TYPE_LRM: 2054218792Snp ifmedia_add(media, m | IFM_10G_LRM, data, NULL); 2055218792Snp ifmedia_set(media, m | IFM_10G_LRM); 2056218792Snp break; 2057218792Snp 2058218792Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2059218792Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2060218792Snp ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL); 2061218792Snp ifmedia_set(media, m | IFM_10G_TWINAX); 2062218792Snp break; 2063218792Snp 2064218792Snp case FW_PORT_MOD_TYPE_NONE: 2065218792Snp m &= ~IFM_FDX; 2066218792Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2067218792Snp ifmedia_set(media, m | IFM_NONE); 2068218792Snp break; 2069218792Snp 2070218792Snp case FW_PORT_MOD_TYPE_NA: 2071218792Snp case FW_PORT_MOD_TYPE_ER: 2072218792Snp default: 2073218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2074218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2075218792Snp break; 2076218792Snp } 2077218792Snp break; 2078218792Snp 2079218792Snp case FW_PORT_TYPE_KX4: 2080218792Snp case FW_PORT_TYPE_KX: 2081218792Snp case FW_PORT_TYPE_KR: 2082218792Snp default: 2083218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2084218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2085218792Snp break; 2086218792Snp } 2087218792Snp 2088218792Snp PORT_UNLOCK(pi); 2089218792Snp} 2090218792Snp 2091231172Snp#define FW_MAC_EXACT_CHUNK 7 2092231172Snp 2093218792Snp/* 2094218792Snp * Program the port's XGMAC based on parameters in ifnet. The caller also 2095218792Snp * indicates which parameters should be programmed (the rest are left alone). 2096218792Snp */ 2097218792Snpstatic int 2098218792Snpupdate_mac_settings(struct port_info *pi, int flags) 2099218792Snp{ 2100218792Snp int rc; 2101218792Snp struct ifnet *ifp = pi->ifp; 2102218792Snp struct adapter *sc = pi->adapter; 2103218792Snp int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1; 2104218792Snp 2105218792Snp PORT_LOCK_ASSERT_OWNED(pi); 2106218792Snp KASSERT(flags, ("%s: not told what to update.", __func__)); 2107218792Snp 2108218792Snp if (flags & XGMAC_MTU) 2109218792Snp mtu = ifp->if_mtu; 2110218792Snp 2111218792Snp if (flags & XGMAC_PROMISC) 2112218792Snp promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0; 2113218792Snp 2114218792Snp if (flags & XGMAC_ALLMULTI) 2115218792Snp allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0; 2116218792Snp 2117218792Snp if (flags & XGMAC_VLANEX) 2118218792Snp vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0; 2119218792Snp 2120218792Snp rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, mtu, promisc, allmulti, 1, 2121218792Snp vlanex, false); 2122218792Snp if (rc) { 2123218792Snp if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, rc); 2124218792Snp return (rc); 2125218792Snp } 2126218792Snp 2127218792Snp if (flags & XGMAC_UCADDR) { 2128218792Snp uint8_t ucaddr[ETHER_ADDR_LEN]; 2129218792Snp 2130218792Snp bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr)); 2131218792Snp rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, 2132218792Snp ucaddr, true, true); 2133218792Snp if (rc < 0) { 2134218792Snp rc = -rc; 2135218792Snp if_printf(ifp, "change_mac failed: %d\n", rc); 2136218792Snp return (rc); 2137218792Snp } else { 2138218792Snp pi->xact_addr_filt = rc; 2139218792Snp rc = 0; 2140218792Snp } 2141218792Snp } 2142218792Snp 2143218792Snp if (flags & XGMAC_MCADDRS) { 2144231172Snp const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK]; 2145218792Snp int del = 1; 2146218792Snp uint64_t hash = 0; 2147218792Snp struct ifmultiaddr *ifma; 2148231172Snp int i = 0, j; 2149218792Snp 2150218792Snp if_maddr_rlock(ifp); 2151218792Snp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2152238054Snp if (ifma->ifma_addr->sa_family != AF_LINK) 2153218792Snp continue; 2154231172Snp mcaddr[i++] = 2155231172Snp LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 2156218792Snp 2157231172Snp if (i == FW_MAC_EXACT_CHUNK) { 2158231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2159231172Snp del, i, mcaddr, NULL, &hash, 0); 2160231172Snp if (rc < 0) { 2161231172Snp rc = -rc; 2162231172Snp for (j = 0; j < i; j++) { 2163231172Snp if_printf(ifp, 2164231172Snp "failed to add mc address" 2165231172Snp " %02x:%02x:%02x:" 2166231172Snp "%02x:%02x:%02x rc=%d\n", 2167231172Snp mcaddr[j][0], mcaddr[j][1], 2168231172Snp mcaddr[j][2], mcaddr[j][3], 2169231172Snp mcaddr[j][4], mcaddr[j][5], 2170231172Snp rc); 2171231172Snp } 2172231172Snp goto mcfail; 2173231172Snp } 2174231172Snp del = 0; 2175231172Snp i = 0; 2176231172Snp } 2177231172Snp } 2178231172Snp if (i > 0) { 2179231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2180231172Snp del, i, mcaddr, NULL, &hash, 0); 2181218792Snp if (rc < 0) { 2182218792Snp rc = -rc; 2183231172Snp for (j = 0; j < i; j++) { 2184231172Snp if_printf(ifp, 2185231172Snp "failed to add mc address" 2186231172Snp " %02x:%02x:%02x:" 2187231172Snp "%02x:%02x:%02x rc=%d\n", 2188231172Snp mcaddr[j][0], mcaddr[j][1], 2189231172Snp mcaddr[j][2], mcaddr[j][3], 2190231172Snp mcaddr[j][4], mcaddr[j][5], 2191231172Snp rc); 2192231172Snp } 2193218792Snp goto mcfail; 2194218792Snp } 2195218792Snp } 2196218792Snp 2197218792Snp rc = -t4_set_addr_hash(sc, sc->mbox, pi->viid, 0, hash, 0); 2198218792Snp if (rc != 0) 2199218792Snp if_printf(ifp, "failed to set mc address hash: %d", rc); 2200218792Snpmcfail: 2201218792Snp if_maddr_runlock(ifp); 2202218792Snp } 2203218792Snp 2204218792Snp return (rc); 2205218792Snp} 2206218792Snp 2207218792Snpstatic int 2208218792Snpcxgbe_init_locked(struct port_info *pi) 2209218792Snp{ 2210218792Snp struct adapter *sc = pi->adapter; 2211218792Snp int rc = 0; 2212218792Snp 2213218792Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 2214218792Snp 2215218792Snp while (!IS_DOOMED(pi) && IS_BUSY(sc)) { 2216218792Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4init", 0)) { 2217218792Snp rc = EINTR; 2218218792Snp goto done; 2219218792Snp } 2220218792Snp } 2221218792Snp if (IS_DOOMED(pi)) { 2222218792Snp rc = ENXIO; 2223218792Snp goto done; 2224218792Snp } 2225218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 2226218792Snp 2227218792Snp /* Give up the adapter lock, port init code can sleep. */ 2228218792Snp SET_BUSY(sc); 2229218792Snp ADAPTER_UNLOCK(sc); 2230218792Snp 2231218792Snp rc = cxgbe_init_synchronized(pi); 2232218792Snp 2233218792Snpdone: 2234218792Snp ADAPTER_LOCK(sc); 2235218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 2236218792Snp CLR_BUSY(sc); 2237218792Snp wakeup_one(&sc->flags); 2238218792Snp ADAPTER_UNLOCK(sc); 2239218792Snp return (rc); 2240218792Snp} 2241218792Snp 2242218792Snpstatic int 2243218792Snpcxgbe_init_synchronized(struct port_info *pi) 2244218792Snp{ 2245218792Snp struct adapter *sc = pi->adapter; 2246218792Snp struct ifnet *ifp = pi->ifp; 2247228561Snp int rc = 0; 2248218792Snp 2249218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2250218792Snp 2251218792Snp if (isset(&sc->open_device_map, pi->port_id)) { 2252218792Snp KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, 2253218792Snp ("mismatch between open_device_map and if_drv_flags")); 2254218792Snp return (0); /* already running */ 2255218792Snp } 2256218792Snp 2257228561Snp if (!(sc->flags & FULL_INIT_DONE) && 2258228561Snp ((rc = adapter_full_init(sc)) != 0)) 2259218792Snp return (rc); /* error message displayed already */ 2260218792Snp 2261228561Snp if (!(pi->flags & PORT_INIT_DONE) && 2262228561Snp ((rc = port_full_init(pi)) != 0)) 2263228561Snp return (rc); /* error message displayed already */ 2264218792Snp 2265218792Snp PORT_LOCK(pi); 2266218792Snp rc = update_mac_settings(pi, XGMAC_ALL); 2267218792Snp PORT_UNLOCK(pi); 2268218792Snp if (rc) 2269218792Snp goto done; /* error message displayed already */ 2270218792Snp 2271218792Snp rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg); 2272218792Snp if (rc != 0) { 2273218792Snp if_printf(ifp, "start_link failed: %d\n", rc); 2274218792Snp goto done; 2275218792Snp } 2276218792Snp 2277218792Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true); 2278218792Snp if (rc != 0) { 2279218792Snp if_printf(ifp, "enable_vi failed: %d\n", rc); 2280218792Snp goto done; 2281218792Snp } 2282218792Snp 2283218792Snp /* all ok */ 2284218792Snp setbit(&sc->open_device_map, pi->port_id); 2285218792Snp ifp->if_drv_flags |= IFF_DRV_RUNNING; 2286218792Snp 2287218792Snp callout_reset(&pi->tick, hz, cxgbe_tick, pi); 2288218792Snpdone: 2289218792Snp if (rc != 0) 2290218792Snp cxgbe_uninit_synchronized(pi); 2291218792Snp 2292218792Snp return (rc); 2293218792Snp} 2294218792Snp 2295218792Snpstatic int 2296218792Snpcxgbe_uninit_locked(struct port_info *pi) 2297218792Snp{ 2298218792Snp struct adapter *sc = pi->adapter; 2299218792Snp int rc; 2300218792Snp 2301218792Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 2302218792Snp 2303218792Snp while (!IS_DOOMED(pi) && IS_BUSY(sc)) { 2304218792Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4uninit", 0)) { 2305218792Snp rc = EINTR; 2306218792Snp goto done; 2307218792Snp } 2308218792Snp } 2309218792Snp if (IS_DOOMED(pi)) { 2310218792Snp rc = ENXIO; 2311218792Snp goto done; 2312218792Snp } 2313218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 2314218792Snp SET_BUSY(sc); 2315218792Snp ADAPTER_UNLOCK(sc); 2316218792Snp 2317218792Snp rc = cxgbe_uninit_synchronized(pi); 2318218792Snp 2319218792Snp ADAPTER_LOCK(sc); 2320218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 2321218792Snp CLR_BUSY(sc); 2322218792Snp wakeup_one(&sc->flags); 2323218792Snpdone: 2324218792Snp ADAPTER_UNLOCK(sc); 2325218792Snp return (rc); 2326218792Snp} 2327218792Snp 2328218792Snp/* 2329218792Snp * Idempotent. 2330218792Snp */ 2331218792Snpstatic int 2332218792Snpcxgbe_uninit_synchronized(struct port_info *pi) 2333218792Snp{ 2334218792Snp struct adapter *sc = pi->adapter; 2335218792Snp struct ifnet *ifp = pi->ifp; 2336218792Snp int rc; 2337218792Snp 2338218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2339218792Snp 2340218792Snp /* 2341228561Snp * Disable the VI so that all its data in either direction is discarded 2342228561Snp * by the MPS. Leave everything else (the queues, interrupts, and 1Hz 2343228561Snp * tick) intact as the TP can deliver negative advice or data that it's 2344228561Snp * holding in its RAM (for an offloaded connection) even after the VI is 2345228561Snp * disabled. 2346218792Snp */ 2347228561Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false); 2348228561Snp if (rc) { 2349228561Snp if_printf(ifp, "disable_vi failed: %d\n", rc); 2350228561Snp return (rc); 2351228561Snp } 2352228561Snp 2353218792Snp clrbit(&sc->open_device_map, pi->port_id); 2354228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2355218792Snp 2356218792Snp pi->link_cfg.link_ok = 0; 2357218792Snp pi->link_cfg.speed = 0; 2358218792Snp t4_os_link_changed(sc, pi->port_id, 0); 2359218792Snp 2360218792Snp return (0); 2361218792Snp} 2362218792Snp 2363222510Snp#define T4_ALLOC_IRQ(sc, irq, rid, handler, arg, name) do { \ 2364222510Snp rc = t4_alloc_irq(sc, irq, rid, handler, arg, name); \ 2365218792Snp if (rc != 0) \ 2366218792Snp goto done; \ 2367218792Snp} while (0) 2368228561Snp 2369218792Snpstatic int 2370228561Snpadapter_full_init(struct adapter *sc) 2371218792Snp{ 2372222510Snp int rc, i, rid, p, q; 2373222510Snp char s[8]; 2374222510Snp struct irq *irq; 2375228561Snp struct port_info *pi; 2376228561Snp struct sge_rxq *rxq; 2377237263Snp#ifdef TCP_OFFLOAD 2378228561Snp struct sge_ofld_rxq *ofld_rxq; 2379228561Snp#endif 2380218792Snp 2381218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2382228561Snp KASSERT((sc->flags & FULL_INIT_DONE) == 0, 2383228561Snp ("%s: FULL_INIT_DONE already", __func__)); 2384218792Snp 2385218792Snp /* 2386220873Snp * queues that belong to the adapter (not any particular port). 2387218792Snp */ 2388220873Snp rc = t4_setup_adapter_queues(sc); 2389218792Snp if (rc != 0) 2390218792Snp goto done; 2391218792Snp 2392240452Snp for (i = 0; i < nitems(sc->tq); i++) { 2393228561Snp sc->tq[i] = taskqueue_create("t4 taskq", M_NOWAIT, 2394228561Snp taskqueue_thread_enqueue, &sc->tq[i]); 2395228561Snp if (sc->tq[i] == NULL) { 2396228561Snp device_printf(sc->dev, 2397228561Snp "failed to allocate task queue %d\n", i); 2398228561Snp rc = ENOMEM; 2399228561Snp goto done; 2400228561Snp } 2401228561Snp taskqueue_start_threads(&sc->tq[i], 1, PI_NET, "%s tq%d", 2402228561Snp device_get_nameunit(sc->dev), i); 2403228561Snp } 2404228561Snp 2405218792Snp /* 2406218792Snp * Setup interrupts. 2407218792Snp */ 2408222510Snp irq = &sc->irq[0]; 2409222510Snp rid = sc->intr_type == INTR_INTX ? 0 : 1; 2410218792Snp if (sc->intr_count == 1) { 2411228561Snp KASSERT(!(sc->flags & INTR_DIRECT), 2412228561Snp ("%s: single interrupt && INTR_DIRECT?", __func__)); 2413222510Snp 2414222510Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr_all, sc, "all"); 2415218792Snp } else { 2416228561Snp /* Multiple interrupts. */ 2417228561Snp KASSERT(sc->intr_count >= T4_EXTRA_INTR + sc->params.nports, 2418228561Snp ("%s: too few intr.", __func__)); 2419228561Snp 2420228561Snp /* The first one is always error intr */ 2421222510Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr_err, sc, "err"); 2422222510Snp irq++; 2423222510Snp rid++; 2424218792Snp 2425228561Snp /* The second one is always the firmware event queue */ 2426228561Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr_evt, &sc->sge.fwq, "evt"); 2427228561Snp irq++; 2428228561Snp rid++; 2429222510Snp 2430228561Snp /* 2431228561Snp * Note that if INTR_DIRECT is not set then either the NIC rx 2432228561Snp * queues or (exclusive or) the TOE rx queueus will be taking 2433228561Snp * direct interrupts. 2434228561Snp * 2435228561Snp * There is no need to check for is_offload(sc) as nofldrxq 2436228561Snp * will be 0 if offload is disabled. 2437228561Snp */ 2438228561Snp for_each_port(sc, p) { 2439228561Snp pi = sc->port[p]; 2440222510Snp 2441237263Snp#ifdef TCP_OFFLOAD 2442228561Snp /* 2443228561Snp * Skip over the NIC queues if they aren't taking direct 2444228561Snp * interrupts. 2445228561Snp */ 2446228561Snp if (!(sc->flags & INTR_DIRECT) && 2447228561Snp pi->nofldrxq > pi->nrxq) 2448228561Snp goto ofld_queues; 2449228561Snp#endif 2450228561Snp rxq = &sc->sge.rxq[pi->first_rxq]; 2451228561Snp for (q = 0; q < pi->nrxq; q++, rxq++) { 2452228561Snp snprintf(s, sizeof(s), "%d.%d", p, q); 2453228561Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr, rxq, s); 2454222510Snp irq++; 2455222510Snp rid++; 2456218792Snp } 2457218792Snp 2458237263Snp#ifdef TCP_OFFLOAD 2459228561Snp /* 2460228561Snp * Skip over the offload queues if they aren't taking 2461228561Snp * direct interrupts. 2462228561Snp */ 2463228561Snp if (!(sc->flags & INTR_DIRECT)) 2464228561Snp continue; 2465228561Snpofld_queues: 2466228561Snp ofld_rxq = &sc->sge.ofld_rxq[pi->first_ofld_rxq]; 2467228561Snp for (q = 0; q < pi->nofldrxq; q++, ofld_rxq++) { 2468228561Snp snprintf(s, sizeof(s), "%d,%d", p, q); 2469228561Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr, ofld_rxq, s); 2470228561Snp irq++; 2471228561Snp rid++; 2472218792Snp } 2473228561Snp#endif 2474218792Snp } 2475218792Snp } 2476218792Snp 2477218792Snp t4_intr_enable(sc); 2478218792Snp sc->flags |= FULL_INIT_DONE; 2479218792Snpdone: 2480218792Snp if (rc != 0) 2481228561Snp adapter_full_uninit(sc); 2482218792Snp 2483218792Snp return (rc); 2484218792Snp} 2485218792Snp#undef T4_ALLOC_IRQ 2486218792Snp 2487218792Snpstatic int 2488228561Snpadapter_full_uninit(struct adapter *sc) 2489218792Snp{ 2490218792Snp int i; 2491218792Snp 2492218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2493218792Snp 2494220873Snp t4_teardown_adapter_queues(sc); 2495218792Snp 2496218792Snp for (i = 0; i < sc->intr_count; i++) 2497218792Snp t4_free_irq(sc, &sc->irq[i]); 2498218792Snp 2499240452Snp for (i = 0; i < nitems(sc->tq) && sc->tq[i]; i++) { 2500228561Snp taskqueue_free(sc->tq[i]); 2501228561Snp sc->tq[i] = NULL; 2502228561Snp } 2503228561Snp 2504218792Snp sc->flags &= ~FULL_INIT_DONE; 2505218792Snp 2506218792Snp return (0); 2507218792Snp} 2508218792Snp 2509218792Snpstatic int 2510228561Snpport_full_init(struct port_info *pi) 2511228561Snp{ 2512228561Snp struct adapter *sc = pi->adapter; 2513228561Snp struct ifnet *ifp = pi->ifp; 2514228561Snp uint16_t *rss; 2515228561Snp struct sge_rxq *rxq; 2516228561Snp int rc, i; 2517228561Snp 2518228561Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2519228561Snp KASSERT((pi->flags & PORT_INIT_DONE) == 0, 2520228561Snp ("%s: PORT_INIT_DONE already", __func__)); 2521228561Snp 2522228561Snp sysctl_ctx_init(&pi->ctx); 2523228561Snp pi->flags |= PORT_SYSCTL_CTX; 2524228561Snp 2525228561Snp /* 2526228561Snp * Allocate tx/rx/fl queues for this port. 2527228561Snp */ 2528228561Snp rc = t4_setup_port_queues(pi); 2529228561Snp if (rc != 0) 2530228561Snp goto done; /* error message displayed already */ 2531228561Snp 2532228561Snp /* 2533228561Snp * Setup RSS for this port. 2534228561Snp */ 2535228561Snp rss = malloc(pi->nrxq * sizeof (*rss), M_CXGBE, 2536228561Snp M_ZERO | M_WAITOK); 2537228561Snp for_each_rxq(pi, i, rxq) { 2538228561Snp rss[i] = rxq->iq.abs_id; 2539228561Snp } 2540228561Snp rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, 2541228561Snp pi->rss_size, rss, pi->nrxq); 2542228561Snp free(rss, M_CXGBE); 2543228561Snp if (rc != 0) { 2544228561Snp if_printf(ifp, "rss_config failed: %d\n", rc); 2545228561Snp goto done; 2546228561Snp } 2547228561Snp 2548228561Snp pi->flags |= PORT_INIT_DONE; 2549228561Snpdone: 2550228561Snp if (rc != 0) 2551228561Snp port_full_uninit(pi); 2552228561Snp 2553228561Snp return (rc); 2554228561Snp} 2555228561Snp 2556228561Snp/* 2557228561Snp * Idempotent. 2558228561Snp */ 2559228561Snpstatic int 2560228561Snpport_full_uninit(struct port_info *pi) 2561228561Snp{ 2562228561Snp struct adapter *sc = pi->adapter; 2563228561Snp int i; 2564228561Snp struct sge_rxq *rxq; 2565228561Snp struct sge_txq *txq; 2566237263Snp#ifdef TCP_OFFLOAD 2567228561Snp struct sge_ofld_rxq *ofld_rxq; 2568228561Snp struct sge_wrq *ofld_txq; 2569228561Snp#endif 2570228561Snp 2571228561Snp if (pi->flags & PORT_INIT_DONE) { 2572228561Snp 2573228561Snp /* Need to quiesce queues. XXX: ctrl queues? */ 2574228561Snp 2575228561Snp for_each_txq(pi, i, txq) { 2576228561Snp quiesce_eq(sc, &txq->eq); 2577228561Snp } 2578228561Snp 2579237263Snp#ifdef TCP_OFFLOAD 2580228561Snp for_each_ofld_txq(pi, i, ofld_txq) { 2581228561Snp quiesce_eq(sc, &ofld_txq->eq); 2582228561Snp } 2583228561Snp#endif 2584228561Snp 2585228561Snp for_each_rxq(pi, i, rxq) { 2586228561Snp quiesce_iq(sc, &rxq->iq); 2587228561Snp quiesce_fl(sc, &rxq->fl); 2588228561Snp } 2589228561Snp 2590237263Snp#ifdef TCP_OFFLOAD 2591228561Snp for_each_ofld_rxq(pi, i, ofld_rxq) { 2592228561Snp quiesce_iq(sc, &ofld_rxq->iq); 2593228561Snp quiesce_fl(sc, &ofld_rxq->fl); 2594228561Snp } 2595228561Snp#endif 2596228561Snp } 2597228561Snp 2598228561Snp t4_teardown_port_queues(pi); 2599228561Snp pi->flags &= ~PORT_INIT_DONE; 2600228561Snp 2601228561Snp return (0); 2602228561Snp} 2603228561Snp 2604228561Snpstatic void 2605228561Snpquiesce_eq(struct adapter *sc, struct sge_eq *eq) 2606228561Snp{ 2607228561Snp EQ_LOCK(eq); 2608228561Snp eq->flags |= EQ_DOOMED; 2609228561Snp 2610228561Snp /* 2611228561Snp * Wait for the response to a credit flush if one's 2612228561Snp * pending. 2613228561Snp */ 2614228561Snp while (eq->flags & EQ_CRFLUSHED) 2615228561Snp mtx_sleep(eq, &eq->eq_lock, 0, "crflush", 0); 2616228561Snp EQ_UNLOCK(eq); 2617228561Snp 2618228561Snp callout_drain(&eq->tx_callout); /* XXX: iffy */ 2619228561Snp pause("callout", 10); /* Still iffy */ 2620228561Snp 2621228561Snp taskqueue_drain(sc->tq[eq->tx_chan], &eq->tx_task); 2622228561Snp} 2623228561Snp 2624228561Snpstatic void 2625228561Snpquiesce_iq(struct adapter *sc, struct sge_iq *iq) 2626228561Snp{ 2627228561Snp (void) sc; /* unused */ 2628228561Snp 2629228561Snp /* Synchronize with the interrupt handler */ 2630228561Snp while (!atomic_cmpset_int(&iq->state, IQS_IDLE, IQS_DISABLED)) 2631228561Snp pause("iqfree", 1); 2632228561Snp} 2633228561Snp 2634228561Snpstatic void 2635228561Snpquiesce_fl(struct adapter *sc, struct sge_fl *fl) 2636228561Snp{ 2637228561Snp mtx_lock(&sc->sfl_lock); 2638228561Snp FL_LOCK(fl); 2639228561Snp fl->flags |= FL_DOOMED; 2640228561Snp FL_UNLOCK(fl); 2641228561Snp mtx_unlock(&sc->sfl_lock); 2642228561Snp 2643228561Snp callout_drain(&sc->sfl_callout); 2644228561Snp KASSERT((fl->flags & FL_STARVING) == 0, 2645228561Snp ("%s: still starving", __func__)); 2646228561Snp} 2647228561Snp 2648228561Snpstatic int 2649218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid, 2650228561Snp driver_intr_t *handler, void *arg, char *name) 2651218792Snp{ 2652218792Snp int rc; 2653218792Snp 2654218792Snp irq->rid = rid; 2655218792Snp irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid, 2656218792Snp RF_SHAREABLE | RF_ACTIVE); 2657218792Snp if (irq->res == NULL) { 2658218792Snp device_printf(sc->dev, 2659218792Snp "failed to allocate IRQ for rid %d, name %s.\n", rid, name); 2660218792Snp return (ENOMEM); 2661218792Snp } 2662218792Snp 2663218792Snp rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET, 2664218792Snp NULL, handler, arg, &irq->tag); 2665218792Snp if (rc != 0) { 2666218792Snp device_printf(sc->dev, 2667218792Snp "failed to setup interrupt for rid %d, name %s: %d\n", 2668218792Snp rid, name, rc); 2669218792Snp } else if (name) 2670218792Snp bus_describe_intr(sc->dev, irq->res, irq->tag, name); 2671218792Snp 2672218792Snp return (rc); 2673218792Snp} 2674218792Snp 2675218792Snpstatic int 2676218792Snpt4_free_irq(struct adapter *sc, struct irq *irq) 2677218792Snp{ 2678218792Snp if (irq->tag) 2679218792Snp bus_teardown_intr(sc->dev, irq->res, irq->tag); 2680218792Snp if (irq->res) 2681218792Snp bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res); 2682218792Snp 2683218792Snp bzero(irq, sizeof(*irq)); 2684218792Snp 2685218792Snp return (0); 2686218792Snp} 2687218792Snp 2688218792Snpstatic void 2689218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start, 2690218792Snp unsigned int end) 2691218792Snp{ 2692218792Snp uint32_t *p = (uint32_t *)(buf + start); 2693218792Snp 2694218792Snp for ( ; start <= end; start += sizeof(uint32_t)) 2695218792Snp *p++ = t4_read_reg(sc, start); 2696218792Snp} 2697218792Snp 2698218792Snpstatic void 2699218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf) 2700218792Snp{ 2701218792Snp int i; 2702218792Snp static const unsigned int reg_ranges[] = { 2703218792Snp 0x1008, 0x1108, 2704218792Snp 0x1180, 0x11b4, 2705218792Snp 0x11fc, 0x123c, 2706218792Snp 0x1300, 0x173c, 2707218792Snp 0x1800, 0x18fc, 2708218792Snp 0x3000, 0x30d8, 2709218792Snp 0x30e0, 0x5924, 2710218792Snp 0x5960, 0x59d4, 2711218792Snp 0x5a00, 0x5af8, 2712218792Snp 0x6000, 0x6098, 2713218792Snp 0x6100, 0x6150, 2714218792Snp 0x6200, 0x6208, 2715218792Snp 0x6240, 0x6248, 2716218792Snp 0x6280, 0x6338, 2717218792Snp 0x6370, 0x638c, 2718218792Snp 0x6400, 0x643c, 2719218792Snp 0x6500, 0x6524, 2720218792Snp 0x6a00, 0x6a38, 2721218792Snp 0x6a60, 0x6a78, 2722218792Snp 0x6b00, 0x6b84, 2723218792Snp 0x6bf0, 0x6c84, 2724218792Snp 0x6cf0, 0x6d84, 2725218792Snp 0x6df0, 0x6e84, 2726218792Snp 0x6ef0, 0x6f84, 2727218792Snp 0x6ff0, 0x7084, 2728218792Snp 0x70f0, 0x7184, 2729218792Snp 0x71f0, 0x7284, 2730218792Snp 0x72f0, 0x7384, 2731218792Snp 0x73f0, 0x7450, 2732218792Snp 0x7500, 0x7530, 2733218792Snp 0x7600, 0x761c, 2734218792Snp 0x7680, 0x76cc, 2735218792Snp 0x7700, 0x7798, 2736218792Snp 0x77c0, 0x77fc, 2737218792Snp 0x7900, 0x79fc, 2738218792Snp 0x7b00, 0x7c38, 2739218792Snp 0x7d00, 0x7efc, 2740218792Snp 0x8dc0, 0x8e1c, 2741218792Snp 0x8e30, 0x8e78, 2742218792Snp 0x8ea0, 0x8f6c, 2743218792Snp 0x8fc0, 0x9074, 2744218792Snp 0x90fc, 0x90fc, 2745218792Snp 0x9400, 0x9458, 2746218792Snp 0x9600, 0x96bc, 2747218792Snp 0x9800, 0x9808, 2748218792Snp 0x9820, 0x983c, 2749218792Snp 0x9850, 0x9864, 2750218792Snp 0x9c00, 0x9c6c, 2751218792Snp 0x9c80, 0x9cec, 2752218792Snp 0x9d00, 0x9d6c, 2753218792Snp 0x9d80, 0x9dec, 2754218792Snp 0x9e00, 0x9e6c, 2755218792Snp 0x9e80, 0x9eec, 2756218792Snp 0x9f00, 0x9f6c, 2757218792Snp 0x9f80, 0x9fec, 2758218792Snp 0xd004, 0xd03c, 2759218792Snp 0xdfc0, 0xdfe0, 2760218792Snp 0xe000, 0xea7c, 2761218792Snp 0xf000, 0x11190, 2762237439Snp 0x19040, 0x1906c, 2763237439Snp 0x19078, 0x19080, 2764237439Snp 0x1908c, 0x19124, 2765218792Snp 0x19150, 0x191b0, 2766218792Snp 0x191d0, 0x191e8, 2767218792Snp 0x19238, 0x1924c, 2768218792Snp 0x193f8, 0x19474, 2769218792Snp 0x19490, 0x194f8, 2770218792Snp 0x19800, 0x19f30, 2771218792Snp 0x1a000, 0x1a06c, 2772218792Snp 0x1a0b0, 0x1a120, 2773218792Snp 0x1a128, 0x1a138, 2774218792Snp 0x1a190, 0x1a1c4, 2775218792Snp 0x1a1fc, 0x1a1fc, 2776218792Snp 0x1e040, 0x1e04c, 2777237439Snp 0x1e284, 0x1e28c, 2778218792Snp 0x1e2c0, 0x1e2c0, 2779218792Snp 0x1e2e0, 0x1e2e0, 2780218792Snp 0x1e300, 0x1e384, 2781218792Snp 0x1e3c0, 0x1e3c8, 2782218792Snp 0x1e440, 0x1e44c, 2783237439Snp 0x1e684, 0x1e68c, 2784218792Snp 0x1e6c0, 0x1e6c0, 2785218792Snp 0x1e6e0, 0x1e6e0, 2786218792Snp 0x1e700, 0x1e784, 2787218792Snp 0x1e7c0, 0x1e7c8, 2788218792Snp 0x1e840, 0x1e84c, 2789237439Snp 0x1ea84, 0x1ea8c, 2790218792Snp 0x1eac0, 0x1eac0, 2791218792Snp 0x1eae0, 0x1eae0, 2792218792Snp 0x1eb00, 0x1eb84, 2793218792Snp 0x1ebc0, 0x1ebc8, 2794218792Snp 0x1ec40, 0x1ec4c, 2795237439Snp 0x1ee84, 0x1ee8c, 2796218792Snp 0x1eec0, 0x1eec0, 2797218792Snp 0x1eee0, 0x1eee0, 2798218792Snp 0x1ef00, 0x1ef84, 2799218792Snp 0x1efc0, 0x1efc8, 2800218792Snp 0x1f040, 0x1f04c, 2801237439Snp 0x1f284, 0x1f28c, 2802218792Snp 0x1f2c0, 0x1f2c0, 2803218792Snp 0x1f2e0, 0x1f2e0, 2804218792Snp 0x1f300, 0x1f384, 2805218792Snp 0x1f3c0, 0x1f3c8, 2806218792Snp 0x1f440, 0x1f44c, 2807237439Snp 0x1f684, 0x1f68c, 2808218792Snp 0x1f6c0, 0x1f6c0, 2809218792Snp 0x1f6e0, 0x1f6e0, 2810218792Snp 0x1f700, 0x1f784, 2811218792Snp 0x1f7c0, 0x1f7c8, 2812218792Snp 0x1f840, 0x1f84c, 2813237439Snp 0x1fa84, 0x1fa8c, 2814218792Snp 0x1fac0, 0x1fac0, 2815218792Snp 0x1fae0, 0x1fae0, 2816218792Snp 0x1fb00, 0x1fb84, 2817218792Snp 0x1fbc0, 0x1fbc8, 2818218792Snp 0x1fc40, 0x1fc4c, 2819237439Snp 0x1fe84, 0x1fe8c, 2820218792Snp 0x1fec0, 0x1fec0, 2821218792Snp 0x1fee0, 0x1fee0, 2822218792Snp 0x1ff00, 0x1ff84, 2823218792Snp 0x1ffc0, 0x1ffc8, 2824218792Snp 0x20000, 0x2002c, 2825218792Snp 0x20100, 0x2013c, 2826218792Snp 0x20190, 0x201c8, 2827218792Snp 0x20200, 0x20318, 2828218792Snp 0x20400, 0x20528, 2829218792Snp 0x20540, 0x20614, 2830218792Snp 0x21000, 0x21040, 2831218792Snp 0x2104c, 0x21060, 2832218792Snp 0x210c0, 0x210ec, 2833218792Snp 0x21200, 0x21268, 2834218792Snp 0x21270, 0x21284, 2835218792Snp 0x212fc, 0x21388, 2836218792Snp 0x21400, 0x21404, 2837218792Snp 0x21500, 0x21518, 2838218792Snp 0x2152c, 0x2153c, 2839218792Snp 0x21550, 0x21554, 2840218792Snp 0x21600, 0x21600, 2841218792Snp 0x21608, 0x21628, 2842218792Snp 0x21630, 0x2163c, 2843218792Snp 0x21700, 0x2171c, 2844218792Snp 0x21780, 0x2178c, 2845218792Snp 0x21800, 0x21c38, 2846218792Snp 0x21c80, 0x21d7c, 2847218792Snp 0x21e00, 0x21e04, 2848218792Snp 0x22000, 0x2202c, 2849218792Snp 0x22100, 0x2213c, 2850218792Snp 0x22190, 0x221c8, 2851218792Snp 0x22200, 0x22318, 2852218792Snp 0x22400, 0x22528, 2853218792Snp 0x22540, 0x22614, 2854218792Snp 0x23000, 0x23040, 2855218792Snp 0x2304c, 0x23060, 2856218792Snp 0x230c0, 0x230ec, 2857218792Snp 0x23200, 0x23268, 2858218792Snp 0x23270, 0x23284, 2859218792Snp 0x232fc, 0x23388, 2860218792Snp 0x23400, 0x23404, 2861218792Snp 0x23500, 0x23518, 2862218792Snp 0x2352c, 0x2353c, 2863218792Snp 0x23550, 0x23554, 2864218792Snp 0x23600, 0x23600, 2865218792Snp 0x23608, 0x23628, 2866218792Snp 0x23630, 0x2363c, 2867218792Snp 0x23700, 0x2371c, 2868218792Snp 0x23780, 0x2378c, 2869218792Snp 0x23800, 0x23c38, 2870218792Snp 0x23c80, 0x23d7c, 2871218792Snp 0x23e00, 0x23e04, 2872218792Snp 0x24000, 0x2402c, 2873218792Snp 0x24100, 0x2413c, 2874218792Snp 0x24190, 0x241c8, 2875218792Snp 0x24200, 0x24318, 2876218792Snp 0x24400, 0x24528, 2877218792Snp 0x24540, 0x24614, 2878218792Snp 0x25000, 0x25040, 2879218792Snp 0x2504c, 0x25060, 2880218792Snp 0x250c0, 0x250ec, 2881218792Snp 0x25200, 0x25268, 2882218792Snp 0x25270, 0x25284, 2883218792Snp 0x252fc, 0x25388, 2884218792Snp 0x25400, 0x25404, 2885218792Snp 0x25500, 0x25518, 2886218792Snp 0x2552c, 0x2553c, 2887218792Snp 0x25550, 0x25554, 2888218792Snp 0x25600, 0x25600, 2889218792Snp 0x25608, 0x25628, 2890218792Snp 0x25630, 0x2563c, 2891218792Snp 0x25700, 0x2571c, 2892218792Snp 0x25780, 0x2578c, 2893218792Snp 0x25800, 0x25c38, 2894218792Snp 0x25c80, 0x25d7c, 2895218792Snp 0x25e00, 0x25e04, 2896218792Snp 0x26000, 0x2602c, 2897218792Snp 0x26100, 0x2613c, 2898218792Snp 0x26190, 0x261c8, 2899218792Snp 0x26200, 0x26318, 2900218792Snp 0x26400, 0x26528, 2901218792Snp 0x26540, 0x26614, 2902218792Snp 0x27000, 0x27040, 2903218792Snp 0x2704c, 0x27060, 2904218792Snp 0x270c0, 0x270ec, 2905218792Snp 0x27200, 0x27268, 2906218792Snp 0x27270, 0x27284, 2907218792Snp 0x272fc, 0x27388, 2908218792Snp 0x27400, 0x27404, 2909218792Snp 0x27500, 0x27518, 2910218792Snp 0x2752c, 0x2753c, 2911218792Snp 0x27550, 0x27554, 2912218792Snp 0x27600, 0x27600, 2913218792Snp 0x27608, 0x27628, 2914218792Snp 0x27630, 0x2763c, 2915218792Snp 0x27700, 0x2771c, 2916218792Snp 0x27780, 0x2778c, 2917218792Snp 0x27800, 0x27c38, 2918218792Snp 0x27c80, 0x27d7c, 2919218792Snp 0x27e00, 0x27e04 2920218792Snp }; 2921218792Snp 2922218792Snp regs->version = 4 | (sc->params.rev << 10); 2923240452Snp for (i = 0; i < nitems(reg_ranges); i += 2) 2924218792Snp reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]); 2925218792Snp} 2926218792Snp 2927218792Snpstatic void 2928218792Snpcxgbe_tick(void *arg) 2929218792Snp{ 2930218792Snp struct port_info *pi = arg; 2931218792Snp struct ifnet *ifp = pi->ifp; 2932218792Snp struct sge_txq *txq; 2933218792Snp int i, drops; 2934218792Snp struct port_stats *s = &pi->stats; 2935218792Snp 2936218792Snp PORT_LOCK(pi); 2937218792Snp if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2938218792Snp PORT_UNLOCK(pi); 2939218792Snp return; /* without scheduling another callout */ 2940218792Snp } 2941218792Snp 2942218792Snp t4_get_port_stats(pi->adapter, pi->tx_chan, s); 2943218792Snp 2944228561Snp ifp->if_opackets = s->tx_frames - s->tx_pause; 2945228561Snp ifp->if_ipackets = s->rx_frames - s->rx_pause; 2946228561Snp ifp->if_obytes = s->tx_octets - s->tx_pause * 64; 2947228561Snp ifp->if_ibytes = s->rx_octets - s->rx_pause * 64; 2948228561Snp ifp->if_omcasts = s->tx_mcast_frames - s->tx_pause; 2949228561Snp ifp->if_imcasts = s->rx_mcast_frames - s->rx_pause; 2950218792Snp ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 + 2951239259Snp s->rx_ovflow3 + s->rx_trunc0 + s->rx_trunc1 + s->rx_trunc2 + 2952239259Snp s->rx_trunc3; 2953218792Snp 2954218792Snp drops = s->tx_drop; 2955218792Snp for_each_txq(pi, i, txq) 2956220873Snp drops += txq->br->br_drops; 2957218792Snp ifp->if_snd.ifq_drops = drops; 2958218792Snp 2959218792Snp ifp->if_oerrors = s->tx_error_frames; 2960218792Snp ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long + 2961218792Snp s->rx_fcs_err + s->rx_len_err; 2962218792Snp 2963218792Snp callout_schedule(&pi->tick, hz); 2964218792Snp PORT_UNLOCK(pi); 2965218792Snp} 2966218792Snp 2967237263Snpstatic void 2968237263Snpcxgbe_vlan_config(void *arg, struct ifnet *ifp, uint16_t vid) 2969237263Snp{ 2970237263Snp struct ifnet *vlan; 2971237263Snp 2972237263Snp if (arg != ifp) 2973237263Snp return; 2974237263Snp 2975237263Snp vlan = VLAN_DEVAT(ifp, vid); 2976237263Snp VLAN_SETCOOKIE(vlan, ifp); 2977237263Snp} 2978237263Snp 2979218792Snpstatic int 2980228561Snpcpl_not_handled(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 2981228561Snp{ 2982237263Snp 2983228561Snp#ifdef INVARIANTS 2984237263Snp panic("%s: opcode 0x%02x on iq %p with payload %p", 2985228561Snp __func__, rss->opcode, iq, m); 2986228561Snp#else 2987239336Snp log(LOG_ERR, "%s: opcode 0x%02x on iq %p with payload %p\n", 2988228561Snp __func__, rss->opcode, iq, m); 2989228561Snp m_freem(m); 2990228561Snp#endif 2991228561Snp return (EDOOFUS); 2992228561Snp} 2993228561Snp 2994228561Snpint 2995228561Snpt4_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h) 2996228561Snp{ 2997228561Snp uintptr_t *loc, new; 2998228561Snp 2999240452Snp if (opcode >= nitems(sc->cpl_handler)) 3000228561Snp return (EINVAL); 3001228561Snp 3002228561Snp new = h ? (uintptr_t)h : (uintptr_t)cpl_not_handled; 3003228561Snp loc = (uintptr_t *) &sc->cpl_handler[opcode]; 3004228561Snp atomic_store_rel_ptr(loc, new); 3005228561Snp 3006228561Snp return (0); 3007228561Snp} 3008228561Snp 3009228561Snpstatic int 3010237263Snpan_not_handled(struct sge_iq *iq, const struct rsp_ctrl *ctrl) 3011237263Snp{ 3012237263Snp 3013237263Snp#ifdef INVARIANTS 3014237263Snp panic("%s: async notification on iq %p (ctrl %p)", __func__, iq, ctrl); 3015237263Snp#else 3016239336Snp log(LOG_ERR, "%s: async notification on iq %p (ctrl %p)\n", 3017237263Snp __func__, iq, ctrl); 3018237263Snp#endif 3019237263Snp return (EDOOFUS); 3020237263Snp} 3021237263Snp 3022237263Snpint 3023237263Snpt4_register_an_handler(struct adapter *sc, an_handler_t h) 3024237263Snp{ 3025237263Snp uintptr_t *loc, new; 3026237263Snp 3027237263Snp new = h ? (uintptr_t)h : (uintptr_t)an_not_handled; 3028237263Snp loc = (uintptr_t *) &sc->an_handler; 3029237263Snp atomic_store_rel_ptr(loc, new); 3030237263Snp 3031237263Snp return (0); 3032237263Snp} 3033237263Snp 3034237263Snpstatic int 3035239336Snpfw_msg_not_handled(struct adapter *sc, const __be64 *rpl) 3036239336Snp{ 3037239336Snp __be64 *r = __DECONST(__be64 *, rpl); 3038239336Snp struct cpl_fw6_msg *cpl = member2struct(cpl_fw6_msg, data, r); 3039239336Snp 3040239336Snp#ifdef INVARIANTS 3041239336Snp panic("%s: fw_msg type %d", __func__, cpl->type); 3042239336Snp#else 3043239336Snp log(LOG_ERR, "%s: fw_msg type %d\n", __func__, cpl->type); 3044239336Snp#endif 3045239336Snp return (EDOOFUS); 3046239336Snp} 3047239336Snp 3048239336Snpint 3049239336Snpt4_register_fw_msg_handler(struct adapter *sc, int type, fw_msg_handler_t h) 3050239336Snp{ 3051239336Snp uintptr_t *loc, new; 3052239336Snp 3053240452Snp if (type >= nitems(sc->fw_msg_handler)) 3054239336Snp return (EINVAL); 3055239336Snp 3056239336Snp new = h ? (uintptr_t)h : (uintptr_t)fw_msg_not_handled; 3057239336Snp loc = (uintptr_t *) &sc->fw_msg_handler[type]; 3058239336Snp atomic_store_rel_ptr(loc, new); 3059239336Snp 3060239336Snp return (0); 3061239336Snp} 3062239336Snp 3063239336Snpstatic int 3064218792Snpt4_sysctls(struct adapter *sc) 3065218792Snp{ 3066218792Snp struct sysctl_ctx_list *ctx; 3067218792Snp struct sysctl_oid *oid; 3068228561Snp struct sysctl_oid_list *children, *c0; 3069228561Snp static char *caps[] = { 3070228561Snp "\20\1PPP\2QFC\3DCBX", /* caps[0] linkcaps */ 3071228561Snp "\20\1NIC\2VM\3IDS\4UM\5UM_ISGL", /* caps[1] niccaps */ 3072228561Snp "\20\1TOE", /* caps[2] toecaps */ 3073228561Snp "\20\1RDDP\2RDMAC", /* caps[3] rdmacaps */ 3074228561Snp "\20\1INITIATOR_PDU\2TARGET_PDU" /* caps[4] iscsicaps */ 3075228561Snp "\3INITIATOR_CNXOFLD\4TARGET_CNXOFLD" 3076228561Snp "\5INITIATOR_SSNOFLD\6TARGET_SSNOFLD", 3077228561Snp "\20\1INITIATOR\2TARGET\3CTRL_OFLD" /* caps[5] fcoecaps */ 3078228561Snp }; 3079218792Snp 3080218792Snp ctx = device_get_sysctl_ctx(sc->dev); 3081228561Snp 3082228561Snp /* 3083228561Snp * dev.t4nex.X. 3084228561Snp */ 3085218792Snp oid = device_get_sysctl_tree(sc->dev); 3086228561Snp c0 = children = SYSCTL_CHILDREN(oid); 3087218792Snp 3088218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, 3089218792Snp &sc->params.nports, 0, "# of ports"); 3090218792Snp 3091218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD, 3092218792Snp &sc->params.rev, 0, "chip hardware revision"); 3093218792Snp 3094218792Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 3095218792Snp CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 3096218792Snp 3097228561Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "cf", 3098228561Snp CTLFLAG_RD, &t4_cfg_file, 0, "configuration file"); 3099218792Snp 3100228561Snp SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cfcsum", CTLFLAG_RD, 3101228561Snp &sc->cfcsum, 0, "config file checksum"); 3102228561Snp 3103228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkcaps", 3104228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[0], sc->linkcaps, 3105228561Snp sysctl_bitfield, "A", "available link capabilities"); 3106228561Snp 3107228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "niccaps", 3108228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[1], sc->niccaps, 3109228561Snp sysctl_bitfield, "A", "available NIC capabilities"); 3110228561Snp 3111228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "toecaps", 3112228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[2], sc->toecaps, 3113228561Snp sysctl_bitfield, "A", "available TCP offload capabilities"); 3114228561Snp 3115228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdmacaps", 3116228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[3], sc->rdmacaps, 3117228561Snp sysctl_bitfield, "A", "available RDMA capabilities"); 3118228561Snp 3119228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "iscsicaps", 3120228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[4], sc->iscsicaps, 3121228561Snp sysctl_bitfield, "A", "available iSCSI capabilities"); 3122228561Snp 3123228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoecaps", 3124228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[5], sc->fcoecaps, 3125228561Snp sysctl_bitfield, "A", "available FCoE capabilities"); 3126228561Snp 3127218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, 3128218792Snp &sc->params.vpd.cclk, 0, "core clock frequency (in KHz)"); 3129218792Snp 3130219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers", 3131228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.timer_val, 3132228561Snp sizeof(sc->sge.timer_val), sysctl_int_array, "A", 3133228561Snp "interrupt holdoff timer values (us)"); 3134218792Snp 3135219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts", 3136228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.counter_val, 3137228561Snp sizeof(sc->sge.counter_val), sysctl_int_array, "A", 3138228561Snp "interrupt holdoff packet counter values"); 3139218792Snp 3140231115Snp#ifdef SBUF_DRAIN 3141228561Snp /* 3142228561Snp * dev.t4nex.X.misc. Marked CTLFLAG_SKIP to avoid information overload. 3143228561Snp */ 3144228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "misc", 3145228561Snp CTLFLAG_RD | CTLFLAG_SKIP, NULL, 3146228561Snp "logs and miscellaneous information"); 3147228561Snp children = SYSCTL_CHILDREN(oid); 3148228561Snp 3149228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cctrl", 3150228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3151228561Snp sysctl_cctrl, "A", "congestion control"); 3152228561Snp 3153228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats", 3154228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3155228561Snp sysctl_cpl_stats, "A", "CPL statistics"); 3156228561Snp 3157228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ddp_stats", 3158228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3159228561Snp sysctl_ddp_stats, "A", "DDP statistics"); 3160228561Snp 3161222551Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog", 3162222551Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3163228561Snp sysctl_devlog, "A", "firmware's device log"); 3164222551Snp 3165228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoe_stats", 3166228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3167228561Snp sysctl_fcoe_stats, "A", "FCoE statistics"); 3168228561Snp 3169228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hw_sched", 3170228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3171228561Snp sysctl_hw_sched, "A", "hardware scheduler "); 3172228561Snp 3173228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "l2t", 3174228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3175228561Snp sysctl_l2t, "A", "hardware L2 table"); 3176228561Snp 3177228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats", 3178228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3179228561Snp sysctl_lb_stats, "A", "loopback statistics"); 3180228561Snp 3181228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "meminfo", 3182228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3183228561Snp sysctl_meminfo, "A", "memory regions"); 3184228561Snp 3185228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "path_mtus", 3186228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3187228561Snp sysctl_path_mtus, "A", "path MTUs"); 3188228561Snp 3189228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pm_stats", 3190228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3191228561Snp sysctl_pm_stats, "A", "PM statistics"); 3192228561Snp 3193228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_stats", 3194228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3195228561Snp sysctl_rdma_stats, "A", "RDMA statistics"); 3196228561Snp 3197228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tcp_stats", 3198228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3199228561Snp sysctl_tcp_stats, "A", "TCP statistics"); 3200228561Snp 3201228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tids", 3202228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3203228561Snp sysctl_tids, "A", "TID information"); 3204228561Snp 3205228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_err_stats", 3206228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3207228561Snp sysctl_tp_err_stats, "A", "TP error statistics"); 3208228561Snp 3209228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_rate", 3210228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3211228561Snp sysctl_tx_rate, "A", "Tx rate"); 3212231115Snp#endif 3213228561Snp 3214237263Snp#ifdef TCP_OFFLOAD 3215228561Snp if (is_offload(sc)) { 3216228561Snp /* 3217228561Snp * dev.t4nex.X.toe. 3218228561Snp */ 3219228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "toe", CTLFLAG_RD, 3220228561Snp NULL, "TOE parameters"); 3221228561Snp children = SYSCTL_CHILDREN(oid); 3222228561Snp 3223228561Snp sc->tt.sndbuf = 256 * 1024; 3224228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "sndbuf", CTLFLAG_RW, 3225228561Snp &sc->tt.sndbuf, 0, "max hardware send buffer size"); 3226228561Snp 3227228561Snp sc->tt.ddp = 0; 3228228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp", CTLFLAG_RW, 3229228561Snp &sc->tt.ddp, 0, "DDP allowed"); 3230239341Snp 3231239341Snp sc->tt.indsz = G_INDICATESIZE(t4_read_reg(sc, A_TP_PARA_REG5)); 3232228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "indsz", CTLFLAG_RW, 3233228561Snp &sc->tt.indsz, 0, "DDP max indicate size allowed"); 3234239341Snp 3235239341Snp sc->tt.ddp_thres = 3236239341Snp G_RXCOALESCESIZE(t4_read_reg(sc, A_TP_PARA_REG2)); 3237228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp_thres", CTLFLAG_RW, 3238228561Snp &sc->tt.ddp_thres, 0, "DDP threshold"); 3239228561Snp } 3240228561Snp#endif 3241228561Snp 3242228561Snp 3243218792Snp return (0); 3244218792Snp} 3245218792Snp 3246218792Snpstatic int 3247218792Snpcxgbe_sysctls(struct port_info *pi) 3248218792Snp{ 3249218792Snp struct sysctl_ctx_list *ctx; 3250218792Snp struct sysctl_oid *oid; 3251218792Snp struct sysctl_oid_list *children; 3252218792Snp 3253218792Snp ctx = device_get_sysctl_ctx(pi->dev); 3254218792Snp 3255218792Snp /* 3256218792Snp * dev.cxgbe.X. 3257218792Snp */ 3258218792Snp oid = device_get_sysctl_tree(pi->dev); 3259218792Snp children = SYSCTL_CHILDREN(oid); 3260218792Snp 3261218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD, 3262218792Snp &pi->nrxq, 0, "# of rx queues"); 3263218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD, 3264218792Snp &pi->ntxq, 0, "# of tx queues"); 3265218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD, 3266218792Snp &pi->first_rxq, 0, "index of first rx queue"); 3267218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD, 3268218792Snp &pi->first_txq, 0, "index of first tx queue"); 3269218792Snp 3270237263Snp#ifdef TCP_OFFLOAD 3271228561Snp if (is_offload(pi->adapter)) { 3272228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldrxq", CTLFLAG_RD, 3273228561Snp &pi->nofldrxq, 0, 3274228561Snp "# of rx queues for offloaded TCP connections"); 3275228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldtxq", CTLFLAG_RD, 3276228561Snp &pi->nofldtxq, 0, 3277228561Snp "# of tx queues for offloaded TCP connections"); 3278228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_rxq", 3279228561Snp CTLFLAG_RD, &pi->first_ofld_rxq, 0, 3280228561Snp "index of first TOE rx queue"); 3281228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_txq", 3282228561Snp CTLFLAG_RD, &pi->first_ofld_txq, 0, 3283228561Snp "index of first TOE tx queue"); 3284228561Snp } 3285228561Snp#endif 3286228561Snp 3287218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx", 3288218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I", 3289218792Snp "holdoff timer index"); 3290218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx", 3291218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I", 3292218792Snp "holdoff packet counter index"); 3293218792Snp 3294218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq", 3295218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I", 3296218792Snp "rx queue size"); 3297218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq", 3298218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I", 3299218792Snp "tx queue size"); 3300218792Snp 3301218792Snp /* 3302218792Snp * dev.cxgbe.X.stats. 3303218792Snp */ 3304218792Snp oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, 3305218792Snp NULL, "port statistics"); 3306218792Snp children = SYSCTL_CHILDREN(oid); 3307218792Snp 3308218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \ 3309218792Snp SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \ 3310218792Snp CTLTYPE_U64 | CTLFLAG_RD, pi->adapter, reg, \ 3311218792Snp sysctl_handle_t4_reg64, "QU", desc) 3312218792Snp 3313218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames", 3314218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L)); 3315218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames", 3316218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L)); 3317218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames", 3318218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L)); 3319218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames", 3320218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L)); 3321218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames", 3322218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L)); 3323218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames", 3324218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L)); 3325218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_64", 3326218792Snp "# of tx frames in this range", 3327218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L)); 3328218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127", 3329218792Snp "# of tx frames in this range", 3330218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L)); 3331218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255", 3332218792Snp "# of tx frames in this range", 3333218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L)); 3334218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511", 3335218792Snp "# of tx frames in this range", 3336218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L)); 3337218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023", 3338218792Snp "# of tx frames in this range", 3339218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L)); 3340218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518", 3341218792Snp "# of tx frames in this range", 3342218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L)); 3343218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max", 3344218792Snp "# of tx frames in this range", 3345218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L)); 3346218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames", 3347218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L)); 3348218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted", 3349218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L)); 3350218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted", 3351218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L)); 3352218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted", 3353218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L)); 3354218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted", 3355218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L)); 3356218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted", 3357218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L)); 3358218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted", 3359218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L)); 3360218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted", 3361218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L)); 3362218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted", 3363218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L)); 3364218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted", 3365218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L)); 3366218792Snp 3367218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames", 3368218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L)); 3369218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames", 3370218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L)); 3371218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames", 3372218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L)); 3373218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames", 3374218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L)); 3375218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames", 3376218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L)); 3377218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU", 3378218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L)); 3379218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames", 3380218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L)); 3381218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err", 3382218792Snp "# of frames received with bad FCS", 3383218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L)); 3384218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_len_err", 3385218792Snp "# of frames received with length error", 3386218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L)); 3387218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors", 3388218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L)); 3389218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received", 3390218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L)); 3391218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_64", 3392218792Snp "# of rx frames in this range", 3393218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L)); 3394218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127", 3395218792Snp "# of rx frames in this range", 3396218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L)); 3397218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255", 3398218792Snp "# of rx frames in this range", 3399218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L)); 3400218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511", 3401218792Snp "# of rx frames in this range", 3402218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L)); 3403218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023", 3404218792Snp "# of rx frames in this range", 3405218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L)); 3406218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518", 3407218792Snp "# of rx frames in this range", 3408218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L)); 3409218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max", 3410218792Snp "# of rx frames in this range", 3411218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L)); 3412218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received", 3413218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L)); 3414218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received", 3415218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L)); 3416218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received", 3417218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L)); 3418218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received", 3419218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L)); 3420218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received", 3421218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L)); 3422218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received", 3423218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L)); 3424218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received", 3425218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L)); 3426218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received", 3427218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L)); 3428218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received", 3429218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L)); 3430218792Snp 3431218792Snp#undef SYSCTL_ADD_T4_REG64 3432218792Snp 3433218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \ 3434218792Snp SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \ 3435218792Snp &pi->stats.name, desc) 3436218792Snp 3437218792Snp /* We get these from port_stats and they may be stale by upto 1s */ 3438218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0, 3439218792Snp "# drops due to buffer-group 0 overflows"); 3440218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1, 3441218792Snp "# drops due to buffer-group 1 overflows"); 3442218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2, 3443218792Snp "# drops due to buffer-group 2 overflows"); 3444218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3, 3445218792Snp "# drops due to buffer-group 3 overflows"); 3446218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc0, 3447218792Snp "# of buffer-group 0 truncated packets"); 3448218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc1, 3449218792Snp "# of buffer-group 1 truncated packets"); 3450218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc2, 3451218792Snp "# of buffer-group 2 truncated packets"); 3452218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc3, 3453218792Snp "# of buffer-group 3 truncated packets"); 3454218792Snp 3455218792Snp#undef SYSCTL_ADD_T4_PORTSTAT 3456218792Snp 3457218792Snp return (0); 3458218792Snp} 3459218792Snp 3460218792Snpstatic int 3461219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS) 3462219436Snp{ 3463219436Snp int rc, *i; 3464219436Snp struct sbuf sb; 3465219436Snp 3466219436Snp sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); 3467219436Snp for (i = arg1; arg2; arg2 -= sizeof(int), i++) 3468219436Snp sbuf_printf(&sb, "%d ", *i); 3469219436Snp sbuf_trim(&sb); 3470219436Snp sbuf_finish(&sb); 3471219436Snp rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 3472219436Snp sbuf_delete(&sb); 3473219436Snp return (rc); 3474219436Snp} 3475219436Snp 3476219436Snpstatic int 3477228561Snpsysctl_bitfield(SYSCTL_HANDLER_ARGS) 3478228561Snp{ 3479228561Snp int rc; 3480228561Snp struct sbuf *sb; 3481228561Snp 3482228561Snp rc = sysctl_wire_old_buffer(req, 0); 3483228561Snp if (rc != 0) 3484228561Snp return(rc); 3485228561Snp 3486228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 3487228561Snp if (sb == NULL) 3488228561Snp return (ENOMEM); 3489228561Snp 3490228561Snp sbuf_printf(sb, "%b", (int)arg2, (char *)arg1); 3491228561Snp rc = sbuf_finish(sb); 3492228561Snp sbuf_delete(sb); 3493228561Snp 3494228561Snp return (rc); 3495228561Snp} 3496228561Snp 3497228561Snpstatic int 3498218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS) 3499218792Snp{ 3500218792Snp struct port_info *pi = arg1; 3501218792Snp struct adapter *sc = pi->adapter; 3502218792Snp int idx, rc, i; 3503218792Snp 3504218792Snp idx = pi->tmr_idx; 3505218792Snp 3506218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 3507218792Snp if (rc != 0 || req->newptr == NULL) 3508218792Snp return (rc); 3509218792Snp 3510218792Snp if (idx < 0 || idx >= SGE_NTIMERS) 3511218792Snp return (EINVAL); 3512218792Snp 3513218792Snp ADAPTER_LOCK(sc); 3514218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3515218792Snp if (rc == 0) { 3516228561Snp struct sge_rxq *rxq; 3517228561Snp uint8_t v; 3518228561Snp 3519228561Snp v = V_QINTR_TIMER_IDX(idx) | V_QINTR_CNT_EN(pi->pktc_idx != -1); 3520218792Snp for_each_rxq(pi, i, rxq) { 3521228561Snp#ifdef atomic_store_rel_8 3522228561Snp atomic_store_rel_8(&rxq->iq.intr_params, v); 3523228561Snp#else 3524228561Snp rxq->iq.intr_params = v; 3525228561Snp#endif 3526218792Snp } 3527218792Snp pi->tmr_idx = idx; 3528218792Snp } 3529218792Snp 3530218792Snp ADAPTER_UNLOCK(sc); 3531218792Snp return (rc); 3532218792Snp} 3533218792Snp 3534218792Snpstatic int 3535218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS) 3536218792Snp{ 3537218792Snp struct port_info *pi = arg1; 3538218792Snp struct adapter *sc = pi->adapter; 3539218792Snp int idx, rc; 3540218792Snp 3541218792Snp idx = pi->pktc_idx; 3542218792Snp 3543218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 3544218792Snp if (rc != 0 || req->newptr == NULL) 3545218792Snp return (rc); 3546218792Snp 3547218792Snp if (idx < -1 || idx >= SGE_NCOUNTERS) 3548218792Snp return (EINVAL); 3549218792Snp 3550218792Snp ADAPTER_LOCK(sc); 3551218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3552228561Snp if (rc == 0 && pi->flags & PORT_INIT_DONE) 3553228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 3554218792Snp 3555218792Snp if (rc == 0) 3556218792Snp pi->pktc_idx = idx; 3557218792Snp 3558218792Snp ADAPTER_UNLOCK(sc); 3559218792Snp return (rc); 3560218792Snp} 3561218792Snp 3562218792Snpstatic int 3563218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS) 3564218792Snp{ 3565218792Snp struct port_info *pi = arg1; 3566218792Snp struct adapter *sc = pi->adapter; 3567218792Snp int qsize, rc; 3568218792Snp 3569218792Snp qsize = pi->qsize_rxq; 3570218792Snp 3571218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 3572218792Snp if (rc != 0 || req->newptr == NULL) 3573218792Snp return (rc); 3574218792Snp 3575218792Snp if (qsize < 128 || (qsize & 7)) 3576218792Snp return (EINVAL); 3577218792Snp 3578218792Snp ADAPTER_LOCK(sc); 3579218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3580228561Snp if (rc == 0 && pi->flags & PORT_INIT_DONE) 3581228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 3582218792Snp 3583218792Snp if (rc == 0) 3584218792Snp pi->qsize_rxq = qsize; 3585218792Snp 3586218792Snp ADAPTER_UNLOCK(sc); 3587218792Snp return (rc); 3588218792Snp} 3589218792Snp 3590218792Snpstatic int 3591218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS) 3592218792Snp{ 3593218792Snp struct port_info *pi = arg1; 3594218792Snp struct adapter *sc = pi->adapter; 3595218792Snp int qsize, rc; 3596218792Snp 3597218792Snp qsize = pi->qsize_txq; 3598218792Snp 3599218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 3600218792Snp if (rc != 0 || req->newptr == NULL) 3601218792Snp return (rc); 3602218792Snp 3603218792Snp if (qsize < 128) 3604218792Snp return (EINVAL); 3605218792Snp 3606218792Snp ADAPTER_LOCK(sc); 3607218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3608228561Snp if (rc == 0 && pi->flags & PORT_INIT_DONE) 3609228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 3610218792Snp 3611218792Snp if (rc == 0) 3612218792Snp pi->qsize_txq = qsize; 3613218792Snp 3614218792Snp ADAPTER_UNLOCK(sc); 3615218792Snp return (rc); 3616218792Snp} 3617218792Snp 3618218792Snpstatic int 3619218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS) 3620218792Snp{ 3621218792Snp struct adapter *sc = arg1; 3622218792Snp int reg = arg2; 3623218792Snp uint64_t val; 3624218792Snp 3625218792Snp val = t4_read_reg64(sc, reg); 3626218792Snp 3627218792Snp return (sysctl_handle_64(oidp, &val, 0, req)); 3628218792Snp} 3629218792Snp 3630231115Snp#ifdef SBUF_DRAIN 3631228561Snpstatic int 3632228561Snpsysctl_cctrl(SYSCTL_HANDLER_ARGS) 3633228561Snp{ 3634228561Snp struct adapter *sc = arg1; 3635228561Snp struct sbuf *sb; 3636228561Snp int rc, i; 3637228561Snp uint16_t incr[NMTUS][NCCTRL_WIN]; 3638228561Snp static const char *dec_fac[] = { 3639228561Snp "0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875", 3640228561Snp "0.9375" 3641228561Snp }; 3642228561Snp 3643228561Snp rc = sysctl_wire_old_buffer(req, 0); 3644228561Snp if (rc != 0) 3645228561Snp return (rc); 3646228561Snp 3647228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3648228561Snp if (sb == NULL) 3649228561Snp return (ENOMEM); 3650228561Snp 3651228561Snp t4_read_cong_tbl(sc, incr); 3652228561Snp 3653228561Snp for (i = 0; i < NCCTRL_WIN; ++i) { 3654228561Snp sbuf_printf(sb, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i, 3655228561Snp incr[0][i], incr[1][i], incr[2][i], incr[3][i], incr[4][i], 3656228561Snp incr[5][i], incr[6][i], incr[7][i]); 3657228561Snp sbuf_printf(sb, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n", 3658228561Snp incr[8][i], incr[9][i], incr[10][i], incr[11][i], 3659228561Snp incr[12][i], incr[13][i], incr[14][i], incr[15][i], 3660228561Snp sc->params.a_wnd[i], dec_fac[sc->params.b_wnd[i]]); 3661228561Snp } 3662228561Snp 3663228561Snp rc = sbuf_finish(sb); 3664228561Snp sbuf_delete(sb); 3665228561Snp 3666228561Snp return (rc); 3667228561Snp} 3668228561Snp 3669228561Snpstatic int 3670228561Snpsysctl_cpl_stats(SYSCTL_HANDLER_ARGS) 3671228561Snp{ 3672228561Snp struct adapter *sc = arg1; 3673228561Snp struct sbuf *sb; 3674228561Snp int rc; 3675228561Snp struct tp_cpl_stats stats; 3676228561Snp 3677228561Snp rc = sysctl_wire_old_buffer(req, 0); 3678228561Snp if (rc != 0) 3679228561Snp return (rc); 3680228561Snp 3681228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3682228561Snp if (sb == NULL) 3683228561Snp return (ENOMEM); 3684228561Snp 3685228561Snp t4_tp_get_cpl_stats(sc, &stats); 3686228561Snp 3687228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 3688228561Snp "channel 3\n"); 3689228561Snp sbuf_printf(sb, "CPL requests: %10u %10u %10u %10u\n", 3690228561Snp stats.req[0], stats.req[1], stats.req[2], stats.req[3]); 3691228561Snp sbuf_printf(sb, "CPL responses: %10u %10u %10u %10u", 3692228561Snp stats.rsp[0], stats.rsp[1], stats.rsp[2], stats.rsp[3]); 3693228561Snp 3694228561Snp rc = sbuf_finish(sb); 3695228561Snp sbuf_delete(sb); 3696228561Snp 3697228561Snp return (rc); 3698228561Snp} 3699228561Snp 3700228561Snpstatic int 3701228561Snpsysctl_ddp_stats(SYSCTL_HANDLER_ARGS) 3702228561Snp{ 3703228561Snp struct adapter *sc = arg1; 3704228561Snp struct sbuf *sb; 3705228561Snp int rc; 3706228561Snp struct tp_usm_stats stats; 3707228561Snp 3708228561Snp rc = sysctl_wire_old_buffer(req, 0); 3709228561Snp if (rc != 0) 3710228561Snp return(rc); 3711228561Snp 3712228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3713228561Snp if (sb == NULL) 3714228561Snp return (ENOMEM); 3715228561Snp 3716228561Snp t4_get_usm_stats(sc, &stats); 3717228561Snp 3718228561Snp sbuf_printf(sb, "Frames: %u\n", stats.frames); 3719228561Snp sbuf_printf(sb, "Octets: %ju\n", stats.octets); 3720228561Snp sbuf_printf(sb, "Drops: %u", stats.drops); 3721228561Snp 3722228561Snp rc = sbuf_finish(sb); 3723228561Snp sbuf_delete(sb); 3724228561Snp 3725228561Snp return (rc); 3726228561Snp} 3727228561Snp 3728222551Snpconst char *devlog_level_strings[] = { 3729222551Snp [FW_DEVLOG_LEVEL_EMERG] = "EMERG", 3730222551Snp [FW_DEVLOG_LEVEL_CRIT] = "CRIT", 3731222551Snp [FW_DEVLOG_LEVEL_ERR] = "ERR", 3732222551Snp [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", 3733222551Snp [FW_DEVLOG_LEVEL_INFO] = "INFO", 3734222551Snp [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" 3735222551Snp}; 3736222551Snp 3737222551Snpconst char *devlog_facility_strings[] = { 3738222551Snp [FW_DEVLOG_FACILITY_CORE] = "CORE", 3739222551Snp [FW_DEVLOG_FACILITY_SCHED] = "SCHED", 3740222551Snp [FW_DEVLOG_FACILITY_TIMER] = "TIMER", 3741222551Snp [FW_DEVLOG_FACILITY_RES] = "RES", 3742222551Snp [FW_DEVLOG_FACILITY_HW] = "HW", 3743222551Snp [FW_DEVLOG_FACILITY_FLR] = "FLR", 3744222551Snp [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", 3745222551Snp [FW_DEVLOG_FACILITY_PHY] = "PHY", 3746222551Snp [FW_DEVLOG_FACILITY_MAC] = "MAC", 3747222551Snp [FW_DEVLOG_FACILITY_PORT] = "PORT", 3748222551Snp [FW_DEVLOG_FACILITY_VI] = "VI", 3749222551Snp [FW_DEVLOG_FACILITY_FILTER] = "FILTER", 3750222551Snp [FW_DEVLOG_FACILITY_ACL] = "ACL", 3751222551Snp [FW_DEVLOG_FACILITY_TM] = "TM", 3752222551Snp [FW_DEVLOG_FACILITY_QFC] = "QFC", 3753222551Snp [FW_DEVLOG_FACILITY_DCB] = "DCB", 3754222551Snp [FW_DEVLOG_FACILITY_ETH] = "ETH", 3755222551Snp [FW_DEVLOG_FACILITY_OFLD] = "OFLD", 3756222551Snp [FW_DEVLOG_FACILITY_RI] = "RI", 3757222551Snp [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", 3758222551Snp [FW_DEVLOG_FACILITY_FCOE] = "FCOE", 3759222551Snp [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", 3760222551Snp [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE" 3761222551Snp}; 3762222551Snp 3763222551Snpstatic int 3764222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS) 3765222551Snp{ 3766222551Snp struct adapter *sc = arg1; 3767222551Snp struct devlog_params *dparams = &sc->params.devlog; 3768222551Snp struct fw_devlog_e *buf, *e; 3769222551Snp int i, j, rc, nentries, first = 0; 3770222551Snp struct sbuf *sb; 3771222551Snp uint64_t ftstamp = UINT64_MAX; 3772222551Snp 3773222551Snp if (dparams->start == 0) 3774222551Snp return (ENXIO); 3775222551Snp 3776222551Snp nentries = dparams->size / sizeof(struct fw_devlog_e); 3777222551Snp 3778222551Snp buf = malloc(dparams->size, M_CXGBE, M_NOWAIT); 3779222551Snp if (buf == NULL) 3780222551Snp return (ENOMEM); 3781222551Snp 3782222551Snp rc = -t4_mem_read(sc, dparams->memtype, dparams->start, dparams->size, 3783222551Snp (void *)buf); 3784222551Snp if (rc != 0) 3785222551Snp goto done; 3786222551Snp 3787222551Snp for (i = 0; i < nentries; i++) { 3788222551Snp e = &buf[i]; 3789222551Snp 3790222551Snp if (e->timestamp == 0) 3791222551Snp break; /* end */ 3792222551Snp 3793222551Snp e->timestamp = be64toh(e->timestamp); 3794222551Snp e->seqno = be32toh(e->seqno); 3795222551Snp for (j = 0; j < 8; j++) 3796222551Snp e->params[j] = be32toh(e->params[j]); 3797222551Snp 3798222551Snp if (e->timestamp < ftstamp) { 3799222551Snp ftstamp = e->timestamp; 3800222551Snp first = i; 3801222551Snp } 3802222551Snp } 3803222551Snp 3804222551Snp if (buf[first].timestamp == 0) 3805222551Snp goto done; /* nothing in the log */ 3806222551Snp 3807222551Snp rc = sysctl_wire_old_buffer(req, 0); 3808222551Snp if (rc != 0) 3809222551Snp goto done; 3810222551Snp 3811222551Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3812228561Snp if (sb == NULL) { 3813228561Snp rc = ENOMEM; 3814228561Snp goto done; 3815228561Snp } 3816228561Snp sbuf_printf(sb, "%10s %15s %8s %8s %s\n", 3817222551Snp "Seq#", "Tstamp", "Level", "Facility", "Message"); 3818222551Snp 3819222551Snp i = first; 3820222551Snp do { 3821222551Snp e = &buf[i]; 3822222551Snp if (e->timestamp == 0) 3823222551Snp break; /* end */ 3824222551Snp 3825222551Snp sbuf_printf(sb, "%10d %15ju %8s %8s ", 3826222551Snp e->seqno, e->timestamp, 3827240452Snp (e->level < nitems(devlog_level_strings) ? 3828222551Snp devlog_level_strings[e->level] : "UNKNOWN"), 3829240452Snp (e->facility < nitems(devlog_facility_strings) ? 3830222551Snp devlog_facility_strings[e->facility] : "UNKNOWN")); 3831222551Snp sbuf_printf(sb, e->fmt, e->params[0], e->params[1], 3832222551Snp e->params[2], e->params[3], e->params[4], 3833222551Snp e->params[5], e->params[6], e->params[7]); 3834222551Snp 3835222551Snp if (++i == nentries) 3836222551Snp i = 0; 3837222551Snp } while (i != first); 3838222551Snp 3839222551Snp rc = sbuf_finish(sb); 3840222551Snp sbuf_delete(sb); 3841222551Snpdone: 3842222551Snp free(buf, M_CXGBE); 3843222551Snp return (rc); 3844222551Snp} 3845222551Snp 3846228561Snpstatic int 3847228561Snpsysctl_fcoe_stats(SYSCTL_HANDLER_ARGS) 3848228561Snp{ 3849228561Snp struct adapter *sc = arg1; 3850228561Snp struct sbuf *sb; 3851228561Snp int rc; 3852228561Snp struct tp_fcoe_stats stats[4]; 3853228561Snp 3854228561Snp rc = sysctl_wire_old_buffer(req, 0); 3855228561Snp if (rc != 0) 3856228561Snp return (rc); 3857228561Snp 3858228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3859228561Snp if (sb == NULL) 3860228561Snp return (ENOMEM); 3861228561Snp 3862228561Snp t4_get_fcoe_stats(sc, 0, &stats[0]); 3863228561Snp t4_get_fcoe_stats(sc, 1, &stats[1]); 3864228561Snp t4_get_fcoe_stats(sc, 2, &stats[2]); 3865228561Snp t4_get_fcoe_stats(sc, 3, &stats[3]); 3866228561Snp 3867228561Snp sbuf_printf(sb, " channel 0 channel 1 " 3868228561Snp "channel 2 channel 3\n"); 3869228561Snp sbuf_printf(sb, "octetsDDP: %16ju %16ju %16ju %16ju\n", 3870228561Snp stats[0].octetsDDP, stats[1].octetsDDP, stats[2].octetsDDP, 3871228561Snp stats[3].octetsDDP); 3872228561Snp sbuf_printf(sb, "framesDDP: %16u %16u %16u %16u\n", stats[0].framesDDP, 3873228561Snp stats[1].framesDDP, stats[2].framesDDP, stats[3].framesDDP); 3874228561Snp sbuf_printf(sb, "framesDrop: %16u %16u %16u %16u", 3875228561Snp stats[0].framesDrop, stats[1].framesDrop, stats[2].framesDrop, 3876228561Snp stats[3].framesDrop); 3877228561Snp 3878228561Snp rc = sbuf_finish(sb); 3879228561Snp sbuf_delete(sb); 3880228561Snp 3881228561Snp return (rc); 3882228561Snp} 3883228561Snp 3884228561Snpstatic int 3885228561Snpsysctl_hw_sched(SYSCTL_HANDLER_ARGS) 3886228561Snp{ 3887228561Snp struct adapter *sc = arg1; 3888228561Snp struct sbuf *sb; 3889228561Snp int rc, i; 3890228561Snp unsigned int map, kbps, ipg, mode; 3891228561Snp unsigned int pace_tab[NTX_SCHED]; 3892228561Snp 3893228561Snp rc = sysctl_wire_old_buffer(req, 0); 3894228561Snp if (rc != 0) 3895228561Snp return (rc); 3896228561Snp 3897228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3898228561Snp if (sb == NULL) 3899228561Snp return (ENOMEM); 3900228561Snp 3901228561Snp map = t4_read_reg(sc, A_TP_TX_MOD_QUEUE_REQ_MAP); 3902228561Snp mode = G_TIMERMODE(t4_read_reg(sc, A_TP_MOD_CONFIG)); 3903228561Snp t4_read_pace_tbl(sc, pace_tab); 3904228561Snp 3905228561Snp sbuf_printf(sb, "Scheduler Mode Channel Rate (Kbps) " 3906228561Snp "Class IPG (0.1 ns) Flow IPG (us)"); 3907228561Snp 3908228561Snp for (i = 0; i < NTX_SCHED; ++i, map >>= 2) { 3909228561Snp t4_get_tx_sched(sc, i, &kbps, &ipg); 3910228561Snp sbuf_printf(sb, "\n %u %-5s %u ", i, 3911228561Snp (mode & (1 << i)) ? "flow" : "class", map & 3); 3912228561Snp if (kbps) 3913228561Snp sbuf_printf(sb, "%9u ", kbps); 3914228561Snp else 3915228561Snp sbuf_printf(sb, " disabled "); 3916228561Snp 3917228561Snp if (ipg) 3918228561Snp sbuf_printf(sb, "%13u ", ipg); 3919228561Snp else 3920228561Snp sbuf_printf(sb, " disabled "); 3921228561Snp 3922228561Snp if (pace_tab[i]) 3923228561Snp sbuf_printf(sb, "%10u", pace_tab[i]); 3924228561Snp else 3925228561Snp sbuf_printf(sb, " disabled"); 3926228561Snp } 3927228561Snp 3928228561Snp rc = sbuf_finish(sb); 3929228561Snp sbuf_delete(sb); 3930228561Snp 3931228561Snp return (rc); 3932228561Snp} 3933228561Snp 3934228561Snpstatic int 3935228561Snpsysctl_lb_stats(SYSCTL_HANDLER_ARGS) 3936228561Snp{ 3937228561Snp struct adapter *sc = arg1; 3938228561Snp struct sbuf *sb; 3939228561Snp int rc, i, j; 3940228561Snp uint64_t *p0, *p1; 3941228561Snp struct lb_port_stats s[2]; 3942228561Snp static const char *stat_name[] = { 3943228561Snp "OctetsOK:", "FramesOK:", "BcastFrames:", "McastFrames:", 3944228561Snp "UcastFrames:", "ErrorFrames:", "Frames64:", "Frames65To127:", 3945228561Snp "Frames128To255:", "Frames256To511:", "Frames512To1023:", 3946228561Snp "Frames1024To1518:", "Frames1519ToMax:", "FramesDropped:", 3947228561Snp "BG0FramesDropped:", "BG1FramesDropped:", "BG2FramesDropped:", 3948228561Snp "BG3FramesDropped:", "BG0FramesTrunc:", "BG1FramesTrunc:", 3949228561Snp "BG2FramesTrunc:", "BG3FramesTrunc:" 3950228561Snp }; 3951228561Snp 3952228561Snp rc = sysctl_wire_old_buffer(req, 0); 3953228561Snp if (rc != 0) 3954228561Snp return (rc); 3955228561Snp 3956228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3957228561Snp if (sb == NULL) 3958228561Snp return (ENOMEM); 3959228561Snp 3960228561Snp memset(s, 0, sizeof(s)); 3961228561Snp 3962228561Snp for (i = 0; i < 4; i += 2) { 3963228561Snp t4_get_lb_stats(sc, i, &s[0]); 3964228561Snp t4_get_lb_stats(sc, i + 1, &s[1]); 3965228561Snp 3966228561Snp p0 = &s[0].octets; 3967228561Snp p1 = &s[1].octets; 3968228561Snp sbuf_printf(sb, "%s Loopback %u" 3969228561Snp " Loopback %u", i == 0 ? "" : "\n", i, i + 1); 3970228561Snp 3971240452Snp for (j = 0; j < nitems(stat_name); j++) 3972228561Snp sbuf_printf(sb, "\n%-17s %20ju %20ju", stat_name[j], 3973228561Snp *p0++, *p1++); 3974228561Snp } 3975228561Snp 3976228561Snp rc = sbuf_finish(sb); 3977228561Snp sbuf_delete(sb); 3978228561Snp 3979228561Snp return (rc); 3980228561Snp} 3981228561Snp 3982228561Snpstruct mem_desc { 3983228561Snp unsigned int base; 3984228561Snp unsigned int limit; 3985228561Snp unsigned int idx; 3986228561Snp}; 3987228561Snp 3988228561Snpstatic int 3989228561Snpmem_desc_cmp(const void *a, const void *b) 3990228561Snp{ 3991228561Snp return ((const struct mem_desc *)a)->base - 3992228561Snp ((const struct mem_desc *)b)->base; 3993228561Snp} 3994228561Snp 3995228561Snpstatic void 3996228561Snpmem_region_show(struct sbuf *sb, const char *name, unsigned int from, 3997228561Snp unsigned int to) 3998228561Snp{ 3999228561Snp unsigned int size; 4000228561Snp 4001228561Snp size = to - from + 1; 4002228561Snp if (size == 0) 4003228561Snp return; 4004228561Snp 4005228561Snp /* XXX: need humanize_number(3) in libkern for a more readable 'size' */ 4006228561Snp sbuf_printf(sb, "%-15s %#x-%#x [%u]\n", name, from, to, size); 4007228561Snp} 4008228561Snp 4009228561Snpstatic int 4010228561Snpsysctl_meminfo(SYSCTL_HANDLER_ARGS) 4011228561Snp{ 4012228561Snp struct adapter *sc = arg1; 4013228561Snp struct sbuf *sb; 4014228561Snp int rc, i, n; 4015228561Snp uint32_t lo, hi; 4016228561Snp static const char *memory[] = { "EDC0:", "EDC1:", "MC:" }; 4017228561Snp static const char *region[] = { 4018228561Snp "DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:", 4019228561Snp "Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:", 4020228561Snp "Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:", 4021228561Snp "TDDP region:", "TPT region:", "STAG region:", "RQ region:", 4022228561Snp "RQUDP region:", "PBL region:", "TXPBL region:", "ULPRX state:", 4023228561Snp "ULPTX state:", "On-chip queues:" 4024228561Snp }; 4025228561Snp struct mem_desc avail[3]; 4026240452Snp struct mem_desc mem[nitems(region) + 3]; /* up to 3 holes */ 4027228561Snp struct mem_desc *md = mem; 4028228561Snp 4029228561Snp rc = sysctl_wire_old_buffer(req, 0); 4030228561Snp if (rc != 0) 4031228561Snp return (rc); 4032228561Snp 4033228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 4034228561Snp if (sb == NULL) 4035228561Snp return (ENOMEM); 4036228561Snp 4037240452Snp for (i = 0; i < nitems(mem); i++) { 4038228561Snp mem[i].limit = 0; 4039228561Snp mem[i].idx = i; 4040228561Snp } 4041228561Snp 4042228561Snp /* Find and sort the populated memory ranges */ 4043228561Snp i = 0; 4044228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 4045228561Snp if (lo & F_EDRAM0_ENABLE) { 4046228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 4047228561Snp avail[i].base = G_EDRAM0_BASE(hi) << 20; 4048228561Snp avail[i].limit = avail[i].base + (G_EDRAM0_SIZE(hi) << 20); 4049228561Snp avail[i].idx = 0; 4050228561Snp i++; 4051228561Snp } 4052228561Snp if (lo & F_EDRAM1_ENABLE) { 4053228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 4054228561Snp avail[i].base = G_EDRAM1_BASE(hi) << 20; 4055228561Snp avail[i].limit = avail[i].base + (G_EDRAM1_SIZE(hi) << 20); 4056228561Snp avail[i].idx = 1; 4057228561Snp i++; 4058228561Snp } 4059228561Snp if (lo & F_EXT_MEM_ENABLE) { 4060228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 4061228561Snp avail[i].base = G_EXT_MEM_BASE(hi) << 20; 4062228561Snp avail[i].limit = avail[i].base + (G_EXT_MEM_SIZE(hi) << 20); 4063228561Snp avail[i].idx = 2; 4064228561Snp i++; 4065228561Snp } 4066228561Snp if (!i) /* no memory available */ 4067228561Snp return 0; 4068228561Snp qsort(avail, i, sizeof(struct mem_desc), mem_desc_cmp); 4069228561Snp 4070228561Snp (md++)->base = t4_read_reg(sc, A_SGE_DBQ_CTXT_BADDR); 4071228561Snp (md++)->base = t4_read_reg(sc, A_SGE_IMSG_CTXT_BADDR); 4072228561Snp (md++)->base = t4_read_reg(sc, A_SGE_FLM_CACHE_BADDR); 4073228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 4074228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_BASE); 4075228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TIMER_BASE); 4076228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_RX_FLST_BASE); 4077228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_TX_FLST_BASE); 4078228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_PS_FLST_BASE); 4079228561Snp 4080228561Snp /* the next few have explicit upper bounds */ 4081228561Snp md->base = t4_read_reg(sc, A_TP_PMM_TX_BASE); 4082228561Snp md->limit = md->base - 1 + 4083228561Snp t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE) * 4084228561Snp G_PMTXMAXPAGE(t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE)); 4085228561Snp md++; 4086228561Snp 4087228561Snp md->base = t4_read_reg(sc, A_TP_PMM_RX_BASE); 4088228561Snp md->limit = md->base - 1 + 4089228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) * 4090228561Snp G_PMRXMAXPAGE(t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE)); 4091228561Snp md++; 4092228561Snp 4093228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 4094228561Snp hi = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4; 4095228561Snp md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE); 4096228561Snp md->limit = (sc->tids.ntids - hi) * 16 + md->base - 1; 4097228561Snp } else { 4098228561Snp md->base = 0; 4099240452Snp md->idx = nitems(region); /* hide it */ 4100228561Snp } 4101228561Snp md++; 4102228561Snp 4103228561Snp#define ulp_region(reg) \ 4104228561Snp md->base = t4_read_reg(sc, A_ULP_ ## reg ## _LLIMIT);\ 4105228561Snp (md++)->limit = t4_read_reg(sc, A_ULP_ ## reg ## _ULIMIT) 4106228561Snp 4107228561Snp ulp_region(RX_ISCSI); 4108228561Snp ulp_region(RX_TDDP); 4109228561Snp ulp_region(TX_TPT); 4110228561Snp ulp_region(RX_STAG); 4111228561Snp ulp_region(RX_RQ); 4112228561Snp ulp_region(RX_RQUDP); 4113228561Snp ulp_region(RX_PBL); 4114228561Snp ulp_region(TX_PBL); 4115228561Snp#undef ulp_region 4116228561Snp 4117228561Snp md->base = t4_read_reg(sc, A_ULP_RX_CTX_BASE); 4118228561Snp md->limit = md->base + sc->tids.ntids - 1; 4119228561Snp md++; 4120228561Snp md->base = t4_read_reg(sc, A_ULP_TX_ERR_TABLE_BASE); 4121228561Snp md->limit = md->base + sc->tids.ntids - 1; 4122228561Snp md++; 4123228561Snp 4124228561Snp md->base = sc->vres.ocq.start; 4125228561Snp if (sc->vres.ocq.size) 4126228561Snp md->limit = md->base + sc->vres.ocq.size - 1; 4127228561Snp else 4128240452Snp md->idx = nitems(region); /* hide it */ 4129228561Snp md++; 4130228561Snp 4131228561Snp /* add any address-space holes, there can be up to 3 */ 4132228561Snp for (n = 0; n < i - 1; n++) 4133228561Snp if (avail[n].limit < avail[n + 1].base) 4134228561Snp (md++)->base = avail[n].limit; 4135228561Snp if (avail[n].limit) 4136228561Snp (md++)->base = avail[n].limit; 4137228561Snp 4138228561Snp n = md - mem; 4139228561Snp qsort(mem, n, sizeof(struct mem_desc), mem_desc_cmp); 4140228561Snp 4141228561Snp for (lo = 0; lo < i; lo++) 4142228561Snp mem_region_show(sb, memory[avail[lo].idx], avail[lo].base, 4143228561Snp avail[lo].limit - 1); 4144228561Snp 4145228561Snp sbuf_printf(sb, "\n"); 4146228561Snp for (i = 0; i < n; i++) { 4147240452Snp if (mem[i].idx >= nitems(region)) 4148228561Snp continue; /* skip holes */ 4149228561Snp if (!mem[i].limit) 4150228561Snp mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0; 4151228561Snp mem_region_show(sb, region[mem[i].idx], mem[i].base, 4152228561Snp mem[i].limit); 4153228561Snp } 4154228561Snp 4155228561Snp sbuf_printf(sb, "\n"); 4156228561Snp lo = t4_read_reg(sc, A_CIM_SDRAM_BASE_ADDR); 4157228561Snp hi = t4_read_reg(sc, A_CIM_SDRAM_ADDR_SIZE) + lo - 1; 4158228561Snp mem_region_show(sb, "uP RAM:", lo, hi); 4159228561Snp 4160228561Snp lo = t4_read_reg(sc, A_CIM_EXTMEM2_BASE_ADDR); 4161228561Snp hi = t4_read_reg(sc, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1; 4162228561Snp mem_region_show(sb, "uP Extmem2:", lo, hi); 4163228561Snp 4164228561Snp lo = t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE); 4165228561Snp sbuf_printf(sb, "\n%u Rx pages of size %uKiB for %u channels\n", 4166228561Snp G_PMRXMAXPAGE(lo), 4167228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) >> 10, 4168228561Snp (lo & F_PMRXNUMCHN) ? 2 : 1); 4169228561Snp 4170228561Snp lo = t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE); 4171228561Snp hi = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE); 4172228561Snp sbuf_printf(sb, "%u Tx pages of size %u%ciB for %u channels\n", 4173228561Snp G_PMTXMAXPAGE(lo), 4174228561Snp hi >= (1 << 20) ? (hi >> 20) : (hi >> 10), 4175228561Snp hi >= (1 << 20) ? 'M' : 'K', 1 << G_PMTXNUMCHN(lo)); 4176228561Snp sbuf_printf(sb, "%u p-structs\n", 4177228561Snp t4_read_reg(sc, A_TP_CMM_MM_MAX_PSTRUCT)); 4178228561Snp 4179228561Snp for (i = 0; i < 4; i++) { 4180228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV0 + i * 4); 4181228561Snp sbuf_printf(sb, "\nPort %d using %u pages out of %u allocated", 4182228561Snp i, G_USED(lo), G_ALLOC(lo)); 4183228561Snp } 4184228561Snp for (i = 0; i < 4; i++) { 4185228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV4 + i * 4); 4186228561Snp sbuf_printf(sb, 4187228561Snp "\nLoopback %d using %u pages out of %u allocated", 4188228561Snp i, G_USED(lo), G_ALLOC(lo)); 4189228561Snp } 4190228561Snp 4191228561Snp rc = sbuf_finish(sb); 4192228561Snp sbuf_delete(sb); 4193228561Snp 4194228561Snp return (rc); 4195228561Snp} 4196228561Snp 4197228561Snpstatic int 4198228561Snpsysctl_path_mtus(SYSCTL_HANDLER_ARGS) 4199228561Snp{ 4200228561Snp struct adapter *sc = arg1; 4201228561Snp struct sbuf *sb; 4202228561Snp int rc; 4203228561Snp uint16_t mtus[NMTUS]; 4204228561Snp 4205228561Snp rc = sysctl_wire_old_buffer(req, 0); 4206228561Snp if (rc != 0) 4207228561Snp return (rc); 4208228561Snp 4209228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4210228561Snp if (sb == NULL) 4211228561Snp return (ENOMEM); 4212228561Snp 4213228561Snp t4_read_mtu_tbl(sc, mtus, NULL); 4214228561Snp 4215228561Snp sbuf_printf(sb, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", 4216228561Snp mtus[0], mtus[1], mtus[2], mtus[3], mtus[4], mtus[5], mtus[6], 4217228561Snp mtus[7], mtus[8], mtus[9], mtus[10], mtus[11], mtus[12], mtus[13], 4218228561Snp mtus[14], mtus[15]); 4219228561Snp 4220228561Snp rc = sbuf_finish(sb); 4221228561Snp sbuf_delete(sb); 4222228561Snp 4223228561Snp return (rc); 4224228561Snp} 4225228561Snp 4226228561Snpstatic int 4227228561Snpsysctl_pm_stats(SYSCTL_HANDLER_ARGS) 4228228561Snp{ 4229228561Snp struct adapter *sc = arg1; 4230228561Snp struct sbuf *sb; 4231228561Snp int rc, i; 4232228561Snp uint32_t tx_cnt[PM_NSTATS], rx_cnt[PM_NSTATS]; 4233228561Snp uint64_t tx_cyc[PM_NSTATS], rx_cyc[PM_NSTATS]; 4234228561Snp static const char *pm_stats[] = { 4235228561Snp "Read:", "Write bypass:", "Write mem:", "Flush:", "FIFO wait:" 4236228561Snp }; 4237228561Snp 4238228561Snp rc = sysctl_wire_old_buffer(req, 0); 4239228561Snp if (rc != 0) 4240228561Snp return (rc); 4241228561Snp 4242228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4243228561Snp if (sb == NULL) 4244228561Snp return (ENOMEM); 4245228561Snp 4246228561Snp t4_pmtx_get_stats(sc, tx_cnt, tx_cyc); 4247228561Snp t4_pmrx_get_stats(sc, rx_cnt, rx_cyc); 4248228561Snp 4249228561Snp sbuf_printf(sb, " Tx count Tx cycles " 4250228561Snp "Rx count Rx cycles"); 4251228561Snp for (i = 0; i < PM_NSTATS; i++) 4252228561Snp sbuf_printf(sb, "\n%-13s %10u %20ju %10u %20ju", 4253228561Snp pm_stats[i], tx_cnt[i], tx_cyc[i], rx_cnt[i], rx_cyc[i]); 4254228561Snp 4255228561Snp rc = sbuf_finish(sb); 4256228561Snp sbuf_delete(sb); 4257228561Snp 4258228561Snp return (rc); 4259228561Snp} 4260228561Snp 4261228561Snpstatic int 4262228561Snpsysctl_rdma_stats(SYSCTL_HANDLER_ARGS) 4263228561Snp{ 4264228561Snp struct adapter *sc = arg1; 4265228561Snp struct sbuf *sb; 4266228561Snp int rc; 4267228561Snp struct tp_rdma_stats stats; 4268228561Snp 4269228561Snp rc = sysctl_wire_old_buffer(req, 0); 4270228561Snp if (rc != 0) 4271228561Snp return (rc); 4272228561Snp 4273228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4274228561Snp if (sb == NULL) 4275228561Snp return (ENOMEM); 4276228561Snp 4277228561Snp t4_tp_get_rdma_stats(sc, &stats); 4278228561Snp sbuf_printf(sb, "NoRQEModDefferals: %u\n", stats.rqe_dfr_mod); 4279228561Snp sbuf_printf(sb, "NoRQEPktDefferals: %u", stats.rqe_dfr_pkt); 4280228561Snp 4281228561Snp rc = sbuf_finish(sb); 4282228561Snp sbuf_delete(sb); 4283228561Snp 4284228561Snp return (rc); 4285228561Snp} 4286228561Snp 4287228561Snpstatic int 4288228561Snpsysctl_tcp_stats(SYSCTL_HANDLER_ARGS) 4289228561Snp{ 4290228561Snp struct adapter *sc = arg1; 4291228561Snp struct sbuf *sb; 4292228561Snp int rc; 4293228561Snp struct tp_tcp_stats v4, v6; 4294228561Snp 4295228561Snp rc = sysctl_wire_old_buffer(req, 0); 4296228561Snp if (rc != 0) 4297228561Snp return (rc); 4298228561Snp 4299228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4300228561Snp if (sb == NULL) 4301228561Snp return (ENOMEM); 4302228561Snp 4303228561Snp t4_tp_get_tcp_stats(sc, &v4, &v6); 4304228561Snp sbuf_printf(sb, 4305228561Snp " IP IPv6\n"); 4306228561Snp sbuf_printf(sb, "OutRsts: %20u %20u\n", 4307228561Snp v4.tcpOutRsts, v6.tcpOutRsts); 4308228561Snp sbuf_printf(sb, "InSegs: %20ju %20ju\n", 4309228561Snp v4.tcpInSegs, v6.tcpInSegs); 4310228561Snp sbuf_printf(sb, "OutSegs: %20ju %20ju\n", 4311228561Snp v4.tcpOutSegs, v6.tcpOutSegs); 4312228561Snp sbuf_printf(sb, "RetransSegs: %20ju %20ju", 4313228561Snp v4.tcpRetransSegs, v6.tcpRetransSegs); 4314228561Snp 4315228561Snp rc = sbuf_finish(sb); 4316228561Snp sbuf_delete(sb); 4317228561Snp 4318228561Snp return (rc); 4319228561Snp} 4320228561Snp 4321228561Snpstatic int 4322228561Snpsysctl_tids(SYSCTL_HANDLER_ARGS) 4323228561Snp{ 4324228561Snp struct adapter *sc = arg1; 4325228561Snp struct sbuf *sb; 4326228561Snp int rc; 4327228561Snp struct tid_info *t = &sc->tids; 4328228561Snp 4329228561Snp rc = sysctl_wire_old_buffer(req, 0); 4330228561Snp if (rc != 0) 4331228561Snp return (rc); 4332228561Snp 4333228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4334228561Snp if (sb == NULL) 4335228561Snp return (ENOMEM); 4336228561Snp 4337228561Snp if (t->natids) { 4338228561Snp sbuf_printf(sb, "ATID range: 0-%u, in use: %u\n", t->natids - 1, 4339228561Snp t->atids_in_use); 4340228561Snp } 4341228561Snp 4342228561Snp if (t->ntids) { 4343228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 4344228561Snp uint32_t b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4; 4345228561Snp 4346228561Snp if (b) { 4347228561Snp sbuf_printf(sb, "TID range: 0-%u, %u-%u", b - 1, 4348228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 4349228561Snp t->ntids - 1); 4350228561Snp } else { 4351228561Snp sbuf_printf(sb, "TID range: %u-%u", 4352228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 4353228561Snp t->ntids - 1); 4354228561Snp } 4355228561Snp } else 4356228561Snp sbuf_printf(sb, "TID range: 0-%u", t->ntids - 1); 4357228561Snp sbuf_printf(sb, ", in use: %u\n", 4358228561Snp atomic_load_acq_int(&t->tids_in_use)); 4359228561Snp } 4360228561Snp 4361228561Snp if (t->nstids) { 4362228561Snp sbuf_printf(sb, "STID range: %u-%u, in use: %u\n", t->stid_base, 4363228561Snp t->stid_base + t->nstids - 1, t->stids_in_use); 4364228561Snp } 4365228561Snp 4366228561Snp if (t->nftids) { 4367228561Snp sbuf_printf(sb, "FTID range: %u-%u\n", t->ftid_base, 4368228561Snp t->ftid_base + t->nftids - 1); 4369228561Snp } 4370228561Snp 4371228561Snp sbuf_printf(sb, "HW TID usage: %u IP users, %u IPv6 users", 4372228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV4), 4373228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV6)); 4374228561Snp 4375228561Snp rc = sbuf_finish(sb); 4376228561Snp sbuf_delete(sb); 4377228561Snp 4378228561Snp return (rc); 4379228561Snp} 4380228561Snp 4381228561Snpstatic int 4382228561Snpsysctl_tp_err_stats(SYSCTL_HANDLER_ARGS) 4383228561Snp{ 4384228561Snp struct adapter *sc = arg1; 4385228561Snp struct sbuf *sb; 4386228561Snp int rc; 4387228561Snp struct tp_err_stats stats; 4388228561Snp 4389228561Snp rc = sysctl_wire_old_buffer(req, 0); 4390228561Snp if (rc != 0) 4391228561Snp return (rc); 4392228561Snp 4393228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4394228561Snp if (sb == NULL) 4395228561Snp return (ENOMEM); 4396228561Snp 4397228561Snp t4_tp_get_err_stats(sc, &stats); 4398228561Snp 4399228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 4400228561Snp "channel 3\n"); 4401228561Snp sbuf_printf(sb, "macInErrs: %10u %10u %10u %10u\n", 4402228561Snp stats.macInErrs[0], stats.macInErrs[1], stats.macInErrs[2], 4403228561Snp stats.macInErrs[3]); 4404228561Snp sbuf_printf(sb, "hdrInErrs: %10u %10u %10u %10u\n", 4405228561Snp stats.hdrInErrs[0], stats.hdrInErrs[1], stats.hdrInErrs[2], 4406228561Snp stats.hdrInErrs[3]); 4407228561Snp sbuf_printf(sb, "tcpInErrs: %10u %10u %10u %10u\n", 4408228561Snp stats.tcpInErrs[0], stats.tcpInErrs[1], stats.tcpInErrs[2], 4409228561Snp stats.tcpInErrs[3]); 4410228561Snp sbuf_printf(sb, "tcp6InErrs: %10u %10u %10u %10u\n", 4411228561Snp stats.tcp6InErrs[0], stats.tcp6InErrs[1], stats.tcp6InErrs[2], 4412228561Snp stats.tcp6InErrs[3]); 4413228561Snp sbuf_printf(sb, "tnlCongDrops: %10u %10u %10u %10u\n", 4414228561Snp stats.tnlCongDrops[0], stats.tnlCongDrops[1], stats.tnlCongDrops[2], 4415228561Snp stats.tnlCongDrops[3]); 4416228561Snp sbuf_printf(sb, "tnlTxDrops: %10u %10u %10u %10u\n", 4417228561Snp stats.tnlTxDrops[0], stats.tnlTxDrops[1], stats.tnlTxDrops[2], 4418228561Snp stats.tnlTxDrops[3]); 4419228561Snp sbuf_printf(sb, "ofldVlanDrops: %10u %10u %10u %10u\n", 4420228561Snp stats.ofldVlanDrops[0], stats.ofldVlanDrops[1], 4421228561Snp stats.ofldVlanDrops[2], stats.ofldVlanDrops[3]); 4422228561Snp sbuf_printf(sb, "ofldChanDrops: %10u %10u %10u %10u\n\n", 4423228561Snp stats.ofldChanDrops[0], stats.ofldChanDrops[1], 4424228561Snp stats.ofldChanDrops[2], stats.ofldChanDrops[3]); 4425228561Snp sbuf_printf(sb, "ofldNoNeigh: %u\nofldCongDefer: %u", 4426228561Snp stats.ofldNoNeigh, stats.ofldCongDefer); 4427228561Snp 4428228561Snp rc = sbuf_finish(sb); 4429228561Snp sbuf_delete(sb); 4430228561Snp 4431228561Snp return (rc); 4432228561Snp} 4433228561Snp 4434228561Snpstatic int 4435228561Snpsysctl_tx_rate(SYSCTL_HANDLER_ARGS) 4436228561Snp{ 4437228561Snp struct adapter *sc = arg1; 4438228561Snp struct sbuf *sb; 4439228561Snp int rc; 4440228561Snp u64 nrate[NCHAN], orate[NCHAN]; 4441228561Snp 4442228561Snp rc = sysctl_wire_old_buffer(req, 0); 4443228561Snp if (rc != 0) 4444228561Snp return (rc); 4445228561Snp 4446228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4447228561Snp if (sb == NULL) 4448228561Snp return (ENOMEM); 4449228561Snp 4450228561Snp t4_get_chan_txrate(sc, nrate, orate); 4451228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 4452228561Snp "channel 3\n"); 4453228561Snp sbuf_printf(sb, "NIC B/s: %10ju %10ju %10ju %10ju\n", 4454228561Snp nrate[0], nrate[1], nrate[2], nrate[3]); 4455228561Snp sbuf_printf(sb, "Offload B/s: %10ju %10ju %10ju %10ju", 4456228561Snp orate[0], orate[1], orate[2], orate[3]); 4457228561Snp 4458228561Snp rc = sbuf_finish(sb); 4459228561Snp sbuf_delete(sb); 4460228561Snp 4461228561Snp return (rc); 4462228561Snp} 4463231115Snp#endif 4464228561Snp 4465219286Snpstatic inline void 4466219286Snptxq_start(struct ifnet *ifp, struct sge_txq *txq) 4467219286Snp{ 4468219286Snp struct buf_ring *br; 4469219286Snp struct mbuf *m; 4470219286Snp 4471219286Snp TXQ_LOCK_ASSERT_OWNED(txq); 4472219286Snp 4473220873Snp br = txq->br; 4474219286Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 4475219286Snp if (m) 4476219286Snp t4_eth_tx(ifp, txq, m); 4477219286Snp} 4478219286Snp 4479219286Snpvoid 4480228561Snpt4_tx_callout(void *arg) 4481219286Snp{ 4482228561Snp struct sge_eq *eq = arg; 4483228561Snp struct adapter *sc; 4484219286Snp 4485228561Snp if (EQ_TRYLOCK(eq) == 0) 4486228561Snp goto reschedule; 4487228561Snp 4488228561Snp if (eq->flags & EQ_STALLED && !can_resume_tx(eq)) { 4489228561Snp EQ_UNLOCK(eq); 4490228561Snpreschedule: 4491228561Snp if (__predict_true(!(eq->flags && EQ_DOOMED))) 4492228561Snp callout_schedule(&eq->tx_callout, 1); 4493228561Snp return; 4494228561Snp } 4495228561Snp 4496228561Snp EQ_LOCK_ASSERT_OWNED(eq); 4497228561Snp 4498228561Snp if (__predict_true((eq->flags & EQ_DOOMED) == 0)) { 4499228561Snp 4500228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 4501228561Snp struct sge_txq *txq = arg; 4502228561Snp struct port_info *pi = txq->ifp->if_softc; 4503228561Snp 4504228561Snp sc = pi->adapter; 4505228561Snp } else { 4506228561Snp struct sge_wrq *wrq = arg; 4507228561Snp 4508228561Snp sc = wrq->adapter; 4509228561Snp } 4510228561Snp 4511228561Snp taskqueue_enqueue(sc->tq[eq->tx_chan], &eq->tx_task); 4512228561Snp } 4513228561Snp 4514228561Snp EQ_UNLOCK(eq); 4515228561Snp} 4516228561Snp 4517228561Snpvoid 4518228561Snpt4_tx_task(void *arg, int count) 4519228561Snp{ 4520228561Snp struct sge_eq *eq = arg; 4521228561Snp 4522228561Snp EQ_LOCK(eq); 4523228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 4524228561Snp struct sge_txq *txq = arg; 4525220649Snp txq_start(txq->ifp, txq); 4526228561Snp } else { 4527228561Snp struct sge_wrq *wrq = arg; 4528228561Snp t4_wrq_tx_locked(wrq->adapter, wrq, NULL); 4529228561Snp } 4530228561Snp EQ_UNLOCK(eq); 4531219286Snp} 4532219286Snp 4533221474Snpstatic uint32_t 4534221474Snpfconf_to_mode(uint32_t fconf) 4535221474Snp{ 4536221474Snp uint32_t mode; 4537221474Snp 4538221474Snp mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR | 4539221474Snp T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT; 4540221474Snp 4541221474Snp if (fconf & F_FRAGMENTATION) 4542221474Snp mode |= T4_FILTER_IP_FRAGMENT; 4543221474Snp 4544221474Snp if (fconf & F_MPSHITTYPE) 4545221474Snp mode |= T4_FILTER_MPS_HIT_TYPE; 4546221474Snp 4547221474Snp if (fconf & F_MACMATCH) 4548221474Snp mode |= T4_FILTER_MAC_IDX; 4549221474Snp 4550221474Snp if (fconf & F_ETHERTYPE) 4551221474Snp mode |= T4_FILTER_ETH_TYPE; 4552221474Snp 4553221474Snp if (fconf & F_PROTOCOL) 4554221474Snp mode |= T4_FILTER_IP_PROTO; 4555221474Snp 4556221474Snp if (fconf & F_TOS) 4557221474Snp mode |= T4_FILTER_IP_TOS; 4558221474Snp 4559221474Snp if (fconf & F_VLAN) 4560228561Snp mode |= T4_FILTER_VLAN; 4561221474Snp 4562221474Snp if (fconf & F_VNIC_ID) 4563228561Snp mode |= T4_FILTER_VNIC; 4564221474Snp 4565221474Snp if (fconf & F_PORT) 4566221474Snp mode |= T4_FILTER_PORT; 4567221474Snp 4568221474Snp if (fconf & F_FCOE) 4569221474Snp mode |= T4_FILTER_FCoE; 4570221474Snp 4571221474Snp return (mode); 4572221474Snp} 4573221474Snp 4574221474Snpstatic uint32_t 4575221474Snpmode_to_fconf(uint32_t mode) 4576221474Snp{ 4577221474Snp uint32_t fconf = 0; 4578221474Snp 4579221474Snp if (mode & T4_FILTER_IP_FRAGMENT) 4580221474Snp fconf |= F_FRAGMENTATION; 4581221474Snp 4582221474Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 4583221474Snp fconf |= F_MPSHITTYPE; 4584221474Snp 4585221474Snp if (mode & T4_FILTER_MAC_IDX) 4586221474Snp fconf |= F_MACMATCH; 4587221474Snp 4588221474Snp if (mode & T4_FILTER_ETH_TYPE) 4589221474Snp fconf |= F_ETHERTYPE; 4590221474Snp 4591221474Snp if (mode & T4_FILTER_IP_PROTO) 4592221474Snp fconf |= F_PROTOCOL; 4593221474Snp 4594221474Snp if (mode & T4_FILTER_IP_TOS) 4595221474Snp fconf |= F_TOS; 4596221474Snp 4597228561Snp if (mode & T4_FILTER_VLAN) 4598221474Snp fconf |= F_VLAN; 4599221474Snp 4600228561Snp if (mode & T4_FILTER_VNIC) 4601221474Snp fconf |= F_VNIC_ID; 4602221474Snp 4603221474Snp if (mode & T4_FILTER_PORT) 4604221474Snp fconf |= F_PORT; 4605221474Snp 4606221474Snp if (mode & T4_FILTER_FCoE) 4607221474Snp fconf |= F_FCOE; 4608221474Snp 4609221474Snp return (fconf); 4610221474Snp} 4611221474Snp 4612221474Snpstatic uint32_t 4613221474Snpfspec_to_fconf(struct t4_filter_specification *fs) 4614221474Snp{ 4615221474Snp uint32_t fconf = 0; 4616221474Snp 4617221474Snp if (fs->val.frag || fs->mask.frag) 4618221474Snp fconf |= F_FRAGMENTATION; 4619221474Snp 4620221474Snp if (fs->val.matchtype || fs->mask.matchtype) 4621221474Snp fconf |= F_MPSHITTYPE; 4622221474Snp 4623221474Snp if (fs->val.macidx || fs->mask.macidx) 4624221474Snp fconf |= F_MACMATCH; 4625221474Snp 4626221474Snp if (fs->val.ethtype || fs->mask.ethtype) 4627221474Snp fconf |= F_ETHERTYPE; 4628221474Snp 4629221474Snp if (fs->val.proto || fs->mask.proto) 4630221474Snp fconf |= F_PROTOCOL; 4631221474Snp 4632221474Snp if (fs->val.tos || fs->mask.tos) 4633221474Snp fconf |= F_TOS; 4634221474Snp 4635228561Snp if (fs->val.vlan_vld || fs->mask.vlan_vld) 4636221474Snp fconf |= F_VLAN; 4637221474Snp 4638228561Snp if (fs->val.vnic_vld || fs->mask.vnic_vld) 4639221474Snp fconf |= F_VNIC_ID; 4640221474Snp 4641221474Snp if (fs->val.iport || fs->mask.iport) 4642221474Snp fconf |= F_PORT; 4643221474Snp 4644221474Snp if (fs->val.fcoe || fs->mask.fcoe) 4645221474Snp fconf |= F_FCOE; 4646221474Snp 4647221474Snp return (fconf); 4648221474Snp} 4649221474Snp 4650221474Snpstatic int 4651221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode) 4652221474Snp{ 4653221474Snp uint32_t fconf; 4654221474Snp 4655221474Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1, 4656221474Snp A_TP_VLAN_PRI_MAP); 4657221474Snp 4658228561Snp if (sc->filter_mode != fconf) { 4659228561Snp log(LOG_WARNING, "%s: cached filter mode out of sync %x %x.\n", 4660228561Snp device_get_nameunit(sc->dev), sc->filter_mode, fconf); 4661228561Snp sc->filter_mode = fconf; 4662228561Snp } 4663221474Snp 4664228561Snp *mode = fconf_to_mode(sc->filter_mode); 4665228561Snp 4666221474Snp return (0); 4667221474Snp} 4668221474Snp 4669221474Snpstatic int 4670221474Snpset_filter_mode(struct adapter *sc, uint32_t mode) 4671221474Snp{ 4672221474Snp uint32_t fconf; 4673221474Snp int rc; 4674221474Snp 4675221474Snp fconf = mode_to_fconf(mode); 4676221474Snp 4677221474Snp ADAPTER_LOCK(sc); 4678221474Snp if (IS_BUSY(sc)) { 4679221474Snp rc = EAGAIN; 4680221474Snp goto done; 4681221474Snp } 4682221474Snp 4683221474Snp if (sc->tids.ftids_in_use > 0) { 4684221474Snp rc = EBUSY; 4685221474Snp goto done; 4686221474Snp } 4687221474Snp 4688237263Snp#ifdef TCP_OFFLOAD 4689228561Snp if (sc->offload_map) { 4690228561Snp rc = EBUSY; 4691228561Snp goto done; 4692228561Snp } 4693228561Snp#endif 4694228561Snp 4695228561Snp#ifdef notyet 4696221474Snp rc = -t4_set_filter_mode(sc, fconf); 4697228561Snp if (rc == 0) 4698228561Snp sc->filter_mode = fconf; 4699228561Snp#else 4700228561Snp rc = ENOTSUP; 4701228561Snp#endif 4702228561Snp 4703221474Snpdone: 4704221474Snp ADAPTER_UNLOCK(sc); 4705221474Snp return (rc); 4706221474Snp} 4707221474Snp 4708222552Snpstatic inline uint64_t 4709222552Snpget_filter_hits(struct adapter *sc, uint32_t fid) 4710222552Snp{ 4711222552Snp uint32_t tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 4712222552Snp uint64_t hits; 4713222552Snp 4714222552Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0), 4715222552Snp tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE); 4716222552Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0)); 4717222552Snp hits = t4_read_reg64(sc, MEMWIN0_BASE + 16); 4718222552Snp 4719222552Snp return (be64toh(hits)); 4720222552Snp} 4721222552Snp 4722221474Snpstatic int 4723221474Snpget_filter(struct adapter *sc, struct t4_filter *t) 4724221474Snp{ 4725221474Snp int i, nfilters = sc->tids.nftids; 4726221474Snp struct filter_entry *f; 4727221474Snp 4728221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4729221474Snp 4730221474Snp if (IS_BUSY(sc)) 4731221474Snp return (EAGAIN); 4732221474Snp 4733221474Snp if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL || 4734221474Snp t->idx >= nfilters) { 4735221474Snp t->idx = 0xffffffff; 4736221474Snp return (0); 4737221474Snp } 4738221474Snp 4739221474Snp f = &sc->tids.ftid_tab[t->idx]; 4740221474Snp for (i = t->idx; i < nfilters; i++, f++) { 4741221474Snp if (f->valid) { 4742221474Snp t->idx = i; 4743222509Snp t->l2tidx = f->l2t ? f->l2t->idx : 0; 4744222509Snp t->smtidx = f->smtidx; 4745222552Snp if (f->fs.hitcnts) 4746222552Snp t->hits = get_filter_hits(sc, t->idx); 4747222552Snp else 4748222552Snp t->hits = UINT64_MAX; 4749221474Snp t->fs = f->fs; 4750221474Snp 4751221474Snp return (0); 4752221474Snp } 4753221474Snp } 4754221474Snp 4755221474Snp t->idx = 0xffffffff; 4756221474Snp return (0); 4757221474Snp} 4758221474Snp 4759221474Snpstatic int 4760221474Snpset_filter(struct adapter *sc, struct t4_filter *t) 4761221474Snp{ 4762221474Snp unsigned int nfilters, nports; 4763221474Snp struct filter_entry *f; 4764221474Snp int i; 4765221474Snp 4766221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4767221474Snp 4768221474Snp nfilters = sc->tids.nftids; 4769221474Snp nports = sc->params.nports; 4770221474Snp 4771221474Snp if (nfilters == 0) 4772221474Snp return (ENOTSUP); 4773221474Snp 4774221474Snp if (!(sc->flags & FULL_INIT_DONE)) 4775221474Snp return (EAGAIN); 4776221474Snp 4777221474Snp if (t->idx >= nfilters) 4778221474Snp return (EINVAL); 4779221474Snp 4780221474Snp /* Validate against the global filter mode */ 4781228561Snp if ((sc->filter_mode | fspec_to_fconf(&t->fs)) != sc->filter_mode) 4782221474Snp return (E2BIG); 4783221474Snp 4784221474Snp if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) 4785221474Snp return (EINVAL); 4786221474Snp 4787221474Snp if (t->fs.val.iport >= nports) 4788221474Snp return (EINVAL); 4789221474Snp 4790221474Snp /* Can't specify an iq if not steering to it */ 4791221474Snp if (!t->fs.dirsteer && t->fs.iq) 4792221474Snp return (EINVAL); 4793221474Snp 4794221474Snp /* IPv6 filter idx must be 4 aligned */ 4795221474Snp if (t->fs.type == 1 && 4796221474Snp ((t->idx & 0x3) || t->idx + 4 >= nfilters)) 4797221474Snp return (EINVAL); 4798221474Snp 4799221474Snp if (sc->tids.ftid_tab == NULL) { 4800221474Snp KASSERT(sc->tids.ftids_in_use == 0, 4801221474Snp ("%s: no memory allocated but filters_in_use > 0", 4802221474Snp __func__)); 4803221474Snp 4804221474Snp sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) * 4805221474Snp nfilters, M_CXGBE, M_NOWAIT | M_ZERO); 4806221474Snp if (sc->tids.ftid_tab == NULL) 4807221474Snp return (ENOMEM); 4808221474Snp } 4809221474Snp 4810221474Snp for (i = 0; i < 4; i++) { 4811221474Snp f = &sc->tids.ftid_tab[t->idx + i]; 4812221474Snp 4813221474Snp if (f->pending || f->valid) 4814221474Snp return (EBUSY); 4815221474Snp if (f->locked) 4816221474Snp return (EPERM); 4817221474Snp 4818221474Snp if (t->fs.type == 0) 4819221474Snp break; 4820221474Snp } 4821221474Snp 4822221474Snp f = &sc->tids.ftid_tab[t->idx]; 4823221474Snp f->fs = t->fs; 4824221474Snp 4825221474Snp return set_filter_wr(sc, t->idx); 4826221474Snp} 4827221474Snp 4828221474Snpstatic int 4829221474Snpdel_filter(struct adapter *sc, struct t4_filter *t) 4830221474Snp{ 4831221474Snp unsigned int nfilters; 4832221474Snp struct filter_entry *f; 4833221474Snp 4834221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4835221474Snp 4836221474Snp if (IS_BUSY(sc)) 4837221474Snp return (EAGAIN); 4838221474Snp 4839221474Snp nfilters = sc->tids.nftids; 4840221474Snp 4841221474Snp if (nfilters == 0) 4842221474Snp return (ENOTSUP); 4843221474Snp 4844221474Snp if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 || 4845221474Snp t->idx >= nfilters) 4846221474Snp return (EINVAL); 4847221474Snp 4848221474Snp if (!(sc->flags & FULL_INIT_DONE)) 4849221474Snp return (EAGAIN); 4850221474Snp 4851221474Snp f = &sc->tids.ftid_tab[t->idx]; 4852221474Snp 4853221474Snp if (f->pending) 4854221474Snp return (EBUSY); 4855221474Snp if (f->locked) 4856221474Snp return (EPERM); 4857221474Snp 4858221474Snp if (f->valid) { 4859221474Snp t->fs = f->fs; /* extra info for the caller */ 4860221474Snp return del_filter_wr(sc, t->idx); 4861221474Snp } 4862221474Snp 4863221474Snp return (0); 4864221474Snp} 4865221474Snp 4866221474Snpstatic void 4867222509Snpclear_filter(struct filter_entry *f) 4868221474Snp{ 4869222509Snp if (f->l2t) 4870222509Snp t4_l2t_release(f->l2t); 4871222509Snp 4872221474Snp bzero(f, sizeof (*f)); 4873221474Snp} 4874221474Snp 4875221474Snpstatic int 4876221474Snpset_filter_wr(struct adapter *sc, int fidx) 4877221474Snp{ 4878221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 4879237263Snp struct wrqe *wr; 4880221474Snp struct fw_filter_wr *fwr; 4881221474Snp unsigned int ftid; 4882221474Snp 4883221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4884221474Snp 4885222509Snp if (f->fs.newdmac || f->fs.newvlan) { 4886222509Snp /* This filter needs an L2T entry; allocate one. */ 4887222509Snp f->l2t = t4_l2t_alloc_switching(sc->l2t); 4888222509Snp if (f->l2t == NULL) 4889222509Snp return (EAGAIN); 4890222509Snp if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport, 4891222509Snp f->fs.dmac)) { 4892222509Snp t4_l2t_release(f->l2t); 4893222509Snp f->l2t = NULL; 4894222509Snp return (ENOMEM); 4895222509Snp } 4896222509Snp } 4897221474Snp 4898221474Snp ftid = sc->tids.ftid_base + fidx; 4899221474Snp 4900237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 4901237263Snp if (wr == NULL) 4902221474Snp return (ENOMEM); 4903221474Snp 4904237263Snp fwr = wrtod(wr); 4905221474Snp bzero(fwr, sizeof (*fwr)); 4906221474Snp 4907221474Snp fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR)); 4908221474Snp fwr->len16_pkd = htobe32(FW_LEN16(*fwr)); 4909221474Snp fwr->tid_to_iq = 4910221474Snp htobe32(V_FW_FILTER_WR_TID(ftid) | 4911221474Snp V_FW_FILTER_WR_RQTYPE(f->fs.type) | 4912221474Snp V_FW_FILTER_WR_NOREPLY(0) | 4913221474Snp V_FW_FILTER_WR_IQ(f->fs.iq)); 4914221474Snp fwr->del_filter_to_l2tix = 4915221474Snp htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) | 4916221474Snp V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) | 4917221474Snp V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) | 4918221474Snp V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) | 4919221474Snp V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) | 4920221474Snp V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) | 4921221474Snp V_FW_FILTER_WR_DMAC(f->fs.newdmac) | 4922221474Snp V_FW_FILTER_WR_SMAC(f->fs.newsmac) | 4923221474Snp V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT || 4924221474Snp f->fs.newvlan == VLAN_REWRITE) | 4925221474Snp V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE || 4926221474Snp f->fs.newvlan == VLAN_REWRITE) | 4927221474Snp V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) | 4928221474Snp V_FW_FILTER_WR_TXCHAN(f->fs.eport) | 4929221474Snp V_FW_FILTER_WR_PRIO(f->fs.prio) | 4930222509Snp V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0)); 4931221474Snp fwr->ethtype = htobe16(f->fs.val.ethtype); 4932221474Snp fwr->ethtypem = htobe16(f->fs.mask.ethtype); 4933221474Snp fwr->frag_to_ovlan_vldm = 4934221474Snp (V_FW_FILTER_WR_FRAG(f->fs.val.frag) | 4935221474Snp V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) | 4936228561Snp V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) | 4937228561Snp V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.vnic_vld) | 4938228561Snp V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) | 4939228561Snp V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.vnic_vld)); 4940221474Snp fwr->smac_sel = 0; 4941221474Snp fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) | 4942228561Snp V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id)); 4943221474Snp fwr->maci_to_matchtypem = 4944221474Snp htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) | 4945221474Snp V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) | 4946221474Snp V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) | 4947221474Snp V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) | 4948221474Snp V_FW_FILTER_WR_PORT(f->fs.val.iport) | 4949221474Snp V_FW_FILTER_WR_PORTM(f->fs.mask.iport) | 4950221474Snp V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) | 4951221474Snp V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype)); 4952221474Snp fwr->ptcl = f->fs.val.proto; 4953221474Snp fwr->ptclm = f->fs.mask.proto; 4954221474Snp fwr->ttyp = f->fs.val.tos; 4955221474Snp fwr->ttypm = f->fs.mask.tos; 4956228561Snp fwr->ivlan = htobe16(f->fs.val.vlan); 4957228561Snp fwr->ivlanm = htobe16(f->fs.mask.vlan); 4958228561Snp fwr->ovlan = htobe16(f->fs.val.vnic); 4959228561Snp fwr->ovlanm = htobe16(f->fs.mask.vnic); 4960221474Snp bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip)); 4961221474Snp bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm)); 4962221474Snp bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip)); 4963221474Snp bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm)); 4964221474Snp fwr->lp = htobe16(f->fs.val.dport); 4965221474Snp fwr->lpm = htobe16(f->fs.mask.dport); 4966221474Snp fwr->fp = htobe16(f->fs.val.sport); 4967221474Snp fwr->fpm = htobe16(f->fs.mask.sport); 4968221474Snp if (f->fs.newsmac) 4969221474Snp bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma)); 4970221474Snp 4971221474Snp f->pending = 1; 4972221474Snp sc->tids.ftids_in_use++; 4973228561Snp 4974237263Snp t4_wrq_tx(sc, wr); 4975228561Snp return (0); 4976221474Snp} 4977221474Snp 4978221474Snpstatic int 4979221474Snpdel_filter_wr(struct adapter *sc, int fidx) 4980221474Snp{ 4981221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 4982237263Snp struct wrqe *wr; 4983221474Snp struct fw_filter_wr *fwr; 4984228561Snp unsigned int ftid; 4985221474Snp 4986221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4987221474Snp 4988221474Snp ftid = sc->tids.ftid_base + fidx; 4989221474Snp 4990237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 4991237263Snp if (wr == NULL) 4992221474Snp return (ENOMEM); 4993237263Snp fwr = wrtod(wr); 4994221474Snp bzero(fwr, sizeof (*fwr)); 4995221474Snp 4996228561Snp t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id); 4997221474Snp 4998221474Snp f->pending = 1; 4999237263Snp t4_wrq_tx(sc, wr); 5000228561Snp return (0); 5001221474Snp} 5002221474Snp 5003239338Snpint 5004239338Snpt4_filter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 5005221474Snp{ 5006228561Snp struct adapter *sc = iq->adapter; 5007228561Snp const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1); 5008221474Snp unsigned int idx = GET_TID(rpl); 5009221474Snp 5010228561Snp KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__, 5011228561Snp rss->opcode)); 5012228561Snp 5013221474Snp if (idx >= sc->tids.ftid_base && 5014221474Snp (idx -= sc->tids.ftid_base) < sc->tids.nftids) { 5015221474Snp unsigned int rc = G_COOKIE(rpl->cookie); 5016221474Snp struct filter_entry *f = &sc->tids.ftid_tab[idx]; 5017221474Snp 5018231120Snp ADAPTER_LOCK(sc); 5019228561Snp if (rc == FW_FILTER_WR_FLT_ADDED) { 5020221474Snp f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff; 5021221474Snp f->pending = 0; /* asynchronous setup completed */ 5022221474Snp f->valid = 1; 5023231120Snp } else { 5024231120Snp if (rc != FW_FILTER_WR_FLT_DELETED) { 5025231120Snp /* Add or delete failed, display an error */ 5026231120Snp log(LOG_ERR, 5027231120Snp "filter %u setup failed with error %u\n", 5028231120Snp idx, rc); 5029231120Snp } 5030228561Snp 5031231120Snp clear_filter(f); 5032231120Snp sc->tids.ftids_in_use--; 5033221474Snp } 5034228561Snp ADAPTER_UNLOCK(sc); 5035221474Snp } 5036228561Snp 5037228561Snp return (0); 5038221474Snp} 5039221474Snp 5040222973Snpstatic int 5041222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt) 5042222973Snp{ 5043222973Snp int rc = EINVAL; 5044222973Snp 5045222973Snp if (cntxt->cid > M_CTXTQID) 5046222973Snp return (rc); 5047222973Snp 5048222973Snp if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS && 5049222973Snp cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM) 5050222973Snp return (rc); 5051222973Snp 5052222973Snp if (sc->flags & FW_OK) { 5053222973Snp ADAPTER_LOCK(sc); /* Avoid parallel t4_wr_mbox */ 5054222973Snp rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id, 5055222973Snp &cntxt->data[0]); 5056222973Snp ADAPTER_UNLOCK(sc); 5057222973Snp } 5058222973Snp 5059222973Snp if (rc != 0) { 5060222973Snp /* Read via firmware failed or wasn't even attempted */ 5061222973Snp 5062222973Snp rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id, 5063222973Snp &cntxt->data[0]); 5064222973Snp } 5065222973Snp 5066222973Snp return (rc); 5067222973Snp} 5068222973Snp 5069228561Snpstatic int 5070228561Snpread_card_mem(struct adapter *sc, struct t4_mem_range *mr) 5071228561Snp{ 5072228561Snp uint32_t base, size, lo, hi, win, off, remaining, i, n; 5073228561Snp uint32_t *buf, *b; 5074228561Snp int rc; 5075228561Snp 5076228561Snp /* reads are in multiples of 32 bits */ 5077228561Snp if (mr->addr & 3 || mr->len & 3 || mr->len == 0) 5078228561Snp return (EINVAL); 5079228561Snp 5080228561Snp /* 5081228561Snp * We don't want to deal with potential holes so we mandate that the 5082228561Snp * requested region must lie entirely within one of the 3 memories. 5083228561Snp */ 5084228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 5085228561Snp if (lo & F_EDRAM0_ENABLE) { 5086228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 5087228561Snp base = G_EDRAM0_BASE(hi) << 20; 5088228561Snp size = G_EDRAM0_SIZE(hi) << 20; 5089228561Snp if (size > 0 && 5090228561Snp mr->addr >= base && mr->addr < base + size && 5091228561Snp mr->addr + mr->len <= base + size) 5092228561Snp goto proceed; 5093228561Snp } 5094228561Snp if (lo & F_EDRAM1_ENABLE) { 5095228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 5096228561Snp base = G_EDRAM1_BASE(hi) << 20; 5097228561Snp size = G_EDRAM1_SIZE(hi) << 20; 5098228561Snp if (size > 0 && 5099228561Snp mr->addr >= base && mr->addr < base + size && 5100228561Snp mr->addr + mr->len <= base + size) 5101228561Snp goto proceed; 5102228561Snp } 5103228561Snp if (lo & F_EXT_MEM_ENABLE) { 5104228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 5105228561Snp base = G_EXT_MEM_BASE(hi) << 20; 5106228561Snp size = G_EXT_MEM_SIZE(hi) << 20; 5107228561Snp if (size > 0 && 5108228561Snp mr->addr >= base && mr->addr < base + size && 5109228561Snp mr->addr + mr->len <= base + size) 5110228561Snp goto proceed; 5111228561Snp } 5112228561Snp return (ENXIO); 5113228561Snp 5114228561Snpproceed: 5115228561Snp buf = b = malloc(mr->len, M_CXGBE, M_WAITOK); 5116228561Snp 5117228561Snp /* 5118228561Snp * Position the PCIe window (we use memwin2) to the 16B aligned area 5119228561Snp * just at/before the requested region. 5120228561Snp */ 5121228561Snp win = mr->addr & ~0xf; 5122228561Snp off = mr->addr - win; /* offset of the requested region in the win */ 5123228561Snp remaining = mr->len; 5124228561Snp 5125228561Snp while (remaining) { 5126228561Snp t4_write_reg(sc, 5127228561Snp PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2), win); 5128228561Snp t4_read_reg(sc, 5129228561Snp PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2)); 5130228561Snp 5131228561Snp /* number of bytes that we'll copy in the inner loop */ 5132228561Snp n = min(remaining, MEMWIN2_APERTURE - off); 5133228561Snp 5134228561Snp for (i = 0; i < n; i += 4, remaining -= 4) 5135228561Snp *b++ = t4_read_reg(sc, MEMWIN2_BASE + off + i); 5136228561Snp 5137228561Snp win += MEMWIN2_APERTURE; 5138228561Snp off = 0; 5139228561Snp } 5140228561Snp 5141228561Snp rc = copyout(buf, mr->data, mr->len); 5142228561Snp free(buf, M_CXGBE); 5143228561Snp 5144228561Snp return (rc); 5145228561Snp} 5146228561Snp 5147218792Snpint 5148218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap) 5149218792Snp{ 5150222102Snp int i; 5151218792Snp 5152222102Snp return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0); 5153218792Snp} 5154218792Snp 5155218792Snpint 5156218792Snpt4_os_pci_save_state(struct adapter *sc) 5157218792Snp{ 5158218792Snp device_t dev; 5159218792Snp struct pci_devinfo *dinfo; 5160218792Snp 5161218792Snp dev = sc->dev; 5162218792Snp dinfo = device_get_ivars(dev); 5163218792Snp 5164218792Snp pci_cfg_save(dev, dinfo, 0); 5165218792Snp return (0); 5166218792Snp} 5167218792Snp 5168218792Snpint 5169218792Snpt4_os_pci_restore_state(struct adapter *sc) 5170218792Snp{ 5171218792Snp device_t dev; 5172218792Snp struct pci_devinfo *dinfo; 5173218792Snp 5174218792Snp dev = sc->dev; 5175218792Snp dinfo = device_get_ivars(dev); 5176218792Snp 5177218792Snp pci_cfg_restore(dev, dinfo); 5178218792Snp return (0); 5179218792Snp} 5180219299Snp 5181218792Snpvoid 5182218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx) 5183218792Snp{ 5184218792Snp struct port_info *pi = sc->port[idx]; 5185218792Snp static const char *mod_str[] = { 5186220232Snp NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM" 5187218792Snp }; 5188218792Snp 5189218792Snp if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 5190218792Snp if_printf(pi->ifp, "transceiver unplugged.\n"); 5191220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) 5192220232Snp if_printf(pi->ifp, "unknown transceiver inserted.\n"); 5193220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) 5194220232Snp if_printf(pi->ifp, "unsupported transceiver inserted.\n"); 5195240452Snp else if (pi->mod_type > 0 && pi->mod_type < nitems(mod_str)) { 5196218792Snp if_printf(pi->ifp, "%s transceiver inserted.\n", 5197218792Snp mod_str[pi->mod_type]); 5198219299Snp } else { 5199219299Snp if_printf(pi->ifp, "transceiver (type %d) inserted.\n", 5200219299Snp pi->mod_type); 5201219299Snp } 5202218792Snp} 5203218792Snp 5204218792Snpvoid 5205218792Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat) 5206218792Snp{ 5207218792Snp struct port_info *pi = sc->port[idx]; 5208218792Snp struct ifnet *ifp = pi->ifp; 5209218792Snp 5210218792Snp if (link_stat) { 5211218792Snp ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed); 5212218792Snp if_link_state_change(ifp, LINK_STATE_UP); 5213218792Snp } else 5214218792Snp if_link_state_change(ifp, LINK_STATE_DOWN); 5215218792Snp} 5216218792Snp 5217228561Snpvoid 5218228561Snpt4_iterate(void (*func)(struct adapter *, void *), void *arg) 5219228561Snp{ 5220228561Snp struct adapter *sc; 5221228561Snp 5222228561Snp mtx_lock(&t4_list_lock); 5223228561Snp SLIST_FOREACH(sc, &t4_list, link) { 5224228561Snp /* 5225228561Snp * func should not make any assumptions about what state sc is 5226228561Snp * in - the only guarantee is that sc->sc_lock is a valid lock. 5227228561Snp */ 5228228561Snp func(sc, arg); 5229228561Snp } 5230228561Snp mtx_unlock(&t4_list_lock); 5231228561Snp} 5232228561Snp 5233218792Snpstatic int 5234218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td) 5235218792Snp{ 5236218792Snp return (0); 5237218792Snp} 5238218792Snp 5239218792Snpstatic int 5240218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td) 5241218792Snp{ 5242218792Snp return (0); 5243218792Snp} 5244218792Snp 5245218792Snpstatic int 5246218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag, 5247218792Snp struct thread *td) 5248218792Snp{ 5249218792Snp int rc; 5250218792Snp struct adapter *sc = dev->si_drv1; 5251218792Snp 5252218792Snp rc = priv_check(td, PRIV_DRIVER); 5253218792Snp if (rc != 0) 5254218792Snp return (rc); 5255218792Snp 5256218792Snp switch (cmd) { 5257220410Snp case CHELSIO_T4_GETREG: { 5258220410Snp struct t4_reg *edata = (struct t4_reg *)data; 5259220410Snp 5260218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 5261218792Snp return (EFAULT); 5262220410Snp 5263220410Snp if (edata->size == 4) 5264220410Snp edata->val = t4_read_reg(sc, edata->addr); 5265220410Snp else if (edata->size == 8) 5266220410Snp edata->val = t4_read_reg64(sc, edata->addr); 5267220410Snp else 5268220410Snp return (EINVAL); 5269220410Snp 5270218792Snp break; 5271218792Snp } 5272220410Snp case CHELSIO_T4_SETREG: { 5273220410Snp struct t4_reg *edata = (struct t4_reg *)data; 5274220410Snp 5275218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 5276218792Snp return (EFAULT); 5277220410Snp 5278220410Snp if (edata->size == 4) { 5279220410Snp if (edata->val & 0xffffffff00000000) 5280220410Snp return (EINVAL); 5281220410Snp t4_write_reg(sc, edata->addr, (uint32_t) edata->val); 5282220410Snp } else if (edata->size == 8) 5283220410Snp t4_write_reg64(sc, edata->addr, edata->val); 5284220410Snp else 5285220410Snp return (EINVAL); 5286218792Snp break; 5287218792Snp } 5288218792Snp case CHELSIO_T4_REGDUMP: { 5289218792Snp struct t4_regdump *regs = (struct t4_regdump *)data; 5290218792Snp int reglen = T4_REGDUMP_SIZE; 5291218792Snp uint8_t *buf; 5292218792Snp 5293218792Snp if (regs->len < reglen) { 5294218792Snp regs->len = reglen; /* hint to the caller */ 5295218792Snp return (ENOBUFS); 5296218792Snp } 5297218792Snp 5298218792Snp regs->len = reglen; 5299218792Snp buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO); 5300218792Snp t4_get_regs(sc, regs, buf); 5301218792Snp rc = copyout(buf, regs->data, reglen); 5302218792Snp free(buf, M_CXGBE); 5303218792Snp break; 5304218792Snp } 5305221474Snp case CHELSIO_T4_GET_FILTER_MODE: 5306221474Snp rc = get_filter_mode(sc, (uint32_t *)data); 5307221474Snp break; 5308221474Snp case CHELSIO_T4_SET_FILTER_MODE: 5309221474Snp rc = set_filter_mode(sc, *(uint32_t *)data); 5310221474Snp break; 5311221474Snp case CHELSIO_T4_GET_FILTER: 5312221474Snp ADAPTER_LOCK(sc); 5313221474Snp rc = get_filter(sc, (struct t4_filter *)data); 5314221474Snp ADAPTER_UNLOCK(sc); 5315221474Snp break; 5316221474Snp case CHELSIO_T4_SET_FILTER: 5317221474Snp ADAPTER_LOCK(sc); 5318221474Snp rc = set_filter(sc, (struct t4_filter *)data); 5319221474Snp ADAPTER_UNLOCK(sc); 5320221474Snp break; 5321221474Snp case CHELSIO_T4_DEL_FILTER: 5322221474Snp ADAPTER_LOCK(sc); 5323221474Snp rc = del_filter(sc, (struct t4_filter *)data); 5324221474Snp ADAPTER_UNLOCK(sc); 5325221474Snp break; 5326222973Snp case CHELSIO_T4_GET_SGE_CONTEXT: 5327222973Snp rc = get_sge_context(sc, (struct t4_sge_context *)data); 5328222973Snp break; 5329228561Snp case CHELSIO_T4_LOAD_FW: { 5330228561Snp struct t4_data *fw = (struct t4_data *)data; 5331228561Snp uint8_t *fw_data; 5332228561Snp 5333228561Snp if (sc->flags & FULL_INIT_DONE) 5334228561Snp return (EBUSY); 5335228561Snp 5336228561Snp fw_data = malloc(fw->len, M_CXGBE, M_NOWAIT); 5337228561Snp if (fw_data == NULL) 5338228561Snp return (ENOMEM); 5339228561Snp 5340228561Snp rc = copyin(fw->data, fw_data, fw->len); 5341228561Snp if (rc == 0) 5342228561Snp rc = -t4_load_fw(sc, fw_data, fw->len); 5343228561Snp 5344228561Snp free(fw_data, M_CXGBE); 5345228561Snp break; 5346228561Snp } 5347228561Snp case CHELSIO_T4_GET_MEM: 5348228561Snp rc = read_card_mem(sc, (struct t4_mem_range *)data); 5349228561Snp break; 5350218792Snp default: 5351218792Snp rc = EINVAL; 5352218792Snp } 5353218792Snp 5354218792Snp return (rc); 5355218792Snp} 5356218792Snp 5357237263Snp#ifdef TCP_OFFLOAD 5358219392Snpstatic int 5359228561Snptoe_capability(struct port_info *pi, int enable) 5360228561Snp{ 5361228561Snp int rc; 5362228561Snp struct adapter *sc = pi->adapter; 5363228561Snp 5364228561Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 5365228561Snp 5366228561Snp if (!is_offload(sc)) 5367228561Snp return (ENODEV); 5368228561Snp 5369228561Snp if (enable) { 5370237263Snp if (!(sc->flags & FULL_INIT_DONE)) { 5371237263Snp log(LOG_WARNING, 5372237263Snp "You must enable a cxgbe interface first\n"); 5373237263Snp return (EAGAIN); 5374237263Snp } 5375237263Snp 5376228561Snp if (isset(&sc->offload_map, pi->port_id)) 5377228561Snp return (0); 5378228561Snp 5379237263Snp if (!(sc->flags & TOM_INIT_DONE)) { 5380237263Snp rc = t4_activate_uld(sc, ULD_TOM); 5381237263Snp if (rc == EAGAIN) { 5382237263Snp log(LOG_WARNING, 5383237263Snp "You must kldload t4_tom.ko before trying " 5384237263Snp "to enable TOE on a cxgbe interface.\n"); 5385237263Snp } 5386228561Snp if (rc != 0) 5387228561Snp return (rc); 5388237263Snp KASSERT(sc->tom_softc != NULL, 5389237263Snp ("%s: TOM activated but softc NULL", __func__)); 5390237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 5391237263Snp ("%s: TOM activated but flag not set", __func__)); 5392228561Snp } 5393228561Snp 5394228561Snp setbit(&sc->offload_map, pi->port_id); 5395228561Snp } else { 5396228561Snp if (!isset(&sc->offload_map, pi->port_id)) 5397228561Snp return (0); 5398228561Snp 5399237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 5400237263Snp ("%s: TOM never initialized?", __func__)); 5401228561Snp clrbit(&sc->offload_map, pi->port_id); 5402228561Snp } 5403228561Snp 5404228561Snp return (0); 5405228561Snp} 5406228561Snp 5407228561Snp/* 5408228561Snp * Add an upper layer driver to the global list. 5409228561Snp */ 5410228561Snpint 5411228561Snpt4_register_uld(struct uld_info *ui) 5412228561Snp{ 5413228561Snp int rc = 0; 5414228561Snp struct uld_info *u; 5415228561Snp 5416228561Snp mtx_lock(&t4_uld_list_lock); 5417228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 5418228561Snp if (u->uld_id == ui->uld_id) { 5419228561Snp rc = EEXIST; 5420228561Snp goto done; 5421228561Snp } 5422228561Snp } 5423228561Snp 5424228561Snp SLIST_INSERT_HEAD(&t4_uld_list, ui, link); 5425228561Snp ui->refcount = 0; 5426228561Snpdone: 5427228561Snp mtx_unlock(&t4_uld_list_lock); 5428228561Snp return (rc); 5429228561Snp} 5430228561Snp 5431228561Snpint 5432228561Snpt4_unregister_uld(struct uld_info *ui) 5433228561Snp{ 5434228561Snp int rc = EINVAL; 5435228561Snp struct uld_info *u; 5436228561Snp 5437228561Snp mtx_lock(&t4_uld_list_lock); 5438228561Snp 5439228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 5440228561Snp if (u == ui) { 5441228561Snp if (ui->refcount > 0) { 5442228561Snp rc = EBUSY; 5443228561Snp goto done; 5444228561Snp } 5445228561Snp 5446228561Snp SLIST_REMOVE(&t4_uld_list, ui, uld_info, link); 5447228561Snp rc = 0; 5448228561Snp goto done; 5449228561Snp } 5450228561Snp } 5451228561Snpdone: 5452228561Snp mtx_unlock(&t4_uld_list_lock); 5453228561Snp return (rc); 5454228561Snp} 5455228561Snp 5456237263Snpint 5457237263Snpt4_activate_uld(struct adapter *sc, int id) 5458228561Snp{ 5459228561Snp int rc = EAGAIN; 5460228561Snp struct uld_info *ui; 5461228561Snp 5462228561Snp mtx_lock(&t4_uld_list_lock); 5463228561Snp 5464228561Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 5465228561Snp if (ui->uld_id == id) { 5466237263Snp rc = ui->activate(sc); 5467237263Snp if (rc == 0) 5468228561Snp ui->refcount++; 5469228561Snp goto done; 5470228561Snp } 5471228561Snp } 5472228561Snpdone: 5473228561Snp mtx_unlock(&t4_uld_list_lock); 5474228561Snp 5475228561Snp return (rc); 5476228561Snp} 5477228561Snp 5478237263Snpint 5479237263Snpt4_deactivate_uld(struct adapter *sc, int id) 5480228561Snp{ 5481237263Snp int rc = EINVAL; 5482237263Snp struct uld_info *ui; 5483228561Snp 5484228561Snp mtx_lock(&t4_uld_list_lock); 5485228561Snp 5486237263Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 5487237263Snp if (ui->uld_id == id) { 5488237263Snp rc = ui->deactivate(sc); 5489237263Snp if (rc == 0) 5490237263Snp ui->refcount--; 5491237263Snp goto done; 5492237263Snp } 5493228561Snp } 5494228561Snpdone: 5495228561Snp mtx_unlock(&t4_uld_list_lock); 5496228561Snp 5497228561Snp return (rc); 5498228561Snp} 5499228561Snp#endif 5500228561Snp 5501228561Snp/* 5502228561Snp * Come up with reasonable defaults for some of the tunables, provided they're 5503228561Snp * not set by the user (in which case we'll use the values as is). 5504228561Snp */ 5505228561Snpstatic void 5506228561Snptweak_tunables(void) 5507228561Snp{ 5508228561Snp int nc = mp_ncpus; /* our snapshot of the number of CPUs */ 5509228561Snp 5510228561Snp if (t4_ntxq10g < 1) 5511228561Snp t4_ntxq10g = min(nc, NTXQ_10G); 5512228561Snp 5513228561Snp if (t4_ntxq1g < 1) 5514228561Snp t4_ntxq1g = min(nc, NTXQ_1G); 5515228561Snp 5516228561Snp if (t4_nrxq10g < 1) 5517228561Snp t4_nrxq10g = min(nc, NRXQ_10G); 5518228561Snp 5519228561Snp if (t4_nrxq1g < 1) 5520228561Snp t4_nrxq1g = min(nc, NRXQ_1G); 5521228561Snp 5522237263Snp#ifdef TCP_OFFLOAD 5523228561Snp if (t4_nofldtxq10g < 1) 5524228561Snp t4_nofldtxq10g = min(nc, NOFLDTXQ_10G); 5525228561Snp 5526228561Snp if (t4_nofldtxq1g < 1) 5527228561Snp t4_nofldtxq1g = min(nc, NOFLDTXQ_1G); 5528228561Snp 5529228561Snp if (t4_nofldrxq10g < 1) 5530228561Snp t4_nofldrxq10g = min(nc, NOFLDRXQ_10G); 5531228561Snp 5532228561Snp if (t4_nofldrxq1g < 1) 5533228561Snp t4_nofldrxq1g = min(nc, NOFLDRXQ_1G); 5534238028Snp 5535238028Snp if (t4_toecaps_allowed == -1) 5536238028Snp t4_toecaps_allowed = FW_CAPS_CONFIG_TOE; 5537238028Snp#else 5538238028Snp if (t4_toecaps_allowed == -1) 5539238028Snp t4_toecaps_allowed = 0; 5540228561Snp#endif 5541228561Snp 5542228561Snp if (t4_tmr_idx_10g < 0 || t4_tmr_idx_10g >= SGE_NTIMERS) 5543228561Snp t4_tmr_idx_10g = TMR_IDX_10G; 5544228561Snp 5545228561Snp if (t4_pktc_idx_10g < -1 || t4_pktc_idx_10g >= SGE_NCOUNTERS) 5546228561Snp t4_pktc_idx_10g = PKTC_IDX_10G; 5547228561Snp 5548228561Snp if (t4_tmr_idx_1g < 0 || t4_tmr_idx_1g >= SGE_NTIMERS) 5549228561Snp t4_tmr_idx_1g = TMR_IDX_1G; 5550228561Snp 5551228561Snp if (t4_pktc_idx_1g < -1 || t4_pktc_idx_1g >= SGE_NCOUNTERS) 5552228561Snp t4_pktc_idx_1g = PKTC_IDX_1G; 5553228561Snp 5554228561Snp if (t4_qsize_txq < 128) 5555228561Snp t4_qsize_txq = 128; 5556228561Snp 5557228561Snp if (t4_qsize_rxq < 128) 5558228561Snp t4_qsize_rxq = 128; 5559228561Snp while (t4_qsize_rxq & 7) 5560228561Snp t4_qsize_rxq++; 5561228561Snp 5562228561Snp t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX; 5563228561Snp} 5564228561Snp 5565228561Snpstatic int 5566219392Snpt4_mod_event(module_t mod, int cmd, void *arg) 5567219392Snp{ 5568228561Snp int rc = 0; 5569219392Snp 5570228561Snp switch (cmd) { 5571228561Snp case MOD_LOAD: 5572219392Snp t4_sge_modload(); 5573228561Snp mtx_init(&t4_list_lock, "T4 adapters", 0, MTX_DEF); 5574228561Snp SLIST_INIT(&t4_list); 5575237263Snp#ifdef TCP_OFFLOAD 5576228561Snp mtx_init(&t4_uld_list_lock, "T4 ULDs", 0, MTX_DEF); 5577228561Snp SLIST_INIT(&t4_uld_list); 5578228561Snp#endif 5579228561Snp tweak_tunables(); 5580228561Snp break; 5581219392Snp 5582228561Snp case MOD_UNLOAD: 5583237263Snp#ifdef TCP_OFFLOAD 5584228561Snp mtx_lock(&t4_uld_list_lock); 5585228561Snp if (!SLIST_EMPTY(&t4_uld_list)) { 5586228561Snp rc = EBUSY; 5587228561Snp mtx_unlock(&t4_uld_list_lock); 5588228561Snp break; 5589228561Snp } 5590228561Snp mtx_unlock(&t4_uld_list_lock); 5591228561Snp mtx_destroy(&t4_uld_list_lock); 5592228561Snp#endif 5593228561Snp mtx_lock(&t4_list_lock); 5594228561Snp if (!SLIST_EMPTY(&t4_list)) { 5595228561Snp rc = EBUSY; 5596228561Snp mtx_unlock(&t4_list_lock); 5597228561Snp break; 5598228561Snp } 5599228561Snp mtx_unlock(&t4_list_lock); 5600228561Snp mtx_destroy(&t4_list_lock); 5601228561Snp break; 5602228561Snp } 5603228561Snp 5604228561Snp return (rc); 5605219392Snp} 5606219392Snp 5607218792Snpstatic devclass_t t4_devclass; 5608218792Snpstatic devclass_t cxgbe_devclass; 5609218792Snp 5610219392SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, t4_mod_event, 0); 5611218792SnpMODULE_VERSION(t4nex, 1); 5612218792Snp 5613218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0); 5614218792SnpMODULE_VERSION(cxgbe, 1); 5615