t4_main.c revision 238054
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 238054 2012-07-03 06:56:11Z 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 *); 309218792Snpstatic int t4_sysctls(struct adapter *); 310218792Snpstatic int cxgbe_sysctls(struct port_info *); 311219436Snpstatic int sysctl_int_array(SYSCTL_HANDLER_ARGS); 312228561Snpstatic int sysctl_bitfield(SYSCTL_HANDLER_ARGS); 313218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS); 314218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS); 315218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS); 316218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS); 317218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS); 318231115Snp#ifdef SBUF_DRAIN 319228561Snpstatic int sysctl_cctrl(SYSCTL_HANDLER_ARGS); 320228561Snpstatic int sysctl_cpl_stats(SYSCTL_HANDLER_ARGS); 321228561Snpstatic int sysctl_ddp_stats(SYSCTL_HANDLER_ARGS); 322222551Snpstatic int sysctl_devlog(SYSCTL_HANDLER_ARGS); 323228561Snpstatic int sysctl_fcoe_stats(SYSCTL_HANDLER_ARGS); 324228561Snpstatic int sysctl_hw_sched(SYSCTL_HANDLER_ARGS); 325228561Snpstatic int sysctl_lb_stats(SYSCTL_HANDLER_ARGS); 326228561Snpstatic int sysctl_meminfo(SYSCTL_HANDLER_ARGS); 327228561Snpstatic int sysctl_path_mtus(SYSCTL_HANDLER_ARGS); 328228561Snpstatic int sysctl_pm_stats(SYSCTL_HANDLER_ARGS); 329228561Snpstatic int sysctl_rdma_stats(SYSCTL_HANDLER_ARGS); 330228561Snpstatic int sysctl_tcp_stats(SYSCTL_HANDLER_ARGS); 331228561Snpstatic int sysctl_tids(SYSCTL_HANDLER_ARGS); 332228561Snpstatic int sysctl_tp_err_stats(SYSCTL_HANDLER_ARGS); 333228561Snpstatic int sysctl_tx_rate(SYSCTL_HANDLER_ARGS); 334231115Snp#endif 335219286Snpstatic inline void txq_start(struct ifnet *, struct sge_txq *); 336221474Snpstatic uint32_t fconf_to_mode(uint32_t); 337221474Snpstatic uint32_t mode_to_fconf(uint32_t); 338221474Snpstatic uint32_t fspec_to_fconf(struct t4_filter_specification *); 339221474Snpstatic int get_filter_mode(struct adapter *, uint32_t *); 340221474Snpstatic int set_filter_mode(struct adapter *, uint32_t); 341222552Snpstatic inline uint64_t get_filter_hits(struct adapter *, uint32_t); 342221474Snpstatic int get_filter(struct adapter *, struct t4_filter *); 343221474Snpstatic int set_filter(struct adapter *, struct t4_filter *); 344221474Snpstatic int del_filter(struct adapter *, struct t4_filter *); 345222509Snpstatic void clear_filter(struct filter_entry *); 346221474Snpstatic int set_filter_wr(struct adapter *, int); 347221474Snpstatic int del_filter_wr(struct adapter *, int); 348228561Snpstatic int filter_rpl(struct sge_iq *, const struct rss_header *, 349228561Snp struct mbuf *); 350222973Snpstatic int get_sge_context(struct adapter *, struct t4_sge_context *); 351228561Snpstatic int read_card_mem(struct adapter *, struct t4_mem_range *); 352237263Snp#ifdef TCP_OFFLOAD 353228561Snpstatic int toe_capability(struct port_info *, int); 354228561Snp#endif 355219392Snpstatic int t4_mod_event(module_t, int, void *); 356218792Snp 357218792Snpstruct t4_pciids { 358218792Snp uint16_t device; 359218792Snp char *desc; 360218792Snp} t4_pciids[] = { 361237587Snp {0xa000, "Chelsio Terminator 4 FPGA"}, 362237587Snp {0x4400, "Chelsio T440-dbg"}, 363237587Snp {0x4401, "Chelsio T420-CR"}, 364237587Snp {0x4402, "Chelsio T422-CR"}, 365237587Snp {0x4403, "Chelsio T440-CR"}, 366237587Snp {0x4404, "Chelsio T420-BCH"}, 367237587Snp {0x4405, "Chelsio T440-BCH"}, 368237587Snp {0x4406, "Chelsio T440-CH"}, 369237587Snp {0x4407, "Chelsio T420-SO"}, 370237587Snp {0x4408, "Chelsio T420-CX"}, 371237587Snp {0x4409, "Chelsio T420-BT"}, 372237587Snp {0x440a, "Chelsio T404-BT"}, 373218792Snp}; 374218792Snp 375237263Snp#ifdef TCP_OFFLOAD 376237263Snp/* 377237263Snp * service_iq() has an iq and needs the fl. Offset of fl from the iq should be 378237263Snp * exactly the same for both rxq and ofld_rxq. 379237263Snp */ 380237263SnpCTASSERT(offsetof(struct sge_ofld_rxq, iq) == offsetof(struct sge_rxq, iq)); 381228561SnpCTASSERT(offsetof(struct sge_ofld_rxq, fl) == offsetof(struct sge_rxq, fl)); 382228561Snp#endif 383228561Snp 384218792Snpstatic int 385218792Snpt4_probe(device_t dev) 386218792Snp{ 387218792Snp int i; 388218792Snp uint16_t v = pci_get_vendor(dev); 389218792Snp uint16_t d = pci_get_device(dev); 390237587Snp uint8_t f = pci_get_function(dev); 391218792Snp 392218792Snp if (v != PCI_VENDOR_ID_CHELSIO) 393218792Snp return (ENXIO); 394218792Snp 395237587Snp /* Attach only to PF0 of the FPGA */ 396237587Snp if (d == 0xa000 && f != 0) 397237587Snp return (ENXIO); 398237587Snp 399218792Snp for (i = 0; i < ARRAY_SIZE(t4_pciids); i++) { 400237587Snp if (d == t4_pciids[i].device) { 401218792Snp device_set_desc(dev, t4_pciids[i].desc); 402218792Snp return (BUS_PROBE_DEFAULT); 403218792Snp } 404218792Snp } 405218792Snp 406218792Snp return (ENXIO); 407218792Snp} 408218792Snp 409218792Snpstatic int 410218792Snpt4_attach(device_t dev) 411218792Snp{ 412218792Snp struct adapter *sc; 413218792Snp int rc = 0, i, n10g, n1g, rqidx, tqidx; 414218792Snp struct intrs_and_queues iaq; 415218792Snp struct sge *s; 416237263Snp#ifdef TCP_OFFLOAD 417228561Snp int ofld_rqidx, ofld_tqidx; 418228561Snp#endif 419218792Snp 420218792Snp sc = device_get_softc(dev); 421218792Snp sc->dev = dev; 422218792Snp 423218792Snp pci_enable_busmaster(dev); 424222085Snp if (pci_find_cap(dev, PCIY_EXPRESS, &i) == 0) { 425228561Snp uint32_t v; 426228561Snp 427222085Snp pci_set_max_read_req(dev, 4096); 428222085Snp v = pci_read_config(dev, i + PCIR_EXPRESS_DEVICE_CTL, 2); 429222085Snp v |= PCIM_EXP_CTL_RELAXED_ORD_ENABLE; 430222085Snp pci_write_config(dev, i + PCIR_EXPRESS_DEVICE_CTL, v, 2); 431222085Snp } 432222085Snp 433218792Snp snprintf(sc->lockname, sizeof(sc->lockname), "%s", 434218792Snp device_get_nameunit(dev)); 435218792Snp mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF); 436228561Snp mtx_lock(&t4_list_lock); 437228561Snp SLIST_INSERT_HEAD(&t4_list, sc, link); 438228561Snp mtx_unlock(&t4_list_lock); 439218792Snp 440228561Snp mtx_init(&sc->sfl_lock, "starving freelists", 0, MTX_DEF); 441228561Snp TAILQ_INIT(&sc->sfl); 442228561Snp callout_init(&sc->sfl_callout, CALLOUT_MPSAFE); 443228561Snp 444218792Snp rc = map_bars(sc); 445218792Snp if (rc != 0) 446218792Snp goto done; /* error message displayed already */ 447218792Snp 448237587Snp /* 449237587Snp * This is the real PF# to which we're attaching. Works from within PCI 450237587Snp * passthrough environments too, where pci_get_function() could return a 451237587Snp * different PF# depending on the passthrough configuration. We need to 452237587Snp * use the real PF# in all our communication with the firmware. 453237587Snp */ 454237587Snp sc->pf = G_SOURCEPF(t4_read_reg(sc, A_PL_WHOAMI)); 455237587Snp sc->mbox = sc->pf; 456237587Snp 457218792Snp memset(sc->chan_map, 0xff, sizeof(sc->chan_map)); 458237263Snp sc->an_handler = an_not_handled; 459228561Snp for (i = 0; i < ARRAY_SIZE(sc->cpl_handler); i++) 460228561Snp sc->cpl_handler[i] = cpl_not_handled; 461228561Snp t4_register_cpl_handler(sc, CPL_SET_TCB_RPL, filter_rpl); 462218792Snp 463218792Snp /* Prepare the adapter for operation */ 464218792Snp rc = -t4_prep_adapter(sc); 465218792Snp if (rc != 0) { 466218792Snp device_printf(dev, "failed to prepare adapter: %d.\n", rc); 467218792Snp goto done; 468218792Snp } 469218792Snp 470228561Snp /* 471228561Snp * Do this really early, with the memory windows set up even before the 472228561Snp * character device. The userland tool's register i/o and mem read 473228561Snp * will work even in "recovery mode". 474228561Snp */ 475228561Snp setup_memwin(sc); 476218792Snp sc->cdev = make_dev(&t4_cdevsw, device_get_unit(dev), UID_ROOT, 477218792Snp GID_WHEEL, 0600, "%s", device_get_nameunit(dev)); 478218792Snp sc->cdev->si_drv1 = sc; 479218792Snp 480228561Snp /* Go no further if recovery mode has been requested. */ 481228561Snp if (TUNABLE_INT_FETCH("hw.cxgbe.sos", &i) && i != 0) { 482228561Snp device_printf(dev, "recovery mode.\n"); 483228561Snp goto done; 484228561Snp } 485228561Snp 486218792Snp /* Prepare the firmware for operation */ 487218792Snp rc = prep_firmware(sc); 488218792Snp if (rc != 0) 489218792Snp goto done; /* error message displayed already */ 490218792Snp 491228561Snp rc = get_params__pre_init(sc); 492228561Snp if (rc != 0) 493228561Snp goto done; /* error message displayed already */ 494222551Snp 495228561Snp rc = t4_sge_init(sc); 496228561Snp if (rc != 0) 497228561Snp goto done; /* error message displayed already */ 498218792Snp 499228561Snp if (sc->flags & MASTER_PF) { 500228561Snp /* get basic stuff going */ 501228561Snp rc = -t4_fw_initialize(sc, sc->mbox); 502228561Snp if (rc != 0) { 503228561Snp device_printf(dev, "early init failed: %d.\n", rc); 504228561Snp goto done; 505228561Snp } 506218792Snp } 507218792Snp 508228561Snp rc = get_params__post_init(sc); 509228561Snp if (rc != 0) 510228561Snp goto done; /* error message displayed already */ 511218792Snp 512228561Snp if (sc->flags & MASTER_PF) { 513218792Snp 514228561Snp /* final tweaks to some settings */ 515218792Snp 516228561Snp t4_load_mtus(sc, sc->params.mtus, sc->params.a_wnd, 517228561Snp sc->params.b_wnd); 518228561Snp t4_write_reg(sc, A_ULP_RX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12)); 519228561Snp t4_set_reg_field(sc, A_TP_PARA_REG3, F_TUNNELCNGDROP0 | 520228561Snp F_TUNNELCNGDROP1 | F_TUNNELCNGDROP2 | F_TUNNELCNGDROP3, 0); 521228561Snp t4_set_reg_field(sc, A_TP_PARA_REG5, 522228561Snp V_INDICATESIZE(M_INDICATESIZE) | 523228561Snp F_REARMDDPOFFSET | F_RESETDDPOFFSET, 524228561Snp V_INDICATESIZE(M_INDICATESIZE) | 525228561Snp F_REARMDDPOFFSET | F_RESETDDPOFFSET); 526228561Snp } else { 527228561Snp /* 528228561Snp * XXX: Verify that we can live with whatever the master driver 529228561Snp * has done so far, and hope that it doesn't change any global 530228561Snp * setting from underneath us in the future. 531228561Snp */ 532218792Snp } 533218792Snp 534228561Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &sc->filter_mode, 1, 535228561Snp A_TP_VLAN_PRI_MAP); 536218792Snp 537228561Snp for (i = 0; i < NCHAN; i++) 538228561Snp sc->params.tp.tx_modq[i] = i; 539218792Snp 540218792Snp rc = t4_create_dma_tag(sc); 541218792Snp if (rc != 0) 542218792Snp goto done; /* error message displayed already */ 543218792Snp 544218792Snp /* 545218792Snp * First pass over all the ports - allocate VIs and initialize some 546218792Snp * basic parameters like mac address, port type, etc. We also figure 547218792Snp * out whether a port is 10G or 1G and use that information when 548218792Snp * calculating how many interrupts to attempt to allocate. 549218792Snp */ 550218792Snp n10g = n1g = 0; 551218792Snp for_each_port(sc, i) { 552218792Snp struct port_info *pi; 553218792Snp 554218792Snp pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK); 555218792Snp sc->port[i] = pi; 556218792Snp 557218792Snp /* These must be set before t4_port_init */ 558218792Snp pi->adapter = sc; 559218792Snp pi->port_id = i; 560218792Snp 561218792Snp /* Allocate the vi and initialize parameters like mac addr */ 562218792Snp rc = -t4_port_init(pi, sc->mbox, sc->pf, 0); 563218792Snp if (rc != 0) { 564218792Snp device_printf(dev, "unable to initialize port %d: %d\n", 565218792Snp i, rc); 566218792Snp free(pi, M_CXGBE); 567222510Snp sc->port[i] = NULL; 568222510Snp goto done; 569218792Snp } 570218792Snp 571218792Snp snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d", 572218792Snp device_get_nameunit(dev), i); 573218792Snp mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF); 574218792Snp 575218792Snp if (is_10G_port(pi)) { 576218792Snp n10g++; 577228561Snp pi->tmr_idx = t4_tmr_idx_10g; 578228561Snp pi->pktc_idx = t4_pktc_idx_10g; 579218792Snp } else { 580218792Snp n1g++; 581228561Snp pi->tmr_idx = t4_tmr_idx_1g; 582228561Snp pi->pktc_idx = t4_pktc_idx_1g; 583218792Snp } 584218792Snp 585218792Snp pi->xact_addr_filt = -1; 586218792Snp 587228561Snp pi->qsize_rxq = t4_qsize_rxq; 588228561Snp pi->qsize_txq = t4_qsize_txq; 589218792Snp 590218792Snp pi->dev = device_add_child(dev, "cxgbe", -1); 591218792Snp if (pi->dev == NULL) { 592218792Snp device_printf(dev, 593218792Snp "failed to add device for port %d.\n", i); 594218792Snp rc = ENXIO; 595218792Snp goto done; 596218792Snp } 597218792Snp device_set_softc(pi->dev, pi); 598218792Snp } 599218792Snp 600218792Snp /* 601218792Snp * Interrupt type, # of interrupts, # of rx/tx queues, etc. 602218792Snp */ 603218792Snp rc = cfg_itype_and_nqueues(sc, n10g, n1g, &iaq); 604218792Snp if (rc != 0) 605218792Snp goto done; /* error message displayed already */ 606218792Snp 607218792Snp sc->intr_type = iaq.intr_type; 608218792Snp sc->intr_count = iaq.nirq; 609228561Snp sc->flags |= iaq.intr_flags; 610218792Snp 611218792Snp s = &sc->sge; 612218792Snp s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g; 613218792Snp s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g; 614220873Snp s->neq = s->ntxq + s->nrxq; /* the free list in an rxq is an eq */ 615228561Snp s->neq += sc->params.nports + 1;/* ctrl queues: 1 per port + 1 mgmt */ 616218792Snp s->niq = s->nrxq + 1; /* 1 extra for firmware event queue */ 617222510Snp 618237263Snp#ifdef TCP_OFFLOAD 619228561Snp if (is_offload(sc)) { 620228561Snp 621228561Snp s->nofldrxq = n10g * iaq.nofldrxq10g + n1g * iaq.nofldrxq1g; 622228561Snp s->nofldtxq = n10g * iaq.nofldtxq10g + n1g * iaq.nofldtxq1g; 623228561Snp s->neq += s->nofldtxq + s->nofldrxq; 624228561Snp s->niq += s->nofldrxq; 625228561Snp 626228561Snp s->ofld_rxq = malloc(s->nofldrxq * sizeof(struct sge_ofld_rxq), 627228561Snp M_CXGBE, M_ZERO | M_WAITOK); 628228561Snp s->ofld_txq = malloc(s->nofldtxq * sizeof(struct sge_wrq), 629228561Snp M_CXGBE, M_ZERO | M_WAITOK); 630228561Snp } 631228561Snp#endif 632228561Snp 633228561Snp s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_wrq), M_CXGBE, 634220873Snp M_ZERO | M_WAITOK); 635218792Snp s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE, 636218792Snp M_ZERO | M_WAITOK); 637218792Snp s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE, 638218792Snp M_ZERO | M_WAITOK); 639218792Snp s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE, 640218792Snp M_ZERO | M_WAITOK); 641218792Snp s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE, 642218792Snp M_ZERO | M_WAITOK); 643218792Snp 644218792Snp sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE, 645218792Snp M_ZERO | M_WAITOK); 646218792Snp 647228561Snp t4_init_l2t(sc, M_WAITOK); 648222509Snp 649218792Snp /* 650218792Snp * Second pass over the ports. This time we know the number of rx and 651218792Snp * tx queues that each port should get. 652218792Snp */ 653218792Snp rqidx = tqidx = 0; 654237263Snp#ifdef TCP_OFFLOAD 655228561Snp ofld_rqidx = ofld_tqidx = 0; 656228561Snp#endif 657218792Snp for_each_port(sc, i) { 658218792Snp struct port_info *pi = sc->port[i]; 659218792Snp 660218792Snp if (pi == NULL) 661218792Snp continue; 662218792Snp 663218792Snp pi->first_rxq = rqidx; 664218792Snp pi->first_txq = tqidx; 665228561Snp if (is_10G_port(pi)) { 666228561Snp pi->nrxq = iaq.nrxq10g; 667228561Snp pi->ntxq = iaq.ntxq10g; 668228561Snp } else { 669228561Snp pi->nrxq = iaq.nrxq1g; 670228561Snp pi->ntxq = iaq.ntxq1g; 671228561Snp } 672218792Snp 673218792Snp rqidx += pi->nrxq; 674218792Snp tqidx += pi->ntxq; 675228561Snp 676237263Snp#ifdef TCP_OFFLOAD 677228561Snp if (is_offload(sc)) { 678228561Snp pi->first_ofld_rxq = ofld_rqidx; 679228561Snp pi->first_ofld_txq = ofld_tqidx; 680228561Snp if (is_10G_port(pi)) { 681228561Snp pi->nofldrxq = iaq.nofldrxq10g; 682228561Snp pi->nofldtxq = iaq.nofldtxq10g; 683228561Snp } else { 684228561Snp pi->nofldrxq = iaq.nofldrxq1g; 685228561Snp pi->nofldtxq = iaq.nofldtxq1g; 686228561Snp } 687228561Snp ofld_rqidx += pi->nofldrxq; 688228561Snp ofld_tqidx += pi->nofldtxq; 689228561Snp } 690228561Snp#endif 691218792Snp } 692218792Snp 693218792Snp rc = bus_generic_attach(dev); 694218792Snp if (rc != 0) { 695218792Snp device_printf(dev, 696218792Snp "failed to attach all child ports: %d\n", rc); 697218792Snp goto done; 698218792Snp } 699218792Snp 700218792Snp device_printf(dev, 701228561Snp "PCIe x%d, %d ports, %d %s interrupt%s, %d eq, %d iq\n", 702228561Snp sc->params.pci.width, sc->params.nports, sc->intr_count, 703228561Snp sc->intr_type == INTR_MSIX ? "MSI-X" : 704228561Snp (sc->intr_type == INTR_MSI ? "MSI" : "INTx"), 705228561Snp sc->intr_count > 1 ? "s" : "", sc->sge.neq, sc->sge.niq); 706228561Snp 707218792Snp t4_set_desc(sc); 708218792Snp 709218792Snpdone: 710228561Snp if (rc != 0 && sc->cdev) { 711228561Snp /* cdev was created and so cxgbetool works; recover that way. */ 712228561Snp device_printf(dev, 713228561Snp "error during attach, adapter is now in recovery mode.\n"); 714228561Snp rc = 0; 715228561Snp } 716228561Snp 717218792Snp if (rc != 0) 718218792Snp t4_detach(dev); 719228561Snp else 720228561Snp t4_sysctls(sc); 721218792Snp 722218792Snp return (rc); 723218792Snp} 724218792Snp 725218792Snp/* 726218792Snp * Idempotent 727218792Snp */ 728218792Snpstatic int 729218792Snpt4_detach(device_t dev) 730218792Snp{ 731218792Snp struct adapter *sc; 732218792Snp struct port_info *pi; 733228561Snp int i, rc; 734218792Snp 735218792Snp sc = device_get_softc(dev); 736218792Snp 737228561Snp if (sc->flags & FULL_INIT_DONE) 738228561Snp t4_intr_disable(sc); 739228561Snp 740228561Snp if (sc->cdev) { 741218792Snp destroy_dev(sc->cdev); 742228561Snp sc->cdev = NULL; 743228561Snp } 744218792Snp 745228561Snp rc = bus_generic_detach(dev); 746228561Snp if (rc) { 747228561Snp device_printf(dev, 748228561Snp "failed to detach child devices: %d\n", rc); 749228561Snp return (rc); 750228561Snp } 751228561Snp 752218792Snp for (i = 0; i < MAX_NPORTS; i++) { 753218792Snp pi = sc->port[i]; 754218792Snp if (pi) { 755218792Snp t4_free_vi(pi->adapter, sc->mbox, sc->pf, 0, pi->viid); 756218792Snp if (pi->dev) 757218792Snp device_delete_child(dev, pi->dev); 758218792Snp 759218792Snp mtx_destroy(&pi->pi_lock); 760218792Snp free(pi, M_CXGBE); 761218792Snp } 762218792Snp } 763218792Snp 764228561Snp if (sc->flags & FULL_INIT_DONE) 765228561Snp adapter_full_uninit(sc); 766228561Snp 767218792Snp if (sc->flags & FW_OK) 768218792Snp t4_fw_bye(sc, sc->mbox); 769218792Snp 770219944Snp if (sc->intr_type == INTR_MSI || sc->intr_type == INTR_MSIX) 771218792Snp pci_release_msi(dev); 772218792Snp 773218792Snp if (sc->regs_res) 774218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid, 775218792Snp sc->regs_res); 776218792Snp 777218792Snp if (sc->msix_res) 778218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid, 779218792Snp sc->msix_res); 780218792Snp 781222509Snp if (sc->l2t) 782222509Snp t4_free_l2t(sc->l2t); 783222509Snp 784237263Snp#ifdef TCP_OFFLOAD 785228561Snp free(sc->sge.ofld_rxq, M_CXGBE); 786228561Snp free(sc->sge.ofld_txq, M_CXGBE); 787228561Snp#endif 788218792Snp free(sc->irq, M_CXGBE); 789218792Snp free(sc->sge.rxq, M_CXGBE); 790218792Snp free(sc->sge.txq, M_CXGBE); 791220873Snp free(sc->sge.ctrlq, M_CXGBE); 792218792Snp free(sc->sge.iqmap, M_CXGBE); 793218792Snp free(sc->sge.eqmap, M_CXGBE); 794221474Snp free(sc->tids.ftid_tab, M_CXGBE); 795218792Snp t4_destroy_dma_tag(sc); 796228561Snp if (mtx_initialized(&sc->sc_lock)) { 797228561Snp mtx_lock(&t4_list_lock); 798228561Snp SLIST_REMOVE(&t4_list, sc, adapter, link); 799228561Snp mtx_unlock(&t4_list_lock); 800228561Snp mtx_destroy(&sc->sc_lock); 801228561Snp } 802218792Snp 803228561Snp if (mtx_initialized(&sc->sfl_lock)) 804228561Snp mtx_destroy(&sc->sfl_lock); 805228561Snp 806218792Snp bzero(sc, sizeof(*sc)); 807218792Snp 808218792Snp return (0); 809218792Snp} 810218792Snp 811218792Snp 812218792Snpstatic int 813218792Snpcxgbe_probe(device_t dev) 814218792Snp{ 815218792Snp char buf[128]; 816218792Snp struct port_info *pi = device_get_softc(dev); 817218792Snp 818228561Snp snprintf(buf, sizeof(buf), "port %d", pi->port_id); 819218792Snp device_set_desc_copy(dev, buf); 820218792Snp 821218792Snp return (BUS_PROBE_DEFAULT); 822218792Snp} 823218792Snp 824218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \ 825218792Snp IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \ 826237831Snp IFCAP_VLAN_HWTSO | IFCAP_LINKSTATE | IFCAP_HWCSUM_IPV6) 827237819Snp#define T4_CAP_ENABLE (T4_CAP) 828218792Snp 829218792Snpstatic int 830218792Snpcxgbe_attach(device_t dev) 831218792Snp{ 832218792Snp struct port_info *pi = device_get_softc(dev); 833218792Snp struct ifnet *ifp; 834218792Snp 835218792Snp /* Allocate an ifnet and set it up */ 836218792Snp ifp = if_alloc(IFT_ETHER); 837218792Snp if (ifp == NULL) { 838218792Snp device_printf(dev, "Cannot allocate ifnet\n"); 839218792Snp return (ENOMEM); 840218792Snp } 841218792Snp pi->ifp = ifp; 842218792Snp ifp->if_softc = pi; 843218792Snp 844218792Snp callout_init(&pi->tick, CALLOUT_MPSAFE); 845218792Snp 846218792Snp if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 847218792Snp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 848218792Snp 849218792Snp ifp->if_init = cxgbe_init; 850218792Snp ifp->if_ioctl = cxgbe_ioctl; 851218792Snp ifp->if_transmit = cxgbe_transmit; 852218792Snp ifp->if_qflush = cxgbe_qflush; 853218792Snp 854218792Snp ifp->if_capabilities = T4_CAP; 855237263Snp#ifdef TCP_OFFLOAD 856228561Snp if (is_offload(pi->adapter)) 857228561Snp ifp->if_capabilities |= IFCAP_TOE4; 858228561Snp#endif 859218792Snp ifp->if_capenable = T4_CAP_ENABLE; 860237799Snp ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO | 861237799Snp CSUM_UDP_IPV6 | CSUM_TCP_IPV6; 862218792Snp 863218792Snp /* Initialize ifmedia for this port */ 864218792Snp ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change, 865218792Snp cxgbe_media_status); 866218792Snp build_medialist(pi); 867218792Snp 868237263Snp pi->vlan_c = EVENTHANDLER_REGISTER(vlan_config, cxgbe_vlan_config, ifp, 869237263Snp EVENTHANDLER_PRI_ANY); 870237263Snp 871218792Snp ether_ifattach(ifp, pi->hw_addr); 872218792Snp 873237263Snp#ifdef TCP_OFFLOAD 874228561Snp if (is_offload(pi->adapter)) { 875228561Snp device_printf(dev, 876228561Snp "%d txq, %d rxq (NIC); %d txq, %d rxq (TOE)\n", 877228561Snp pi->ntxq, pi->nrxq, pi->nofldtxq, pi->nofldrxq); 878228561Snp } else 879218792Snp#endif 880228561Snp device_printf(dev, "%d txq, %d rxq\n", pi->ntxq, pi->nrxq); 881218792Snp 882218792Snp cxgbe_sysctls(pi); 883218792Snp 884218792Snp return (0); 885218792Snp} 886218792Snp 887218792Snpstatic int 888218792Snpcxgbe_detach(device_t dev) 889218792Snp{ 890218792Snp struct port_info *pi = device_get_softc(dev); 891218792Snp struct adapter *sc = pi->adapter; 892228561Snp struct ifnet *ifp = pi->ifp; 893218792Snp 894218792Snp /* Tell if_ioctl and if_init that the port is going away */ 895218792Snp ADAPTER_LOCK(sc); 896218792Snp SET_DOOMED(pi); 897218792Snp wakeup(&sc->flags); 898218792Snp while (IS_BUSY(sc)) 899218792Snp mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0); 900218792Snp SET_BUSY(sc); 901218792Snp ADAPTER_UNLOCK(sc); 902218792Snp 903237263Snp if (pi->vlan_c) 904237263Snp EVENTHANDLER_DEREGISTER(vlan_config, pi->vlan_c); 905237263Snp 906228561Snp PORT_LOCK(pi); 907228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 908228561Snp callout_stop(&pi->tick); 909228561Snp PORT_UNLOCK(pi); 910228561Snp callout_drain(&pi->tick); 911218792Snp 912228561Snp /* Let detach proceed even if these fail. */ 913228561Snp cxgbe_uninit_synchronized(pi); 914228561Snp port_full_uninit(pi); 915219286Snp 916218792Snp ifmedia_removeall(&pi->media); 917218792Snp ether_ifdetach(pi->ifp); 918218792Snp if_free(pi->ifp); 919218792Snp 920218792Snp ADAPTER_LOCK(sc); 921218792Snp CLR_BUSY(sc); 922218792Snp wakeup_one(&sc->flags); 923218792Snp ADAPTER_UNLOCK(sc); 924218792Snp 925218792Snp return (0); 926218792Snp} 927218792Snp 928218792Snpstatic void 929218792Snpcxgbe_init(void *arg) 930218792Snp{ 931218792Snp struct port_info *pi = arg; 932218792Snp struct adapter *sc = pi->adapter; 933218792Snp 934218792Snp ADAPTER_LOCK(sc); 935218792Snp cxgbe_init_locked(pi); /* releases adapter lock */ 936218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 937218792Snp} 938218792Snp 939218792Snpstatic int 940218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) 941218792Snp{ 942218792Snp int rc = 0, mtu, flags; 943218792Snp struct port_info *pi = ifp->if_softc; 944218792Snp struct adapter *sc = pi->adapter; 945218792Snp struct ifreq *ifr = (struct ifreq *)data; 946218792Snp uint32_t mask; 947218792Snp 948218792Snp switch (cmd) { 949218792Snp case SIOCSIFMTU: 950218792Snp ADAPTER_LOCK(sc); 951218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 952218792Snp if (rc) { 953218792Snpfail: 954218792Snp ADAPTER_UNLOCK(sc); 955218792Snp return (rc); 956218792Snp } 957218792Snp 958218792Snp mtu = ifr->ifr_mtu; 959218792Snp if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) { 960218792Snp rc = EINVAL; 961218792Snp } else { 962218792Snp ifp->if_mtu = mtu; 963218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 964218792Snp t4_update_fl_bufsize(ifp); 965218792Snp PORT_LOCK(pi); 966218792Snp rc = update_mac_settings(pi, XGMAC_MTU); 967218792Snp PORT_UNLOCK(pi); 968218792Snp } 969218792Snp } 970218792Snp ADAPTER_UNLOCK(sc); 971218792Snp break; 972218792Snp 973218792Snp case SIOCSIFFLAGS: 974218792Snp ADAPTER_LOCK(sc); 975218792Snp if (IS_DOOMED(pi)) { 976218792Snp rc = ENXIO; 977218792Snp goto fail; 978218792Snp } 979218792Snp if (ifp->if_flags & IFF_UP) { 980218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 981218792Snp flags = pi->if_flags; 982218792Snp if ((ifp->if_flags ^ flags) & 983218792Snp (IFF_PROMISC | IFF_ALLMULTI)) { 984218792Snp if (IS_BUSY(sc)) { 985218792Snp rc = EBUSY; 986218792Snp goto fail; 987218792Snp } 988218792Snp PORT_LOCK(pi); 989218792Snp rc = update_mac_settings(pi, 990218792Snp XGMAC_PROMISC | XGMAC_ALLMULTI); 991218792Snp PORT_UNLOCK(pi); 992218792Snp } 993218792Snp ADAPTER_UNLOCK(sc); 994218792Snp } else 995218792Snp rc = cxgbe_init_locked(pi); 996218792Snp pi->if_flags = ifp->if_flags; 997218792Snp } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 998218792Snp rc = cxgbe_uninit_locked(pi); 999218792Snp else 1000218792Snp ADAPTER_UNLOCK(sc); 1001218792Snp 1002218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 1003218792Snp break; 1004218792Snp 1005218792Snp case SIOCADDMULTI: 1006218792Snp case SIOCDELMULTI: /* these two can be called with a mutex held :-( */ 1007218792Snp ADAPTER_LOCK(sc); 1008218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 1009218792Snp if (rc) 1010218792Snp goto fail; 1011218792Snp 1012218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1013218792Snp PORT_LOCK(pi); 1014218792Snp rc = update_mac_settings(pi, XGMAC_MCADDRS); 1015218792Snp PORT_UNLOCK(pi); 1016218792Snp } 1017218792Snp ADAPTER_UNLOCK(sc); 1018218792Snp break; 1019218792Snp 1020218792Snp case SIOCSIFCAP: 1021218792Snp ADAPTER_LOCK(sc); 1022218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 1023218792Snp if (rc) 1024218792Snp goto fail; 1025218792Snp 1026218792Snp mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1027218792Snp if (mask & IFCAP_TXCSUM) { 1028218792Snp ifp->if_capenable ^= IFCAP_TXCSUM; 1029218792Snp ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 1030218792Snp 1031237831Snp if (IFCAP_TSO4 & ifp->if_capenable && 1032218792Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1033237799Snp ifp->if_capenable &= ~IFCAP_TSO4; 1034218792Snp if_printf(ifp, 1035237831Snp "tso4 disabled due to -txcsum.\n"); 1036218792Snp } 1037218792Snp } 1038237799Snp if (mask & IFCAP_TXCSUM_IPV6) { 1039237799Snp ifp->if_capenable ^= IFCAP_TXCSUM_IPV6; 1040237799Snp ifp->if_hwassist ^= (CSUM_UDP_IPV6 | CSUM_TCP_IPV6); 1041237799Snp 1042237799Snp if (IFCAP_TSO6 & ifp->if_capenable && 1043237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1044237799Snp ifp->if_capenable &= ~IFCAP_TSO6; 1045237799Snp if_printf(ifp, 1046237799Snp "tso6 disabled due to -txcsum6.\n"); 1047237799Snp } 1048237799Snp } 1049218792Snp if (mask & IFCAP_RXCSUM) 1050218792Snp ifp->if_capenable ^= IFCAP_RXCSUM; 1051237799Snp if (mask & IFCAP_RXCSUM_IPV6) 1052237799Snp ifp->if_capenable ^= IFCAP_RXCSUM_IPV6; 1053237799Snp 1054237799Snp /* 1055237799Snp * Note that we leave CSUM_TSO alone (it is always set). The 1056237799Snp * kernel takes both IFCAP_TSOx and CSUM_TSO into account before 1057237799Snp * sending a TSO request our way, so it's sufficient to toggle 1058237799Snp * IFCAP_TSOx only. 1059237799Snp */ 1060218792Snp if (mask & IFCAP_TSO4) { 1061237799Snp if (!(IFCAP_TSO4 & ifp->if_capenable) && 1062237799Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 1063237799Snp if_printf(ifp, "enable txcsum first.\n"); 1064237799Snp rc = EAGAIN; 1065237799Snp goto fail; 1066237799Snp } 1067218792Snp ifp->if_capenable ^= IFCAP_TSO4; 1068218792Snp } 1069237799Snp if (mask & IFCAP_TSO6) { 1070237799Snp if (!(IFCAP_TSO6 & ifp->if_capenable) && 1071237799Snp !(IFCAP_TXCSUM_IPV6 & ifp->if_capenable)) { 1072237799Snp if_printf(ifp, "enable txcsum6 first.\n"); 1073237799Snp rc = EAGAIN; 1074237799Snp goto fail; 1075237799Snp } 1076237799Snp ifp->if_capenable ^= IFCAP_TSO6; 1077237799Snp } 1078218792Snp if (mask & IFCAP_LRO) { 1079237819Snp#if defined(INET) || defined(INET6) 1080218792Snp int i; 1081218792Snp struct sge_rxq *rxq; 1082218792Snp 1083218792Snp ifp->if_capenable ^= IFCAP_LRO; 1084218792Snp for_each_rxq(pi, i, rxq) { 1085218792Snp if (ifp->if_capenable & IFCAP_LRO) 1086228561Snp rxq->iq.flags |= IQ_LRO_ENABLED; 1087218792Snp else 1088228561Snp rxq->iq.flags &= ~IQ_LRO_ENABLED; 1089218792Snp } 1090218792Snp#endif 1091218792Snp } 1092237263Snp#ifdef TCP_OFFLOAD 1093228561Snp if (mask & IFCAP_TOE) { 1094228561Snp int enable = (ifp->if_capenable ^ mask) & IFCAP_TOE; 1095228561Snp 1096228561Snp rc = toe_capability(pi, enable); 1097228561Snp if (rc != 0) 1098228561Snp goto fail; 1099228561Snp 1100228561Snp ifp->if_capenable ^= mask; 1101218792Snp } 1102218792Snp#endif 1103218792Snp if (mask & IFCAP_VLAN_HWTAGGING) { 1104218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1105218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1106218792Snp PORT_LOCK(pi); 1107218792Snp rc = update_mac_settings(pi, XGMAC_VLANEX); 1108218792Snp PORT_UNLOCK(pi); 1109218792Snp } 1110218792Snp } 1111218792Snp if (mask & IFCAP_VLAN_MTU) { 1112218792Snp ifp->if_capenable ^= IFCAP_VLAN_MTU; 1113218792Snp 1114218792Snp /* Need to find out how to disable auto-mtu-inflation */ 1115218792Snp } 1116218792Snp if (mask & IFCAP_VLAN_HWTSO) 1117218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1118218792Snp if (mask & IFCAP_VLAN_HWCSUM) 1119218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 1120218792Snp 1121218792Snp#ifdef VLAN_CAPABILITIES 1122218792Snp VLAN_CAPABILITIES(ifp); 1123218792Snp#endif 1124218792Snp ADAPTER_UNLOCK(sc); 1125218792Snp break; 1126218792Snp 1127218792Snp case SIOCSIFMEDIA: 1128218792Snp case SIOCGIFMEDIA: 1129218792Snp ifmedia_ioctl(ifp, ifr, &pi->media, cmd); 1130218792Snp break; 1131218792Snp 1132218792Snp default: 1133218792Snp rc = ether_ioctl(ifp, cmd, data); 1134218792Snp } 1135218792Snp 1136218792Snp return (rc); 1137218792Snp} 1138218792Snp 1139218792Snpstatic int 1140218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m) 1141218792Snp{ 1142218792Snp struct port_info *pi = ifp->if_softc; 1143218792Snp struct adapter *sc = pi->adapter; 1144218792Snp struct sge_txq *txq = &sc->sge.txq[pi->first_txq]; 1145218792Snp struct buf_ring *br; 1146218792Snp int rc; 1147218792Snp 1148218792Snp M_ASSERTPKTHDR(m); 1149218792Snp 1150228561Snp if (__predict_false(pi->link_cfg.link_ok == 0)) { 1151218792Snp m_freem(m); 1152228561Snp return (ENETDOWN); 1153218792Snp } 1154218792Snp 1155218792Snp if (m->m_flags & M_FLOWID) 1156218792Snp txq += (m->m_pkthdr.flowid % pi->ntxq); 1157220873Snp br = txq->br; 1158218792Snp 1159218792Snp if (TXQ_TRYLOCK(txq) == 0) { 1160228561Snp struct sge_eq *eq = &txq->eq; 1161228561Snp 1162218792Snp /* 1163228561Snp * It is possible that t4_eth_tx finishes up and releases the 1164228561Snp * lock between the TRYLOCK above and the drbr_enqueue here. We 1165228561Snp * need to make sure that this mbuf doesn't just sit there in 1166228561Snp * the drbr. 1167218792Snp */ 1168218792Snp 1169228561Snp rc = drbr_enqueue(ifp, br, m); 1170228561Snp if (rc == 0 && callout_pending(&eq->tx_callout) == 0 && 1171228561Snp !(eq->flags & EQ_DOOMED)) 1172228561Snp callout_reset(&eq->tx_callout, 1, t4_tx_callout, eq); 1173228561Snp return (rc); 1174218792Snp } 1175218792Snp 1176218792Snp /* 1177218792Snp * txq->m is the mbuf that is held up due to a temporary shortage of 1178218792Snp * resources and it should be put on the wire first. Then what's in 1179218792Snp * drbr and finally the mbuf that was just passed in to us. 1180218792Snp * 1181218792Snp * Return code should indicate the fate of the mbuf that was passed in 1182218792Snp * this time. 1183218792Snp */ 1184218792Snp 1185218792Snp TXQ_LOCK_ASSERT_OWNED(txq); 1186218792Snp if (drbr_needs_enqueue(ifp, br) || txq->m) { 1187218792Snp 1188218792Snp /* Queued for transmission. */ 1189218792Snp 1190218792Snp rc = drbr_enqueue(ifp, br, m); 1191218792Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 1192218792Snp (void) t4_eth_tx(ifp, txq, m); 1193218792Snp TXQ_UNLOCK(txq); 1194218792Snp return (rc); 1195218792Snp } 1196218792Snp 1197218792Snp /* Direct transmission. */ 1198218792Snp rc = t4_eth_tx(ifp, txq, m); 1199218792Snp if (rc != 0 && txq->m) 1200218792Snp rc = 0; /* held, will be transmitted soon (hopefully) */ 1201218792Snp 1202218792Snp TXQ_UNLOCK(txq); 1203218792Snp return (rc); 1204218792Snp} 1205218792Snp 1206218792Snpstatic void 1207218792Snpcxgbe_qflush(struct ifnet *ifp) 1208218792Snp{ 1209218792Snp struct port_info *pi = ifp->if_softc; 1210220649Snp struct sge_txq *txq; 1211220649Snp int i; 1212220649Snp struct mbuf *m; 1213218792Snp 1214228561Snp /* queues do not exist if !PORT_INIT_DONE. */ 1215228561Snp if (pi->flags & PORT_INIT_DONE) { 1216220649Snp for_each_txq(pi, i, txq) { 1217220649Snp TXQ_LOCK(txq); 1218220649Snp m_freem(txq->m); 1219228561Snp txq->m = NULL; 1220220873Snp while ((m = buf_ring_dequeue_sc(txq->br)) != NULL) 1221220649Snp m_freem(m); 1222220649Snp TXQ_UNLOCK(txq); 1223220649Snp } 1224220649Snp } 1225220649Snp if_qflush(ifp); 1226218792Snp} 1227218792Snp 1228218792Snpstatic int 1229218792Snpcxgbe_media_change(struct ifnet *ifp) 1230218792Snp{ 1231218792Snp struct port_info *pi = ifp->if_softc; 1232218792Snp 1233218792Snp device_printf(pi->dev, "%s unimplemented.\n", __func__); 1234218792Snp 1235218792Snp return (EOPNOTSUPP); 1236218792Snp} 1237218792Snp 1238218792Snpstatic void 1239218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1240218792Snp{ 1241218792Snp struct port_info *pi = ifp->if_softc; 1242218792Snp struct ifmedia_entry *cur = pi->media.ifm_cur; 1243218792Snp int speed = pi->link_cfg.speed; 1244218792Snp int data = (pi->port_type << 8) | pi->mod_type; 1245218792Snp 1246218792Snp if (cur->ifm_data != data) { 1247218792Snp build_medialist(pi); 1248218792Snp cur = pi->media.ifm_cur; 1249218792Snp } 1250218792Snp 1251218792Snp ifmr->ifm_status = IFM_AVALID; 1252218792Snp if (!pi->link_cfg.link_ok) 1253218792Snp return; 1254218792Snp 1255218792Snp ifmr->ifm_status |= IFM_ACTIVE; 1256218792Snp 1257218792Snp /* active and current will differ iff current media is autoselect. */ 1258218792Snp if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO) 1259218792Snp return; 1260218792Snp 1261218792Snp ifmr->ifm_active = IFM_ETHER | IFM_FDX; 1262218792Snp if (speed == SPEED_10000) 1263218792Snp ifmr->ifm_active |= IFM_10G_T; 1264218792Snp else if (speed == SPEED_1000) 1265218792Snp ifmr->ifm_active |= IFM_1000_T; 1266218792Snp else if (speed == SPEED_100) 1267218792Snp ifmr->ifm_active |= IFM_100_TX; 1268218792Snp else if (speed == SPEED_10) 1269218792Snp ifmr->ifm_active |= IFM_10_T; 1270218792Snp else 1271218792Snp KASSERT(0, ("%s: link up but speed unknown (%u)", __func__, 1272218792Snp speed)); 1273218792Snp} 1274218792Snp 1275218792Snpvoid 1276218792Snpt4_fatal_err(struct adapter *sc) 1277218792Snp{ 1278218792Snp t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0); 1279218792Snp t4_intr_disable(sc); 1280218792Snp log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n", 1281218792Snp device_get_nameunit(sc->dev)); 1282218792Snp} 1283218792Snp 1284218792Snpstatic int 1285218792Snpmap_bars(struct adapter *sc) 1286218792Snp{ 1287218792Snp sc->regs_rid = PCIR_BAR(0); 1288218792Snp sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1289218792Snp &sc->regs_rid, RF_ACTIVE); 1290218792Snp if (sc->regs_res == NULL) { 1291218792Snp device_printf(sc->dev, "cannot map registers.\n"); 1292218792Snp return (ENXIO); 1293218792Snp } 1294218792Snp sc->bt = rman_get_bustag(sc->regs_res); 1295218792Snp sc->bh = rman_get_bushandle(sc->regs_res); 1296218792Snp sc->mmio_len = rman_get_size(sc->regs_res); 1297218792Snp 1298218792Snp sc->msix_rid = PCIR_BAR(4); 1299218792Snp sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1300218792Snp &sc->msix_rid, RF_ACTIVE); 1301218792Snp if (sc->msix_res == NULL) { 1302218792Snp device_printf(sc->dev, "cannot map MSI-X BAR.\n"); 1303218792Snp return (ENXIO); 1304218792Snp } 1305218792Snp 1306218792Snp return (0); 1307218792Snp} 1308218792Snp 1309218792Snpstatic void 1310218792Snpsetup_memwin(struct adapter *sc) 1311218792Snp{ 1312237587Snp uint32_t bar0; 1313218792Snp 1314237587Snp /* 1315237587Snp * Read low 32b of bar0 indirectly via the hardware backdoor mechanism. 1316237587Snp * Works from within PCI passthrough environments too, where 1317237587Snp * rman_get_start() can return a different value. We need to program 1318237587Snp * the memory window decoders with the actual addresses that will be 1319237587Snp * coming across the PCIe link. 1320237587Snp */ 1321237587Snp bar0 = t4_hw_pci_read_cfg4(sc, PCIR_BAR(0)); 1322237587Snp bar0 &= (uint32_t) PCIM_BAR_MEM_BASE; 1323218792Snp 1324218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 0), 1325218792Snp (bar0 + MEMWIN0_BASE) | V_BIR(0) | 1326218792Snp V_WINDOW(ilog2(MEMWIN0_APERTURE) - 10)); 1327218792Snp 1328218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 1), 1329218792Snp (bar0 + MEMWIN1_BASE) | V_BIR(0) | 1330218792Snp V_WINDOW(ilog2(MEMWIN1_APERTURE) - 10)); 1331218792Snp 1332218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2), 1333218792Snp (bar0 + MEMWIN2_BASE) | V_BIR(0) | 1334218792Snp V_WINDOW(ilog2(MEMWIN2_APERTURE) - 10)); 1335237587Snp 1336237587Snp /* flush */ 1337237587Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2)); 1338218792Snp} 1339218792Snp 1340218792Snpstatic int 1341218792Snpcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g, 1342218792Snp struct intrs_and_queues *iaq) 1343218792Snp{ 1344228561Snp int rc, itype, navail, nrxq10g, nrxq1g, n; 1345228561Snp int nofldrxq10g = 0, nofldrxq1g = 0; 1346218792Snp 1347218792Snp bzero(iaq, sizeof(*iaq)); 1348218792Snp 1349228561Snp iaq->ntxq10g = t4_ntxq10g; 1350228561Snp iaq->ntxq1g = t4_ntxq1g; 1351228561Snp iaq->nrxq10g = nrxq10g = t4_nrxq10g; 1352228561Snp iaq->nrxq1g = nrxq1g = t4_nrxq1g; 1353237263Snp#ifdef TCP_OFFLOAD 1354237463Snp if (is_offload(sc)) { 1355237463Snp iaq->nofldtxq10g = t4_nofldtxq10g; 1356237463Snp iaq->nofldtxq1g = t4_nofldtxq1g; 1357237463Snp iaq->nofldrxq10g = nofldrxq10g = t4_nofldrxq10g; 1358237463Snp iaq->nofldrxq1g = nofldrxq1g = t4_nofldrxq1g; 1359237463Snp } 1360228561Snp#endif 1361228561Snp 1362219944Snp for (itype = INTR_MSIX; itype; itype >>= 1) { 1363218792Snp 1364228561Snp if ((itype & t4_intr_types) == 0) 1365218792Snp continue; /* not allowed */ 1366218792Snp 1367219944Snp if (itype == INTR_MSIX) 1368218792Snp navail = pci_msix_count(sc->dev); 1369219944Snp else if (itype == INTR_MSI) 1370218792Snp navail = pci_msi_count(sc->dev); 1371218792Snp else 1372218792Snp navail = 1; 1373228561Snprestart: 1374218792Snp if (navail == 0) 1375218792Snp continue; 1376218792Snp 1377218792Snp iaq->intr_type = itype; 1378228561Snp iaq->intr_flags = 0; 1379218792Snp 1380228561Snp /* 1381228561Snp * Best option: an interrupt vector for errors, one for the 1382228561Snp * firmware event queue, and one each for each rxq (NIC as well 1383228561Snp * as offload). 1384228561Snp */ 1385228561Snp iaq->nirq = T4_EXTRA_INTR; 1386228561Snp iaq->nirq += n10g * (nrxq10g + nofldrxq10g); 1387228561Snp iaq->nirq += n1g * (nrxq1g + nofldrxq1g); 1388228561Snp if (iaq->nirq <= navail && 1389228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) { 1390228561Snp iaq->intr_flags |= INTR_DIRECT; 1391228561Snp goto allocate; 1392228561Snp } 1393218792Snp 1394228561Snp /* 1395228561Snp * Second best option: an interrupt vector for errors, one for 1396228561Snp * the firmware event queue, and one each for either NIC or 1397228561Snp * offload rxq's. 1398228561Snp */ 1399228561Snp iaq->nirq = T4_EXTRA_INTR; 1400228561Snp iaq->nirq += n10g * max(nrxq10g, nofldrxq10g); 1401228561Snp iaq->nirq += n1g * max(nrxq1g, nofldrxq1g); 1402228561Snp if (iaq->nirq <= navail && 1403228561Snp (itype != INTR_MSI || powerof2(iaq->nirq))) 1404228561Snp goto allocate; 1405218792Snp 1406228561Snp /* 1407228561Snp * Next best option: an interrupt vector for errors, one for the 1408228561Snp * firmware event queue, and at least one per port. At this 1409228561Snp * point we know we'll have to downsize nrxq or nofldrxq to fit 1410228561Snp * what's available to us. 1411228561Snp */ 1412228561Snp iaq->nirq = T4_EXTRA_INTR; 1413228561Snp iaq->nirq += n10g + n1g; 1414228561Snp if (iaq->nirq <= navail) { 1415228561Snp int leftover = navail - iaq->nirq; 1416218792Snp 1417228561Snp if (n10g > 0) { 1418228561Snp int target = max(nrxq10g, nofldrxq10g); 1419219944Snp 1420228561Snp n = 1; 1421228561Snp while (n < target && leftover >= n10g) { 1422228561Snp leftover -= n10g; 1423228561Snp iaq->nirq += n10g; 1424228561Snp n++; 1425228561Snp } 1426228561Snp iaq->nrxq10g = min(n, nrxq10g); 1427237263Snp#ifdef TCP_OFFLOAD 1428237463Snp if (is_offload(sc)) 1429237463Snp iaq->nofldrxq10g = min(n, nofldrxq10g); 1430228561Snp#endif 1431228561Snp } 1432218792Snp 1433228561Snp if (n1g > 0) { 1434228561Snp int target = max(nrxq1g, nofldrxq1g); 1435219944Snp 1436228561Snp n = 1; 1437228561Snp while (n < target && leftover >= n1g) { 1438228561Snp leftover -= n1g; 1439228561Snp iaq->nirq += n1g; 1440228561Snp n++; 1441219944Snp } 1442228561Snp iaq->nrxq1g = min(n, nrxq1g); 1443237263Snp#ifdef TCP_OFFLOAD 1444237463Snp if (is_offload(sc)) 1445237463Snp iaq->nofldrxq1g = min(n, nofldrxq1g); 1446228561Snp#endif 1447219944Snp } 1448219944Snp 1449228561Snp if (itype != INTR_MSI || powerof2(iaq->nirq)) 1450228561Snp goto allocate; 1451218792Snp } 1452218792Snp 1453228561Snp /* 1454228561Snp * Least desirable option: one interrupt vector for everything. 1455228561Snp */ 1456228561Snp iaq->nirq = iaq->nrxq10g = iaq->nrxq1g = 1; 1457237263Snp#ifdef TCP_OFFLOAD 1458237463Snp if (is_offload(sc)) 1459237463Snp iaq->nofldrxq10g = iaq->nofldrxq1g = 1; 1460228561Snp#endif 1461228561Snp 1462228561Snpallocate: 1463218792Snp navail = iaq->nirq; 1464218792Snp rc = 0; 1465219944Snp if (itype == INTR_MSIX) 1466218792Snp rc = pci_alloc_msix(sc->dev, &navail); 1467219944Snp else if (itype == INTR_MSI) 1468218792Snp rc = pci_alloc_msi(sc->dev, &navail); 1469218792Snp 1470218792Snp if (rc == 0) { 1471218792Snp if (navail == iaq->nirq) 1472218792Snp return (0); 1473218792Snp 1474218792Snp /* 1475218792Snp * Didn't get the number requested. Use whatever number 1476218792Snp * the kernel is willing to allocate (it's in navail). 1477218792Snp */ 1478228561Snp device_printf(sc->dev, "fewer vectors than requested, " 1479228561Snp "type=%d, req=%d, rcvd=%d; will downshift req.\n", 1480228561Snp itype, iaq->nirq, navail); 1481218792Snp pci_release_msi(sc->dev); 1482228561Snp goto restart; 1483218792Snp } 1484218792Snp 1485218792Snp device_printf(sc->dev, 1486218792Snp "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n", 1487218792Snp itype, rc, iaq->nirq, navail); 1488218792Snp } 1489218792Snp 1490218792Snp device_printf(sc->dev, 1491218792Snp "failed to find a usable interrupt type. " 1492228561Snp "allowed=%d, msi-x=%d, msi=%d, intx=1", t4_intr_types, 1493218792Snp pci_msix_count(sc->dev), pci_msi_count(sc->dev)); 1494218792Snp 1495218792Snp return (ENXIO); 1496218792Snp} 1497218792Snp 1498218792Snp/* 1499228561Snp * Install a compatible firmware (if required), establish contact with it (by 1500228561Snp * saying hello), and reset the device. If we end up as the master driver, 1501228561Snp * partition adapter resources by providing a configuration file to the 1502228561Snp * firmware. 1503218792Snp */ 1504218792Snpstatic int 1505218792Snpprep_firmware(struct adapter *sc) 1506218792Snp{ 1507228561Snp const struct firmware *fw = NULL, *cfg = NULL, *default_cfg; 1508218792Snp int rc; 1509218792Snp enum dev_state state; 1510218792Snp 1511228561Snp default_cfg = firmware_get(T4_CFGNAME); 1512228561Snp 1513218792Snp /* Check firmware version and install a different one if necessary */ 1514218792Snp rc = t4_check_fw_version(sc); 1515234831Snp snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u", 1516234831Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1517234831Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1518234831Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1519234831Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 1520228561Snp if (rc != 0) { 1521219287Snp uint32_t v = 0; 1522218792Snp 1523218792Snp fw = firmware_get(T4_FWNAME); 1524219287Snp if (fw != NULL) { 1525219287Snp const struct fw_hdr *hdr = (const void *)fw->data; 1526219287Snp 1527219287Snp v = ntohl(hdr->fw_ver); 1528219287Snp 1529219287Snp /* 1530219287Snp * The firmware module will not be used if it isn't the 1531219287Snp * same major version as what the driver was compiled 1532228561Snp * with. 1533219287Snp */ 1534219287Snp if (G_FW_HDR_FW_VER_MAJOR(v) != FW_VERSION_MAJOR) { 1535219287Snp device_printf(sc->dev, 1536219287Snp "Found firmware image but version %d " 1537219287Snp "can not be used with this driver (%d)\n", 1538219287Snp G_FW_HDR_FW_VER_MAJOR(v), FW_VERSION_MAJOR); 1539219287Snp 1540219287Snp firmware_put(fw, FIRMWARE_UNLOAD); 1541219287Snp fw = NULL; 1542219287Snp } 1543218792Snp } 1544218792Snp 1545228561Snp if (fw == NULL && rc < 0) { 1546219287Snp device_printf(sc->dev, "No usable firmware. " 1547228561Snp "card has %d.%d.%d, driver compiled with %d.%d.%d", 1548219287Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1549219287Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1550219287Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1551219287Snp FW_VERSION_MAJOR, FW_VERSION_MINOR, 1552228561Snp FW_VERSION_MICRO); 1553228561Snp rc = EAGAIN; 1554228561Snp goto done; 1555219287Snp } 1556219287Snp 1557219287Snp /* 1558219287Snp * Always upgrade, even for minor/micro/build mismatches. 1559219287Snp * Downgrade only for a major version mismatch or if 1560219287Snp * force_firmware_install was specified. 1561219287Snp */ 1562228561Snp if (fw != NULL && (rc < 0 || v > sc->params.fw_vers)) { 1563218792Snp device_printf(sc->dev, 1564219287Snp "installing firmware %d.%d.%d.%d on card.\n", 1565219287Snp G_FW_HDR_FW_VER_MAJOR(v), G_FW_HDR_FW_VER_MINOR(v), 1566219287Snp G_FW_HDR_FW_VER_MICRO(v), G_FW_HDR_FW_VER_BUILD(v)); 1567219287Snp 1568219287Snp rc = -t4_load_fw(sc, fw->data, fw->datasize); 1569219287Snp if (rc != 0) { 1570219287Snp device_printf(sc->dev, 1571219287Snp "failed to install firmware: %d\n", rc); 1572228561Snp goto done; 1573219287Snp } else { 1574219287Snp /* refresh */ 1575219287Snp (void) t4_check_fw_version(sc); 1576234831Snp snprintf(sc->fw_version, 1577234831Snp sizeof(sc->fw_version), "%u.%u.%u.%u", 1578234831Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1579234831Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1580234831Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1581234831Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 1582219287Snp } 1583218792Snp } 1584218792Snp } 1585218792Snp 1586228561Snp /* Contact firmware. */ 1587228561Snp rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MAY, &state); 1588218792Snp if (rc < 0) { 1589218792Snp rc = -rc; 1590218792Snp device_printf(sc->dev, 1591218792Snp "failed to connect to the firmware: %d.\n", rc); 1592228561Snp goto done; 1593218792Snp } 1594228561Snp if (rc == sc->mbox) 1595228561Snp sc->flags |= MASTER_PF; 1596218792Snp 1597218792Snp /* Reset device */ 1598218792Snp rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST); 1599218792Snp if (rc != 0) { 1600218792Snp device_printf(sc->dev, "firmware reset failed: %d.\n", rc); 1601218792Snp if (rc != ETIMEDOUT && rc != EIO) 1602218792Snp t4_fw_bye(sc, sc->mbox); 1603228561Snp goto done; 1604218792Snp } 1605218792Snp 1606228561Snp /* Partition adapter resources as specified in the config file. */ 1607228561Snp if (sc->flags & MASTER_PF) { 1608228561Snp if (strncmp(t4_cfg_file, "default", sizeof(t4_cfg_file))) { 1609228561Snp char s[32]; 1610228561Snp 1611228561Snp snprintf(s, sizeof(s), "t4fw_cfg_%s", t4_cfg_file); 1612228561Snp cfg = firmware_get(s); 1613228561Snp if (cfg == NULL) { 1614228561Snp device_printf(sc->dev, 1615228561Snp "unable to locate %s module, " 1616228561Snp "will use default config file.\n", s); 1617228561Snp } 1618228561Snp } 1619228561Snp 1620228561Snp rc = partition_resources(sc, cfg ? cfg : default_cfg); 1621228561Snp if (rc != 0) 1622228561Snp goto done; /* error message displayed already */ 1623228561Snp } 1624228561Snp 1625218792Snp sc->flags |= FW_OK; 1626218792Snp 1627228561Snpdone: 1628228561Snp if (fw != NULL) 1629228561Snp firmware_put(fw, FIRMWARE_UNLOAD); 1630228561Snp if (cfg != NULL) 1631228561Snp firmware_put(cfg, FIRMWARE_UNLOAD); 1632228561Snp if (default_cfg != NULL) 1633228561Snp firmware_put(default_cfg, FIRMWARE_UNLOAD); 1634228561Snp 1635228561Snp return (rc); 1636218792Snp} 1637218792Snp 1638228561Snp#define FW_PARAM_DEV(param) \ 1639228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ 1640228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) 1641228561Snp#define FW_PARAM_PFVF(param) \ 1642228561Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ 1643228561Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)) 1644228561Snp 1645228561Snp/* 1646228561Snp * Upload configuration file to card's memory. 1647228561Snp */ 1648218792Snpstatic int 1649228561Snpupload_config_file(struct adapter *sc, const struct firmware *fw, uint32_t *mt, 1650228561Snp uint32_t *ma) 1651222551Snp{ 1652228561Snp int rc, i; 1653228561Snp uint32_t param, val, mtype, maddr, bar, off, win, remaining; 1654228561Snp const uint32_t *b; 1655222551Snp 1656228561Snp /* Figure out where the firmware wants us to upload it. */ 1657228561Snp param = FW_PARAM_DEV(CF); 1658228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, ¶m, &val); 1659222551Snp if (rc != 0) { 1660228561Snp /* Firmwares without config file support will fail this way */ 1661222551Snp device_printf(sc->dev, 1662228561Snp "failed to query config file location: %d.\n", rc); 1663222551Snp return (rc); 1664222551Snp } 1665228561Snp *mt = mtype = G_FW_PARAMS_PARAM_Y(val); 1666228561Snp *ma = maddr = G_FW_PARAMS_PARAM_Z(val) << 16; 1667222551Snp 1668228561Snp if (maddr & 3) { 1669228561Snp device_printf(sc->dev, 1670228561Snp "cannot upload config file (type %u, addr %x).\n", 1671228561Snp mtype, maddr); 1672228561Snp return (EFAULT); 1673228561Snp } 1674222551Snp 1675228561Snp /* Translate mtype/maddr to an address suitable for the PCIe window */ 1676228561Snp val = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 1677228561Snp val &= F_EDRAM0_ENABLE | F_EDRAM1_ENABLE | F_EXT_MEM_ENABLE; 1678228561Snp switch (mtype) { 1679228561Snp case FW_MEMTYPE_CF_EDC0: 1680228561Snp if (!(val & F_EDRAM0_ENABLE)) 1681228561Snp goto err; 1682228561Snp bar = t4_read_reg(sc, A_MA_EDRAM0_BAR); 1683228561Snp maddr += G_EDRAM0_BASE(bar) << 20; 1684228561Snp break; 1685228561Snp 1686228561Snp case FW_MEMTYPE_CF_EDC1: 1687228561Snp if (!(val & F_EDRAM1_ENABLE)) 1688228561Snp goto err; 1689228561Snp bar = t4_read_reg(sc, A_MA_EDRAM1_BAR); 1690228561Snp maddr += G_EDRAM1_BASE(bar) << 20; 1691228561Snp break; 1692228561Snp 1693228561Snp case FW_MEMTYPE_CF_EXTMEM: 1694228561Snp if (!(val & F_EXT_MEM_ENABLE)) 1695228561Snp goto err; 1696228561Snp bar = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 1697228561Snp maddr += G_EXT_MEM_BASE(bar) << 20; 1698228561Snp break; 1699228561Snp 1700228561Snp default: 1701228561Snperr: 1702228561Snp device_printf(sc->dev, 1703228561Snp "cannot upload config file (type %u, enabled %u).\n", 1704228561Snp mtype, val); 1705228561Snp return (EFAULT); 1706228561Snp } 1707228561Snp 1708228561Snp /* 1709228561Snp * Position the PCIe window (we use memwin2) to the 16B aligned area 1710228561Snp * just at/before the upload location. 1711228561Snp */ 1712228561Snp win = maddr & ~0xf; 1713228561Snp off = maddr - win; /* offset from the start of the window. */ 1714228561Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2), win); 1715228561Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2)); 1716228561Snp 1717228561Snp remaining = fw->datasize; 1718228561Snp if (remaining > FLASH_CFG_MAX_SIZE || 1719228561Snp remaining > MEMWIN2_APERTURE - off) { 1720228561Snp device_printf(sc->dev, "cannot upload config file all at once " 1721228561Snp "(size %u, max %u, room %u).\n", 1722228561Snp remaining, FLASH_CFG_MAX_SIZE, MEMWIN2_APERTURE - off); 1723228561Snp return (EFBIG); 1724228561Snp } 1725228561Snp 1726228561Snp /* 1727228561Snp * XXX: sheer laziness. We deliberately added 4 bytes of useless 1728228561Snp * stuffing/comments at the end of the config file so it's ok to simply 1729228561Snp * throw away the last remaining bytes when the config file is not an 1730228561Snp * exact multiple of 4. 1731228561Snp */ 1732228561Snp b = fw->data; 1733228561Snp for (i = 0; remaining >= 4; i += 4, remaining -= 4) 1734228561Snp t4_write_reg(sc, MEMWIN2_BASE + off + i, *b++); 1735228561Snp 1736228561Snp return (rc); 1737222551Snp} 1738222551Snp 1739228561Snp/* 1740228561Snp * Partition chip resources for use between various PFs, VFs, etc. This is done 1741228561Snp * by uploading the firmware configuration file to the adapter and instructing 1742228561Snp * the firmware to process it. 1743228561Snp */ 1744222551Snpstatic int 1745228561Snppartition_resources(struct adapter *sc, const struct firmware *cfg) 1746218792Snp{ 1747218792Snp int rc; 1748228561Snp struct fw_caps_config_cmd caps; 1749228561Snp uint32_t mtype, maddr, finicsum, cfcsum; 1750218792Snp 1751228561Snp rc = cfg ? upload_config_file(sc, cfg, &mtype, &maddr) : ENOENT; 1752228561Snp if (rc != 0) { 1753228561Snp mtype = FW_MEMTYPE_CF_FLASH; 1754228561Snp maddr = t4_flash_cfg_addr(sc); 1755228561Snp } 1756228561Snp 1757228561Snp bzero(&caps, sizeof(caps)); 1758228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1759218792Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1760228561Snp caps.cfvalid_to_len16 = htobe32(F_FW_CAPS_CONFIG_CMD_CFVALID | 1761228561Snp V_FW_CAPS_CONFIG_CMD_MEMTYPE_CF(mtype) | 1762228561Snp V_FW_CAPS_CONFIG_CMD_MEMADDR64K_CF(maddr >> 16) | FW_LEN16(caps)); 1763228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 1764228561Snp if (rc != 0) { 1765228561Snp device_printf(sc->dev, 1766228561Snp "failed to pre-process config file: %d.\n", rc); 1767218792Snp return (rc); 1768228561Snp } 1769218792Snp 1770228561Snp finicsum = be32toh(caps.finicsum); 1771228561Snp cfcsum = be32toh(caps.cfcsum); 1772228561Snp if (finicsum != cfcsum) { 1773228561Snp device_printf(sc->dev, 1774228561Snp "WARNING: config file checksum mismatch: %08x %08x\n", 1775228561Snp finicsum, cfcsum); 1776228561Snp } 1777228561Snp sc->cfcsum = cfcsum; 1778218792Snp 1779228561Snp#define LIMIT_CAPS(x) do { \ 1780228561Snp caps.x &= htobe16(t4_##x##_allowed); \ 1781228561Snp sc->x = htobe16(caps.x); \ 1782228561Snp} while (0) 1783228561Snp 1784228561Snp /* 1785228561Snp * Let the firmware know what features will (not) be used so it can tune 1786228561Snp * things accordingly. 1787228561Snp */ 1788228561Snp LIMIT_CAPS(linkcaps); 1789228561Snp LIMIT_CAPS(niccaps); 1790228561Snp LIMIT_CAPS(toecaps); 1791228561Snp LIMIT_CAPS(rdmacaps); 1792228561Snp LIMIT_CAPS(iscsicaps); 1793228561Snp LIMIT_CAPS(fcoecaps); 1794228561Snp#undef LIMIT_CAPS 1795228561Snp 1796228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1797218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE); 1798228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 1799228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), NULL); 1800228561Snp if (rc != 0) { 1801228561Snp device_printf(sc->dev, 1802228561Snp "failed to process config file: %d.\n", rc); 1803228561Snp return (rc); 1804228561Snp } 1805218792Snp 1806228561Snp return (0); 1807218792Snp} 1808218792Snp 1809228561Snp/* 1810228561Snp * Retrieve parameters that are needed (or nice to have) prior to calling 1811228561Snp * t4_sge_init and t4_fw_initialize. 1812228561Snp */ 1813218792Snpstatic int 1814228561Snpget_params__pre_init(struct adapter *sc) 1815218792Snp{ 1816218792Snp int rc; 1817228561Snp uint32_t param[2], val[2]; 1818228561Snp struct fw_devlog_cmd cmd; 1819228561Snp struct devlog_params *dlog = &sc->params.devlog; 1820218792Snp 1821228561Snp param[0] = FW_PARAM_DEV(PORTVEC); 1822228561Snp param[1] = FW_PARAM_DEV(CCLK); 1823228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 1824218792Snp if (rc != 0) { 1825218792Snp device_printf(sc->dev, 1826228561Snp "failed to query parameters (pre_init): %d.\n", rc); 1827228561Snp return (rc); 1828218792Snp } 1829218792Snp 1830218792Snp sc->params.portvec = val[0]; 1831218792Snp sc->params.nports = 0; 1832218792Snp while (val[0]) { 1833218792Snp sc->params.nports++; 1834218792Snp val[0] &= val[0] - 1; 1835218792Snp } 1836218792Snp 1837228561Snp sc->params.vpd.cclk = val[1]; 1838218792Snp 1839228561Snp /* Read device log parameters. */ 1840228561Snp bzero(&cmd, sizeof(cmd)); 1841228561Snp cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) | 1842228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1843228561Snp cmd.retval_len16 = htobe32(FW_LEN16(cmd)); 1844228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &cmd, sizeof(cmd), &cmd); 1845228561Snp if (rc != 0) { 1846228561Snp device_printf(sc->dev, 1847228561Snp "failed to get devlog parameters: %d.\n", rc); 1848228561Snp bzero(dlog, sizeof (*dlog)); 1849228561Snp rc = 0; /* devlog isn't critical for device operation */ 1850228561Snp } else { 1851228561Snp val[0] = be32toh(cmd.memtype_devlog_memaddr16_devlog); 1852228561Snp dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(val[0]); 1853228561Snp dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(val[0]) << 4; 1854228561Snp dlog->size = be32toh(cmd.memsize_devlog); 1855228561Snp } 1856228561Snp 1857228561Snp return (rc); 1858228561Snp} 1859228561Snp 1860228561Snp/* 1861228561Snp * Retrieve various parameters that are of interest to the driver. The device 1862228561Snp * has been initialized by the firmware at this point. 1863228561Snp */ 1864228561Snpstatic int 1865228561Snpget_params__post_init(struct adapter *sc) 1866228561Snp{ 1867228561Snp int rc; 1868228561Snp uint32_t param[7], val[7]; 1869228561Snp struct fw_caps_config_cmd caps; 1870228561Snp 1871228561Snp param[0] = FW_PARAM_PFVF(IQFLINT_START); 1872228561Snp param[1] = FW_PARAM_PFVF(EQ_START); 1873228561Snp param[2] = FW_PARAM_PFVF(FILTER_START); 1874228561Snp param[3] = FW_PARAM_PFVF(FILTER_END); 1875228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 4, param, val); 1876228561Snp if (rc != 0) { 1877228561Snp device_printf(sc->dev, 1878228561Snp "failed to query parameters (post_init): %d.\n", rc); 1879228561Snp return (rc); 1880228561Snp } 1881228561Snp 1882228561Snp sc->sge.iq_start = val[0]; 1883228561Snp sc->sge.eq_start = val[1]; 1884228561Snp sc->tids.ftid_base = val[2]; 1885228561Snp sc->tids.nftids = val[3] - val[2] + 1; 1886228561Snp 1887228561Snp /* get capabilites */ 1888228561Snp bzero(&caps, sizeof(caps)); 1889228561Snp caps.op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1890228561Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1891228561Snp caps.cfvalid_to_len16 = htobe32(FW_LEN16(caps)); 1892228561Snp rc = -t4_wr_mbox(sc, sc->mbox, &caps, sizeof(caps), &caps); 1893228561Snp if (rc != 0) { 1894228561Snp device_printf(sc->dev, 1895228561Snp "failed to get card capabilities: %d.\n", rc); 1896228561Snp return (rc); 1897228561Snp } 1898228561Snp 1899228561Snp if (caps.toecaps) { 1900218792Snp /* query offload-related parameters */ 1901228561Snp param[0] = FW_PARAM_DEV(NTID); 1902228561Snp param[1] = FW_PARAM_PFVF(SERVER_START); 1903228561Snp param[2] = FW_PARAM_PFVF(SERVER_END); 1904228561Snp param[3] = FW_PARAM_PFVF(TDDP_START); 1905228561Snp param[4] = FW_PARAM_PFVF(TDDP_END); 1906228561Snp param[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 1907228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 1908218792Snp if (rc != 0) { 1909218792Snp device_printf(sc->dev, 1910218792Snp "failed to query TOE parameters: %d.\n", rc); 1911228561Snp return (rc); 1912218792Snp } 1913218792Snp sc->tids.ntids = val[0]; 1914218792Snp sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS); 1915218792Snp sc->tids.stid_base = val[1]; 1916218792Snp sc->tids.nstids = val[2] - val[1] + 1; 1917218792Snp sc->vres.ddp.start = val[3]; 1918218792Snp sc->vres.ddp.size = val[4] - val[3] + 1; 1919218792Snp sc->params.ofldq_wr_cred = val[5]; 1920218792Snp sc->params.offload = 1; 1921218792Snp } 1922228561Snp if (caps.rdmacaps) { 1923228561Snp param[0] = FW_PARAM_PFVF(STAG_START); 1924228561Snp param[1] = FW_PARAM_PFVF(STAG_END); 1925228561Snp param[2] = FW_PARAM_PFVF(RQ_START); 1926228561Snp param[3] = FW_PARAM_PFVF(RQ_END); 1927228561Snp param[4] = FW_PARAM_PFVF(PBL_START); 1928228561Snp param[5] = FW_PARAM_PFVF(PBL_END); 1929228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, param, val); 1930218792Snp if (rc != 0) { 1931218792Snp device_printf(sc->dev, 1932228561Snp "failed to query RDMA parameters(1): %d.\n", rc); 1933228561Snp return (rc); 1934218792Snp } 1935218792Snp sc->vres.stag.start = val[0]; 1936218792Snp sc->vres.stag.size = val[1] - val[0] + 1; 1937218792Snp sc->vres.rq.start = val[2]; 1938218792Snp sc->vres.rq.size = val[3] - val[2] + 1; 1939218792Snp sc->vres.pbl.start = val[4]; 1940218792Snp sc->vres.pbl.size = val[5] - val[4] + 1; 1941228561Snp 1942228561Snp param[0] = FW_PARAM_PFVF(SQRQ_START); 1943228561Snp param[1] = FW_PARAM_PFVF(SQRQ_END); 1944228561Snp param[2] = FW_PARAM_PFVF(CQ_START); 1945228561Snp param[3] = FW_PARAM_PFVF(CQ_END); 1946228561Snp param[4] = FW_PARAM_PFVF(OCQ_START); 1947228561Snp param[5] = FW_PARAM_PFVF(OCQ_END); 1948228561Snp rc = -t4_query_params(sc, 0, 0, 0, 6, param, val); 1949228561Snp if (rc != 0) { 1950228561Snp device_printf(sc->dev, 1951228561Snp "failed to query RDMA parameters(2): %d.\n", rc); 1952228561Snp return (rc); 1953228561Snp } 1954228561Snp sc->vres.qp.start = val[0]; 1955228561Snp sc->vres.qp.size = val[1] - val[0] + 1; 1956228561Snp sc->vres.cq.start = val[2]; 1957228561Snp sc->vres.cq.size = val[3] - val[2] + 1; 1958228561Snp sc->vres.ocq.start = val[4]; 1959228561Snp sc->vres.ocq.size = val[5] - val[4] + 1; 1960218792Snp } 1961228561Snp if (caps.iscsicaps) { 1962228561Snp param[0] = FW_PARAM_PFVF(ISCSI_START); 1963228561Snp param[1] = FW_PARAM_PFVF(ISCSI_END); 1964228561Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, param, val); 1965218792Snp if (rc != 0) { 1966218792Snp device_printf(sc->dev, 1967218792Snp "failed to query iSCSI parameters: %d.\n", rc); 1968228561Snp return (rc); 1969218792Snp } 1970218792Snp sc->vres.iscsi.start = val[0]; 1971218792Snp sc->vres.iscsi.size = val[1] - val[0] + 1; 1972218792Snp } 1973218792Snp 1974228561Snp /* These are finalized by FW initialization, load their values now */ 1975228561Snp val[0] = t4_read_reg(sc, A_TP_TIMER_RESOLUTION); 1976228561Snp sc->params.tp.tre = G_TIMERRESOLUTION(val[0]); 1977228561Snp sc->params.tp.dack_re = G_DELAYEDACKRESOLUTION(val[0]); 1978228561Snp t4_read_mtu_tbl(sc, sc->params.mtus, NULL); 1979228561Snp 1980218792Snp return (rc); 1981218792Snp} 1982218792Snp 1983228561Snp#undef FW_PARAM_PFVF 1984228561Snp#undef FW_PARAM_DEV 1985228561Snp 1986218792Snpstatic void 1987218792Snpt4_set_desc(struct adapter *sc) 1988218792Snp{ 1989218792Snp char buf[128]; 1990218792Snp struct adapter_params *p = &sc->params; 1991218792Snp 1992228561Snp snprintf(buf, sizeof(buf), "Chelsio %s %sNIC (rev %d), S/N:%s, E/C:%s", 1993228561Snp p->vpd.id, is_offload(sc) ? "R" : "", p->rev, p->vpd.sn, p->vpd.ec); 1994218792Snp 1995218792Snp device_set_desc_copy(sc->dev, buf); 1996218792Snp} 1997218792Snp 1998218792Snpstatic void 1999218792Snpbuild_medialist(struct port_info *pi) 2000218792Snp{ 2001218792Snp struct ifmedia *media = &pi->media; 2002218792Snp int data, m; 2003218792Snp 2004218792Snp PORT_LOCK(pi); 2005218792Snp 2006218792Snp ifmedia_removeall(media); 2007218792Snp 2008218792Snp m = IFM_ETHER | IFM_FDX; 2009218792Snp data = (pi->port_type << 8) | pi->mod_type; 2010218792Snp 2011218792Snp switch(pi->port_type) { 2012218792Snp case FW_PORT_TYPE_BT_XFI: 2013218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2014218792Snp break; 2015218792Snp 2016218792Snp case FW_PORT_TYPE_BT_XAUI: 2017218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 2018218792Snp /* fall through */ 2019218792Snp 2020218792Snp case FW_PORT_TYPE_BT_SGMII: 2021218792Snp ifmedia_add(media, m | IFM_1000_T, data, NULL); 2022218792Snp ifmedia_add(media, m | IFM_100_TX, data, NULL); 2023218792Snp ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL); 2024218792Snp ifmedia_set(media, IFM_ETHER | IFM_AUTO); 2025218792Snp break; 2026218792Snp 2027218792Snp case FW_PORT_TYPE_CX4: 2028218792Snp ifmedia_add(media, m | IFM_10G_CX4, data, NULL); 2029218792Snp ifmedia_set(media, m | IFM_10G_CX4); 2030218792Snp break; 2031218792Snp 2032218792Snp case FW_PORT_TYPE_SFP: 2033218792Snp case FW_PORT_TYPE_FIBER_XFI: 2034218792Snp case FW_PORT_TYPE_FIBER_XAUI: 2035218792Snp switch (pi->mod_type) { 2036218792Snp 2037218792Snp case FW_PORT_MOD_TYPE_LR: 2038218792Snp ifmedia_add(media, m | IFM_10G_LR, data, NULL); 2039218792Snp ifmedia_set(media, m | IFM_10G_LR); 2040218792Snp break; 2041218792Snp 2042218792Snp case FW_PORT_MOD_TYPE_SR: 2043218792Snp ifmedia_add(media, m | IFM_10G_SR, data, NULL); 2044218792Snp ifmedia_set(media, m | IFM_10G_SR); 2045218792Snp break; 2046218792Snp 2047218792Snp case FW_PORT_MOD_TYPE_LRM: 2048218792Snp ifmedia_add(media, m | IFM_10G_LRM, data, NULL); 2049218792Snp ifmedia_set(media, m | IFM_10G_LRM); 2050218792Snp break; 2051218792Snp 2052218792Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 2053218792Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 2054218792Snp ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL); 2055218792Snp ifmedia_set(media, m | IFM_10G_TWINAX); 2056218792Snp break; 2057218792Snp 2058218792Snp case FW_PORT_MOD_TYPE_NONE: 2059218792Snp m &= ~IFM_FDX; 2060218792Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 2061218792Snp ifmedia_set(media, m | IFM_NONE); 2062218792Snp break; 2063218792Snp 2064218792Snp case FW_PORT_MOD_TYPE_NA: 2065218792Snp case FW_PORT_MOD_TYPE_ER: 2066218792Snp default: 2067218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2068218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2069218792Snp break; 2070218792Snp } 2071218792Snp break; 2072218792Snp 2073218792Snp case FW_PORT_TYPE_KX4: 2074218792Snp case FW_PORT_TYPE_KX: 2075218792Snp case FW_PORT_TYPE_KR: 2076218792Snp default: 2077218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 2078218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 2079218792Snp break; 2080218792Snp } 2081218792Snp 2082218792Snp PORT_UNLOCK(pi); 2083218792Snp} 2084218792Snp 2085231172Snp#define FW_MAC_EXACT_CHUNK 7 2086231172Snp 2087218792Snp/* 2088218792Snp * Program the port's XGMAC based on parameters in ifnet. The caller also 2089218792Snp * indicates which parameters should be programmed (the rest are left alone). 2090218792Snp */ 2091218792Snpstatic int 2092218792Snpupdate_mac_settings(struct port_info *pi, int flags) 2093218792Snp{ 2094218792Snp int rc; 2095218792Snp struct ifnet *ifp = pi->ifp; 2096218792Snp struct adapter *sc = pi->adapter; 2097218792Snp int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1; 2098218792Snp 2099218792Snp PORT_LOCK_ASSERT_OWNED(pi); 2100218792Snp KASSERT(flags, ("%s: not told what to update.", __func__)); 2101218792Snp 2102218792Snp if (flags & XGMAC_MTU) 2103218792Snp mtu = ifp->if_mtu; 2104218792Snp 2105218792Snp if (flags & XGMAC_PROMISC) 2106218792Snp promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0; 2107218792Snp 2108218792Snp if (flags & XGMAC_ALLMULTI) 2109218792Snp allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0; 2110218792Snp 2111218792Snp if (flags & XGMAC_VLANEX) 2112218792Snp vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0; 2113218792Snp 2114218792Snp rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, mtu, promisc, allmulti, 1, 2115218792Snp vlanex, false); 2116218792Snp if (rc) { 2117218792Snp if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, rc); 2118218792Snp return (rc); 2119218792Snp } 2120218792Snp 2121218792Snp if (flags & XGMAC_UCADDR) { 2122218792Snp uint8_t ucaddr[ETHER_ADDR_LEN]; 2123218792Snp 2124218792Snp bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr)); 2125218792Snp rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, 2126218792Snp ucaddr, true, true); 2127218792Snp if (rc < 0) { 2128218792Snp rc = -rc; 2129218792Snp if_printf(ifp, "change_mac failed: %d\n", rc); 2130218792Snp return (rc); 2131218792Snp } else { 2132218792Snp pi->xact_addr_filt = rc; 2133218792Snp rc = 0; 2134218792Snp } 2135218792Snp } 2136218792Snp 2137218792Snp if (flags & XGMAC_MCADDRS) { 2138231172Snp const uint8_t *mcaddr[FW_MAC_EXACT_CHUNK]; 2139218792Snp int del = 1; 2140218792Snp uint64_t hash = 0; 2141218792Snp struct ifmultiaddr *ifma; 2142231172Snp int i = 0, j; 2143218792Snp 2144218792Snp if_maddr_rlock(ifp); 2145218792Snp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 2146238054Snp if (ifma->ifma_addr->sa_family != AF_LINK) 2147218792Snp continue; 2148231172Snp mcaddr[i++] = 2149231172Snp LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 2150218792Snp 2151231172Snp if (i == FW_MAC_EXACT_CHUNK) { 2152231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2153231172Snp del, i, mcaddr, NULL, &hash, 0); 2154231172Snp if (rc < 0) { 2155231172Snp rc = -rc; 2156231172Snp for (j = 0; j < i; j++) { 2157231172Snp if_printf(ifp, 2158231172Snp "failed to add mc address" 2159231172Snp " %02x:%02x:%02x:" 2160231172Snp "%02x:%02x:%02x rc=%d\n", 2161231172Snp mcaddr[j][0], mcaddr[j][1], 2162231172Snp mcaddr[j][2], mcaddr[j][3], 2163231172Snp mcaddr[j][4], mcaddr[j][5], 2164231172Snp rc); 2165231172Snp } 2166231172Snp goto mcfail; 2167231172Snp } 2168231172Snp del = 0; 2169231172Snp i = 0; 2170231172Snp } 2171231172Snp } 2172231172Snp if (i > 0) { 2173231172Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, 2174231172Snp del, i, mcaddr, NULL, &hash, 0); 2175218792Snp if (rc < 0) { 2176218792Snp rc = -rc; 2177231172Snp for (j = 0; j < i; j++) { 2178231172Snp if_printf(ifp, 2179231172Snp "failed to add mc address" 2180231172Snp " %02x:%02x:%02x:" 2181231172Snp "%02x:%02x:%02x rc=%d\n", 2182231172Snp mcaddr[j][0], mcaddr[j][1], 2183231172Snp mcaddr[j][2], mcaddr[j][3], 2184231172Snp mcaddr[j][4], mcaddr[j][5], 2185231172Snp rc); 2186231172Snp } 2187218792Snp goto mcfail; 2188218792Snp } 2189218792Snp } 2190218792Snp 2191218792Snp rc = -t4_set_addr_hash(sc, sc->mbox, pi->viid, 0, hash, 0); 2192218792Snp if (rc != 0) 2193218792Snp if_printf(ifp, "failed to set mc address hash: %d", rc); 2194218792Snpmcfail: 2195218792Snp if_maddr_runlock(ifp); 2196218792Snp } 2197218792Snp 2198218792Snp return (rc); 2199218792Snp} 2200218792Snp 2201218792Snpstatic int 2202218792Snpcxgbe_init_locked(struct port_info *pi) 2203218792Snp{ 2204218792Snp struct adapter *sc = pi->adapter; 2205218792Snp int rc = 0; 2206218792Snp 2207218792Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 2208218792Snp 2209218792Snp while (!IS_DOOMED(pi) && IS_BUSY(sc)) { 2210218792Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4init", 0)) { 2211218792Snp rc = EINTR; 2212218792Snp goto done; 2213218792Snp } 2214218792Snp } 2215218792Snp if (IS_DOOMED(pi)) { 2216218792Snp rc = ENXIO; 2217218792Snp goto done; 2218218792Snp } 2219218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 2220218792Snp 2221218792Snp /* Give up the adapter lock, port init code can sleep. */ 2222218792Snp SET_BUSY(sc); 2223218792Snp ADAPTER_UNLOCK(sc); 2224218792Snp 2225218792Snp rc = cxgbe_init_synchronized(pi); 2226218792Snp 2227218792Snpdone: 2228218792Snp ADAPTER_LOCK(sc); 2229218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 2230218792Snp CLR_BUSY(sc); 2231218792Snp wakeup_one(&sc->flags); 2232218792Snp ADAPTER_UNLOCK(sc); 2233218792Snp return (rc); 2234218792Snp} 2235218792Snp 2236218792Snpstatic int 2237218792Snpcxgbe_init_synchronized(struct port_info *pi) 2238218792Snp{ 2239218792Snp struct adapter *sc = pi->adapter; 2240218792Snp struct ifnet *ifp = pi->ifp; 2241228561Snp int rc = 0; 2242218792Snp 2243218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2244218792Snp 2245218792Snp if (isset(&sc->open_device_map, pi->port_id)) { 2246218792Snp KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, 2247218792Snp ("mismatch between open_device_map and if_drv_flags")); 2248218792Snp return (0); /* already running */ 2249218792Snp } 2250218792Snp 2251228561Snp if (!(sc->flags & FULL_INIT_DONE) && 2252228561Snp ((rc = adapter_full_init(sc)) != 0)) 2253218792Snp return (rc); /* error message displayed already */ 2254218792Snp 2255228561Snp if (!(pi->flags & PORT_INIT_DONE) && 2256228561Snp ((rc = port_full_init(pi)) != 0)) 2257228561Snp return (rc); /* error message displayed already */ 2258218792Snp 2259218792Snp PORT_LOCK(pi); 2260218792Snp rc = update_mac_settings(pi, XGMAC_ALL); 2261218792Snp PORT_UNLOCK(pi); 2262218792Snp if (rc) 2263218792Snp goto done; /* error message displayed already */ 2264218792Snp 2265218792Snp rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg); 2266218792Snp if (rc != 0) { 2267218792Snp if_printf(ifp, "start_link failed: %d\n", rc); 2268218792Snp goto done; 2269218792Snp } 2270218792Snp 2271218792Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true); 2272218792Snp if (rc != 0) { 2273218792Snp if_printf(ifp, "enable_vi failed: %d\n", rc); 2274218792Snp goto done; 2275218792Snp } 2276218792Snp 2277218792Snp /* all ok */ 2278218792Snp setbit(&sc->open_device_map, pi->port_id); 2279218792Snp ifp->if_drv_flags |= IFF_DRV_RUNNING; 2280218792Snp 2281218792Snp callout_reset(&pi->tick, hz, cxgbe_tick, pi); 2282218792Snpdone: 2283218792Snp if (rc != 0) 2284218792Snp cxgbe_uninit_synchronized(pi); 2285218792Snp 2286218792Snp return (rc); 2287218792Snp} 2288218792Snp 2289218792Snpstatic int 2290218792Snpcxgbe_uninit_locked(struct port_info *pi) 2291218792Snp{ 2292218792Snp struct adapter *sc = pi->adapter; 2293218792Snp int rc; 2294218792Snp 2295218792Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 2296218792Snp 2297218792Snp while (!IS_DOOMED(pi) && IS_BUSY(sc)) { 2298218792Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4uninit", 0)) { 2299218792Snp rc = EINTR; 2300218792Snp goto done; 2301218792Snp } 2302218792Snp } 2303218792Snp if (IS_DOOMED(pi)) { 2304218792Snp rc = ENXIO; 2305218792Snp goto done; 2306218792Snp } 2307218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 2308218792Snp SET_BUSY(sc); 2309218792Snp ADAPTER_UNLOCK(sc); 2310218792Snp 2311218792Snp rc = cxgbe_uninit_synchronized(pi); 2312218792Snp 2313218792Snp ADAPTER_LOCK(sc); 2314218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 2315218792Snp CLR_BUSY(sc); 2316218792Snp wakeup_one(&sc->flags); 2317218792Snpdone: 2318218792Snp ADAPTER_UNLOCK(sc); 2319218792Snp return (rc); 2320218792Snp} 2321218792Snp 2322218792Snp/* 2323218792Snp * Idempotent. 2324218792Snp */ 2325218792Snpstatic int 2326218792Snpcxgbe_uninit_synchronized(struct port_info *pi) 2327218792Snp{ 2328218792Snp struct adapter *sc = pi->adapter; 2329218792Snp struct ifnet *ifp = pi->ifp; 2330218792Snp int rc; 2331218792Snp 2332218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2333218792Snp 2334218792Snp /* 2335228561Snp * Disable the VI so that all its data in either direction is discarded 2336228561Snp * by the MPS. Leave everything else (the queues, interrupts, and 1Hz 2337228561Snp * tick) intact as the TP can deliver negative advice or data that it's 2338228561Snp * holding in its RAM (for an offloaded connection) even after the VI is 2339228561Snp * disabled. 2340218792Snp */ 2341228561Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false); 2342228561Snp if (rc) { 2343228561Snp if_printf(ifp, "disable_vi failed: %d\n", rc); 2344228561Snp return (rc); 2345228561Snp } 2346228561Snp 2347218792Snp clrbit(&sc->open_device_map, pi->port_id); 2348228561Snp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2349218792Snp 2350218792Snp pi->link_cfg.link_ok = 0; 2351218792Snp pi->link_cfg.speed = 0; 2352218792Snp t4_os_link_changed(sc, pi->port_id, 0); 2353218792Snp 2354218792Snp return (0); 2355218792Snp} 2356218792Snp 2357222510Snp#define T4_ALLOC_IRQ(sc, irq, rid, handler, arg, name) do { \ 2358222510Snp rc = t4_alloc_irq(sc, irq, rid, handler, arg, name); \ 2359218792Snp if (rc != 0) \ 2360218792Snp goto done; \ 2361218792Snp} while (0) 2362228561Snp 2363218792Snpstatic int 2364228561Snpadapter_full_init(struct adapter *sc) 2365218792Snp{ 2366222510Snp int rc, i, rid, p, q; 2367222510Snp char s[8]; 2368222510Snp struct irq *irq; 2369228561Snp struct port_info *pi; 2370228561Snp struct sge_rxq *rxq; 2371237263Snp#ifdef TCP_OFFLOAD 2372228561Snp struct sge_ofld_rxq *ofld_rxq; 2373228561Snp#endif 2374218792Snp 2375218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2376228561Snp KASSERT((sc->flags & FULL_INIT_DONE) == 0, 2377228561Snp ("%s: FULL_INIT_DONE already", __func__)); 2378218792Snp 2379218792Snp /* 2380220873Snp * queues that belong to the adapter (not any particular port). 2381218792Snp */ 2382220873Snp rc = t4_setup_adapter_queues(sc); 2383218792Snp if (rc != 0) 2384218792Snp goto done; 2385218792Snp 2386228561Snp for (i = 0; i < ARRAY_SIZE(sc->tq); i++) { 2387228561Snp sc->tq[i] = taskqueue_create("t4 taskq", M_NOWAIT, 2388228561Snp taskqueue_thread_enqueue, &sc->tq[i]); 2389228561Snp if (sc->tq[i] == NULL) { 2390228561Snp device_printf(sc->dev, 2391228561Snp "failed to allocate task queue %d\n", i); 2392228561Snp rc = ENOMEM; 2393228561Snp goto done; 2394228561Snp } 2395228561Snp taskqueue_start_threads(&sc->tq[i], 1, PI_NET, "%s tq%d", 2396228561Snp device_get_nameunit(sc->dev), i); 2397228561Snp } 2398228561Snp 2399218792Snp /* 2400218792Snp * Setup interrupts. 2401218792Snp */ 2402222510Snp irq = &sc->irq[0]; 2403222510Snp rid = sc->intr_type == INTR_INTX ? 0 : 1; 2404218792Snp if (sc->intr_count == 1) { 2405228561Snp KASSERT(!(sc->flags & INTR_DIRECT), 2406228561Snp ("%s: single interrupt && INTR_DIRECT?", __func__)); 2407222510Snp 2408222510Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr_all, sc, "all"); 2409218792Snp } else { 2410228561Snp /* Multiple interrupts. */ 2411228561Snp KASSERT(sc->intr_count >= T4_EXTRA_INTR + sc->params.nports, 2412228561Snp ("%s: too few intr.", __func__)); 2413228561Snp 2414228561Snp /* The first one is always error intr */ 2415222510Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr_err, sc, "err"); 2416222510Snp irq++; 2417222510Snp rid++; 2418218792Snp 2419228561Snp /* The second one is always the firmware event queue */ 2420228561Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr_evt, &sc->sge.fwq, "evt"); 2421228561Snp irq++; 2422228561Snp rid++; 2423222510Snp 2424228561Snp /* 2425228561Snp * Note that if INTR_DIRECT is not set then either the NIC rx 2426228561Snp * queues or (exclusive or) the TOE rx queueus will be taking 2427228561Snp * direct interrupts. 2428228561Snp * 2429228561Snp * There is no need to check for is_offload(sc) as nofldrxq 2430228561Snp * will be 0 if offload is disabled. 2431228561Snp */ 2432228561Snp for_each_port(sc, p) { 2433228561Snp pi = sc->port[p]; 2434222510Snp 2435237263Snp#ifdef TCP_OFFLOAD 2436228561Snp /* 2437228561Snp * Skip over the NIC queues if they aren't taking direct 2438228561Snp * interrupts. 2439228561Snp */ 2440228561Snp if (!(sc->flags & INTR_DIRECT) && 2441228561Snp pi->nofldrxq > pi->nrxq) 2442228561Snp goto ofld_queues; 2443228561Snp#endif 2444228561Snp rxq = &sc->sge.rxq[pi->first_rxq]; 2445228561Snp for (q = 0; q < pi->nrxq; q++, rxq++) { 2446228561Snp snprintf(s, sizeof(s), "%d.%d", p, q); 2447228561Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr, rxq, s); 2448222510Snp irq++; 2449222510Snp rid++; 2450218792Snp } 2451218792Snp 2452237263Snp#ifdef TCP_OFFLOAD 2453228561Snp /* 2454228561Snp * Skip over the offload queues if they aren't taking 2455228561Snp * direct interrupts. 2456228561Snp */ 2457228561Snp if (!(sc->flags & INTR_DIRECT)) 2458228561Snp continue; 2459228561Snpofld_queues: 2460228561Snp ofld_rxq = &sc->sge.ofld_rxq[pi->first_ofld_rxq]; 2461228561Snp for (q = 0; q < pi->nofldrxq; q++, ofld_rxq++) { 2462228561Snp snprintf(s, sizeof(s), "%d,%d", p, q); 2463228561Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr, ofld_rxq, s); 2464228561Snp irq++; 2465228561Snp rid++; 2466218792Snp } 2467228561Snp#endif 2468218792Snp } 2469218792Snp } 2470218792Snp 2471218792Snp t4_intr_enable(sc); 2472218792Snp sc->flags |= FULL_INIT_DONE; 2473218792Snpdone: 2474218792Snp if (rc != 0) 2475228561Snp adapter_full_uninit(sc); 2476218792Snp 2477218792Snp return (rc); 2478218792Snp} 2479218792Snp#undef T4_ALLOC_IRQ 2480218792Snp 2481218792Snpstatic int 2482228561Snpadapter_full_uninit(struct adapter *sc) 2483218792Snp{ 2484218792Snp int i; 2485218792Snp 2486218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2487218792Snp 2488220873Snp t4_teardown_adapter_queues(sc); 2489218792Snp 2490218792Snp for (i = 0; i < sc->intr_count; i++) 2491218792Snp t4_free_irq(sc, &sc->irq[i]); 2492218792Snp 2493228561Snp for (i = 0; i < ARRAY_SIZE(sc->tq) && sc->tq[i]; i++) { 2494228561Snp taskqueue_free(sc->tq[i]); 2495228561Snp sc->tq[i] = NULL; 2496228561Snp } 2497228561Snp 2498218792Snp sc->flags &= ~FULL_INIT_DONE; 2499218792Snp 2500218792Snp return (0); 2501218792Snp} 2502218792Snp 2503218792Snpstatic int 2504228561Snpport_full_init(struct port_info *pi) 2505228561Snp{ 2506228561Snp struct adapter *sc = pi->adapter; 2507228561Snp struct ifnet *ifp = pi->ifp; 2508228561Snp uint16_t *rss; 2509228561Snp struct sge_rxq *rxq; 2510228561Snp int rc, i; 2511228561Snp 2512228561Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2513228561Snp KASSERT((pi->flags & PORT_INIT_DONE) == 0, 2514228561Snp ("%s: PORT_INIT_DONE already", __func__)); 2515228561Snp 2516228561Snp sysctl_ctx_init(&pi->ctx); 2517228561Snp pi->flags |= PORT_SYSCTL_CTX; 2518228561Snp 2519228561Snp /* 2520228561Snp * Allocate tx/rx/fl queues for this port. 2521228561Snp */ 2522228561Snp rc = t4_setup_port_queues(pi); 2523228561Snp if (rc != 0) 2524228561Snp goto done; /* error message displayed already */ 2525228561Snp 2526228561Snp /* 2527228561Snp * Setup RSS for this port. 2528228561Snp */ 2529228561Snp rss = malloc(pi->nrxq * sizeof (*rss), M_CXGBE, 2530228561Snp M_ZERO | M_WAITOK); 2531228561Snp for_each_rxq(pi, i, rxq) { 2532228561Snp rss[i] = rxq->iq.abs_id; 2533228561Snp } 2534228561Snp rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, 2535228561Snp pi->rss_size, rss, pi->nrxq); 2536228561Snp free(rss, M_CXGBE); 2537228561Snp if (rc != 0) { 2538228561Snp if_printf(ifp, "rss_config failed: %d\n", rc); 2539228561Snp goto done; 2540228561Snp } 2541228561Snp 2542228561Snp pi->flags |= PORT_INIT_DONE; 2543228561Snpdone: 2544228561Snp if (rc != 0) 2545228561Snp port_full_uninit(pi); 2546228561Snp 2547228561Snp return (rc); 2548228561Snp} 2549228561Snp 2550228561Snp/* 2551228561Snp * Idempotent. 2552228561Snp */ 2553228561Snpstatic int 2554228561Snpport_full_uninit(struct port_info *pi) 2555228561Snp{ 2556228561Snp struct adapter *sc = pi->adapter; 2557228561Snp int i; 2558228561Snp struct sge_rxq *rxq; 2559228561Snp struct sge_txq *txq; 2560237263Snp#ifdef TCP_OFFLOAD 2561228561Snp struct sge_ofld_rxq *ofld_rxq; 2562228561Snp struct sge_wrq *ofld_txq; 2563228561Snp#endif 2564228561Snp 2565228561Snp if (pi->flags & PORT_INIT_DONE) { 2566228561Snp 2567228561Snp /* Need to quiesce queues. XXX: ctrl queues? */ 2568228561Snp 2569228561Snp for_each_txq(pi, i, txq) { 2570228561Snp quiesce_eq(sc, &txq->eq); 2571228561Snp } 2572228561Snp 2573237263Snp#ifdef TCP_OFFLOAD 2574228561Snp for_each_ofld_txq(pi, i, ofld_txq) { 2575228561Snp quiesce_eq(sc, &ofld_txq->eq); 2576228561Snp } 2577228561Snp#endif 2578228561Snp 2579228561Snp for_each_rxq(pi, i, rxq) { 2580228561Snp quiesce_iq(sc, &rxq->iq); 2581228561Snp quiesce_fl(sc, &rxq->fl); 2582228561Snp } 2583228561Snp 2584237263Snp#ifdef TCP_OFFLOAD 2585228561Snp for_each_ofld_rxq(pi, i, ofld_rxq) { 2586228561Snp quiesce_iq(sc, &ofld_rxq->iq); 2587228561Snp quiesce_fl(sc, &ofld_rxq->fl); 2588228561Snp } 2589228561Snp#endif 2590228561Snp } 2591228561Snp 2592228561Snp t4_teardown_port_queues(pi); 2593228561Snp pi->flags &= ~PORT_INIT_DONE; 2594228561Snp 2595228561Snp return (0); 2596228561Snp} 2597228561Snp 2598228561Snpstatic void 2599228561Snpquiesce_eq(struct adapter *sc, struct sge_eq *eq) 2600228561Snp{ 2601228561Snp EQ_LOCK(eq); 2602228561Snp eq->flags |= EQ_DOOMED; 2603228561Snp 2604228561Snp /* 2605228561Snp * Wait for the response to a credit flush if one's 2606228561Snp * pending. 2607228561Snp */ 2608228561Snp while (eq->flags & EQ_CRFLUSHED) 2609228561Snp mtx_sleep(eq, &eq->eq_lock, 0, "crflush", 0); 2610228561Snp EQ_UNLOCK(eq); 2611228561Snp 2612228561Snp callout_drain(&eq->tx_callout); /* XXX: iffy */ 2613228561Snp pause("callout", 10); /* Still iffy */ 2614228561Snp 2615228561Snp taskqueue_drain(sc->tq[eq->tx_chan], &eq->tx_task); 2616228561Snp} 2617228561Snp 2618228561Snpstatic void 2619228561Snpquiesce_iq(struct adapter *sc, struct sge_iq *iq) 2620228561Snp{ 2621228561Snp (void) sc; /* unused */ 2622228561Snp 2623228561Snp /* Synchronize with the interrupt handler */ 2624228561Snp while (!atomic_cmpset_int(&iq->state, IQS_IDLE, IQS_DISABLED)) 2625228561Snp pause("iqfree", 1); 2626228561Snp} 2627228561Snp 2628228561Snpstatic void 2629228561Snpquiesce_fl(struct adapter *sc, struct sge_fl *fl) 2630228561Snp{ 2631228561Snp mtx_lock(&sc->sfl_lock); 2632228561Snp FL_LOCK(fl); 2633228561Snp fl->flags |= FL_DOOMED; 2634228561Snp FL_UNLOCK(fl); 2635228561Snp mtx_unlock(&sc->sfl_lock); 2636228561Snp 2637228561Snp callout_drain(&sc->sfl_callout); 2638228561Snp KASSERT((fl->flags & FL_STARVING) == 0, 2639228561Snp ("%s: still starving", __func__)); 2640228561Snp} 2641228561Snp 2642228561Snpstatic int 2643218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid, 2644228561Snp driver_intr_t *handler, void *arg, char *name) 2645218792Snp{ 2646218792Snp int rc; 2647218792Snp 2648218792Snp irq->rid = rid; 2649218792Snp irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid, 2650218792Snp RF_SHAREABLE | RF_ACTIVE); 2651218792Snp if (irq->res == NULL) { 2652218792Snp device_printf(sc->dev, 2653218792Snp "failed to allocate IRQ for rid %d, name %s.\n", rid, name); 2654218792Snp return (ENOMEM); 2655218792Snp } 2656218792Snp 2657218792Snp rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET, 2658218792Snp NULL, handler, arg, &irq->tag); 2659218792Snp if (rc != 0) { 2660218792Snp device_printf(sc->dev, 2661218792Snp "failed to setup interrupt for rid %d, name %s: %d\n", 2662218792Snp rid, name, rc); 2663218792Snp } else if (name) 2664218792Snp bus_describe_intr(sc->dev, irq->res, irq->tag, name); 2665218792Snp 2666218792Snp return (rc); 2667218792Snp} 2668218792Snp 2669218792Snpstatic int 2670218792Snpt4_free_irq(struct adapter *sc, struct irq *irq) 2671218792Snp{ 2672218792Snp if (irq->tag) 2673218792Snp bus_teardown_intr(sc->dev, irq->res, irq->tag); 2674218792Snp if (irq->res) 2675218792Snp bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res); 2676218792Snp 2677218792Snp bzero(irq, sizeof(*irq)); 2678218792Snp 2679218792Snp return (0); 2680218792Snp} 2681218792Snp 2682218792Snpstatic void 2683218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start, 2684218792Snp unsigned int end) 2685218792Snp{ 2686218792Snp uint32_t *p = (uint32_t *)(buf + start); 2687218792Snp 2688218792Snp for ( ; start <= end; start += sizeof(uint32_t)) 2689218792Snp *p++ = t4_read_reg(sc, start); 2690218792Snp} 2691218792Snp 2692218792Snpstatic void 2693218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf) 2694218792Snp{ 2695218792Snp int i; 2696218792Snp static const unsigned int reg_ranges[] = { 2697218792Snp 0x1008, 0x1108, 2698218792Snp 0x1180, 0x11b4, 2699218792Snp 0x11fc, 0x123c, 2700218792Snp 0x1300, 0x173c, 2701218792Snp 0x1800, 0x18fc, 2702218792Snp 0x3000, 0x30d8, 2703218792Snp 0x30e0, 0x5924, 2704218792Snp 0x5960, 0x59d4, 2705218792Snp 0x5a00, 0x5af8, 2706218792Snp 0x6000, 0x6098, 2707218792Snp 0x6100, 0x6150, 2708218792Snp 0x6200, 0x6208, 2709218792Snp 0x6240, 0x6248, 2710218792Snp 0x6280, 0x6338, 2711218792Snp 0x6370, 0x638c, 2712218792Snp 0x6400, 0x643c, 2713218792Snp 0x6500, 0x6524, 2714218792Snp 0x6a00, 0x6a38, 2715218792Snp 0x6a60, 0x6a78, 2716218792Snp 0x6b00, 0x6b84, 2717218792Snp 0x6bf0, 0x6c84, 2718218792Snp 0x6cf0, 0x6d84, 2719218792Snp 0x6df0, 0x6e84, 2720218792Snp 0x6ef0, 0x6f84, 2721218792Snp 0x6ff0, 0x7084, 2722218792Snp 0x70f0, 0x7184, 2723218792Snp 0x71f0, 0x7284, 2724218792Snp 0x72f0, 0x7384, 2725218792Snp 0x73f0, 0x7450, 2726218792Snp 0x7500, 0x7530, 2727218792Snp 0x7600, 0x761c, 2728218792Snp 0x7680, 0x76cc, 2729218792Snp 0x7700, 0x7798, 2730218792Snp 0x77c0, 0x77fc, 2731218792Snp 0x7900, 0x79fc, 2732218792Snp 0x7b00, 0x7c38, 2733218792Snp 0x7d00, 0x7efc, 2734218792Snp 0x8dc0, 0x8e1c, 2735218792Snp 0x8e30, 0x8e78, 2736218792Snp 0x8ea0, 0x8f6c, 2737218792Snp 0x8fc0, 0x9074, 2738218792Snp 0x90fc, 0x90fc, 2739218792Snp 0x9400, 0x9458, 2740218792Snp 0x9600, 0x96bc, 2741218792Snp 0x9800, 0x9808, 2742218792Snp 0x9820, 0x983c, 2743218792Snp 0x9850, 0x9864, 2744218792Snp 0x9c00, 0x9c6c, 2745218792Snp 0x9c80, 0x9cec, 2746218792Snp 0x9d00, 0x9d6c, 2747218792Snp 0x9d80, 0x9dec, 2748218792Snp 0x9e00, 0x9e6c, 2749218792Snp 0x9e80, 0x9eec, 2750218792Snp 0x9f00, 0x9f6c, 2751218792Snp 0x9f80, 0x9fec, 2752218792Snp 0xd004, 0xd03c, 2753218792Snp 0xdfc0, 0xdfe0, 2754218792Snp 0xe000, 0xea7c, 2755218792Snp 0xf000, 0x11190, 2756237439Snp 0x19040, 0x1906c, 2757237439Snp 0x19078, 0x19080, 2758237439Snp 0x1908c, 0x19124, 2759218792Snp 0x19150, 0x191b0, 2760218792Snp 0x191d0, 0x191e8, 2761218792Snp 0x19238, 0x1924c, 2762218792Snp 0x193f8, 0x19474, 2763218792Snp 0x19490, 0x194f8, 2764218792Snp 0x19800, 0x19f30, 2765218792Snp 0x1a000, 0x1a06c, 2766218792Snp 0x1a0b0, 0x1a120, 2767218792Snp 0x1a128, 0x1a138, 2768218792Snp 0x1a190, 0x1a1c4, 2769218792Snp 0x1a1fc, 0x1a1fc, 2770218792Snp 0x1e040, 0x1e04c, 2771237439Snp 0x1e284, 0x1e28c, 2772218792Snp 0x1e2c0, 0x1e2c0, 2773218792Snp 0x1e2e0, 0x1e2e0, 2774218792Snp 0x1e300, 0x1e384, 2775218792Snp 0x1e3c0, 0x1e3c8, 2776218792Snp 0x1e440, 0x1e44c, 2777237439Snp 0x1e684, 0x1e68c, 2778218792Snp 0x1e6c0, 0x1e6c0, 2779218792Snp 0x1e6e0, 0x1e6e0, 2780218792Snp 0x1e700, 0x1e784, 2781218792Snp 0x1e7c0, 0x1e7c8, 2782218792Snp 0x1e840, 0x1e84c, 2783237439Snp 0x1ea84, 0x1ea8c, 2784218792Snp 0x1eac0, 0x1eac0, 2785218792Snp 0x1eae0, 0x1eae0, 2786218792Snp 0x1eb00, 0x1eb84, 2787218792Snp 0x1ebc0, 0x1ebc8, 2788218792Snp 0x1ec40, 0x1ec4c, 2789237439Snp 0x1ee84, 0x1ee8c, 2790218792Snp 0x1eec0, 0x1eec0, 2791218792Snp 0x1eee0, 0x1eee0, 2792218792Snp 0x1ef00, 0x1ef84, 2793218792Snp 0x1efc0, 0x1efc8, 2794218792Snp 0x1f040, 0x1f04c, 2795237439Snp 0x1f284, 0x1f28c, 2796218792Snp 0x1f2c0, 0x1f2c0, 2797218792Snp 0x1f2e0, 0x1f2e0, 2798218792Snp 0x1f300, 0x1f384, 2799218792Snp 0x1f3c0, 0x1f3c8, 2800218792Snp 0x1f440, 0x1f44c, 2801237439Snp 0x1f684, 0x1f68c, 2802218792Snp 0x1f6c0, 0x1f6c0, 2803218792Snp 0x1f6e0, 0x1f6e0, 2804218792Snp 0x1f700, 0x1f784, 2805218792Snp 0x1f7c0, 0x1f7c8, 2806218792Snp 0x1f840, 0x1f84c, 2807237439Snp 0x1fa84, 0x1fa8c, 2808218792Snp 0x1fac0, 0x1fac0, 2809218792Snp 0x1fae0, 0x1fae0, 2810218792Snp 0x1fb00, 0x1fb84, 2811218792Snp 0x1fbc0, 0x1fbc8, 2812218792Snp 0x1fc40, 0x1fc4c, 2813237439Snp 0x1fe84, 0x1fe8c, 2814218792Snp 0x1fec0, 0x1fec0, 2815218792Snp 0x1fee0, 0x1fee0, 2816218792Snp 0x1ff00, 0x1ff84, 2817218792Snp 0x1ffc0, 0x1ffc8, 2818218792Snp 0x20000, 0x2002c, 2819218792Snp 0x20100, 0x2013c, 2820218792Snp 0x20190, 0x201c8, 2821218792Snp 0x20200, 0x20318, 2822218792Snp 0x20400, 0x20528, 2823218792Snp 0x20540, 0x20614, 2824218792Snp 0x21000, 0x21040, 2825218792Snp 0x2104c, 0x21060, 2826218792Snp 0x210c0, 0x210ec, 2827218792Snp 0x21200, 0x21268, 2828218792Snp 0x21270, 0x21284, 2829218792Snp 0x212fc, 0x21388, 2830218792Snp 0x21400, 0x21404, 2831218792Snp 0x21500, 0x21518, 2832218792Snp 0x2152c, 0x2153c, 2833218792Snp 0x21550, 0x21554, 2834218792Snp 0x21600, 0x21600, 2835218792Snp 0x21608, 0x21628, 2836218792Snp 0x21630, 0x2163c, 2837218792Snp 0x21700, 0x2171c, 2838218792Snp 0x21780, 0x2178c, 2839218792Snp 0x21800, 0x21c38, 2840218792Snp 0x21c80, 0x21d7c, 2841218792Snp 0x21e00, 0x21e04, 2842218792Snp 0x22000, 0x2202c, 2843218792Snp 0x22100, 0x2213c, 2844218792Snp 0x22190, 0x221c8, 2845218792Snp 0x22200, 0x22318, 2846218792Snp 0x22400, 0x22528, 2847218792Snp 0x22540, 0x22614, 2848218792Snp 0x23000, 0x23040, 2849218792Snp 0x2304c, 0x23060, 2850218792Snp 0x230c0, 0x230ec, 2851218792Snp 0x23200, 0x23268, 2852218792Snp 0x23270, 0x23284, 2853218792Snp 0x232fc, 0x23388, 2854218792Snp 0x23400, 0x23404, 2855218792Snp 0x23500, 0x23518, 2856218792Snp 0x2352c, 0x2353c, 2857218792Snp 0x23550, 0x23554, 2858218792Snp 0x23600, 0x23600, 2859218792Snp 0x23608, 0x23628, 2860218792Snp 0x23630, 0x2363c, 2861218792Snp 0x23700, 0x2371c, 2862218792Snp 0x23780, 0x2378c, 2863218792Snp 0x23800, 0x23c38, 2864218792Snp 0x23c80, 0x23d7c, 2865218792Snp 0x23e00, 0x23e04, 2866218792Snp 0x24000, 0x2402c, 2867218792Snp 0x24100, 0x2413c, 2868218792Snp 0x24190, 0x241c8, 2869218792Snp 0x24200, 0x24318, 2870218792Snp 0x24400, 0x24528, 2871218792Snp 0x24540, 0x24614, 2872218792Snp 0x25000, 0x25040, 2873218792Snp 0x2504c, 0x25060, 2874218792Snp 0x250c0, 0x250ec, 2875218792Snp 0x25200, 0x25268, 2876218792Snp 0x25270, 0x25284, 2877218792Snp 0x252fc, 0x25388, 2878218792Snp 0x25400, 0x25404, 2879218792Snp 0x25500, 0x25518, 2880218792Snp 0x2552c, 0x2553c, 2881218792Snp 0x25550, 0x25554, 2882218792Snp 0x25600, 0x25600, 2883218792Snp 0x25608, 0x25628, 2884218792Snp 0x25630, 0x2563c, 2885218792Snp 0x25700, 0x2571c, 2886218792Snp 0x25780, 0x2578c, 2887218792Snp 0x25800, 0x25c38, 2888218792Snp 0x25c80, 0x25d7c, 2889218792Snp 0x25e00, 0x25e04, 2890218792Snp 0x26000, 0x2602c, 2891218792Snp 0x26100, 0x2613c, 2892218792Snp 0x26190, 0x261c8, 2893218792Snp 0x26200, 0x26318, 2894218792Snp 0x26400, 0x26528, 2895218792Snp 0x26540, 0x26614, 2896218792Snp 0x27000, 0x27040, 2897218792Snp 0x2704c, 0x27060, 2898218792Snp 0x270c0, 0x270ec, 2899218792Snp 0x27200, 0x27268, 2900218792Snp 0x27270, 0x27284, 2901218792Snp 0x272fc, 0x27388, 2902218792Snp 0x27400, 0x27404, 2903218792Snp 0x27500, 0x27518, 2904218792Snp 0x2752c, 0x2753c, 2905218792Snp 0x27550, 0x27554, 2906218792Snp 0x27600, 0x27600, 2907218792Snp 0x27608, 0x27628, 2908218792Snp 0x27630, 0x2763c, 2909218792Snp 0x27700, 0x2771c, 2910218792Snp 0x27780, 0x2778c, 2911218792Snp 0x27800, 0x27c38, 2912218792Snp 0x27c80, 0x27d7c, 2913218792Snp 0x27e00, 0x27e04 2914218792Snp }; 2915218792Snp 2916218792Snp regs->version = 4 | (sc->params.rev << 10); 2917218792Snp for (i = 0; i < ARRAY_SIZE(reg_ranges); i += 2) 2918218792Snp reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]); 2919218792Snp} 2920218792Snp 2921218792Snpstatic void 2922218792Snpcxgbe_tick(void *arg) 2923218792Snp{ 2924218792Snp struct port_info *pi = arg; 2925218792Snp struct ifnet *ifp = pi->ifp; 2926218792Snp struct sge_txq *txq; 2927218792Snp int i, drops; 2928218792Snp struct port_stats *s = &pi->stats; 2929218792Snp 2930218792Snp PORT_LOCK(pi); 2931218792Snp if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2932218792Snp PORT_UNLOCK(pi); 2933218792Snp return; /* without scheduling another callout */ 2934218792Snp } 2935218792Snp 2936218792Snp t4_get_port_stats(pi->adapter, pi->tx_chan, s); 2937218792Snp 2938228561Snp ifp->if_opackets = s->tx_frames - s->tx_pause; 2939228561Snp ifp->if_ipackets = s->rx_frames - s->rx_pause; 2940228561Snp ifp->if_obytes = s->tx_octets - s->tx_pause * 64; 2941228561Snp ifp->if_ibytes = s->rx_octets - s->rx_pause * 64; 2942228561Snp ifp->if_omcasts = s->tx_mcast_frames - s->tx_pause; 2943228561Snp ifp->if_imcasts = s->rx_mcast_frames - s->rx_pause; 2944218792Snp ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 + 2945218792Snp s->rx_ovflow3; 2946218792Snp 2947218792Snp drops = s->tx_drop; 2948218792Snp for_each_txq(pi, i, txq) 2949220873Snp drops += txq->br->br_drops; 2950218792Snp ifp->if_snd.ifq_drops = drops; 2951218792Snp 2952218792Snp ifp->if_oerrors = s->tx_error_frames; 2953218792Snp ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long + 2954218792Snp s->rx_fcs_err + s->rx_len_err; 2955218792Snp 2956218792Snp callout_schedule(&pi->tick, hz); 2957218792Snp PORT_UNLOCK(pi); 2958218792Snp} 2959218792Snp 2960237263Snpstatic void 2961237263Snpcxgbe_vlan_config(void *arg, struct ifnet *ifp, uint16_t vid) 2962237263Snp{ 2963237263Snp struct ifnet *vlan; 2964237263Snp 2965237263Snp if (arg != ifp) 2966237263Snp return; 2967237263Snp 2968237263Snp vlan = VLAN_DEVAT(ifp, vid); 2969237263Snp VLAN_SETCOOKIE(vlan, ifp); 2970237263Snp} 2971237263Snp 2972218792Snpstatic int 2973228561Snpcpl_not_handled(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 2974228561Snp{ 2975237263Snp 2976228561Snp#ifdef INVARIANTS 2977237263Snp panic("%s: opcode 0x%02x on iq %p with payload %p", 2978228561Snp __func__, rss->opcode, iq, m); 2979228561Snp#else 2980237263Snp log(LOG_ERR, "%s: opcode 0x%02x on iq %p with payload %p", 2981228561Snp __func__, rss->opcode, iq, m); 2982228561Snp m_freem(m); 2983228561Snp#endif 2984228561Snp return (EDOOFUS); 2985228561Snp} 2986228561Snp 2987228561Snpint 2988228561Snpt4_register_cpl_handler(struct adapter *sc, int opcode, cpl_handler_t h) 2989228561Snp{ 2990228561Snp uintptr_t *loc, new; 2991228561Snp 2992228561Snp if (opcode >= ARRAY_SIZE(sc->cpl_handler)) 2993228561Snp return (EINVAL); 2994228561Snp 2995228561Snp new = h ? (uintptr_t)h : (uintptr_t)cpl_not_handled; 2996228561Snp loc = (uintptr_t *) &sc->cpl_handler[opcode]; 2997228561Snp atomic_store_rel_ptr(loc, new); 2998228561Snp 2999228561Snp return (0); 3000228561Snp} 3001228561Snp 3002228561Snpstatic int 3003237263Snpan_not_handled(struct sge_iq *iq, const struct rsp_ctrl *ctrl) 3004237263Snp{ 3005237263Snp 3006237263Snp#ifdef INVARIANTS 3007237263Snp panic("%s: async notification on iq %p (ctrl %p)", __func__, iq, ctrl); 3008237263Snp#else 3009237263Snp log(LOG_ERR, "%s: async notification on iq %p (ctrl %p)", 3010237263Snp __func__, iq, ctrl); 3011237263Snp#endif 3012237263Snp return (EDOOFUS); 3013237263Snp} 3014237263Snp 3015237263Snpint 3016237263Snpt4_register_an_handler(struct adapter *sc, an_handler_t h) 3017237263Snp{ 3018237263Snp uintptr_t *loc, new; 3019237263Snp 3020237263Snp new = h ? (uintptr_t)h : (uintptr_t)an_not_handled; 3021237263Snp loc = (uintptr_t *) &sc->an_handler; 3022237263Snp atomic_store_rel_ptr(loc, new); 3023237263Snp 3024237263Snp return (0); 3025237263Snp} 3026237263Snp 3027237263Snpstatic int 3028218792Snpt4_sysctls(struct adapter *sc) 3029218792Snp{ 3030218792Snp struct sysctl_ctx_list *ctx; 3031218792Snp struct sysctl_oid *oid; 3032228561Snp struct sysctl_oid_list *children, *c0; 3033228561Snp static char *caps[] = { 3034228561Snp "\20\1PPP\2QFC\3DCBX", /* caps[0] linkcaps */ 3035228561Snp "\20\1NIC\2VM\3IDS\4UM\5UM_ISGL", /* caps[1] niccaps */ 3036228561Snp "\20\1TOE", /* caps[2] toecaps */ 3037228561Snp "\20\1RDDP\2RDMAC", /* caps[3] rdmacaps */ 3038228561Snp "\20\1INITIATOR_PDU\2TARGET_PDU" /* caps[4] iscsicaps */ 3039228561Snp "\3INITIATOR_CNXOFLD\4TARGET_CNXOFLD" 3040228561Snp "\5INITIATOR_SSNOFLD\6TARGET_SSNOFLD", 3041228561Snp "\20\1INITIATOR\2TARGET\3CTRL_OFLD" /* caps[5] fcoecaps */ 3042228561Snp }; 3043218792Snp 3044218792Snp ctx = device_get_sysctl_ctx(sc->dev); 3045228561Snp 3046228561Snp /* 3047228561Snp * dev.t4nex.X. 3048228561Snp */ 3049218792Snp oid = device_get_sysctl_tree(sc->dev); 3050228561Snp c0 = children = SYSCTL_CHILDREN(oid); 3051218792Snp 3052218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, 3053218792Snp &sc->params.nports, 0, "# of ports"); 3054218792Snp 3055218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD, 3056218792Snp &sc->params.rev, 0, "chip hardware revision"); 3057218792Snp 3058218792Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 3059218792Snp CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 3060218792Snp 3061228561Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "cf", 3062228561Snp CTLFLAG_RD, &t4_cfg_file, 0, "configuration file"); 3063218792Snp 3064228561Snp SYSCTL_ADD_UINT(ctx, children, OID_AUTO, "cfcsum", CTLFLAG_RD, 3065228561Snp &sc->cfcsum, 0, "config file checksum"); 3066228561Snp 3067228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "linkcaps", 3068228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[0], sc->linkcaps, 3069228561Snp sysctl_bitfield, "A", "available link capabilities"); 3070228561Snp 3071228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "niccaps", 3072228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[1], sc->niccaps, 3073228561Snp sysctl_bitfield, "A", "available NIC capabilities"); 3074228561Snp 3075228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "toecaps", 3076228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[2], sc->toecaps, 3077228561Snp sysctl_bitfield, "A", "available TCP offload capabilities"); 3078228561Snp 3079228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdmacaps", 3080228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[3], sc->rdmacaps, 3081228561Snp sysctl_bitfield, "A", "available RDMA capabilities"); 3082228561Snp 3083228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "iscsicaps", 3084228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[4], sc->iscsicaps, 3085228561Snp sysctl_bitfield, "A", "available iSCSI capabilities"); 3086228561Snp 3087228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoecaps", 3088228561Snp CTLTYPE_STRING | CTLFLAG_RD, caps[5], sc->fcoecaps, 3089228561Snp sysctl_bitfield, "A", "available FCoE capabilities"); 3090228561Snp 3091218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, 3092218792Snp &sc->params.vpd.cclk, 0, "core clock frequency (in KHz)"); 3093218792Snp 3094219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers", 3095228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.timer_val, 3096228561Snp sizeof(sc->sge.timer_val), sysctl_int_array, "A", 3097228561Snp "interrupt holdoff timer values (us)"); 3098218792Snp 3099219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts", 3100228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc->sge.counter_val, 3101228561Snp sizeof(sc->sge.counter_val), sysctl_int_array, "A", 3102228561Snp "interrupt holdoff packet counter values"); 3103218792Snp 3104231115Snp#ifdef SBUF_DRAIN 3105228561Snp /* 3106228561Snp * dev.t4nex.X.misc. Marked CTLFLAG_SKIP to avoid information overload. 3107228561Snp */ 3108228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "misc", 3109228561Snp CTLFLAG_RD | CTLFLAG_SKIP, NULL, 3110228561Snp "logs and miscellaneous information"); 3111228561Snp children = SYSCTL_CHILDREN(oid); 3112228561Snp 3113228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cctrl", 3114228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3115228561Snp sysctl_cctrl, "A", "congestion control"); 3116228561Snp 3117228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "cpl_stats", 3118228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3119228561Snp sysctl_cpl_stats, "A", "CPL statistics"); 3120228561Snp 3121228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "ddp_stats", 3122228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3123228561Snp sysctl_ddp_stats, "A", "DDP statistics"); 3124228561Snp 3125222551Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog", 3126222551Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3127228561Snp sysctl_devlog, "A", "firmware's device log"); 3128222551Snp 3129228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "fcoe_stats", 3130228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3131228561Snp sysctl_fcoe_stats, "A", "FCoE statistics"); 3132228561Snp 3133228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "hw_sched", 3134228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3135228561Snp sysctl_hw_sched, "A", "hardware scheduler "); 3136228561Snp 3137228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "l2t", 3138228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3139228561Snp sysctl_l2t, "A", "hardware L2 table"); 3140228561Snp 3141228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "lb_stats", 3142228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3143228561Snp sysctl_lb_stats, "A", "loopback statistics"); 3144228561Snp 3145228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "meminfo", 3146228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3147228561Snp sysctl_meminfo, "A", "memory regions"); 3148228561Snp 3149228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "path_mtus", 3150228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3151228561Snp sysctl_path_mtus, "A", "path MTUs"); 3152228561Snp 3153228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "pm_stats", 3154228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3155228561Snp sysctl_pm_stats, "A", "PM statistics"); 3156228561Snp 3157228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "rdma_stats", 3158228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3159228561Snp sysctl_rdma_stats, "A", "RDMA statistics"); 3160228561Snp 3161228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tcp_stats", 3162228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3163228561Snp sysctl_tcp_stats, "A", "TCP statistics"); 3164228561Snp 3165228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tids", 3166228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3167228561Snp sysctl_tids, "A", "TID information"); 3168228561Snp 3169228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tp_err_stats", 3170228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3171228561Snp sysctl_tp_err_stats, "A", "TP error statistics"); 3172228561Snp 3173228561Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "tx_rate", 3174228561Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 3175228561Snp sysctl_tx_rate, "A", "Tx rate"); 3176231115Snp#endif 3177228561Snp 3178237263Snp#ifdef TCP_OFFLOAD 3179228561Snp if (is_offload(sc)) { 3180228561Snp /* 3181228561Snp * dev.t4nex.X.toe. 3182228561Snp */ 3183228561Snp oid = SYSCTL_ADD_NODE(ctx, c0, OID_AUTO, "toe", CTLFLAG_RD, 3184228561Snp NULL, "TOE parameters"); 3185228561Snp children = SYSCTL_CHILDREN(oid); 3186228561Snp 3187228561Snp sc->tt.sndbuf = 256 * 1024; 3188228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "sndbuf", CTLFLAG_RW, 3189228561Snp &sc->tt.sndbuf, 0, "max hardware send buffer size"); 3190228561Snp 3191228561Snp sc->tt.ddp = 0; 3192228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp", CTLFLAG_RW, 3193228561Snp &sc->tt.ddp, 0, "DDP allowed"); 3194228561Snp sc->tt.indsz = M_INDICATESIZE; 3195228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "indsz", CTLFLAG_RW, 3196228561Snp &sc->tt.indsz, 0, "DDP max indicate size allowed"); 3197228561Snp sc->tt.ddp_thres = 3*4096; 3198228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ddp_thres", CTLFLAG_RW, 3199228561Snp &sc->tt.ddp_thres, 0, "DDP threshold"); 3200228561Snp } 3201228561Snp#endif 3202228561Snp 3203228561Snp 3204218792Snp return (0); 3205218792Snp} 3206218792Snp 3207218792Snpstatic int 3208218792Snpcxgbe_sysctls(struct port_info *pi) 3209218792Snp{ 3210218792Snp struct sysctl_ctx_list *ctx; 3211218792Snp struct sysctl_oid *oid; 3212218792Snp struct sysctl_oid_list *children; 3213218792Snp 3214218792Snp ctx = device_get_sysctl_ctx(pi->dev); 3215218792Snp 3216218792Snp /* 3217218792Snp * dev.cxgbe.X. 3218218792Snp */ 3219218792Snp oid = device_get_sysctl_tree(pi->dev); 3220218792Snp children = SYSCTL_CHILDREN(oid); 3221218792Snp 3222218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD, 3223218792Snp &pi->nrxq, 0, "# of rx queues"); 3224218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD, 3225218792Snp &pi->ntxq, 0, "# of tx queues"); 3226218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD, 3227218792Snp &pi->first_rxq, 0, "index of first rx queue"); 3228218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD, 3229218792Snp &pi->first_txq, 0, "index of first tx queue"); 3230218792Snp 3231237263Snp#ifdef TCP_OFFLOAD 3232228561Snp if (is_offload(pi->adapter)) { 3233228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldrxq", CTLFLAG_RD, 3234228561Snp &pi->nofldrxq, 0, 3235228561Snp "# of rx queues for offloaded TCP connections"); 3236228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nofldtxq", CTLFLAG_RD, 3237228561Snp &pi->nofldtxq, 0, 3238228561Snp "# of tx queues for offloaded TCP connections"); 3239228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_rxq", 3240228561Snp CTLFLAG_RD, &pi->first_ofld_rxq, 0, 3241228561Snp "index of first TOE rx queue"); 3242228561Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_ofld_txq", 3243228561Snp CTLFLAG_RD, &pi->first_ofld_txq, 0, 3244228561Snp "index of first TOE tx queue"); 3245228561Snp } 3246228561Snp#endif 3247228561Snp 3248218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx", 3249218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I", 3250218792Snp "holdoff timer index"); 3251218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx", 3252218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I", 3253218792Snp "holdoff packet counter index"); 3254218792Snp 3255218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq", 3256218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I", 3257218792Snp "rx queue size"); 3258218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq", 3259218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I", 3260218792Snp "tx queue size"); 3261218792Snp 3262218792Snp /* 3263218792Snp * dev.cxgbe.X.stats. 3264218792Snp */ 3265218792Snp oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, 3266218792Snp NULL, "port statistics"); 3267218792Snp children = SYSCTL_CHILDREN(oid); 3268218792Snp 3269218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \ 3270218792Snp SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \ 3271218792Snp CTLTYPE_U64 | CTLFLAG_RD, pi->adapter, reg, \ 3272218792Snp sysctl_handle_t4_reg64, "QU", desc) 3273218792Snp 3274218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames", 3275218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L)); 3276218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames", 3277218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L)); 3278218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames", 3279218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L)); 3280218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames", 3281218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L)); 3282218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames", 3283218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L)); 3284218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames", 3285218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L)); 3286218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_64", 3287218792Snp "# of tx frames in this range", 3288218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L)); 3289218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127", 3290218792Snp "# of tx frames in this range", 3291218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L)); 3292218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255", 3293218792Snp "# of tx frames in this range", 3294218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L)); 3295218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511", 3296218792Snp "# of tx frames in this range", 3297218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L)); 3298218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023", 3299218792Snp "# of tx frames in this range", 3300218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L)); 3301218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518", 3302218792Snp "# of tx frames in this range", 3303218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L)); 3304218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max", 3305218792Snp "# of tx frames in this range", 3306218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L)); 3307218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames", 3308218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L)); 3309218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted", 3310218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L)); 3311218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted", 3312218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L)); 3313218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted", 3314218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L)); 3315218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted", 3316218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L)); 3317218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted", 3318218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L)); 3319218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted", 3320218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L)); 3321218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted", 3322218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L)); 3323218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted", 3324218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L)); 3325218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted", 3326218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L)); 3327218792Snp 3328218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames", 3329218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L)); 3330218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames", 3331218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L)); 3332218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames", 3333218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L)); 3334218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames", 3335218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L)); 3336218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames", 3337218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L)); 3338218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU", 3339218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L)); 3340218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames", 3341218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L)); 3342218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err", 3343218792Snp "# of frames received with bad FCS", 3344218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L)); 3345218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_len_err", 3346218792Snp "# of frames received with length error", 3347218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L)); 3348218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors", 3349218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L)); 3350218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received", 3351218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L)); 3352218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_64", 3353218792Snp "# of rx frames in this range", 3354218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L)); 3355218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127", 3356218792Snp "# of rx frames in this range", 3357218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L)); 3358218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255", 3359218792Snp "# of rx frames in this range", 3360218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L)); 3361218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511", 3362218792Snp "# of rx frames in this range", 3363218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L)); 3364218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023", 3365218792Snp "# of rx frames in this range", 3366218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L)); 3367218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518", 3368218792Snp "# of rx frames in this range", 3369218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L)); 3370218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max", 3371218792Snp "# of rx frames in this range", 3372218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L)); 3373218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received", 3374218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L)); 3375218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received", 3376218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L)); 3377218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received", 3378218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L)); 3379218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received", 3380218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L)); 3381218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received", 3382218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L)); 3383218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received", 3384218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L)); 3385218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received", 3386218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L)); 3387218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received", 3388218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L)); 3389218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received", 3390218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L)); 3391218792Snp 3392218792Snp#undef SYSCTL_ADD_T4_REG64 3393218792Snp 3394218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \ 3395218792Snp SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \ 3396218792Snp &pi->stats.name, desc) 3397218792Snp 3398218792Snp /* We get these from port_stats and they may be stale by upto 1s */ 3399218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0, 3400218792Snp "# drops due to buffer-group 0 overflows"); 3401218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1, 3402218792Snp "# drops due to buffer-group 1 overflows"); 3403218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2, 3404218792Snp "# drops due to buffer-group 2 overflows"); 3405218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3, 3406218792Snp "# drops due to buffer-group 3 overflows"); 3407218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc0, 3408218792Snp "# of buffer-group 0 truncated packets"); 3409218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc1, 3410218792Snp "# of buffer-group 1 truncated packets"); 3411218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc2, 3412218792Snp "# of buffer-group 2 truncated packets"); 3413218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc3, 3414218792Snp "# of buffer-group 3 truncated packets"); 3415218792Snp 3416218792Snp#undef SYSCTL_ADD_T4_PORTSTAT 3417218792Snp 3418218792Snp return (0); 3419218792Snp} 3420218792Snp 3421218792Snpstatic int 3422219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS) 3423219436Snp{ 3424219436Snp int rc, *i; 3425219436Snp struct sbuf sb; 3426219436Snp 3427219436Snp sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); 3428219436Snp for (i = arg1; arg2; arg2 -= sizeof(int), i++) 3429219436Snp sbuf_printf(&sb, "%d ", *i); 3430219436Snp sbuf_trim(&sb); 3431219436Snp sbuf_finish(&sb); 3432219436Snp rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 3433219436Snp sbuf_delete(&sb); 3434219436Snp return (rc); 3435219436Snp} 3436219436Snp 3437219436Snpstatic int 3438228561Snpsysctl_bitfield(SYSCTL_HANDLER_ARGS) 3439228561Snp{ 3440228561Snp int rc; 3441228561Snp struct sbuf *sb; 3442228561Snp 3443228561Snp rc = sysctl_wire_old_buffer(req, 0); 3444228561Snp if (rc != 0) 3445228561Snp return(rc); 3446228561Snp 3447228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 128, req); 3448228561Snp if (sb == NULL) 3449228561Snp return (ENOMEM); 3450228561Snp 3451228561Snp sbuf_printf(sb, "%b", (int)arg2, (char *)arg1); 3452228561Snp rc = sbuf_finish(sb); 3453228561Snp sbuf_delete(sb); 3454228561Snp 3455228561Snp return (rc); 3456228561Snp} 3457228561Snp 3458228561Snpstatic int 3459218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS) 3460218792Snp{ 3461218792Snp struct port_info *pi = arg1; 3462218792Snp struct adapter *sc = pi->adapter; 3463218792Snp int idx, rc, i; 3464218792Snp 3465218792Snp idx = pi->tmr_idx; 3466218792Snp 3467218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 3468218792Snp if (rc != 0 || req->newptr == NULL) 3469218792Snp return (rc); 3470218792Snp 3471218792Snp if (idx < 0 || idx >= SGE_NTIMERS) 3472218792Snp return (EINVAL); 3473218792Snp 3474218792Snp ADAPTER_LOCK(sc); 3475218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3476218792Snp if (rc == 0) { 3477228561Snp struct sge_rxq *rxq; 3478228561Snp uint8_t v; 3479228561Snp 3480228561Snp v = V_QINTR_TIMER_IDX(idx) | V_QINTR_CNT_EN(pi->pktc_idx != -1); 3481218792Snp for_each_rxq(pi, i, rxq) { 3482228561Snp#ifdef atomic_store_rel_8 3483228561Snp atomic_store_rel_8(&rxq->iq.intr_params, v); 3484228561Snp#else 3485228561Snp rxq->iq.intr_params = v; 3486228561Snp#endif 3487218792Snp } 3488218792Snp pi->tmr_idx = idx; 3489218792Snp } 3490218792Snp 3491218792Snp ADAPTER_UNLOCK(sc); 3492218792Snp return (rc); 3493218792Snp} 3494218792Snp 3495218792Snpstatic int 3496218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS) 3497218792Snp{ 3498218792Snp struct port_info *pi = arg1; 3499218792Snp struct adapter *sc = pi->adapter; 3500218792Snp int idx, rc; 3501218792Snp 3502218792Snp idx = pi->pktc_idx; 3503218792Snp 3504218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 3505218792Snp if (rc != 0 || req->newptr == NULL) 3506218792Snp return (rc); 3507218792Snp 3508218792Snp if (idx < -1 || idx >= SGE_NCOUNTERS) 3509218792Snp return (EINVAL); 3510218792Snp 3511218792Snp ADAPTER_LOCK(sc); 3512218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3513228561Snp if (rc == 0 && pi->flags & PORT_INIT_DONE) 3514228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 3515218792Snp 3516218792Snp if (rc == 0) 3517218792Snp pi->pktc_idx = idx; 3518218792Snp 3519218792Snp ADAPTER_UNLOCK(sc); 3520218792Snp return (rc); 3521218792Snp} 3522218792Snp 3523218792Snpstatic int 3524218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS) 3525218792Snp{ 3526218792Snp struct port_info *pi = arg1; 3527218792Snp struct adapter *sc = pi->adapter; 3528218792Snp int qsize, rc; 3529218792Snp 3530218792Snp qsize = pi->qsize_rxq; 3531218792Snp 3532218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 3533218792Snp if (rc != 0 || req->newptr == NULL) 3534218792Snp return (rc); 3535218792Snp 3536218792Snp if (qsize < 128 || (qsize & 7)) 3537218792Snp return (EINVAL); 3538218792Snp 3539218792Snp ADAPTER_LOCK(sc); 3540218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3541228561Snp if (rc == 0 && pi->flags & PORT_INIT_DONE) 3542228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 3543218792Snp 3544218792Snp if (rc == 0) 3545218792Snp pi->qsize_rxq = qsize; 3546218792Snp 3547218792Snp ADAPTER_UNLOCK(sc); 3548218792Snp return (rc); 3549218792Snp} 3550218792Snp 3551218792Snpstatic int 3552218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS) 3553218792Snp{ 3554218792Snp struct port_info *pi = arg1; 3555218792Snp struct adapter *sc = pi->adapter; 3556218792Snp int qsize, rc; 3557218792Snp 3558218792Snp qsize = pi->qsize_txq; 3559218792Snp 3560218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 3561218792Snp if (rc != 0 || req->newptr == NULL) 3562218792Snp return (rc); 3563218792Snp 3564218792Snp if (qsize < 128) 3565218792Snp return (EINVAL); 3566218792Snp 3567218792Snp ADAPTER_LOCK(sc); 3568218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 3569228561Snp if (rc == 0 && pi->flags & PORT_INIT_DONE) 3570228561Snp rc = EBUSY; /* cannot be changed once the queues are created */ 3571218792Snp 3572218792Snp if (rc == 0) 3573218792Snp pi->qsize_txq = qsize; 3574218792Snp 3575218792Snp ADAPTER_UNLOCK(sc); 3576218792Snp return (rc); 3577218792Snp} 3578218792Snp 3579218792Snpstatic int 3580218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS) 3581218792Snp{ 3582218792Snp struct adapter *sc = arg1; 3583218792Snp int reg = arg2; 3584218792Snp uint64_t val; 3585218792Snp 3586218792Snp val = t4_read_reg64(sc, reg); 3587218792Snp 3588218792Snp return (sysctl_handle_64(oidp, &val, 0, req)); 3589218792Snp} 3590218792Snp 3591231115Snp#ifdef SBUF_DRAIN 3592228561Snpstatic int 3593228561Snpsysctl_cctrl(SYSCTL_HANDLER_ARGS) 3594228561Snp{ 3595228561Snp struct adapter *sc = arg1; 3596228561Snp struct sbuf *sb; 3597228561Snp int rc, i; 3598228561Snp uint16_t incr[NMTUS][NCCTRL_WIN]; 3599228561Snp static const char *dec_fac[] = { 3600228561Snp "0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875", 3601228561Snp "0.9375" 3602228561Snp }; 3603228561Snp 3604228561Snp rc = sysctl_wire_old_buffer(req, 0); 3605228561Snp if (rc != 0) 3606228561Snp return (rc); 3607228561Snp 3608228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3609228561Snp if (sb == NULL) 3610228561Snp return (ENOMEM); 3611228561Snp 3612228561Snp t4_read_cong_tbl(sc, incr); 3613228561Snp 3614228561Snp for (i = 0; i < NCCTRL_WIN; ++i) { 3615228561Snp sbuf_printf(sb, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i, 3616228561Snp incr[0][i], incr[1][i], incr[2][i], incr[3][i], incr[4][i], 3617228561Snp incr[5][i], incr[6][i], incr[7][i]); 3618228561Snp sbuf_printf(sb, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n", 3619228561Snp incr[8][i], incr[9][i], incr[10][i], incr[11][i], 3620228561Snp incr[12][i], incr[13][i], incr[14][i], incr[15][i], 3621228561Snp sc->params.a_wnd[i], dec_fac[sc->params.b_wnd[i]]); 3622228561Snp } 3623228561Snp 3624228561Snp rc = sbuf_finish(sb); 3625228561Snp sbuf_delete(sb); 3626228561Snp 3627228561Snp return (rc); 3628228561Snp} 3629228561Snp 3630228561Snpstatic int 3631228561Snpsysctl_cpl_stats(SYSCTL_HANDLER_ARGS) 3632228561Snp{ 3633228561Snp struct adapter *sc = arg1; 3634228561Snp struct sbuf *sb; 3635228561Snp int rc; 3636228561Snp struct tp_cpl_stats stats; 3637228561Snp 3638228561Snp rc = sysctl_wire_old_buffer(req, 0); 3639228561Snp if (rc != 0) 3640228561Snp return (rc); 3641228561Snp 3642228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3643228561Snp if (sb == NULL) 3644228561Snp return (ENOMEM); 3645228561Snp 3646228561Snp t4_tp_get_cpl_stats(sc, &stats); 3647228561Snp 3648228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 3649228561Snp "channel 3\n"); 3650228561Snp sbuf_printf(sb, "CPL requests: %10u %10u %10u %10u\n", 3651228561Snp stats.req[0], stats.req[1], stats.req[2], stats.req[3]); 3652228561Snp sbuf_printf(sb, "CPL responses: %10u %10u %10u %10u", 3653228561Snp stats.rsp[0], stats.rsp[1], stats.rsp[2], stats.rsp[3]); 3654228561Snp 3655228561Snp rc = sbuf_finish(sb); 3656228561Snp sbuf_delete(sb); 3657228561Snp 3658228561Snp return (rc); 3659228561Snp} 3660228561Snp 3661228561Snpstatic int 3662228561Snpsysctl_ddp_stats(SYSCTL_HANDLER_ARGS) 3663228561Snp{ 3664228561Snp struct adapter *sc = arg1; 3665228561Snp struct sbuf *sb; 3666228561Snp int rc; 3667228561Snp struct tp_usm_stats stats; 3668228561Snp 3669228561Snp rc = sysctl_wire_old_buffer(req, 0); 3670228561Snp if (rc != 0) 3671228561Snp return(rc); 3672228561Snp 3673228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3674228561Snp if (sb == NULL) 3675228561Snp return (ENOMEM); 3676228561Snp 3677228561Snp t4_get_usm_stats(sc, &stats); 3678228561Snp 3679228561Snp sbuf_printf(sb, "Frames: %u\n", stats.frames); 3680228561Snp sbuf_printf(sb, "Octets: %ju\n", stats.octets); 3681228561Snp sbuf_printf(sb, "Drops: %u", stats.drops); 3682228561Snp 3683228561Snp rc = sbuf_finish(sb); 3684228561Snp sbuf_delete(sb); 3685228561Snp 3686228561Snp return (rc); 3687228561Snp} 3688228561Snp 3689222551Snpconst char *devlog_level_strings[] = { 3690222551Snp [FW_DEVLOG_LEVEL_EMERG] = "EMERG", 3691222551Snp [FW_DEVLOG_LEVEL_CRIT] = "CRIT", 3692222551Snp [FW_DEVLOG_LEVEL_ERR] = "ERR", 3693222551Snp [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", 3694222551Snp [FW_DEVLOG_LEVEL_INFO] = "INFO", 3695222551Snp [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" 3696222551Snp}; 3697222551Snp 3698222551Snpconst char *devlog_facility_strings[] = { 3699222551Snp [FW_DEVLOG_FACILITY_CORE] = "CORE", 3700222551Snp [FW_DEVLOG_FACILITY_SCHED] = "SCHED", 3701222551Snp [FW_DEVLOG_FACILITY_TIMER] = "TIMER", 3702222551Snp [FW_DEVLOG_FACILITY_RES] = "RES", 3703222551Snp [FW_DEVLOG_FACILITY_HW] = "HW", 3704222551Snp [FW_DEVLOG_FACILITY_FLR] = "FLR", 3705222551Snp [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", 3706222551Snp [FW_DEVLOG_FACILITY_PHY] = "PHY", 3707222551Snp [FW_DEVLOG_FACILITY_MAC] = "MAC", 3708222551Snp [FW_DEVLOG_FACILITY_PORT] = "PORT", 3709222551Snp [FW_DEVLOG_FACILITY_VI] = "VI", 3710222551Snp [FW_DEVLOG_FACILITY_FILTER] = "FILTER", 3711222551Snp [FW_DEVLOG_FACILITY_ACL] = "ACL", 3712222551Snp [FW_DEVLOG_FACILITY_TM] = "TM", 3713222551Snp [FW_DEVLOG_FACILITY_QFC] = "QFC", 3714222551Snp [FW_DEVLOG_FACILITY_DCB] = "DCB", 3715222551Snp [FW_DEVLOG_FACILITY_ETH] = "ETH", 3716222551Snp [FW_DEVLOG_FACILITY_OFLD] = "OFLD", 3717222551Snp [FW_DEVLOG_FACILITY_RI] = "RI", 3718222551Snp [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", 3719222551Snp [FW_DEVLOG_FACILITY_FCOE] = "FCOE", 3720222551Snp [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", 3721222551Snp [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE" 3722222551Snp}; 3723222551Snp 3724222551Snpstatic int 3725222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS) 3726222551Snp{ 3727222551Snp struct adapter *sc = arg1; 3728222551Snp struct devlog_params *dparams = &sc->params.devlog; 3729222551Snp struct fw_devlog_e *buf, *e; 3730222551Snp int i, j, rc, nentries, first = 0; 3731222551Snp struct sbuf *sb; 3732222551Snp uint64_t ftstamp = UINT64_MAX; 3733222551Snp 3734222551Snp if (dparams->start == 0) 3735222551Snp return (ENXIO); 3736222551Snp 3737222551Snp nentries = dparams->size / sizeof(struct fw_devlog_e); 3738222551Snp 3739222551Snp buf = malloc(dparams->size, M_CXGBE, M_NOWAIT); 3740222551Snp if (buf == NULL) 3741222551Snp return (ENOMEM); 3742222551Snp 3743222551Snp rc = -t4_mem_read(sc, dparams->memtype, dparams->start, dparams->size, 3744222551Snp (void *)buf); 3745222551Snp if (rc != 0) 3746222551Snp goto done; 3747222551Snp 3748222551Snp for (i = 0; i < nentries; i++) { 3749222551Snp e = &buf[i]; 3750222551Snp 3751222551Snp if (e->timestamp == 0) 3752222551Snp break; /* end */ 3753222551Snp 3754222551Snp e->timestamp = be64toh(e->timestamp); 3755222551Snp e->seqno = be32toh(e->seqno); 3756222551Snp for (j = 0; j < 8; j++) 3757222551Snp e->params[j] = be32toh(e->params[j]); 3758222551Snp 3759222551Snp if (e->timestamp < ftstamp) { 3760222551Snp ftstamp = e->timestamp; 3761222551Snp first = i; 3762222551Snp } 3763222551Snp } 3764222551Snp 3765222551Snp if (buf[first].timestamp == 0) 3766222551Snp goto done; /* nothing in the log */ 3767222551Snp 3768222551Snp rc = sysctl_wire_old_buffer(req, 0); 3769222551Snp if (rc != 0) 3770222551Snp goto done; 3771222551Snp 3772222551Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3773228561Snp if (sb == NULL) { 3774228561Snp rc = ENOMEM; 3775228561Snp goto done; 3776228561Snp } 3777228561Snp sbuf_printf(sb, "%10s %15s %8s %8s %s\n", 3778222551Snp "Seq#", "Tstamp", "Level", "Facility", "Message"); 3779222551Snp 3780222551Snp i = first; 3781222551Snp do { 3782222551Snp e = &buf[i]; 3783222551Snp if (e->timestamp == 0) 3784222551Snp break; /* end */ 3785222551Snp 3786222551Snp sbuf_printf(sb, "%10d %15ju %8s %8s ", 3787222551Snp e->seqno, e->timestamp, 3788222551Snp (e->level < ARRAY_SIZE(devlog_level_strings) ? 3789222551Snp devlog_level_strings[e->level] : "UNKNOWN"), 3790222551Snp (e->facility < ARRAY_SIZE(devlog_facility_strings) ? 3791222551Snp devlog_facility_strings[e->facility] : "UNKNOWN")); 3792222551Snp sbuf_printf(sb, e->fmt, e->params[0], e->params[1], 3793222551Snp e->params[2], e->params[3], e->params[4], 3794222551Snp e->params[5], e->params[6], e->params[7]); 3795222551Snp 3796222551Snp if (++i == nentries) 3797222551Snp i = 0; 3798222551Snp } while (i != first); 3799222551Snp 3800222551Snp rc = sbuf_finish(sb); 3801222551Snp sbuf_delete(sb); 3802222551Snpdone: 3803222551Snp free(buf, M_CXGBE); 3804222551Snp return (rc); 3805222551Snp} 3806222551Snp 3807228561Snpstatic int 3808228561Snpsysctl_fcoe_stats(SYSCTL_HANDLER_ARGS) 3809228561Snp{ 3810228561Snp struct adapter *sc = arg1; 3811228561Snp struct sbuf *sb; 3812228561Snp int rc; 3813228561Snp struct tp_fcoe_stats stats[4]; 3814228561Snp 3815228561Snp rc = sysctl_wire_old_buffer(req, 0); 3816228561Snp if (rc != 0) 3817228561Snp return (rc); 3818228561Snp 3819228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 3820228561Snp if (sb == NULL) 3821228561Snp return (ENOMEM); 3822228561Snp 3823228561Snp t4_get_fcoe_stats(sc, 0, &stats[0]); 3824228561Snp t4_get_fcoe_stats(sc, 1, &stats[1]); 3825228561Snp t4_get_fcoe_stats(sc, 2, &stats[2]); 3826228561Snp t4_get_fcoe_stats(sc, 3, &stats[3]); 3827228561Snp 3828228561Snp sbuf_printf(sb, " channel 0 channel 1 " 3829228561Snp "channel 2 channel 3\n"); 3830228561Snp sbuf_printf(sb, "octetsDDP: %16ju %16ju %16ju %16ju\n", 3831228561Snp stats[0].octetsDDP, stats[1].octetsDDP, stats[2].octetsDDP, 3832228561Snp stats[3].octetsDDP); 3833228561Snp sbuf_printf(sb, "framesDDP: %16u %16u %16u %16u\n", stats[0].framesDDP, 3834228561Snp stats[1].framesDDP, stats[2].framesDDP, stats[3].framesDDP); 3835228561Snp sbuf_printf(sb, "framesDrop: %16u %16u %16u %16u", 3836228561Snp stats[0].framesDrop, stats[1].framesDrop, stats[2].framesDrop, 3837228561Snp stats[3].framesDrop); 3838228561Snp 3839228561Snp rc = sbuf_finish(sb); 3840228561Snp sbuf_delete(sb); 3841228561Snp 3842228561Snp return (rc); 3843228561Snp} 3844228561Snp 3845228561Snpstatic int 3846228561Snpsysctl_hw_sched(SYSCTL_HANDLER_ARGS) 3847228561Snp{ 3848228561Snp struct adapter *sc = arg1; 3849228561Snp struct sbuf *sb; 3850228561Snp int rc, i; 3851228561Snp unsigned int map, kbps, ipg, mode; 3852228561Snp unsigned int pace_tab[NTX_SCHED]; 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 map = t4_read_reg(sc, A_TP_TX_MOD_QUEUE_REQ_MAP); 3863228561Snp mode = G_TIMERMODE(t4_read_reg(sc, A_TP_MOD_CONFIG)); 3864228561Snp t4_read_pace_tbl(sc, pace_tab); 3865228561Snp 3866228561Snp sbuf_printf(sb, "Scheduler Mode Channel Rate (Kbps) " 3867228561Snp "Class IPG (0.1 ns) Flow IPG (us)"); 3868228561Snp 3869228561Snp for (i = 0; i < NTX_SCHED; ++i, map >>= 2) { 3870228561Snp t4_get_tx_sched(sc, i, &kbps, &ipg); 3871228561Snp sbuf_printf(sb, "\n %u %-5s %u ", i, 3872228561Snp (mode & (1 << i)) ? "flow" : "class", map & 3); 3873228561Snp if (kbps) 3874228561Snp sbuf_printf(sb, "%9u ", kbps); 3875228561Snp else 3876228561Snp sbuf_printf(sb, " disabled "); 3877228561Snp 3878228561Snp if (ipg) 3879228561Snp sbuf_printf(sb, "%13u ", ipg); 3880228561Snp else 3881228561Snp sbuf_printf(sb, " disabled "); 3882228561Snp 3883228561Snp if (pace_tab[i]) 3884228561Snp sbuf_printf(sb, "%10u", pace_tab[i]); 3885228561Snp else 3886228561Snp sbuf_printf(sb, " disabled"); 3887228561Snp } 3888228561Snp 3889228561Snp rc = sbuf_finish(sb); 3890228561Snp sbuf_delete(sb); 3891228561Snp 3892228561Snp return (rc); 3893228561Snp} 3894228561Snp 3895228561Snpstatic int 3896228561Snpsysctl_lb_stats(SYSCTL_HANDLER_ARGS) 3897228561Snp{ 3898228561Snp struct adapter *sc = arg1; 3899228561Snp struct sbuf *sb; 3900228561Snp int rc, i, j; 3901228561Snp uint64_t *p0, *p1; 3902228561Snp struct lb_port_stats s[2]; 3903228561Snp static const char *stat_name[] = { 3904228561Snp "OctetsOK:", "FramesOK:", "BcastFrames:", "McastFrames:", 3905228561Snp "UcastFrames:", "ErrorFrames:", "Frames64:", "Frames65To127:", 3906228561Snp "Frames128To255:", "Frames256To511:", "Frames512To1023:", 3907228561Snp "Frames1024To1518:", "Frames1519ToMax:", "FramesDropped:", 3908228561Snp "BG0FramesDropped:", "BG1FramesDropped:", "BG2FramesDropped:", 3909228561Snp "BG3FramesDropped:", "BG0FramesTrunc:", "BG1FramesTrunc:", 3910228561Snp "BG2FramesTrunc:", "BG3FramesTrunc:" 3911228561Snp }; 3912228561Snp 3913228561Snp rc = sysctl_wire_old_buffer(req, 0); 3914228561Snp if (rc != 0) 3915228561Snp return (rc); 3916228561Snp 3917228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3918228561Snp if (sb == NULL) 3919228561Snp return (ENOMEM); 3920228561Snp 3921228561Snp memset(s, 0, sizeof(s)); 3922228561Snp 3923228561Snp for (i = 0; i < 4; i += 2) { 3924228561Snp t4_get_lb_stats(sc, i, &s[0]); 3925228561Snp t4_get_lb_stats(sc, i + 1, &s[1]); 3926228561Snp 3927228561Snp p0 = &s[0].octets; 3928228561Snp p1 = &s[1].octets; 3929228561Snp sbuf_printf(sb, "%s Loopback %u" 3930228561Snp " Loopback %u", i == 0 ? "" : "\n", i, i + 1); 3931228561Snp 3932228561Snp for (j = 0; j < ARRAY_SIZE(stat_name); j++) 3933228561Snp sbuf_printf(sb, "\n%-17s %20ju %20ju", stat_name[j], 3934228561Snp *p0++, *p1++); 3935228561Snp } 3936228561Snp 3937228561Snp rc = sbuf_finish(sb); 3938228561Snp sbuf_delete(sb); 3939228561Snp 3940228561Snp return (rc); 3941228561Snp} 3942228561Snp 3943228561Snpstruct mem_desc { 3944228561Snp unsigned int base; 3945228561Snp unsigned int limit; 3946228561Snp unsigned int idx; 3947228561Snp}; 3948228561Snp 3949228561Snpstatic int 3950228561Snpmem_desc_cmp(const void *a, const void *b) 3951228561Snp{ 3952228561Snp return ((const struct mem_desc *)a)->base - 3953228561Snp ((const struct mem_desc *)b)->base; 3954228561Snp} 3955228561Snp 3956228561Snpstatic void 3957228561Snpmem_region_show(struct sbuf *sb, const char *name, unsigned int from, 3958228561Snp unsigned int to) 3959228561Snp{ 3960228561Snp unsigned int size; 3961228561Snp 3962228561Snp size = to - from + 1; 3963228561Snp if (size == 0) 3964228561Snp return; 3965228561Snp 3966228561Snp /* XXX: need humanize_number(3) in libkern for a more readable 'size' */ 3967228561Snp sbuf_printf(sb, "%-15s %#x-%#x [%u]\n", name, from, to, size); 3968228561Snp} 3969228561Snp 3970228561Snpstatic int 3971228561Snpsysctl_meminfo(SYSCTL_HANDLER_ARGS) 3972228561Snp{ 3973228561Snp struct adapter *sc = arg1; 3974228561Snp struct sbuf *sb; 3975228561Snp int rc, i, n; 3976228561Snp uint32_t lo, hi; 3977228561Snp static const char *memory[] = { "EDC0:", "EDC1:", "MC:" }; 3978228561Snp static const char *region[] = { 3979228561Snp "DBQ contexts:", "IMSG contexts:", "FLM cache:", "TCBs:", 3980228561Snp "Pstructs:", "Timers:", "Rx FL:", "Tx FL:", "Pstruct FL:", 3981228561Snp "Tx payload:", "Rx payload:", "LE hash:", "iSCSI region:", 3982228561Snp "TDDP region:", "TPT region:", "STAG region:", "RQ region:", 3983228561Snp "RQUDP region:", "PBL region:", "TXPBL region:", "ULPRX state:", 3984228561Snp "ULPTX state:", "On-chip queues:" 3985228561Snp }; 3986228561Snp struct mem_desc avail[3]; 3987228561Snp struct mem_desc mem[ARRAY_SIZE(region) + 3]; /* up to 3 holes */ 3988228561Snp struct mem_desc *md = mem; 3989228561Snp 3990228561Snp rc = sysctl_wire_old_buffer(req, 0); 3991228561Snp if (rc != 0) 3992228561Snp return (rc); 3993228561Snp 3994228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 3995228561Snp if (sb == NULL) 3996228561Snp return (ENOMEM); 3997228561Snp 3998228561Snp for (i = 0; i < ARRAY_SIZE(mem); i++) { 3999228561Snp mem[i].limit = 0; 4000228561Snp mem[i].idx = i; 4001228561Snp } 4002228561Snp 4003228561Snp /* Find and sort the populated memory ranges */ 4004228561Snp i = 0; 4005228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 4006228561Snp if (lo & F_EDRAM0_ENABLE) { 4007228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 4008228561Snp avail[i].base = G_EDRAM0_BASE(hi) << 20; 4009228561Snp avail[i].limit = avail[i].base + (G_EDRAM0_SIZE(hi) << 20); 4010228561Snp avail[i].idx = 0; 4011228561Snp i++; 4012228561Snp } 4013228561Snp if (lo & F_EDRAM1_ENABLE) { 4014228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 4015228561Snp avail[i].base = G_EDRAM1_BASE(hi) << 20; 4016228561Snp avail[i].limit = avail[i].base + (G_EDRAM1_SIZE(hi) << 20); 4017228561Snp avail[i].idx = 1; 4018228561Snp i++; 4019228561Snp } 4020228561Snp if (lo & F_EXT_MEM_ENABLE) { 4021228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 4022228561Snp avail[i].base = G_EXT_MEM_BASE(hi) << 20; 4023228561Snp avail[i].limit = avail[i].base + (G_EXT_MEM_SIZE(hi) << 20); 4024228561Snp avail[i].idx = 2; 4025228561Snp i++; 4026228561Snp } 4027228561Snp if (!i) /* no memory available */ 4028228561Snp return 0; 4029228561Snp qsort(avail, i, sizeof(struct mem_desc), mem_desc_cmp); 4030228561Snp 4031228561Snp (md++)->base = t4_read_reg(sc, A_SGE_DBQ_CTXT_BADDR); 4032228561Snp (md++)->base = t4_read_reg(sc, A_SGE_IMSG_CTXT_BADDR); 4033228561Snp (md++)->base = t4_read_reg(sc, A_SGE_FLM_CACHE_BADDR); 4034228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 4035228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_BASE); 4036228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_TIMER_BASE); 4037228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_RX_FLST_BASE); 4038228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_TX_FLST_BASE); 4039228561Snp (md++)->base = t4_read_reg(sc, A_TP_CMM_MM_PS_FLST_BASE); 4040228561Snp 4041228561Snp /* the next few have explicit upper bounds */ 4042228561Snp md->base = t4_read_reg(sc, A_TP_PMM_TX_BASE); 4043228561Snp md->limit = md->base - 1 + 4044228561Snp t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE) * 4045228561Snp G_PMTXMAXPAGE(t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE)); 4046228561Snp md++; 4047228561Snp 4048228561Snp md->base = t4_read_reg(sc, A_TP_PMM_RX_BASE); 4049228561Snp md->limit = md->base - 1 + 4050228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) * 4051228561Snp G_PMRXMAXPAGE(t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE)); 4052228561Snp md++; 4053228561Snp 4054228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 4055228561Snp hi = t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4; 4056228561Snp md->base = t4_read_reg(sc, A_LE_DB_HASH_TID_BASE); 4057228561Snp md->limit = (sc->tids.ntids - hi) * 16 + md->base - 1; 4058228561Snp } else { 4059228561Snp md->base = 0; 4060228561Snp md->idx = ARRAY_SIZE(region); /* hide it */ 4061228561Snp } 4062228561Snp md++; 4063228561Snp 4064228561Snp#define ulp_region(reg) \ 4065228561Snp md->base = t4_read_reg(sc, A_ULP_ ## reg ## _LLIMIT);\ 4066228561Snp (md++)->limit = t4_read_reg(sc, A_ULP_ ## reg ## _ULIMIT) 4067228561Snp 4068228561Snp ulp_region(RX_ISCSI); 4069228561Snp ulp_region(RX_TDDP); 4070228561Snp ulp_region(TX_TPT); 4071228561Snp ulp_region(RX_STAG); 4072228561Snp ulp_region(RX_RQ); 4073228561Snp ulp_region(RX_RQUDP); 4074228561Snp ulp_region(RX_PBL); 4075228561Snp ulp_region(TX_PBL); 4076228561Snp#undef ulp_region 4077228561Snp 4078228561Snp md->base = t4_read_reg(sc, A_ULP_RX_CTX_BASE); 4079228561Snp md->limit = md->base + sc->tids.ntids - 1; 4080228561Snp md++; 4081228561Snp md->base = t4_read_reg(sc, A_ULP_TX_ERR_TABLE_BASE); 4082228561Snp md->limit = md->base + sc->tids.ntids - 1; 4083228561Snp md++; 4084228561Snp 4085228561Snp md->base = sc->vres.ocq.start; 4086228561Snp if (sc->vres.ocq.size) 4087228561Snp md->limit = md->base + sc->vres.ocq.size - 1; 4088228561Snp else 4089228561Snp md->idx = ARRAY_SIZE(region); /* hide it */ 4090228561Snp md++; 4091228561Snp 4092228561Snp /* add any address-space holes, there can be up to 3 */ 4093228561Snp for (n = 0; n < i - 1; n++) 4094228561Snp if (avail[n].limit < avail[n + 1].base) 4095228561Snp (md++)->base = avail[n].limit; 4096228561Snp if (avail[n].limit) 4097228561Snp (md++)->base = avail[n].limit; 4098228561Snp 4099228561Snp n = md - mem; 4100228561Snp qsort(mem, n, sizeof(struct mem_desc), mem_desc_cmp); 4101228561Snp 4102228561Snp for (lo = 0; lo < i; lo++) 4103228561Snp mem_region_show(sb, memory[avail[lo].idx], avail[lo].base, 4104228561Snp avail[lo].limit - 1); 4105228561Snp 4106228561Snp sbuf_printf(sb, "\n"); 4107228561Snp for (i = 0; i < n; i++) { 4108228561Snp if (mem[i].idx >= ARRAY_SIZE(region)) 4109228561Snp continue; /* skip holes */ 4110228561Snp if (!mem[i].limit) 4111228561Snp mem[i].limit = i < n - 1 ? mem[i + 1].base - 1 : ~0; 4112228561Snp mem_region_show(sb, region[mem[i].idx], mem[i].base, 4113228561Snp mem[i].limit); 4114228561Snp } 4115228561Snp 4116228561Snp sbuf_printf(sb, "\n"); 4117228561Snp lo = t4_read_reg(sc, A_CIM_SDRAM_BASE_ADDR); 4118228561Snp hi = t4_read_reg(sc, A_CIM_SDRAM_ADDR_SIZE) + lo - 1; 4119228561Snp mem_region_show(sb, "uP RAM:", lo, hi); 4120228561Snp 4121228561Snp lo = t4_read_reg(sc, A_CIM_EXTMEM2_BASE_ADDR); 4122228561Snp hi = t4_read_reg(sc, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1; 4123228561Snp mem_region_show(sb, "uP Extmem2:", lo, hi); 4124228561Snp 4125228561Snp lo = t4_read_reg(sc, A_TP_PMM_RX_MAX_PAGE); 4126228561Snp sbuf_printf(sb, "\n%u Rx pages of size %uKiB for %u channels\n", 4127228561Snp G_PMRXMAXPAGE(lo), 4128228561Snp t4_read_reg(sc, A_TP_PMM_RX_PAGE_SIZE) >> 10, 4129228561Snp (lo & F_PMRXNUMCHN) ? 2 : 1); 4130228561Snp 4131228561Snp lo = t4_read_reg(sc, A_TP_PMM_TX_MAX_PAGE); 4132228561Snp hi = t4_read_reg(sc, A_TP_PMM_TX_PAGE_SIZE); 4133228561Snp sbuf_printf(sb, "%u Tx pages of size %u%ciB for %u channels\n", 4134228561Snp G_PMTXMAXPAGE(lo), 4135228561Snp hi >= (1 << 20) ? (hi >> 20) : (hi >> 10), 4136228561Snp hi >= (1 << 20) ? 'M' : 'K', 1 << G_PMTXNUMCHN(lo)); 4137228561Snp sbuf_printf(sb, "%u p-structs\n", 4138228561Snp t4_read_reg(sc, A_TP_CMM_MM_MAX_PSTRUCT)); 4139228561Snp 4140228561Snp for (i = 0; i < 4; i++) { 4141228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV0 + i * 4); 4142228561Snp sbuf_printf(sb, "\nPort %d using %u pages out of %u allocated", 4143228561Snp i, G_USED(lo), G_ALLOC(lo)); 4144228561Snp } 4145228561Snp for (i = 0; i < 4; i++) { 4146228561Snp lo = t4_read_reg(sc, A_MPS_RX_PG_RSV4 + i * 4); 4147228561Snp sbuf_printf(sb, 4148228561Snp "\nLoopback %d using %u pages out of %u allocated", 4149228561Snp i, G_USED(lo), G_ALLOC(lo)); 4150228561Snp } 4151228561Snp 4152228561Snp rc = sbuf_finish(sb); 4153228561Snp sbuf_delete(sb); 4154228561Snp 4155228561Snp return (rc); 4156228561Snp} 4157228561Snp 4158228561Snpstatic int 4159228561Snpsysctl_path_mtus(SYSCTL_HANDLER_ARGS) 4160228561Snp{ 4161228561Snp struct adapter *sc = arg1; 4162228561Snp struct sbuf *sb; 4163228561Snp int rc; 4164228561Snp uint16_t mtus[NMTUS]; 4165228561Snp 4166228561Snp rc = sysctl_wire_old_buffer(req, 0); 4167228561Snp if (rc != 0) 4168228561Snp return (rc); 4169228561Snp 4170228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4171228561Snp if (sb == NULL) 4172228561Snp return (ENOMEM); 4173228561Snp 4174228561Snp t4_read_mtu_tbl(sc, mtus, NULL); 4175228561Snp 4176228561Snp sbuf_printf(sb, "%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", 4177228561Snp mtus[0], mtus[1], mtus[2], mtus[3], mtus[4], mtus[5], mtus[6], 4178228561Snp mtus[7], mtus[8], mtus[9], mtus[10], mtus[11], mtus[12], mtus[13], 4179228561Snp mtus[14], mtus[15]); 4180228561Snp 4181228561Snp rc = sbuf_finish(sb); 4182228561Snp sbuf_delete(sb); 4183228561Snp 4184228561Snp return (rc); 4185228561Snp} 4186228561Snp 4187228561Snpstatic int 4188228561Snpsysctl_pm_stats(SYSCTL_HANDLER_ARGS) 4189228561Snp{ 4190228561Snp struct adapter *sc = arg1; 4191228561Snp struct sbuf *sb; 4192228561Snp int rc, i; 4193228561Snp uint32_t tx_cnt[PM_NSTATS], rx_cnt[PM_NSTATS]; 4194228561Snp uint64_t tx_cyc[PM_NSTATS], rx_cyc[PM_NSTATS]; 4195228561Snp static const char *pm_stats[] = { 4196228561Snp "Read:", "Write bypass:", "Write mem:", "Flush:", "FIFO wait:" 4197228561Snp }; 4198228561Snp 4199228561Snp rc = sysctl_wire_old_buffer(req, 0); 4200228561Snp if (rc != 0) 4201228561Snp return (rc); 4202228561Snp 4203228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4204228561Snp if (sb == NULL) 4205228561Snp return (ENOMEM); 4206228561Snp 4207228561Snp t4_pmtx_get_stats(sc, tx_cnt, tx_cyc); 4208228561Snp t4_pmrx_get_stats(sc, rx_cnt, rx_cyc); 4209228561Snp 4210228561Snp sbuf_printf(sb, " Tx count Tx cycles " 4211228561Snp "Rx count Rx cycles"); 4212228561Snp for (i = 0; i < PM_NSTATS; i++) 4213228561Snp sbuf_printf(sb, "\n%-13s %10u %20ju %10u %20ju", 4214228561Snp pm_stats[i], tx_cnt[i], tx_cyc[i], rx_cnt[i], rx_cyc[i]); 4215228561Snp 4216228561Snp rc = sbuf_finish(sb); 4217228561Snp sbuf_delete(sb); 4218228561Snp 4219228561Snp return (rc); 4220228561Snp} 4221228561Snp 4222228561Snpstatic int 4223228561Snpsysctl_rdma_stats(SYSCTL_HANDLER_ARGS) 4224228561Snp{ 4225228561Snp struct adapter *sc = arg1; 4226228561Snp struct sbuf *sb; 4227228561Snp int rc; 4228228561Snp struct tp_rdma_stats stats; 4229228561Snp 4230228561Snp rc = sysctl_wire_old_buffer(req, 0); 4231228561Snp if (rc != 0) 4232228561Snp return (rc); 4233228561Snp 4234228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4235228561Snp if (sb == NULL) 4236228561Snp return (ENOMEM); 4237228561Snp 4238228561Snp t4_tp_get_rdma_stats(sc, &stats); 4239228561Snp sbuf_printf(sb, "NoRQEModDefferals: %u\n", stats.rqe_dfr_mod); 4240228561Snp sbuf_printf(sb, "NoRQEPktDefferals: %u", stats.rqe_dfr_pkt); 4241228561Snp 4242228561Snp rc = sbuf_finish(sb); 4243228561Snp sbuf_delete(sb); 4244228561Snp 4245228561Snp return (rc); 4246228561Snp} 4247228561Snp 4248228561Snpstatic int 4249228561Snpsysctl_tcp_stats(SYSCTL_HANDLER_ARGS) 4250228561Snp{ 4251228561Snp struct adapter *sc = arg1; 4252228561Snp struct sbuf *sb; 4253228561Snp int rc; 4254228561Snp struct tp_tcp_stats v4, v6; 4255228561Snp 4256228561Snp rc = sysctl_wire_old_buffer(req, 0); 4257228561Snp if (rc != 0) 4258228561Snp return (rc); 4259228561Snp 4260228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4261228561Snp if (sb == NULL) 4262228561Snp return (ENOMEM); 4263228561Snp 4264228561Snp t4_tp_get_tcp_stats(sc, &v4, &v6); 4265228561Snp sbuf_printf(sb, 4266228561Snp " IP IPv6\n"); 4267228561Snp sbuf_printf(sb, "OutRsts: %20u %20u\n", 4268228561Snp v4.tcpOutRsts, v6.tcpOutRsts); 4269228561Snp sbuf_printf(sb, "InSegs: %20ju %20ju\n", 4270228561Snp v4.tcpInSegs, v6.tcpInSegs); 4271228561Snp sbuf_printf(sb, "OutSegs: %20ju %20ju\n", 4272228561Snp v4.tcpOutSegs, v6.tcpOutSegs); 4273228561Snp sbuf_printf(sb, "RetransSegs: %20ju %20ju", 4274228561Snp v4.tcpRetransSegs, v6.tcpRetransSegs); 4275228561Snp 4276228561Snp rc = sbuf_finish(sb); 4277228561Snp sbuf_delete(sb); 4278228561Snp 4279228561Snp return (rc); 4280228561Snp} 4281228561Snp 4282228561Snpstatic int 4283228561Snpsysctl_tids(SYSCTL_HANDLER_ARGS) 4284228561Snp{ 4285228561Snp struct adapter *sc = arg1; 4286228561Snp struct sbuf *sb; 4287228561Snp int rc; 4288228561Snp struct tid_info *t = &sc->tids; 4289228561Snp 4290228561Snp rc = sysctl_wire_old_buffer(req, 0); 4291228561Snp if (rc != 0) 4292228561Snp return (rc); 4293228561Snp 4294228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4295228561Snp if (sb == NULL) 4296228561Snp return (ENOMEM); 4297228561Snp 4298228561Snp if (t->natids) { 4299228561Snp sbuf_printf(sb, "ATID range: 0-%u, in use: %u\n", t->natids - 1, 4300228561Snp t->atids_in_use); 4301228561Snp } 4302228561Snp 4303228561Snp if (t->ntids) { 4304228561Snp if (t4_read_reg(sc, A_LE_DB_CONFIG) & F_HASHEN) { 4305228561Snp uint32_t b = t4_read_reg(sc, A_LE_DB_SERVER_INDEX) / 4; 4306228561Snp 4307228561Snp if (b) { 4308228561Snp sbuf_printf(sb, "TID range: 0-%u, %u-%u", b - 1, 4309228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 4310228561Snp t->ntids - 1); 4311228561Snp } else { 4312228561Snp sbuf_printf(sb, "TID range: %u-%u", 4313228561Snp t4_read_reg(sc, A_LE_DB_TID_HASHBASE) / 4, 4314228561Snp t->ntids - 1); 4315228561Snp } 4316228561Snp } else 4317228561Snp sbuf_printf(sb, "TID range: 0-%u", t->ntids - 1); 4318228561Snp sbuf_printf(sb, ", in use: %u\n", 4319228561Snp atomic_load_acq_int(&t->tids_in_use)); 4320228561Snp } 4321228561Snp 4322228561Snp if (t->nstids) { 4323228561Snp sbuf_printf(sb, "STID range: %u-%u, in use: %u\n", t->stid_base, 4324228561Snp t->stid_base + t->nstids - 1, t->stids_in_use); 4325228561Snp } 4326228561Snp 4327228561Snp if (t->nftids) { 4328228561Snp sbuf_printf(sb, "FTID range: %u-%u\n", t->ftid_base, 4329228561Snp t->ftid_base + t->nftids - 1); 4330228561Snp } 4331228561Snp 4332228561Snp sbuf_printf(sb, "HW TID usage: %u IP users, %u IPv6 users", 4333228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV4), 4334228561Snp t4_read_reg(sc, A_LE_DB_ACT_CNT_IPV6)); 4335228561Snp 4336228561Snp rc = sbuf_finish(sb); 4337228561Snp sbuf_delete(sb); 4338228561Snp 4339228561Snp return (rc); 4340228561Snp} 4341228561Snp 4342228561Snpstatic int 4343228561Snpsysctl_tp_err_stats(SYSCTL_HANDLER_ARGS) 4344228561Snp{ 4345228561Snp struct adapter *sc = arg1; 4346228561Snp struct sbuf *sb; 4347228561Snp int rc; 4348228561Snp struct tp_err_stats stats; 4349228561Snp 4350228561Snp rc = sysctl_wire_old_buffer(req, 0); 4351228561Snp if (rc != 0) 4352228561Snp return (rc); 4353228561Snp 4354228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4355228561Snp if (sb == NULL) 4356228561Snp return (ENOMEM); 4357228561Snp 4358228561Snp t4_tp_get_err_stats(sc, &stats); 4359228561Snp 4360228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 4361228561Snp "channel 3\n"); 4362228561Snp sbuf_printf(sb, "macInErrs: %10u %10u %10u %10u\n", 4363228561Snp stats.macInErrs[0], stats.macInErrs[1], stats.macInErrs[2], 4364228561Snp stats.macInErrs[3]); 4365228561Snp sbuf_printf(sb, "hdrInErrs: %10u %10u %10u %10u\n", 4366228561Snp stats.hdrInErrs[0], stats.hdrInErrs[1], stats.hdrInErrs[2], 4367228561Snp stats.hdrInErrs[3]); 4368228561Snp sbuf_printf(sb, "tcpInErrs: %10u %10u %10u %10u\n", 4369228561Snp stats.tcpInErrs[0], stats.tcpInErrs[1], stats.tcpInErrs[2], 4370228561Snp stats.tcpInErrs[3]); 4371228561Snp sbuf_printf(sb, "tcp6InErrs: %10u %10u %10u %10u\n", 4372228561Snp stats.tcp6InErrs[0], stats.tcp6InErrs[1], stats.tcp6InErrs[2], 4373228561Snp stats.tcp6InErrs[3]); 4374228561Snp sbuf_printf(sb, "tnlCongDrops: %10u %10u %10u %10u\n", 4375228561Snp stats.tnlCongDrops[0], stats.tnlCongDrops[1], stats.tnlCongDrops[2], 4376228561Snp stats.tnlCongDrops[3]); 4377228561Snp sbuf_printf(sb, "tnlTxDrops: %10u %10u %10u %10u\n", 4378228561Snp stats.tnlTxDrops[0], stats.tnlTxDrops[1], stats.tnlTxDrops[2], 4379228561Snp stats.tnlTxDrops[3]); 4380228561Snp sbuf_printf(sb, "ofldVlanDrops: %10u %10u %10u %10u\n", 4381228561Snp stats.ofldVlanDrops[0], stats.ofldVlanDrops[1], 4382228561Snp stats.ofldVlanDrops[2], stats.ofldVlanDrops[3]); 4383228561Snp sbuf_printf(sb, "ofldChanDrops: %10u %10u %10u %10u\n\n", 4384228561Snp stats.ofldChanDrops[0], stats.ofldChanDrops[1], 4385228561Snp stats.ofldChanDrops[2], stats.ofldChanDrops[3]); 4386228561Snp sbuf_printf(sb, "ofldNoNeigh: %u\nofldCongDefer: %u", 4387228561Snp stats.ofldNoNeigh, stats.ofldCongDefer); 4388228561Snp 4389228561Snp rc = sbuf_finish(sb); 4390228561Snp sbuf_delete(sb); 4391228561Snp 4392228561Snp return (rc); 4393228561Snp} 4394228561Snp 4395228561Snpstatic int 4396228561Snpsysctl_tx_rate(SYSCTL_HANDLER_ARGS) 4397228561Snp{ 4398228561Snp struct adapter *sc = arg1; 4399228561Snp struct sbuf *sb; 4400228561Snp int rc; 4401228561Snp u64 nrate[NCHAN], orate[NCHAN]; 4402228561Snp 4403228561Snp rc = sysctl_wire_old_buffer(req, 0); 4404228561Snp if (rc != 0) 4405228561Snp return (rc); 4406228561Snp 4407228561Snp sb = sbuf_new_for_sysctl(NULL, NULL, 256, req); 4408228561Snp if (sb == NULL) 4409228561Snp return (ENOMEM); 4410228561Snp 4411228561Snp t4_get_chan_txrate(sc, nrate, orate); 4412228561Snp sbuf_printf(sb, " channel 0 channel 1 channel 2 " 4413228561Snp "channel 3\n"); 4414228561Snp sbuf_printf(sb, "NIC B/s: %10ju %10ju %10ju %10ju\n", 4415228561Snp nrate[0], nrate[1], nrate[2], nrate[3]); 4416228561Snp sbuf_printf(sb, "Offload B/s: %10ju %10ju %10ju %10ju", 4417228561Snp orate[0], orate[1], orate[2], orate[3]); 4418228561Snp 4419228561Snp rc = sbuf_finish(sb); 4420228561Snp sbuf_delete(sb); 4421228561Snp 4422228561Snp return (rc); 4423228561Snp} 4424231115Snp#endif 4425228561Snp 4426219286Snpstatic inline void 4427219286Snptxq_start(struct ifnet *ifp, struct sge_txq *txq) 4428219286Snp{ 4429219286Snp struct buf_ring *br; 4430219286Snp struct mbuf *m; 4431219286Snp 4432219286Snp TXQ_LOCK_ASSERT_OWNED(txq); 4433219286Snp 4434220873Snp br = txq->br; 4435219286Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 4436219286Snp if (m) 4437219286Snp t4_eth_tx(ifp, txq, m); 4438219286Snp} 4439219286Snp 4440219286Snpvoid 4441228561Snpt4_tx_callout(void *arg) 4442219286Snp{ 4443228561Snp struct sge_eq *eq = arg; 4444228561Snp struct adapter *sc; 4445219286Snp 4446228561Snp if (EQ_TRYLOCK(eq) == 0) 4447228561Snp goto reschedule; 4448228561Snp 4449228561Snp if (eq->flags & EQ_STALLED && !can_resume_tx(eq)) { 4450228561Snp EQ_UNLOCK(eq); 4451228561Snpreschedule: 4452228561Snp if (__predict_true(!(eq->flags && EQ_DOOMED))) 4453228561Snp callout_schedule(&eq->tx_callout, 1); 4454228561Snp return; 4455228561Snp } 4456228561Snp 4457228561Snp EQ_LOCK_ASSERT_OWNED(eq); 4458228561Snp 4459228561Snp if (__predict_true((eq->flags & EQ_DOOMED) == 0)) { 4460228561Snp 4461228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 4462228561Snp struct sge_txq *txq = arg; 4463228561Snp struct port_info *pi = txq->ifp->if_softc; 4464228561Snp 4465228561Snp sc = pi->adapter; 4466228561Snp } else { 4467228561Snp struct sge_wrq *wrq = arg; 4468228561Snp 4469228561Snp sc = wrq->adapter; 4470228561Snp } 4471228561Snp 4472228561Snp taskqueue_enqueue(sc->tq[eq->tx_chan], &eq->tx_task); 4473228561Snp } 4474228561Snp 4475228561Snp EQ_UNLOCK(eq); 4476228561Snp} 4477228561Snp 4478228561Snpvoid 4479228561Snpt4_tx_task(void *arg, int count) 4480228561Snp{ 4481228561Snp struct sge_eq *eq = arg; 4482228561Snp 4483228561Snp EQ_LOCK(eq); 4484228561Snp if ((eq->flags & EQ_TYPEMASK) == EQ_ETH) { 4485228561Snp struct sge_txq *txq = arg; 4486220649Snp txq_start(txq->ifp, txq); 4487228561Snp } else { 4488228561Snp struct sge_wrq *wrq = arg; 4489228561Snp t4_wrq_tx_locked(wrq->adapter, wrq, NULL); 4490228561Snp } 4491228561Snp EQ_UNLOCK(eq); 4492219286Snp} 4493219286Snp 4494221474Snpstatic uint32_t 4495221474Snpfconf_to_mode(uint32_t fconf) 4496221474Snp{ 4497221474Snp uint32_t mode; 4498221474Snp 4499221474Snp mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR | 4500221474Snp T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT; 4501221474Snp 4502221474Snp if (fconf & F_FRAGMENTATION) 4503221474Snp mode |= T4_FILTER_IP_FRAGMENT; 4504221474Snp 4505221474Snp if (fconf & F_MPSHITTYPE) 4506221474Snp mode |= T4_FILTER_MPS_HIT_TYPE; 4507221474Snp 4508221474Snp if (fconf & F_MACMATCH) 4509221474Snp mode |= T4_FILTER_MAC_IDX; 4510221474Snp 4511221474Snp if (fconf & F_ETHERTYPE) 4512221474Snp mode |= T4_FILTER_ETH_TYPE; 4513221474Snp 4514221474Snp if (fconf & F_PROTOCOL) 4515221474Snp mode |= T4_FILTER_IP_PROTO; 4516221474Snp 4517221474Snp if (fconf & F_TOS) 4518221474Snp mode |= T4_FILTER_IP_TOS; 4519221474Snp 4520221474Snp if (fconf & F_VLAN) 4521228561Snp mode |= T4_FILTER_VLAN; 4522221474Snp 4523221474Snp if (fconf & F_VNIC_ID) 4524228561Snp mode |= T4_FILTER_VNIC; 4525221474Snp 4526221474Snp if (fconf & F_PORT) 4527221474Snp mode |= T4_FILTER_PORT; 4528221474Snp 4529221474Snp if (fconf & F_FCOE) 4530221474Snp mode |= T4_FILTER_FCoE; 4531221474Snp 4532221474Snp return (mode); 4533221474Snp} 4534221474Snp 4535221474Snpstatic uint32_t 4536221474Snpmode_to_fconf(uint32_t mode) 4537221474Snp{ 4538221474Snp uint32_t fconf = 0; 4539221474Snp 4540221474Snp if (mode & T4_FILTER_IP_FRAGMENT) 4541221474Snp fconf |= F_FRAGMENTATION; 4542221474Snp 4543221474Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 4544221474Snp fconf |= F_MPSHITTYPE; 4545221474Snp 4546221474Snp if (mode & T4_FILTER_MAC_IDX) 4547221474Snp fconf |= F_MACMATCH; 4548221474Snp 4549221474Snp if (mode & T4_FILTER_ETH_TYPE) 4550221474Snp fconf |= F_ETHERTYPE; 4551221474Snp 4552221474Snp if (mode & T4_FILTER_IP_PROTO) 4553221474Snp fconf |= F_PROTOCOL; 4554221474Snp 4555221474Snp if (mode & T4_FILTER_IP_TOS) 4556221474Snp fconf |= F_TOS; 4557221474Snp 4558228561Snp if (mode & T4_FILTER_VLAN) 4559221474Snp fconf |= F_VLAN; 4560221474Snp 4561228561Snp if (mode & T4_FILTER_VNIC) 4562221474Snp fconf |= F_VNIC_ID; 4563221474Snp 4564221474Snp if (mode & T4_FILTER_PORT) 4565221474Snp fconf |= F_PORT; 4566221474Snp 4567221474Snp if (mode & T4_FILTER_FCoE) 4568221474Snp fconf |= F_FCOE; 4569221474Snp 4570221474Snp return (fconf); 4571221474Snp} 4572221474Snp 4573221474Snpstatic uint32_t 4574221474Snpfspec_to_fconf(struct t4_filter_specification *fs) 4575221474Snp{ 4576221474Snp uint32_t fconf = 0; 4577221474Snp 4578221474Snp if (fs->val.frag || fs->mask.frag) 4579221474Snp fconf |= F_FRAGMENTATION; 4580221474Snp 4581221474Snp if (fs->val.matchtype || fs->mask.matchtype) 4582221474Snp fconf |= F_MPSHITTYPE; 4583221474Snp 4584221474Snp if (fs->val.macidx || fs->mask.macidx) 4585221474Snp fconf |= F_MACMATCH; 4586221474Snp 4587221474Snp if (fs->val.ethtype || fs->mask.ethtype) 4588221474Snp fconf |= F_ETHERTYPE; 4589221474Snp 4590221474Snp if (fs->val.proto || fs->mask.proto) 4591221474Snp fconf |= F_PROTOCOL; 4592221474Snp 4593221474Snp if (fs->val.tos || fs->mask.tos) 4594221474Snp fconf |= F_TOS; 4595221474Snp 4596228561Snp if (fs->val.vlan_vld || fs->mask.vlan_vld) 4597221474Snp fconf |= F_VLAN; 4598221474Snp 4599228561Snp if (fs->val.vnic_vld || fs->mask.vnic_vld) 4600221474Snp fconf |= F_VNIC_ID; 4601221474Snp 4602221474Snp if (fs->val.iport || fs->mask.iport) 4603221474Snp fconf |= F_PORT; 4604221474Snp 4605221474Snp if (fs->val.fcoe || fs->mask.fcoe) 4606221474Snp fconf |= F_FCOE; 4607221474Snp 4608221474Snp return (fconf); 4609221474Snp} 4610221474Snp 4611221474Snpstatic int 4612221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode) 4613221474Snp{ 4614221474Snp uint32_t fconf; 4615221474Snp 4616221474Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1, 4617221474Snp A_TP_VLAN_PRI_MAP); 4618221474Snp 4619228561Snp if (sc->filter_mode != fconf) { 4620228561Snp log(LOG_WARNING, "%s: cached filter mode out of sync %x %x.\n", 4621228561Snp device_get_nameunit(sc->dev), sc->filter_mode, fconf); 4622228561Snp sc->filter_mode = fconf; 4623228561Snp } 4624221474Snp 4625228561Snp *mode = fconf_to_mode(sc->filter_mode); 4626228561Snp 4627221474Snp return (0); 4628221474Snp} 4629221474Snp 4630221474Snpstatic int 4631221474Snpset_filter_mode(struct adapter *sc, uint32_t mode) 4632221474Snp{ 4633221474Snp uint32_t fconf; 4634221474Snp int rc; 4635221474Snp 4636221474Snp fconf = mode_to_fconf(mode); 4637221474Snp 4638221474Snp ADAPTER_LOCK(sc); 4639221474Snp if (IS_BUSY(sc)) { 4640221474Snp rc = EAGAIN; 4641221474Snp goto done; 4642221474Snp } 4643221474Snp 4644221474Snp if (sc->tids.ftids_in_use > 0) { 4645221474Snp rc = EBUSY; 4646221474Snp goto done; 4647221474Snp } 4648221474Snp 4649237263Snp#ifdef TCP_OFFLOAD 4650228561Snp if (sc->offload_map) { 4651228561Snp rc = EBUSY; 4652228561Snp goto done; 4653228561Snp } 4654228561Snp#endif 4655228561Snp 4656228561Snp#ifdef notyet 4657221474Snp rc = -t4_set_filter_mode(sc, fconf); 4658228561Snp if (rc == 0) 4659228561Snp sc->filter_mode = fconf; 4660228561Snp#else 4661228561Snp rc = ENOTSUP; 4662228561Snp#endif 4663228561Snp 4664221474Snpdone: 4665221474Snp ADAPTER_UNLOCK(sc); 4666221474Snp return (rc); 4667221474Snp} 4668221474Snp 4669222552Snpstatic inline uint64_t 4670222552Snpget_filter_hits(struct adapter *sc, uint32_t fid) 4671222552Snp{ 4672222552Snp uint32_t tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 4673222552Snp uint64_t hits; 4674222552Snp 4675222552Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0), 4676222552Snp tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE); 4677222552Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0)); 4678222552Snp hits = t4_read_reg64(sc, MEMWIN0_BASE + 16); 4679222552Snp 4680222552Snp return (be64toh(hits)); 4681222552Snp} 4682222552Snp 4683221474Snpstatic int 4684221474Snpget_filter(struct adapter *sc, struct t4_filter *t) 4685221474Snp{ 4686221474Snp int i, nfilters = sc->tids.nftids; 4687221474Snp struct filter_entry *f; 4688221474Snp 4689221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4690221474Snp 4691221474Snp if (IS_BUSY(sc)) 4692221474Snp return (EAGAIN); 4693221474Snp 4694221474Snp if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL || 4695221474Snp t->idx >= nfilters) { 4696221474Snp t->idx = 0xffffffff; 4697221474Snp return (0); 4698221474Snp } 4699221474Snp 4700221474Snp f = &sc->tids.ftid_tab[t->idx]; 4701221474Snp for (i = t->idx; i < nfilters; i++, f++) { 4702221474Snp if (f->valid) { 4703221474Snp t->idx = i; 4704222509Snp t->l2tidx = f->l2t ? f->l2t->idx : 0; 4705222509Snp t->smtidx = f->smtidx; 4706222552Snp if (f->fs.hitcnts) 4707222552Snp t->hits = get_filter_hits(sc, t->idx); 4708222552Snp else 4709222552Snp t->hits = UINT64_MAX; 4710221474Snp t->fs = f->fs; 4711221474Snp 4712221474Snp return (0); 4713221474Snp } 4714221474Snp } 4715221474Snp 4716221474Snp t->idx = 0xffffffff; 4717221474Snp return (0); 4718221474Snp} 4719221474Snp 4720221474Snpstatic int 4721221474Snpset_filter(struct adapter *sc, struct t4_filter *t) 4722221474Snp{ 4723221474Snp unsigned int nfilters, nports; 4724221474Snp struct filter_entry *f; 4725221474Snp int i; 4726221474Snp 4727221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4728221474Snp 4729221474Snp nfilters = sc->tids.nftids; 4730221474Snp nports = sc->params.nports; 4731221474Snp 4732221474Snp if (nfilters == 0) 4733221474Snp return (ENOTSUP); 4734221474Snp 4735221474Snp if (!(sc->flags & FULL_INIT_DONE)) 4736221474Snp return (EAGAIN); 4737221474Snp 4738221474Snp if (t->idx >= nfilters) 4739221474Snp return (EINVAL); 4740221474Snp 4741221474Snp /* Validate against the global filter mode */ 4742228561Snp if ((sc->filter_mode | fspec_to_fconf(&t->fs)) != sc->filter_mode) 4743221474Snp return (E2BIG); 4744221474Snp 4745221474Snp if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) 4746221474Snp return (EINVAL); 4747221474Snp 4748221474Snp if (t->fs.val.iport >= nports) 4749221474Snp return (EINVAL); 4750221474Snp 4751221474Snp /* Can't specify an iq if not steering to it */ 4752221474Snp if (!t->fs.dirsteer && t->fs.iq) 4753221474Snp return (EINVAL); 4754221474Snp 4755221474Snp /* IPv6 filter idx must be 4 aligned */ 4756221474Snp if (t->fs.type == 1 && 4757221474Snp ((t->idx & 0x3) || t->idx + 4 >= nfilters)) 4758221474Snp return (EINVAL); 4759221474Snp 4760221474Snp if (sc->tids.ftid_tab == NULL) { 4761221474Snp KASSERT(sc->tids.ftids_in_use == 0, 4762221474Snp ("%s: no memory allocated but filters_in_use > 0", 4763221474Snp __func__)); 4764221474Snp 4765221474Snp sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) * 4766221474Snp nfilters, M_CXGBE, M_NOWAIT | M_ZERO); 4767221474Snp if (sc->tids.ftid_tab == NULL) 4768221474Snp return (ENOMEM); 4769221474Snp } 4770221474Snp 4771221474Snp for (i = 0; i < 4; i++) { 4772221474Snp f = &sc->tids.ftid_tab[t->idx + i]; 4773221474Snp 4774221474Snp if (f->pending || f->valid) 4775221474Snp return (EBUSY); 4776221474Snp if (f->locked) 4777221474Snp return (EPERM); 4778221474Snp 4779221474Snp if (t->fs.type == 0) 4780221474Snp break; 4781221474Snp } 4782221474Snp 4783221474Snp f = &sc->tids.ftid_tab[t->idx]; 4784221474Snp f->fs = t->fs; 4785221474Snp 4786221474Snp return set_filter_wr(sc, t->idx); 4787221474Snp} 4788221474Snp 4789221474Snpstatic int 4790221474Snpdel_filter(struct adapter *sc, struct t4_filter *t) 4791221474Snp{ 4792221474Snp unsigned int nfilters; 4793221474Snp struct filter_entry *f; 4794221474Snp 4795221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4796221474Snp 4797221474Snp if (IS_BUSY(sc)) 4798221474Snp return (EAGAIN); 4799221474Snp 4800221474Snp nfilters = sc->tids.nftids; 4801221474Snp 4802221474Snp if (nfilters == 0) 4803221474Snp return (ENOTSUP); 4804221474Snp 4805221474Snp if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 || 4806221474Snp t->idx >= nfilters) 4807221474Snp return (EINVAL); 4808221474Snp 4809221474Snp if (!(sc->flags & FULL_INIT_DONE)) 4810221474Snp return (EAGAIN); 4811221474Snp 4812221474Snp f = &sc->tids.ftid_tab[t->idx]; 4813221474Snp 4814221474Snp if (f->pending) 4815221474Snp return (EBUSY); 4816221474Snp if (f->locked) 4817221474Snp return (EPERM); 4818221474Snp 4819221474Snp if (f->valid) { 4820221474Snp t->fs = f->fs; /* extra info for the caller */ 4821221474Snp return del_filter_wr(sc, t->idx); 4822221474Snp } 4823221474Snp 4824221474Snp return (0); 4825221474Snp} 4826221474Snp 4827221474Snpstatic void 4828222509Snpclear_filter(struct filter_entry *f) 4829221474Snp{ 4830222509Snp if (f->l2t) 4831222509Snp t4_l2t_release(f->l2t); 4832222509Snp 4833221474Snp bzero(f, sizeof (*f)); 4834221474Snp} 4835221474Snp 4836221474Snpstatic int 4837221474Snpset_filter_wr(struct adapter *sc, int fidx) 4838221474Snp{ 4839221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 4840237263Snp struct wrqe *wr; 4841221474Snp struct fw_filter_wr *fwr; 4842221474Snp unsigned int ftid; 4843221474Snp 4844221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4845221474Snp 4846222509Snp if (f->fs.newdmac || f->fs.newvlan) { 4847222509Snp /* This filter needs an L2T entry; allocate one. */ 4848222509Snp f->l2t = t4_l2t_alloc_switching(sc->l2t); 4849222509Snp if (f->l2t == NULL) 4850222509Snp return (EAGAIN); 4851222509Snp if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport, 4852222509Snp f->fs.dmac)) { 4853222509Snp t4_l2t_release(f->l2t); 4854222509Snp f->l2t = NULL; 4855222509Snp return (ENOMEM); 4856222509Snp } 4857222509Snp } 4858221474Snp 4859221474Snp ftid = sc->tids.ftid_base + fidx; 4860221474Snp 4861237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 4862237263Snp if (wr == NULL) 4863221474Snp return (ENOMEM); 4864221474Snp 4865237263Snp fwr = wrtod(wr); 4866221474Snp bzero(fwr, sizeof (*fwr)); 4867221474Snp 4868221474Snp fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR)); 4869221474Snp fwr->len16_pkd = htobe32(FW_LEN16(*fwr)); 4870221474Snp fwr->tid_to_iq = 4871221474Snp htobe32(V_FW_FILTER_WR_TID(ftid) | 4872221474Snp V_FW_FILTER_WR_RQTYPE(f->fs.type) | 4873221474Snp V_FW_FILTER_WR_NOREPLY(0) | 4874221474Snp V_FW_FILTER_WR_IQ(f->fs.iq)); 4875221474Snp fwr->del_filter_to_l2tix = 4876221474Snp htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) | 4877221474Snp V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) | 4878221474Snp V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) | 4879221474Snp V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) | 4880221474Snp V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) | 4881221474Snp V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) | 4882221474Snp V_FW_FILTER_WR_DMAC(f->fs.newdmac) | 4883221474Snp V_FW_FILTER_WR_SMAC(f->fs.newsmac) | 4884221474Snp V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT || 4885221474Snp f->fs.newvlan == VLAN_REWRITE) | 4886221474Snp V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE || 4887221474Snp f->fs.newvlan == VLAN_REWRITE) | 4888221474Snp V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) | 4889221474Snp V_FW_FILTER_WR_TXCHAN(f->fs.eport) | 4890221474Snp V_FW_FILTER_WR_PRIO(f->fs.prio) | 4891222509Snp V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0)); 4892221474Snp fwr->ethtype = htobe16(f->fs.val.ethtype); 4893221474Snp fwr->ethtypem = htobe16(f->fs.mask.ethtype); 4894221474Snp fwr->frag_to_ovlan_vldm = 4895221474Snp (V_FW_FILTER_WR_FRAG(f->fs.val.frag) | 4896221474Snp V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) | 4897228561Snp V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.vlan_vld) | 4898228561Snp V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.vnic_vld) | 4899228561Snp V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.vlan_vld) | 4900228561Snp V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.vnic_vld)); 4901221474Snp fwr->smac_sel = 0; 4902221474Snp fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) | 4903228561Snp V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.fwq.abs_id)); 4904221474Snp fwr->maci_to_matchtypem = 4905221474Snp htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) | 4906221474Snp V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) | 4907221474Snp V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) | 4908221474Snp V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) | 4909221474Snp V_FW_FILTER_WR_PORT(f->fs.val.iport) | 4910221474Snp V_FW_FILTER_WR_PORTM(f->fs.mask.iport) | 4911221474Snp V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) | 4912221474Snp V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype)); 4913221474Snp fwr->ptcl = f->fs.val.proto; 4914221474Snp fwr->ptclm = f->fs.mask.proto; 4915221474Snp fwr->ttyp = f->fs.val.tos; 4916221474Snp fwr->ttypm = f->fs.mask.tos; 4917228561Snp fwr->ivlan = htobe16(f->fs.val.vlan); 4918228561Snp fwr->ivlanm = htobe16(f->fs.mask.vlan); 4919228561Snp fwr->ovlan = htobe16(f->fs.val.vnic); 4920228561Snp fwr->ovlanm = htobe16(f->fs.mask.vnic); 4921221474Snp bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip)); 4922221474Snp bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm)); 4923221474Snp bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip)); 4924221474Snp bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm)); 4925221474Snp fwr->lp = htobe16(f->fs.val.dport); 4926221474Snp fwr->lpm = htobe16(f->fs.mask.dport); 4927221474Snp fwr->fp = htobe16(f->fs.val.sport); 4928221474Snp fwr->fpm = htobe16(f->fs.mask.sport); 4929221474Snp if (f->fs.newsmac) 4930221474Snp bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma)); 4931221474Snp 4932221474Snp f->pending = 1; 4933221474Snp sc->tids.ftids_in_use++; 4934228561Snp 4935237263Snp t4_wrq_tx(sc, wr); 4936228561Snp return (0); 4937221474Snp} 4938221474Snp 4939221474Snpstatic int 4940221474Snpdel_filter_wr(struct adapter *sc, int fidx) 4941221474Snp{ 4942221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 4943237263Snp struct wrqe *wr; 4944221474Snp struct fw_filter_wr *fwr; 4945228561Snp unsigned int ftid; 4946221474Snp 4947221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 4948221474Snp 4949221474Snp ftid = sc->tids.ftid_base + fidx; 4950221474Snp 4951237263Snp wr = alloc_wrqe(sizeof(*fwr), &sc->sge.mgmtq); 4952237263Snp if (wr == NULL) 4953221474Snp return (ENOMEM); 4954237263Snp fwr = wrtod(wr); 4955221474Snp bzero(fwr, sizeof (*fwr)); 4956221474Snp 4957228561Snp t4_mk_filtdelwr(ftid, fwr, sc->sge.fwq.abs_id); 4958221474Snp 4959221474Snp f->pending = 1; 4960237263Snp t4_wrq_tx(sc, wr); 4961228561Snp return (0); 4962221474Snp} 4963221474Snp 4964228561Snpstatic int 4965228561Snpfilter_rpl(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m) 4966221474Snp{ 4967228561Snp struct adapter *sc = iq->adapter; 4968228561Snp const struct cpl_set_tcb_rpl *rpl = (const void *)(rss + 1); 4969221474Snp unsigned int idx = GET_TID(rpl); 4970221474Snp 4971228561Snp KASSERT(m == NULL, ("%s: payload with opcode %02x", __func__, 4972228561Snp rss->opcode)); 4973228561Snp 4974221474Snp if (idx >= sc->tids.ftid_base && 4975221474Snp (idx -= sc->tids.ftid_base) < sc->tids.nftids) { 4976221474Snp unsigned int rc = G_COOKIE(rpl->cookie); 4977221474Snp struct filter_entry *f = &sc->tids.ftid_tab[idx]; 4978221474Snp 4979231120Snp ADAPTER_LOCK(sc); 4980228561Snp if (rc == FW_FILTER_WR_FLT_ADDED) { 4981221474Snp f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff; 4982221474Snp f->pending = 0; /* asynchronous setup completed */ 4983221474Snp f->valid = 1; 4984231120Snp } else { 4985231120Snp if (rc != FW_FILTER_WR_FLT_DELETED) { 4986231120Snp /* Add or delete failed, display an error */ 4987231120Snp log(LOG_ERR, 4988231120Snp "filter %u setup failed with error %u\n", 4989231120Snp idx, rc); 4990231120Snp } 4991228561Snp 4992231120Snp clear_filter(f); 4993231120Snp sc->tids.ftids_in_use--; 4994221474Snp } 4995228561Snp ADAPTER_UNLOCK(sc); 4996221474Snp } 4997228561Snp 4998228561Snp return (0); 4999221474Snp} 5000221474Snp 5001222973Snpstatic int 5002222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt) 5003222973Snp{ 5004222973Snp int rc = EINVAL; 5005222973Snp 5006222973Snp if (cntxt->cid > M_CTXTQID) 5007222973Snp return (rc); 5008222973Snp 5009222973Snp if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS && 5010222973Snp cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM) 5011222973Snp return (rc); 5012222973Snp 5013222973Snp if (sc->flags & FW_OK) { 5014222973Snp ADAPTER_LOCK(sc); /* Avoid parallel t4_wr_mbox */ 5015222973Snp rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id, 5016222973Snp &cntxt->data[0]); 5017222973Snp ADAPTER_UNLOCK(sc); 5018222973Snp } 5019222973Snp 5020222973Snp if (rc != 0) { 5021222973Snp /* Read via firmware failed or wasn't even attempted */ 5022222973Snp 5023222973Snp rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id, 5024222973Snp &cntxt->data[0]); 5025222973Snp } 5026222973Snp 5027222973Snp return (rc); 5028222973Snp} 5029222973Snp 5030228561Snpstatic int 5031228561Snpread_card_mem(struct adapter *sc, struct t4_mem_range *mr) 5032228561Snp{ 5033228561Snp uint32_t base, size, lo, hi, win, off, remaining, i, n; 5034228561Snp uint32_t *buf, *b; 5035228561Snp int rc; 5036228561Snp 5037228561Snp /* reads are in multiples of 32 bits */ 5038228561Snp if (mr->addr & 3 || mr->len & 3 || mr->len == 0) 5039228561Snp return (EINVAL); 5040228561Snp 5041228561Snp /* 5042228561Snp * We don't want to deal with potential holes so we mandate that the 5043228561Snp * requested region must lie entirely within one of the 3 memories. 5044228561Snp */ 5045228561Snp lo = t4_read_reg(sc, A_MA_TARGET_MEM_ENABLE); 5046228561Snp if (lo & F_EDRAM0_ENABLE) { 5047228561Snp hi = t4_read_reg(sc, A_MA_EDRAM0_BAR); 5048228561Snp base = G_EDRAM0_BASE(hi) << 20; 5049228561Snp size = G_EDRAM0_SIZE(hi) << 20; 5050228561Snp if (size > 0 && 5051228561Snp mr->addr >= base && mr->addr < base + size && 5052228561Snp mr->addr + mr->len <= base + size) 5053228561Snp goto proceed; 5054228561Snp } 5055228561Snp if (lo & F_EDRAM1_ENABLE) { 5056228561Snp hi = t4_read_reg(sc, A_MA_EDRAM1_BAR); 5057228561Snp base = G_EDRAM1_BASE(hi) << 20; 5058228561Snp size = G_EDRAM1_SIZE(hi) << 20; 5059228561Snp if (size > 0 && 5060228561Snp mr->addr >= base && mr->addr < base + size && 5061228561Snp mr->addr + mr->len <= base + size) 5062228561Snp goto proceed; 5063228561Snp } 5064228561Snp if (lo & F_EXT_MEM_ENABLE) { 5065228561Snp hi = t4_read_reg(sc, A_MA_EXT_MEMORY_BAR); 5066228561Snp base = G_EXT_MEM_BASE(hi) << 20; 5067228561Snp size = G_EXT_MEM_SIZE(hi) << 20; 5068228561Snp if (size > 0 && 5069228561Snp mr->addr >= base && mr->addr < base + size && 5070228561Snp mr->addr + mr->len <= base + size) 5071228561Snp goto proceed; 5072228561Snp } 5073228561Snp return (ENXIO); 5074228561Snp 5075228561Snpproceed: 5076228561Snp buf = b = malloc(mr->len, M_CXGBE, M_WAITOK); 5077228561Snp 5078228561Snp /* 5079228561Snp * Position the PCIe window (we use memwin2) to the 16B aligned area 5080228561Snp * just at/before the requested region. 5081228561Snp */ 5082228561Snp win = mr->addr & ~0xf; 5083228561Snp off = mr->addr - win; /* offset of the requested region in the win */ 5084228561Snp remaining = mr->len; 5085228561Snp 5086228561Snp while (remaining) { 5087228561Snp t4_write_reg(sc, 5088228561Snp PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2), win); 5089228561Snp t4_read_reg(sc, 5090228561Snp PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 2)); 5091228561Snp 5092228561Snp /* number of bytes that we'll copy in the inner loop */ 5093228561Snp n = min(remaining, MEMWIN2_APERTURE - off); 5094228561Snp 5095228561Snp for (i = 0; i < n; i += 4, remaining -= 4) 5096228561Snp *b++ = t4_read_reg(sc, MEMWIN2_BASE + off + i); 5097228561Snp 5098228561Snp win += MEMWIN2_APERTURE; 5099228561Snp off = 0; 5100228561Snp } 5101228561Snp 5102228561Snp rc = copyout(buf, mr->data, mr->len); 5103228561Snp free(buf, M_CXGBE); 5104228561Snp 5105228561Snp return (rc); 5106228561Snp} 5107228561Snp 5108218792Snpint 5109218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap) 5110218792Snp{ 5111222102Snp int i; 5112218792Snp 5113222102Snp return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0); 5114218792Snp} 5115218792Snp 5116218792Snpint 5117218792Snpt4_os_pci_save_state(struct adapter *sc) 5118218792Snp{ 5119218792Snp device_t dev; 5120218792Snp struct pci_devinfo *dinfo; 5121218792Snp 5122218792Snp dev = sc->dev; 5123218792Snp dinfo = device_get_ivars(dev); 5124218792Snp 5125218792Snp pci_cfg_save(dev, dinfo, 0); 5126218792Snp return (0); 5127218792Snp} 5128218792Snp 5129218792Snpint 5130218792Snpt4_os_pci_restore_state(struct adapter *sc) 5131218792Snp{ 5132218792Snp device_t dev; 5133218792Snp struct pci_devinfo *dinfo; 5134218792Snp 5135218792Snp dev = sc->dev; 5136218792Snp dinfo = device_get_ivars(dev); 5137218792Snp 5138218792Snp pci_cfg_restore(dev, dinfo); 5139218792Snp return (0); 5140218792Snp} 5141219299Snp 5142218792Snpvoid 5143218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx) 5144218792Snp{ 5145218792Snp struct port_info *pi = sc->port[idx]; 5146218792Snp static const char *mod_str[] = { 5147220232Snp NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM" 5148218792Snp }; 5149218792Snp 5150218792Snp if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 5151218792Snp if_printf(pi->ifp, "transceiver unplugged.\n"); 5152220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) 5153220232Snp if_printf(pi->ifp, "unknown transceiver inserted.\n"); 5154220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) 5155220232Snp if_printf(pi->ifp, "unsupported transceiver inserted.\n"); 5156219299Snp else if (pi->mod_type > 0 && pi->mod_type < ARRAY_SIZE(mod_str)) { 5157218792Snp if_printf(pi->ifp, "%s transceiver inserted.\n", 5158218792Snp mod_str[pi->mod_type]); 5159219299Snp } else { 5160219299Snp if_printf(pi->ifp, "transceiver (type %d) inserted.\n", 5161219299Snp pi->mod_type); 5162219299Snp } 5163218792Snp} 5164218792Snp 5165218792Snpvoid 5166218792Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat) 5167218792Snp{ 5168218792Snp struct port_info *pi = sc->port[idx]; 5169218792Snp struct ifnet *ifp = pi->ifp; 5170218792Snp 5171218792Snp if (link_stat) { 5172218792Snp ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed); 5173218792Snp if_link_state_change(ifp, LINK_STATE_UP); 5174218792Snp } else 5175218792Snp if_link_state_change(ifp, LINK_STATE_DOWN); 5176218792Snp} 5177218792Snp 5178228561Snpvoid 5179228561Snpt4_iterate(void (*func)(struct adapter *, void *), void *arg) 5180228561Snp{ 5181228561Snp struct adapter *sc; 5182228561Snp 5183228561Snp mtx_lock(&t4_list_lock); 5184228561Snp SLIST_FOREACH(sc, &t4_list, link) { 5185228561Snp /* 5186228561Snp * func should not make any assumptions about what state sc is 5187228561Snp * in - the only guarantee is that sc->sc_lock is a valid lock. 5188228561Snp */ 5189228561Snp func(sc, arg); 5190228561Snp } 5191228561Snp mtx_unlock(&t4_list_lock); 5192228561Snp} 5193228561Snp 5194218792Snpstatic int 5195218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td) 5196218792Snp{ 5197218792Snp return (0); 5198218792Snp} 5199218792Snp 5200218792Snpstatic int 5201218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td) 5202218792Snp{ 5203218792Snp return (0); 5204218792Snp} 5205218792Snp 5206218792Snpstatic int 5207218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag, 5208218792Snp struct thread *td) 5209218792Snp{ 5210218792Snp int rc; 5211218792Snp struct adapter *sc = dev->si_drv1; 5212218792Snp 5213218792Snp rc = priv_check(td, PRIV_DRIVER); 5214218792Snp if (rc != 0) 5215218792Snp return (rc); 5216218792Snp 5217218792Snp switch (cmd) { 5218220410Snp case CHELSIO_T4_GETREG: { 5219220410Snp struct t4_reg *edata = (struct t4_reg *)data; 5220220410Snp 5221218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 5222218792Snp return (EFAULT); 5223220410Snp 5224220410Snp if (edata->size == 4) 5225220410Snp edata->val = t4_read_reg(sc, edata->addr); 5226220410Snp else if (edata->size == 8) 5227220410Snp edata->val = t4_read_reg64(sc, edata->addr); 5228220410Snp else 5229220410Snp return (EINVAL); 5230220410Snp 5231218792Snp break; 5232218792Snp } 5233220410Snp case CHELSIO_T4_SETREG: { 5234220410Snp struct t4_reg *edata = (struct t4_reg *)data; 5235220410Snp 5236218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 5237218792Snp return (EFAULT); 5238220410Snp 5239220410Snp if (edata->size == 4) { 5240220410Snp if (edata->val & 0xffffffff00000000) 5241220410Snp return (EINVAL); 5242220410Snp t4_write_reg(sc, edata->addr, (uint32_t) edata->val); 5243220410Snp } else if (edata->size == 8) 5244220410Snp t4_write_reg64(sc, edata->addr, edata->val); 5245220410Snp else 5246220410Snp return (EINVAL); 5247218792Snp break; 5248218792Snp } 5249218792Snp case CHELSIO_T4_REGDUMP: { 5250218792Snp struct t4_regdump *regs = (struct t4_regdump *)data; 5251218792Snp int reglen = T4_REGDUMP_SIZE; 5252218792Snp uint8_t *buf; 5253218792Snp 5254218792Snp if (regs->len < reglen) { 5255218792Snp regs->len = reglen; /* hint to the caller */ 5256218792Snp return (ENOBUFS); 5257218792Snp } 5258218792Snp 5259218792Snp regs->len = reglen; 5260218792Snp buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO); 5261218792Snp t4_get_regs(sc, regs, buf); 5262218792Snp rc = copyout(buf, regs->data, reglen); 5263218792Snp free(buf, M_CXGBE); 5264218792Snp break; 5265218792Snp } 5266221474Snp case CHELSIO_T4_GET_FILTER_MODE: 5267221474Snp rc = get_filter_mode(sc, (uint32_t *)data); 5268221474Snp break; 5269221474Snp case CHELSIO_T4_SET_FILTER_MODE: 5270221474Snp rc = set_filter_mode(sc, *(uint32_t *)data); 5271221474Snp break; 5272221474Snp case CHELSIO_T4_GET_FILTER: 5273221474Snp ADAPTER_LOCK(sc); 5274221474Snp rc = get_filter(sc, (struct t4_filter *)data); 5275221474Snp ADAPTER_UNLOCK(sc); 5276221474Snp break; 5277221474Snp case CHELSIO_T4_SET_FILTER: 5278221474Snp ADAPTER_LOCK(sc); 5279221474Snp rc = set_filter(sc, (struct t4_filter *)data); 5280221474Snp ADAPTER_UNLOCK(sc); 5281221474Snp break; 5282221474Snp case CHELSIO_T4_DEL_FILTER: 5283221474Snp ADAPTER_LOCK(sc); 5284221474Snp rc = del_filter(sc, (struct t4_filter *)data); 5285221474Snp ADAPTER_UNLOCK(sc); 5286221474Snp break; 5287222973Snp case CHELSIO_T4_GET_SGE_CONTEXT: 5288222973Snp rc = get_sge_context(sc, (struct t4_sge_context *)data); 5289222973Snp break; 5290228561Snp case CHELSIO_T4_LOAD_FW: { 5291228561Snp struct t4_data *fw = (struct t4_data *)data; 5292228561Snp uint8_t *fw_data; 5293228561Snp 5294228561Snp if (sc->flags & FULL_INIT_DONE) 5295228561Snp return (EBUSY); 5296228561Snp 5297228561Snp fw_data = malloc(fw->len, M_CXGBE, M_NOWAIT); 5298228561Snp if (fw_data == NULL) 5299228561Snp return (ENOMEM); 5300228561Snp 5301228561Snp rc = copyin(fw->data, fw_data, fw->len); 5302228561Snp if (rc == 0) 5303228561Snp rc = -t4_load_fw(sc, fw_data, fw->len); 5304228561Snp 5305228561Snp free(fw_data, M_CXGBE); 5306228561Snp break; 5307228561Snp } 5308228561Snp case CHELSIO_T4_GET_MEM: 5309228561Snp rc = read_card_mem(sc, (struct t4_mem_range *)data); 5310228561Snp break; 5311218792Snp default: 5312218792Snp rc = EINVAL; 5313218792Snp } 5314218792Snp 5315218792Snp return (rc); 5316218792Snp} 5317218792Snp 5318237263Snp#ifdef TCP_OFFLOAD 5319219392Snpstatic int 5320228561Snptoe_capability(struct port_info *pi, int enable) 5321228561Snp{ 5322228561Snp int rc; 5323228561Snp struct adapter *sc = pi->adapter; 5324228561Snp 5325228561Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 5326228561Snp 5327228561Snp if (!is_offload(sc)) 5328228561Snp return (ENODEV); 5329228561Snp 5330228561Snp if (enable) { 5331237263Snp if (!(sc->flags & FULL_INIT_DONE)) { 5332237263Snp log(LOG_WARNING, 5333237263Snp "You must enable a cxgbe interface first\n"); 5334237263Snp return (EAGAIN); 5335237263Snp } 5336237263Snp 5337228561Snp if (isset(&sc->offload_map, pi->port_id)) 5338228561Snp return (0); 5339228561Snp 5340237263Snp if (!(sc->flags & TOM_INIT_DONE)) { 5341237263Snp rc = t4_activate_uld(sc, ULD_TOM); 5342237263Snp if (rc == EAGAIN) { 5343237263Snp log(LOG_WARNING, 5344237263Snp "You must kldload t4_tom.ko before trying " 5345237263Snp "to enable TOE on a cxgbe interface.\n"); 5346237263Snp } 5347228561Snp if (rc != 0) 5348228561Snp return (rc); 5349237263Snp KASSERT(sc->tom_softc != NULL, 5350237263Snp ("%s: TOM activated but softc NULL", __func__)); 5351237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 5352237263Snp ("%s: TOM activated but flag not set", __func__)); 5353228561Snp } 5354228561Snp 5355228561Snp setbit(&sc->offload_map, pi->port_id); 5356228561Snp } else { 5357228561Snp if (!isset(&sc->offload_map, pi->port_id)) 5358228561Snp return (0); 5359228561Snp 5360237263Snp KASSERT(sc->flags & TOM_INIT_DONE, 5361237263Snp ("%s: TOM never initialized?", __func__)); 5362228561Snp clrbit(&sc->offload_map, pi->port_id); 5363228561Snp } 5364228561Snp 5365228561Snp return (0); 5366228561Snp} 5367228561Snp 5368228561Snp/* 5369228561Snp * Add an upper layer driver to the global list. 5370228561Snp */ 5371228561Snpint 5372228561Snpt4_register_uld(struct uld_info *ui) 5373228561Snp{ 5374228561Snp int rc = 0; 5375228561Snp struct uld_info *u; 5376228561Snp 5377228561Snp mtx_lock(&t4_uld_list_lock); 5378228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 5379228561Snp if (u->uld_id == ui->uld_id) { 5380228561Snp rc = EEXIST; 5381228561Snp goto done; 5382228561Snp } 5383228561Snp } 5384228561Snp 5385228561Snp SLIST_INSERT_HEAD(&t4_uld_list, ui, link); 5386228561Snp ui->refcount = 0; 5387228561Snpdone: 5388228561Snp mtx_unlock(&t4_uld_list_lock); 5389228561Snp return (rc); 5390228561Snp} 5391228561Snp 5392228561Snpint 5393228561Snpt4_unregister_uld(struct uld_info *ui) 5394228561Snp{ 5395228561Snp int rc = EINVAL; 5396228561Snp struct uld_info *u; 5397228561Snp 5398228561Snp mtx_lock(&t4_uld_list_lock); 5399228561Snp 5400228561Snp SLIST_FOREACH(u, &t4_uld_list, link) { 5401228561Snp if (u == ui) { 5402228561Snp if (ui->refcount > 0) { 5403228561Snp rc = EBUSY; 5404228561Snp goto done; 5405228561Snp } 5406228561Snp 5407228561Snp SLIST_REMOVE(&t4_uld_list, ui, uld_info, link); 5408228561Snp rc = 0; 5409228561Snp goto done; 5410228561Snp } 5411228561Snp } 5412228561Snpdone: 5413228561Snp mtx_unlock(&t4_uld_list_lock); 5414228561Snp return (rc); 5415228561Snp} 5416228561Snp 5417237263Snpint 5418237263Snpt4_activate_uld(struct adapter *sc, int id) 5419228561Snp{ 5420228561Snp int rc = EAGAIN; 5421228561Snp struct uld_info *ui; 5422228561Snp 5423228561Snp mtx_lock(&t4_uld_list_lock); 5424228561Snp 5425228561Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 5426228561Snp if (ui->uld_id == id) { 5427237263Snp rc = ui->activate(sc); 5428237263Snp if (rc == 0) 5429228561Snp ui->refcount++; 5430228561Snp goto done; 5431228561Snp } 5432228561Snp } 5433228561Snpdone: 5434228561Snp mtx_unlock(&t4_uld_list_lock); 5435228561Snp 5436228561Snp return (rc); 5437228561Snp} 5438228561Snp 5439237263Snpint 5440237263Snpt4_deactivate_uld(struct adapter *sc, int id) 5441228561Snp{ 5442237263Snp int rc = EINVAL; 5443237263Snp struct uld_info *ui; 5444228561Snp 5445228561Snp mtx_lock(&t4_uld_list_lock); 5446228561Snp 5447237263Snp SLIST_FOREACH(ui, &t4_uld_list, link) { 5448237263Snp if (ui->uld_id == id) { 5449237263Snp rc = ui->deactivate(sc); 5450237263Snp if (rc == 0) 5451237263Snp ui->refcount--; 5452237263Snp goto done; 5453237263Snp } 5454228561Snp } 5455228561Snpdone: 5456228561Snp mtx_unlock(&t4_uld_list_lock); 5457228561Snp 5458228561Snp return (rc); 5459228561Snp} 5460228561Snp#endif 5461228561Snp 5462228561Snp/* 5463228561Snp * Come up with reasonable defaults for some of the tunables, provided they're 5464228561Snp * not set by the user (in which case we'll use the values as is). 5465228561Snp */ 5466228561Snpstatic void 5467228561Snptweak_tunables(void) 5468228561Snp{ 5469228561Snp int nc = mp_ncpus; /* our snapshot of the number of CPUs */ 5470228561Snp 5471228561Snp if (t4_ntxq10g < 1) 5472228561Snp t4_ntxq10g = min(nc, NTXQ_10G); 5473228561Snp 5474228561Snp if (t4_ntxq1g < 1) 5475228561Snp t4_ntxq1g = min(nc, NTXQ_1G); 5476228561Snp 5477228561Snp if (t4_nrxq10g < 1) 5478228561Snp t4_nrxq10g = min(nc, NRXQ_10G); 5479228561Snp 5480228561Snp if (t4_nrxq1g < 1) 5481228561Snp t4_nrxq1g = min(nc, NRXQ_1G); 5482228561Snp 5483237263Snp#ifdef TCP_OFFLOAD 5484228561Snp if (t4_nofldtxq10g < 1) 5485228561Snp t4_nofldtxq10g = min(nc, NOFLDTXQ_10G); 5486228561Snp 5487228561Snp if (t4_nofldtxq1g < 1) 5488228561Snp t4_nofldtxq1g = min(nc, NOFLDTXQ_1G); 5489228561Snp 5490228561Snp if (t4_nofldrxq10g < 1) 5491228561Snp t4_nofldrxq10g = min(nc, NOFLDRXQ_10G); 5492228561Snp 5493228561Snp if (t4_nofldrxq1g < 1) 5494228561Snp t4_nofldrxq1g = min(nc, NOFLDRXQ_1G); 5495238028Snp 5496238028Snp if (t4_toecaps_allowed == -1) 5497238028Snp t4_toecaps_allowed = FW_CAPS_CONFIG_TOE; 5498238028Snp#else 5499238028Snp if (t4_toecaps_allowed == -1) 5500238028Snp t4_toecaps_allowed = 0; 5501228561Snp#endif 5502228561Snp 5503228561Snp if (t4_tmr_idx_10g < 0 || t4_tmr_idx_10g >= SGE_NTIMERS) 5504228561Snp t4_tmr_idx_10g = TMR_IDX_10G; 5505228561Snp 5506228561Snp if (t4_pktc_idx_10g < -1 || t4_pktc_idx_10g >= SGE_NCOUNTERS) 5507228561Snp t4_pktc_idx_10g = PKTC_IDX_10G; 5508228561Snp 5509228561Snp if (t4_tmr_idx_1g < 0 || t4_tmr_idx_1g >= SGE_NTIMERS) 5510228561Snp t4_tmr_idx_1g = TMR_IDX_1G; 5511228561Snp 5512228561Snp if (t4_pktc_idx_1g < -1 || t4_pktc_idx_1g >= SGE_NCOUNTERS) 5513228561Snp t4_pktc_idx_1g = PKTC_IDX_1G; 5514228561Snp 5515228561Snp if (t4_qsize_txq < 128) 5516228561Snp t4_qsize_txq = 128; 5517228561Snp 5518228561Snp if (t4_qsize_rxq < 128) 5519228561Snp t4_qsize_rxq = 128; 5520228561Snp while (t4_qsize_rxq & 7) 5521228561Snp t4_qsize_rxq++; 5522228561Snp 5523228561Snp t4_intr_types &= INTR_MSIX | INTR_MSI | INTR_INTX; 5524228561Snp} 5525228561Snp 5526228561Snpstatic int 5527219392Snpt4_mod_event(module_t mod, int cmd, void *arg) 5528219392Snp{ 5529228561Snp int rc = 0; 5530219392Snp 5531228561Snp switch (cmd) { 5532228561Snp case MOD_LOAD: 5533219392Snp t4_sge_modload(); 5534228561Snp mtx_init(&t4_list_lock, "T4 adapters", 0, MTX_DEF); 5535228561Snp SLIST_INIT(&t4_list); 5536237263Snp#ifdef TCP_OFFLOAD 5537228561Snp mtx_init(&t4_uld_list_lock, "T4 ULDs", 0, MTX_DEF); 5538228561Snp SLIST_INIT(&t4_uld_list); 5539228561Snp#endif 5540228561Snp tweak_tunables(); 5541228561Snp break; 5542219392Snp 5543228561Snp case MOD_UNLOAD: 5544237263Snp#ifdef TCP_OFFLOAD 5545228561Snp mtx_lock(&t4_uld_list_lock); 5546228561Snp if (!SLIST_EMPTY(&t4_uld_list)) { 5547228561Snp rc = EBUSY; 5548228561Snp mtx_unlock(&t4_uld_list_lock); 5549228561Snp break; 5550228561Snp } 5551228561Snp mtx_unlock(&t4_uld_list_lock); 5552228561Snp mtx_destroy(&t4_uld_list_lock); 5553228561Snp#endif 5554228561Snp mtx_lock(&t4_list_lock); 5555228561Snp if (!SLIST_EMPTY(&t4_list)) { 5556228561Snp rc = EBUSY; 5557228561Snp mtx_unlock(&t4_list_lock); 5558228561Snp break; 5559228561Snp } 5560228561Snp mtx_unlock(&t4_list_lock); 5561228561Snp mtx_destroy(&t4_list_lock); 5562228561Snp break; 5563228561Snp } 5564228561Snp 5565228561Snp return (rc); 5566219392Snp} 5567219392Snp 5568218792Snpstatic devclass_t t4_devclass; 5569218792Snpstatic devclass_t cxgbe_devclass; 5570218792Snp 5571219392SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, t4_mod_event, 0); 5572218792SnpMODULE_VERSION(t4nex, 1); 5573218792Snp 5574218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0); 5575218792SnpMODULE_VERSION(cxgbe, 1); 5576