t4_main.c revision 227843
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 227843 2011-11-22 21:28:20Z marius $"); 30218792Snp 31218792Snp#include "opt_inet.h" 32218792Snp 33218792Snp#include <sys/param.h> 34218792Snp#include <sys/conf.h> 35218792Snp#include <sys/priv.h> 36218792Snp#include <sys/kernel.h> 37218792Snp#include <sys/bus.h> 38218792Snp#include <sys/module.h> 39219286Snp#include <sys/malloc.h> 40219286Snp#include <sys/queue.h> 41219286Snp#include <sys/taskqueue.h> 42218792Snp#include <sys/pciio.h> 43218792Snp#include <dev/pci/pcireg.h> 44218792Snp#include <dev/pci/pcivar.h> 45218792Snp#include <dev/pci/pci_private.h> 46218792Snp#include <sys/firmware.h> 47219436Snp#include <sys/sbuf.h> 48218792Snp#include <sys/smp.h> 49218792Snp#include <sys/socket.h> 50218792Snp#include <sys/sockio.h> 51218792Snp#include <sys/sysctl.h> 52218792Snp#include <net/ethernet.h> 53218792Snp#include <net/if.h> 54218792Snp#include <net/if_types.h> 55218792Snp#include <net/if_dl.h> 56222003Snp#include <net/if_vlan_var.h> 57218792Snp 58218792Snp#include "common/t4_hw.h" 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 "common/t4fw_interface.h" 64218792Snp#include "t4_ioctl.h" 65222509Snp#include "t4_l2t.h" 66218792Snp 67218792Snp/* T4 bus driver interface */ 68218792Snpstatic int t4_probe(device_t); 69218792Snpstatic int t4_attach(device_t); 70218792Snpstatic int t4_detach(device_t); 71218792Snpstatic device_method_t t4_methods[] = { 72218792Snp DEVMETHOD(device_probe, t4_probe), 73218792Snp DEVMETHOD(device_attach, t4_attach), 74218792Snp DEVMETHOD(device_detach, t4_detach), 75218792Snp 76227843Smarius DEVMETHOD_END 77218792Snp}; 78218792Snpstatic driver_t t4_driver = { 79218792Snp "t4nex", 80218792Snp t4_methods, 81218792Snp sizeof(struct adapter) 82218792Snp}; 83218792Snp 84218792Snp 85218792Snp/* T4 port (cxgbe) interface */ 86218792Snpstatic int cxgbe_probe(device_t); 87218792Snpstatic int cxgbe_attach(device_t); 88218792Snpstatic int cxgbe_detach(device_t); 89218792Snpstatic device_method_t cxgbe_methods[] = { 90218792Snp DEVMETHOD(device_probe, cxgbe_probe), 91218792Snp DEVMETHOD(device_attach, cxgbe_attach), 92218792Snp DEVMETHOD(device_detach, cxgbe_detach), 93218792Snp { 0, 0 } 94218792Snp}; 95218792Snpstatic driver_t cxgbe_driver = { 96218792Snp "cxgbe", 97218792Snp cxgbe_methods, 98218792Snp sizeof(struct port_info) 99218792Snp}; 100218792Snp 101218792Snpstatic d_ioctl_t t4_ioctl; 102218792Snpstatic d_open_t t4_open; 103218792Snpstatic d_close_t t4_close; 104218792Snp 105218792Snpstatic struct cdevsw t4_cdevsw = { 106218792Snp .d_version = D_VERSION, 107218792Snp .d_flags = 0, 108218792Snp .d_open = t4_open, 109218792Snp .d_close = t4_close, 110218792Snp .d_ioctl = t4_ioctl, 111218792Snp .d_name = "t4nex", 112218792Snp}; 113218792Snp 114218792Snp/* ifnet + media interface */ 115218792Snpstatic void cxgbe_init(void *); 116218792Snpstatic int cxgbe_ioctl(struct ifnet *, unsigned long, caddr_t); 117218792Snpstatic void cxgbe_start(struct ifnet *); 118218792Snpstatic int cxgbe_transmit(struct ifnet *, struct mbuf *); 119218792Snpstatic void cxgbe_qflush(struct ifnet *); 120218792Snpstatic int cxgbe_media_change(struct ifnet *); 121218792Snpstatic void cxgbe_media_status(struct ifnet *, struct ifmediareq *); 122218792Snp 123218792SnpMALLOC_DEFINE(M_CXGBE, "cxgbe", "Chelsio T4 Ethernet driver and services"); 124218792Snp 125218792Snp/* 126218792Snp * Tunables. 127218792Snp */ 128227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, cxgbe, CTLFLAG_RD, 0, 129227309Sed "cxgbe driver parameters"); 130218792Snp 131218792Snpstatic int force_firmware_install = 0; 132218792SnpTUNABLE_INT("hw.cxgbe.force_firmware_install", &force_firmware_install); 133218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, force_firmware_install, CTLFLAG_RDTUN, 134218792Snp &force_firmware_install, 0, "install firmware on every attach."); 135218792Snp 136218792Snp/* 137218792Snp * Holdoff timer and packet counter values. 138218792Snp */ 139218792Snpstatic unsigned int intr_timer[SGE_NTIMERS] = {1, 5, 10, 50, 100, 200}; 140218792Snpstatic unsigned int intr_pktcount[SGE_NCOUNTERS] = {1, 8, 16, 32}; /* 63 max */ 141218792Snp 142218792Snp/* 143218792Snp * Max # of tx and rx queues to use for each 10G and 1G port. 144218792Snp */ 145218792Snpstatic unsigned int max_ntxq_10g = 8; 146218792SnpTUNABLE_INT("hw.cxgbe.max_ntxq_10G_port", &max_ntxq_10g); 147218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_ntxq_10G_port, CTLFLAG_RDTUN, 148218792Snp &max_ntxq_10g, 0, "maximum number of tx queues per 10G port."); 149218792Snp 150218792Snpstatic unsigned int max_nrxq_10g = 8; 151218792SnpTUNABLE_INT("hw.cxgbe.max_nrxq_10G_port", &max_nrxq_10g); 152218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_nrxq_10G_port, CTLFLAG_RDTUN, 153218792Snp &max_nrxq_10g, 0, "maximum number of rxq's (per 10G port)."); 154218792Snp 155218792Snpstatic unsigned int max_ntxq_1g = 2; 156218792SnpTUNABLE_INT("hw.cxgbe.max_ntxq_1G_port", &max_ntxq_1g); 157218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_ntxq_1G_port, CTLFLAG_RDTUN, 158218792Snp &max_ntxq_1g, 0, "maximum number of tx queues per 1G port."); 159218792Snp 160218792Snpstatic unsigned int max_nrxq_1g = 2; 161218792SnpTUNABLE_INT("hw.cxgbe.max_nrxq_1G_port", &max_nrxq_1g); 162218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_nrxq_1G_port, CTLFLAG_RDTUN, 163218792Snp &max_nrxq_1g, 0, "maximum number of rxq's (per 1G port)."); 164218792Snp 165218792Snp/* 166218792Snp * Holdoff parameters for 10G and 1G ports. 167218792Snp */ 168218792Snpstatic unsigned int tmr_idx_10g = 1; 169218792SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_10G", &tmr_idx_10g); 170218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_timer_idx_10G, CTLFLAG_RDTUN, 171218792Snp &tmr_idx_10g, 0, 172218792Snp "default timer index for interrupt holdoff (10G ports)."); 173218792Snp 174218792Snpstatic int pktc_idx_10g = 2; 175218792SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_10G", &pktc_idx_10g); 176218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_pktc_idx_10G, CTLFLAG_RDTUN, 177218792Snp &pktc_idx_10g, 0, 178218792Snp "default pkt counter index for interrupt holdoff (10G ports)."); 179218792Snp 180218792Snpstatic unsigned int tmr_idx_1g = 1; 181218792SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_1G", &tmr_idx_1g); 182218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_timer_idx_1G, CTLFLAG_RDTUN, 183218792Snp &tmr_idx_1g, 0, 184218792Snp "default timer index for interrupt holdoff (1G ports)."); 185218792Snp 186218792Snpstatic int pktc_idx_1g = 2; 187218792SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_1G", &pktc_idx_1g); 188218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_pktc_idx_1G, CTLFLAG_RDTUN, 189218792Snp &pktc_idx_1g, 0, 190218792Snp "default pkt counter index for interrupt holdoff (1G ports)."); 191218792Snp 192218792Snp/* 193218792Snp * Size (# of entries) of each tx and rx queue. 194218792Snp */ 195218792Snpstatic unsigned int qsize_txq = TX_EQ_QSIZE; 196218792SnpTUNABLE_INT("hw.cxgbe.qsize_txq", &qsize_txq); 197218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, qsize_txq, CTLFLAG_RDTUN, 198218792Snp &qsize_txq, 0, "default queue size of NIC tx queues."); 199218792Snp 200218792Snpstatic unsigned int qsize_rxq = RX_IQ_QSIZE; 201218792SnpTUNABLE_INT("hw.cxgbe.qsize_rxq", &qsize_rxq); 202218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, qsize_rxq, CTLFLAG_RDTUN, 203218792Snp &qsize_rxq, 0, "default queue size of NIC rx queues."); 204218792Snp 205218792Snp/* 206218792Snp * Interrupt types allowed. 207218792Snp */ 208219944Snpstatic int intr_types = INTR_MSIX | INTR_MSI | INTR_INTX; 209218792SnpTUNABLE_INT("hw.cxgbe.interrupt_types", &intr_types); 210218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, interrupt_types, CTLFLAG_RDTUN, &intr_types, 0, 211218792Snp "interrupt types allowed (bits 0, 1, 2 = INTx, MSI, MSI-X respectively)"); 212218792Snp 213218792Snp/* 214222510Snp * Force the driver to use the same set of interrupts for all ports. 215218792Snp */ 216222510Snpstatic int intr_shared = 0; 217222510SnpTUNABLE_INT("hw.cxgbe.interrupts_shared", &intr_shared); 218222510SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, interrupts_shared, CTLFLAG_RDTUN, 219222510Snp &intr_shared, 0, "interrupts shared between all ports"); 220218792Snp 221221474Snpstatic unsigned int filter_mode = HW_TPL_FR_MT_PR_IV_P_FC; 222221474SnpTUNABLE_INT("hw.cxgbe.filter_mode", &filter_mode); 223221474SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, filter_mode, CTLFLAG_RDTUN, 224221474Snp &filter_mode, 0, "default global filter mode."); 225221474Snp 226218792Snpstruct intrs_and_queues { 227219944Snp int intr_type; /* INTx, MSI, or MSI-X */ 228218792Snp int nirq; /* Number of vectors */ 229222510Snp int intr_shared; /* Interrupts shared between all ports */ 230218792Snp int ntxq10g; /* # of NIC txq's for each 10G port */ 231218792Snp int nrxq10g; /* # of NIC rxq's for each 10G port */ 232218792Snp int ntxq1g; /* # of NIC txq's for each 1G port */ 233218792Snp int nrxq1g; /* # of NIC rxq's for each 1G port */ 234218792Snp}; 235218792Snp 236221474Snpstruct filter_entry { 237221474Snp uint32_t valid:1; /* filter allocated and valid */ 238221474Snp uint32_t locked:1; /* filter is administratively locked */ 239221474Snp uint32_t pending:1; /* filter action is pending firmware reply */ 240221474Snp uint32_t smtidx:8; /* Source MAC Table index for smac */ 241222509Snp struct l2t_entry *l2t; /* Layer Two Table entry for dmac */ 242221474Snp 243221474Snp struct t4_filter_specification fs; 244221474Snp}; 245221474Snp 246218792Snpenum { 247218792Snp MEMWIN0_APERTURE = 2048, 248218792Snp MEMWIN0_BASE = 0x1b800, 249218792Snp MEMWIN1_APERTURE = 32768, 250218792Snp MEMWIN1_BASE = 0x28000, 251218792Snp MEMWIN2_APERTURE = 65536, 252218792Snp MEMWIN2_BASE = 0x30000, 253218792Snp}; 254218792Snp 255218792Snpenum { 256218792Snp XGMAC_MTU = (1 << 0), 257218792Snp XGMAC_PROMISC = (1 << 1), 258218792Snp XGMAC_ALLMULTI = (1 << 2), 259218792Snp XGMAC_VLANEX = (1 << 3), 260218792Snp XGMAC_UCADDR = (1 << 4), 261218792Snp XGMAC_MCADDRS = (1 << 5), 262218792Snp 263218792Snp XGMAC_ALL = 0xffff 264218792Snp}; 265218792Snp 266218792Snpstatic int map_bars(struct adapter *); 267218792Snpstatic void setup_memwin(struct adapter *); 268218792Snpstatic int cfg_itype_and_nqueues(struct adapter *, int, int, 269218792Snp struct intrs_and_queues *); 270218792Snpstatic int prep_firmware(struct adapter *); 271222551Snpstatic int get_devlog_params(struct adapter *, struct devlog_params *); 272218792Snpstatic int get_capabilities(struct adapter *, struct fw_caps_config_cmd *); 273218792Snpstatic int get_params(struct adapter *, struct fw_caps_config_cmd *); 274218792Snpstatic void t4_set_desc(struct adapter *); 275218792Snpstatic void build_medialist(struct port_info *); 276218792Snpstatic int update_mac_settings(struct port_info *, int); 277218792Snpstatic int cxgbe_init_locked(struct port_info *); 278218792Snpstatic int cxgbe_init_synchronized(struct port_info *); 279218792Snpstatic int cxgbe_uninit_locked(struct port_info *); 280218792Snpstatic int cxgbe_uninit_synchronized(struct port_info *); 281218792Snpstatic int first_port_up(struct adapter *); 282218792Snpstatic int last_port_down(struct adapter *); 283218792Snpstatic int t4_alloc_irq(struct adapter *, struct irq *, int rid, 284218792Snp iq_intr_handler_t *, void *, char *); 285218792Snpstatic int t4_free_irq(struct adapter *, struct irq *); 286218792Snpstatic void reg_block_dump(struct adapter *, uint8_t *, unsigned int, 287218792Snp unsigned int); 288218792Snpstatic void t4_get_regs(struct adapter *, struct t4_regdump *, uint8_t *); 289218792Snpstatic void cxgbe_tick(void *); 290218792Snpstatic int t4_sysctls(struct adapter *); 291218792Snpstatic int cxgbe_sysctls(struct port_info *); 292219436Snpstatic int sysctl_int_array(SYSCTL_HANDLER_ARGS); 293218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS); 294218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS); 295218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS); 296218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS); 297218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS); 298222551Snpstatic int sysctl_devlog(SYSCTL_HANDLER_ARGS); 299219286Snpstatic inline void txq_start(struct ifnet *, struct sge_txq *); 300221474Snpstatic uint32_t fconf_to_mode(uint32_t); 301221474Snpstatic uint32_t mode_to_fconf(uint32_t); 302221474Snpstatic uint32_t fspec_to_fconf(struct t4_filter_specification *); 303221474Snpstatic int get_filter_mode(struct adapter *, uint32_t *); 304221474Snpstatic int set_filter_mode(struct adapter *, uint32_t); 305222552Snpstatic inline uint64_t get_filter_hits(struct adapter *, uint32_t); 306221474Snpstatic int get_filter(struct adapter *, struct t4_filter *); 307221474Snpstatic int set_filter(struct adapter *, struct t4_filter *); 308221474Snpstatic int del_filter(struct adapter *, struct t4_filter *); 309222509Snpstatic void clear_filter(struct filter_entry *); 310221474Snpstatic int set_filter_wr(struct adapter *, int); 311221474Snpstatic int del_filter_wr(struct adapter *, int); 312221474Snpvoid filter_rpl(struct adapter *, const struct cpl_set_tcb_rpl *); 313222973Snpstatic int get_sge_context(struct adapter *, struct t4_sge_context *); 314219392Snpstatic int t4_mod_event(module_t, int, void *); 315218792Snp 316218792Snpstruct t4_pciids { 317218792Snp uint16_t device; 318218792Snp uint8_t mpf; 319218792Snp char *desc; 320218792Snp} t4_pciids[] = { 321218792Snp {0xa000, 0, "Chelsio Terminator 4 FPGA"}, 322218792Snp {0x4400, 4, "Chelsio T440-dbg"}, 323218792Snp {0x4401, 4, "Chelsio T420-CR"}, 324218792Snp {0x4402, 4, "Chelsio T422-CR"}, 325218792Snp {0x4403, 4, "Chelsio T440-CR"}, 326218792Snp {0x4404, 4, "Chelsio T420-BCH"}, 327218792Snp {0x4405, 4, "Chelsio T440-BCH"}, 328218792Snp {0x4406, 4, "Chelsio T440-CH"}, 329218792Snp {0x4407, 4, "Chelsio T420-SO"}, 330218792Snp {0x4408, 4, "Chelsio T420-CX"}, 331218792Snp {0x4409, 4, "Chelsio T420-BT"}, 332218792Snp {0x440a, 4, "Chelsio T404-BT"}, 333218792Snp}; 334218792Snp 335218792Snpstatic int 336218792Snpt4_probe(device_t dev) 337218792Snp{ 338218792Snp int i; 339218792Snp uint16_t v = pci_get_vendor(dev); 340218792Snp uint16_t d = pci_get_device(dev); 341218792Snp 342218792Snp if (v != PCI_VENDOR_ID_CHELSIO) 343218792Snp return (ENXIO); 344218792Snp 345218792Snp for (i = 0; i < ARRAY_SIZE(t4_pciids); i++) { 346218792Snp if (d == t4_pciids[i].device && 347218792Snp pci_get_function(dev) == t4_pciids[i].mpf) { 348218792Snp device_set_desc(dev, t4_pciids[i].desc); 349218792Snp return (BUS_PROBE_DEFAULT); 350218792Snp } 351218792Snp } 352218792Snp 353218792Snp return (ENXIO); 354218792Snp} 355218792Snp 356218792Snpstatic int 357218792Snpt4_attach(device_t dev) 358218792Snp{ 359218792Snp struct adapter *sc; 360218792Snp int rc = 0, i, n10g, n1g, rqidx, tqidx; 361218792Snp struct fw_caps_config_cmd caps; 362218792Snp uint32_t p, v; 363218792Snp struct intrs_and_queues iaq; 364218792Snp struct sge *s; 365218792Snp 366218792Snp sc = device_get_softc(dev); 367218792Snp sc->dev = dev; 368218792Snp sc->pf = pci_get_function(dev); 369218792Snp sc->mbox = sc->pf; 370218792Snp 371218792Snp pci_enable_busmaster(dev); 372222085Snp if (pci_find_cap(dev, PCIY_EXPRESS, &i) == 0) { 373222085Snp pci_set_max_read_req(dev, 4096); 374222085Snp v = pci_read_config(dev, i + PCIR_EXPRESS_DEVICE_CTL, 2); 375222085Snp v |= PCIM_EXP_CTL_RELAXED_ORD_ENABLE; 376222085Snp pci_write_config(dev, i + PCIR_EXPRESS_DEVICE_CTL, v, 2); 377222085Snp } 378222085Snp 379218792Snp snprintf(sc->lockname, sizeof(sc->lockname), "%s", 380218792Snp device_get_nameunit(dev)); 381218792Snp mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF); 382218792Snp 383218792Snp rc = map_bars(sc); 384218792Snp if (rc != 0) 385218792Snp goto done; /* error message displayed already */ 386218792Snp 387218792Snp memset(sc->chan_map, 0xff, sizeof(sc->chan_map)); 388218792Snp 389218792Snp /* Prepare the adapter for operation */ 390218792Snp rc = -t4_prep_adapter(sc); 391218792Snp if (rc != 0) { 392218792Snp device_printf(dev, "failed to prepare adapter: %d.\n", rc); 393218792Snp goto done; 394218792Snp } 395218792Snp 396218792Snp /* Do this really early */ 397218792Snp sc->cdev = make_dev(&t4_cdevsw, device_get_unit(dev), UID_ROOT, 398218792Snp GID_WHEEL, 0600, "%s", device_get_nameunit(dev)); 399218792Snp sc->cdev->si_drv1 = sc; 400218792Snp 401218792Snp /* Prepare the firmware for operation */ 402218792Snp rc = prep_firmware(sc); 403218792Snp if (rc != 0) 404218792Snp goto done; /* error message displayed already */ 405218792Snp 406222551Snp /* Read firmware devlog parameters */ 407222551Snp (void) get_devlog_params(sc, &sc->params.devlog); 408222551Snp 409218792Snp /* Get device capabilities and select which ones we'll use */ 410218792Snp rc = get_capabilities(sc, &caps); 411218792Snp if (rc != 0) { 412218792Snp device_printf(dev, 413218792Snp "failed to initialize adapter capabilities: %d.\n", rc); 414218792Snp goto done; 415218792Snp } 416218792Snp 417218792Snp /* Choose the global RSS mode. */ 418218792Snp rc = -t4_config_glbl_rss(sc, sc->mbox, 419218792Snp FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL, 420218792Snp F_FW_RSS_GLB_CONFIG_CMD_TNLMAPEN | 421220874Snp F_FW_RSS_GLB_CONFIG_CMD_HASHTOEPLITZ | 422218792Snp F_FW_RSS_GLB_CONFIG_CMD_TNLALLLKP); 423218792Snp if (rc != 0) { 424218792Snp device_printf(dev, 425218792Snp "failed to select global RSS mode: %d.\n", rc); 426218792Snp goto done; 427218792Snp } 428218792Snp 429218792Snp /* These are total (sum of all ports) limits for a bus driver */ 430218792Snp rc = -t4_cfg_pfvf(sc, sc->mbox, sc->pf, 0, 431221516Snp 128, /* max # of egress queues */ 432218792Snp 64, /* max # of egress Ethernet or control queues */ 433218792Snp 64, /* max # of ingress queues with fl/interrupt */ 434218792Snp 0, /* max # of ingress queues without interrupt */ 435218792Snp 0, /* PCIe traffic class */ 436218792Snp 4, /* max # of virtual interfaces */ 437218792Snp M_FW_PFVF_CMD_CMASK, M_FW_PFVF_CMD_PMASK, 16, 438218792Snp FW_CMD_CAP_PF, FW_CMD_CAP_PF); 439218792Snp if (rc != 0) { 440218792Snp device_printf(dev, 441218792Snp "failed to configure pf/vf resources: %d.\n", rc); 442218792Snp goto done; 443218792Snp } 444218792Snp 445218792Snp /* Need this before sge_init */ 446218792Snp for (i = 0; i < SGE_NTIMERS; i++) 447218792Snp sc->sge.timer_val[i] = min(intr_timer[i], 200U); 448218792Snp for (i = 0; i < SGE_NCOUNTERS; i++) 449218792Snp sc->sge.counter_val[i] = min(intr_pktcount[i], M_THRESHOLD_0); 450218792Snp 451218792Snp /* Also need the cooked value of cclk before sge_init */ 452218792Snp p = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | 453218792Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CCLK)); 454218792Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, &p, &v); 455218792Snp if (rc != 0) { 456218792Snp device_printf(sc->dev, 457218792Snp "failed to obtain core clock value: %d.\n", rc); 458218792Snp goto done; 459218792Snp } 460218792Snp sc->params.vpd.cclk = v; 461218792Snp 462218792Snp t4_sge_init(sc); 463218792Snp 464221474Snp t4_set_filter_mode(sc, filter_mode); 465221474Snp t4_set_reg_field(sc, A_TP_GLOBAL_CONFIG, 466221474Snp V_FIVETUPLELOOKUP(M_FIVETUPLELOOKUP), 467221474Snp V_FIVETUPLELOOKUP(M_FIVETUPLELOOKUP)); 468221474Snp t4_tp_wr_bits_indirect(sc, A_TP_INGRESS_CONFIG, F_CSUM_HAS_PSEUDO_HDR, 469221474Snp F_LOOKUPEVERYPKT); 470218792Snp 471218792Snp /* get basic stuff going */ 472218792Snp rc = -t4_early_init(sc, sc->mbox); 473218792Snp if (rc != 0) { 474218792Snp device_printf(dev, "early init failed: %d.\n", rc); 475218792Snp goto done; 476218792Snp } 477218792Snp 478218792Snp rc = get_params(sc, &caps); 479218792Snp if (rc != 0) 480218792Snp goto done; /* error message displayed already */ 481218792Snp 482218792Snp /* These are finalized by FW initialization, load their values now */ 483218792Snp v = t4_read_reg(sc, A_TP_TIMER_RESOLUTION); 484218792Snp sc->params.tp.tre = G_TIMERRESOLUTION(v); 485218792Snp sc->params.tp.dack_re = G_DELAYEDACKRESOLUTION(v); 486218792Snp t4_read_mtu_tbl(sc, sc->params.mtus, NULL); 487218792Snp 488218792Snp /* tweak some settings */ 489218792Snp t4_write_reg(sc, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) | V_RXTSHIFTMAXR1(4) | 490218792Snp V_RXTSHIFTMAXR2(15) | V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) | 491218792Snp V_KEEPALIVEMAXR1(4) | V_KEEPALIVEMAXR2(9)); 492218792Snp t4_write_reg(sc, A_ULP_RX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12)); 493222703Snp t4_set_reg_field(sc, A_TP_PARA_REG3, F_TUNNELCNGDROP0 | 494222703Snp F_TUNNELCNGDROP1 | F_TUNNELCNGDROP2 | F_TUNNELCNGDROP3, 0); 495218792Snp 496218792Snp setup_memwin(sc); 497218792Snp 498218792Snp rc = t4_create_dma_tag(sc); 499218792Snp if (rc != 0) 500218792Snp goto done; /* error message displayed already */ 501218792Snp 502218792Snp /* 503218792Snp * First pass over all the ports - allocate VIs and initialize some 504218792Snp * basic parameters like mac address, port type, etc. We also figure 505218792Snp * out whether a port is 10G or 1G and use that information when 506218792Snp * calculating how many interrupts to attempt to allocate. 507218792Snp */ 508218792Snp n10g = n1g = 0; 509218792Snp for_each_port(sc, i) { 510218792Snp struct port_info *pi; 511218792Snp 512218792Snp pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK); 513218792Snp sc->port[i] = pi; 514218792Snp 515218792Snp /* These must be set before t4_port_init */ 516218792Snp pi->adapter = sc; 517218792Snp pi->port_id = i; 518218792Snp 519218792Snp /* Allocate the vi and initialize parameters like mac addr */ 520218792Snp rc = -t4_port_init(pi, sc->mbox, sc->pf, 0); 521218792Snp if (rc != 0) { 522218792Snp device_printf(dev, "unable to initialize port %d: %d\n", 523218792Snp i, rc); 524218792Snp free(pi, M_CXGBE); 525222510Snp sc->port[i] = NULL; 526222510Snp goto done; 527218792Snp } 528218792Snp 529218792Snp snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d", 530218792Snp device_get_nameunit(dev), i); 531218792Snp mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF); 532218792Snp 533218792Snp if (is_10G_port(pi)) { 534218792Snp n10g++; 535218792Snp pi->tmr_idx = tmr_idx_10g; 536218792Snp pi->pktc_idx = pktc_idx_10g; 537218792Snp } else { 538218792Snp n1g++; 539218792Snp pi->tmr_idx = tmr_idx_1g; 540218792Snp pi->pktc_idx = pktc_idx_1g; 541218792Snp } 542218792Snp 543218792Snp pi->xact_addr_filt = -1; 544218792Snp 545218792Snp pi->qsize_rxq = max(qsize_rxq, 128); 546218792Snp while (pi->qsize_rxq & 7) 547218792Snp pi->qsize_rxq++; 548218792Snp pi->qsize_txq = max(qsize_txq, 128); 549218792Snp 550218792Snp if (pi->qsize_rxq != qsize_rxq) { 551218792Snp device_printf(dev, 552218792Snp "using %d instead of %d as the rx queue size.\n", 553218792Snp pi->qsize_rxq, qsize_rxq); 554218792Snp } 555218792Snp if (pi->qsize_txq != qsize_txq) { 556218792Snp device_printf(dev, 557218792Snp "using %d instead of %d as the tx queue size.\n", 558218792Snp pi->qsize_txq, qsize_txq); 559218792Snp } 560218792Snp 561218792Snp pi->dev = device_add_child(dev, "cxgbe", -1); 562218792Snp if (pi->dev == NULL) { 563218792Snp device_printf(dev, 564218792Snp "failed to add device for port %d.\n", i); 565218792Snp rc = ENXIO; 566218792Snp goto done; 567218792Snp } 568218792Snp device_set_softc(pi->dev, pi); 569218792Snp 570218792Snp setbit(&sc->registered_device_map, i); 571218792Snp } 572218792Snp 573218792Snp if (sc->registered_device_map == 0) { 574218792Snp device_printf(dev, "no usable ports\n"); 575218792Snp rc = ENXIO; 576218792Snp goto done; 577218792Snp } 578218792Snp 579218792Snp /* 580218792Snp * Interrupt type, # of interrupts, # of rx/tx queues, etc. 581218792Snp */ 582218792Snp rc = cfg_itype_and_nqueues(sc, n10g, n1g, &iaq); 583218792Snp if (rc != 0) 584218792Snp goto done; /* error message displayed already */ 585218792Snp 586218792Snp sc->intr_type = iaq.intr_type; 587218792Snp sc->intr_count = iaq.nirq; 588218792Snp 589218792Snp s = &sc->sge; 590218792Snp s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g; 591218792Snp s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g; 592220873Snp s->neq = s->ntxq + s->nrxq; /* the free list in an rxq is an eq */ 593222510Snp s->neq += sc->params.nports; /* control queues, 1 per port */ 594218792Snp s->niq = s->nrxq + 1; /* 1 extra for firmware event queue */ 595222510Snp if (iaq.intr_shared) 596222510Snp sc->flags |= INTR_SHARED; 597222510Snp s->niq += NINTRQ(sc); /* interrupt queues */ 598222510Snp 599222510Snp s->intrq = malloc(NINTRQ(sc) * sizeof(struct sge_iq), M_CXGBE, 600220873Snp M_ZERO | M_WAITOK); 601222510Snp s->ctrlq = malloc(sc->params.nports * sizeof(struct sge_ctrlq), M_CXGBE, 602222510Snp M_ZERO | M_WAITOK); 603218792Snp s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE, 604218792Snp M_ZERO | M_WAITOK); 605218792Snp s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE, 606218792Snp M_ZERO | M_WAITOK); 607218792Snp s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE, 608218792Snp M_ZERO | M_WAITOK); 609218792Snp s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE, 610218792Snp M_ZERO | M_WAITOK); 611218792Snp 612218792Snp sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE, 613218792Snp M_ZERO | M_WAITOK); 614218792Snp 615222509Snp sc->l2t = t4_init_l2t(M_WAITOK); 616222509Snp 617218792Snp t4_sysctls(sc); 618218792Snp 619218792Snp /* 620218792Snp * Second pass over the ports. This time we know the number of rx and 621218792Snp * tx queues that each port should get. 622218792Snp */ 623218792Snp rqidx = tqidx = 0; 624218792Snp for_each_port(sc, i) { 625218792Snp struct port_info *pi = sc->port[i]; 626218792Snp 627218792Snp if (pi == NULL) 628218792Snp continue; 629218792Snp 630218792Snp pi->first_rxq = rqidx; 631218792Snp pi->nrxq = is_10G_port(pi) ? iaq.nrxq10g : iaq.nrxq1g; 632218792Snp 633218792Snp pi->first_txq = tqidx; 634218792Snp pi->ntxq = is_10G_port(pi) ? iaq.ntxq10g : iaq.ntxq1g; 635218792Snp 636218792Snp rqidx += pi->nrxq; 637218792Snp tqidx += pi->ntxq; 638218792Snp } 639218792Snp 640218792Snp rc = bus_generic_attach(dev); 641218792Snp if (rc != 0) { 642218792Snp device_printf(dev, 643218792Snp "failed to attach all child ports: %d\n", rc); 644218792Snp goto done; 645218792Snp } 646218792Snp 647218792Snp#ifdef INVARIANTS 648218792Snp device_printf(dev, 649218792Snp "%p, %d ports (0x%x), %d intr_type, %d intr_count\n", 650218792Snp sc, sc->params.nports, sc->params.portvec, 651218792Snp sc->intr_type, sc->intr_count); 652218792Snp#endif 653218792Snp t4_set_desc(sc); 654218792Snp 655218792Snpdone: 656218792Snp if (rc != 0) 657218792Snp t4_detach(dev); 658218792Snp 659218792Snp return (rc); 660218792Snp} 661218792Snp 662218792Snp/* 663218792Snp * Idempotent 664218792Snp */ 665218792Snpstatic int 666218792Snpt4_detach(device_t dev) 667218792Snp{ 668218792Snp struct adapter *sc; 669218792Snp struct port_info *pi; 670218792Snp int i; 671218792Snp 672218792Snp sc = device_get_softc(dev); 673218792Snp 674218792Snp if (sc->cdev) 675218792Snp destroy_dev(sc->cdev); 676218792Snp 677218792Snp bus_generic_detach(dev); 678218792Snp for (i = 0; i < MAX_NPORTS; i++) { 679218792Snp pi = sc->port[i]; 680218792Snp if (pi) { 681218792Snp t4_free_vi(pi->adapter, sc->mbox, sc->pf, 0, pi->viid); 682218792Snp if (pi->dev) 683218792Snp device_delete_child(dev, pi->dev); 684218792Snp 685218792Snp mtx_destroy(&pi->pi_lock); 686218792Snp free(pi, M_CXGBE); 687218792Snp } 688218792Snp } 689218792Snp 690218792Snp if (sc->flags & FW_OK) 691218792Snp t4_fw_bye(sc, sc->mbox); 692218792Snp 693219944Snp if (sc->intr_type == INTR_MSI || sc->intr_type == INTR_MSIX) 694218792Snp pci_release_msi(dev); 695218792Snp 696218792Snp if (sc->regs_res) 697218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid, 698218792Snp sc->regs_res); 699218792Snp 700218792Snp if (sc->msix_res) 701218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid, 702218792Snp sc->msix_res); 703218792Snp 704222509Snp if (sc->l2t) 705222509Snp t4_free_l2t(sc->l2t); 706222509Snp 707218792Snp free(sc->irq, M_CXGBE); 708218792Snp free(sc->sge.rxq, M_CXGBE); 709218792Snp free(sc->sge.txq, M_CXGBE); 710220873Snp free(sc->sge.ctrlq, M_CXGBE); 711222510Snp free(sc->sge.intrq, M_CXGBE); 712218792Snp free(sc->sge.iqmap, M_CXGBE); 713218792Snp free(sc->sge.eqmap, M_CXGBE); 714221474Snp free(sc->tids.ftid_tab, M_CXGBE); 715218792Snp t4_destroy_dma_tag(sc); 716218792Snp mtx_destroy(&sc->sc_lock); 717218792Snp 718218792Snp bzero(sc, sizeof(*sc)); 719218792Snp 720218792Snp return (0); 721218792Snp} 722218792Snp 723218792Snp 724218792Snpstatic int 725218792Snpcxgbe_probe(device_t dev) 726218792Snp{ 727218792Snp char buf[128]; 728218792Snp struct port_info *pi = device_get_softc(dev); 729218792Snp 730218792Snp snprintf(buf, sizeof(buf), "Port %d", pi->port_id); 731218792Snp device_set_desc_copy(dev, buf); 732218792Snp 733218792Snp return (BUS_PROBE_DEFAULT); 734218792Snp} 735218792Snp 736218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \ 737218792Snp IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \ 738218792Snp IFCAP_VLAN_HWTSO) 739218792Snp#define T4_CAP_ENABLE (T4_CAP & ~IFCAP_TSO6) 740218792Snp 741218792Snpstatic int 742218792Snpcxgbe_attach(device_t dev) 743218792Snp{ 744218792Snp struct port_info *pi = device_get_softc(dev); 745218792Snp struct ifnet *ifp; 746218792Snp 747218792Snp /* Allocate an ifnet and set it up */ 748218792Snp ifp = if_alloc(IFT_ETHER); 749218792Snp if (ifp == NULL) { 750218792Snp device_printf(dev, "Cannot allocate ifnet\n"); 751218792Snp return (ENOMEM); 752218792Snp } 753218792Snp pi->ifp = ifp; 754218792Snp ifp->if_softc = pi; 755218792Snp 756218792Snp callout_init(&pi->tick, CALLOUT_MPSAFE); 757219286Snp pi->tq = taskqueue_create("cxgbe_taskq", M_NOWAIT, 758219286Snp taskqueue_thread_enqueue, &pi->tq); 759219286Snp if (pi->tq == NULL) { 760219286Snp device_printf(dev, "failed to allocate port task queue\n"); 761219286Snp if_free(pi->ifp); 762219286Snp return (ENOMEM); 763219286Snp } 764219286Snp taskqueue_start_threads(&pi->tq, 1, PI_NET, "%s taskq", 765219286Snp device_get_nameunit(dev)); 766218792Snp 767218792Snp if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 768218792Snp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 769218792Snp 770218792Snp ifp->if_init = cxgbe_init; 771218792Snp ifp->if_ioctl = cxgbe_ioctl; 772218792Snp ifp->if_start = cxgbe_start; 773218792Snp ifp->if_transmit = cxgbe_transmit; 774218792Snp ifp->if_qflush = cxgbe_qflush; 775218792Snp 776218792Snp ifp->if_snd.ifq_drv_maxlen = 1024; 777218792Snp IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 778218792Snp IFQ_SET_READY(&ifp->if_snd); 779218792Snp 780218792Snp ifp->if_capabilities = T4_CAP; 781218792Snp ifp->if_capenable = T4_CAP_ENABLE; 782218792Snp ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO; 783218792Snp 784218792Snp /* Initialize ifmedia for this port */ 785218792Snp ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change, 786218792Snp cxgbe_media_status); 787218792Snp build_medialist(pi); 788218792Snp 789218792Snp ether_ifattach(ifp, pi->hw_addr); 790218792Snp 791218792Snp#ifdef INVARIANTS 792218792Snp device_printf(dev, "%p, %d txq, %d rxq\n", pi, pi->ntxq, pi->nrxq); 793218792Snp#endif 794218792Snp 795218792Snp cxgbe_sysctls(pi); 796218792Snp 797218792Snp return (0); 798218792Snp} 799218792Snp 800218792Snpstatic int 801218792Snpcxgbe_detach(device_t dev) 802218792Snp{ 803218792Snp struct port_info *pi = device_get_softc(dev); 804218792Snp struct adapter *sc = pi->adapter; 805218792Snp int rc; 806218792Snp 807218792Snp /* Tell if_ioctl and if_init that the port is going away */ 808218792Snp ADAPTER_LOCK(sc); 809218792Snp SET_DOOMED(pi); 810218792Snp wakeup(&sc->flags); 811218792Snp while (IS_BUSY(sc)) 812218792Snp mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0); 813218792Snp SET_BUSY(sc); 814218792Snp ADAPTER_UNLOCK(sc); 815218792Snp 816218792Snp rc = cxgbe_uninit_synchronized(pi); 817218792Snp if (rc != 0) 818218792Snp device_printf(dev, "port uninit failed: %d.\n", rc); 819218792Snp 820219286Snp taskqueue_free(pi->tq); 821219286Snp 822218792Snp ifmedia_removeall(&pi->media); 823218792Snp ether_ifdetach(pi->ifp); 824218792Snp if_free(pi->ifp); 825218792Snp 826218792Snp ADAPTER_LOCK(sc); 827218792Snp CLR_BUSY(sc); 828218792Snp wakeup_one(&sc->flags); 829218792Snp ADAPTER_UNLOCK(sc); 830218792Snp 831218792Snp return (0); 832218792Snp} 833218792Snp 834218792Snpstatic void 835218792Snpcxgbe_init(void *arg) 836218792Snp{ 837218792Snp struct port_info *pi = arg; 838218792Snp struct adapter *sc = pi->adapter; 839218792Snp 840218792Snp ADAPTER_LOCK(sc); 841218792Snp cxgbe_init_locked(pi); /* releases adapter lock */ 842218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 843218792Snp} 844218792Snp 845218792Snpstatic int 846218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) 847218792Snp{ 848218792Snp int rc = 0, mtu, flags; 849218792Snp struct port_info *pi = ifp->if_softc; 850218792Snp struct adapter *sc = pi->adapter; 851218792Snp struct ifreq *ifr = (struct ifreq *)data; 852218792Snp uint32_t mask; 853218792Snp 854218792Snp switch (cmd) { 855218792Snp case SIOCSIFMTU: 856218792Snp ADAPTER_LOCK(sc); 857218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 858218792Snp if (rc) { 859218792Snpfail: 860218792Snp ADAPTER_UNLOCK(sc); 861218792Snp return (rc); 862218792Snp } 863218792Snp 864218792Snp mtu = ifr->ifr_mtu; 865218792Snp if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) { 866218792Snp rc = EINVAL; 867218792Snp } else { 868218792Snp ifp->if_mtu = mtu; 869218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 870218792Snp t4_update_fl_bufsize(ifp); 871218792Snp PORT_LOCK(pi); 872218792Snp rc = update_mac_settings(pi, XGMAC_MTU); 873218792Snp PORT_UNLOCK(pi); 874218792Snp } 875218792Snp } 876218792Snp ADAPTER_UNLOCK(sc); 877218792Snp break; 878218792Snp 879218792Snp case SIOCSIFFLAGS: 880218792Snp ADAPTER_LOCK(sc); 881218792Snp if (IS_DOOMED(pi)) { 882218792Snp rc = ENXIO; 883218792Snp goto fail; 884218792Snp } 885218792Snp if (ifp->if_flags & IFF_UP) { 886218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 887218792Snp flags = pi->if_flags; 888218792Snp if ((ifp->if_flags ^ flags) & 889218792Snp (IFF_PROMISC | IFF_ALLMULTI)) { 890218792Snp if (IS_BUSY(sc)) { 891218792Snp rc = EBUSY; 892218792Snp goto fail; 893218792Snp } 894218792Snp PORT_LOCK(pi); 895218792Snp rc = update_mac_settings(pi, 896218792Snp XGMAC_PROMISC | XGMAC_ALLMULTI); 897218792Snp PORT_UNLOCK(pi); 898218792Snp } 899218792Snp ADAPTER_UNLOCK(sc); 900218792Snp } else 901218792Snp rc = cxgbe_init_locked(pi); 902218792Snp pi->if_flags = ifp->if_flags; 903218792Snp } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 904218792Snp rc = cxgbe_uninit_locked(pi); 905218792Snp else 906218792Snp ADAPTER_UNLOCK(sc); 907218792Snp 908218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 909218792Snp break; 910218792Snp 911218792Snp case SIOCADDMULTI: 912218792Snp case SIOCDELMULTI: /* these two can be called with a mutex held :-( */ 913218792Snp ADAPTER_LOCK(sc); 914218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 915218792Snp if (rc) 916218792Snp goto fail; 917218792Snp 918218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 919218792Snp PORT_LOCK(pi); 920218792Snp rc = update_mac_settings(pi, XGMAC_MCADDRS); 921218792Snp PORT_UNLOCK(pi); 922218792Snp } 923218792Snp ADAPTER_UNLOCK(sc); 924218792Snp break; 925218792Snp 926218792Snp case SIOCSIFCAP: 927218792Snp ADAPTER_LOCK(sc); 928218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 929218792Snp if (rc) 930218792Snp goto fail; 931218792Snp 932218792Snp mask = ifr->ifr_reqcap ^ ifp->if_capenable; 933218792Snp if (mask & IFCAP_TXCSUM) { 934218792Snp ifp->if_capenable ^= IFCAP_TXCSUM; 935218792Snp ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 936218792Snp 937218792Snp if (IFCAP_TSO & ifp->if_capenable && 938218792Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 939218792Snp ifp->if_capenable &= ~IFCAP_TSO; 940218792Snp ifp->if_hwassist &= ~CSUM_TSO; 941218792Snp if_printf(ifp, 942218792Snp "tso disabled due to -txcsum.\n"); 943218792Snp } 944218792Snp } 945218792Snp if (mask & IFCAP_RXCSUM) 946218792Snp ifp->if_capenable ^= IFCAP_RXCSUM; 947218792Snp if (mask & IFCAP_TSO4) { 948218792Snp ifp->if_capenable ^= IFCAP_TSO4; 949218792Snp 950218792Snp if (IFCAP_TSO & ifp->if_capenable) { 951218792Snp if (IFCAP_TXCSUM & ifp->if_capenable) 952218792Snp ifp->if_hwassist |= CSUM_TSO; 953218792Snp else { 954218792Snp ifp->if_capenable &= ~IFCAP_TSO; 955218792Snp ifp->if_hwassist &= ~CSUM_TSO; 956218792Snp if_printf(ifp, 957218792Snp "enable txcsum first.\n"); 958218792Snp rc = EAGAIN; 959218792Snp } 960218792Snp } else 961218792Snp ifp->if_hwassist &= ~CSUM_TSO; 962218792Snp } 963218792Snp if (mask & IFCAP_LRO) { 964218792Snp#ifdef INET 965218792Snp int i; 966218792Snp struct sge_rxq *rxq; 967218792Snp 968218792Snp ifp->if_capenable ^= IFCAP_LRO; 969218792Snp for_each_rxq(pi, i, rxq) { 970218792Snp if (ifp->if_capenable & IFCAP_LRO) 971218792Snp rxq->flags |= RXQ_LRO_ENABLED; 972218792Snp else 973218792Snp rxq->flags &= ~RXQ_LRO_ENABLED; 974218792Snp } 975218792Snp#endif 976218792Snp } 977218792Snp#ifndef TCP_OFFLOAD_DISABLE 978218792Snp if (mask & IFCAP_TOE4) { 979218792Snp rc = EOPNOTSUPP; 980218792Snp } 981218792Snp#endif 982218792Snp if (mask & IFCAP_VLAN_HWTAGGING) { 983218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 984218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 985218792Snp PORT_LOCK(pi); 986218792Snp rc = update_mac_settings(pi, XGMAC_VLANEX); 987218792Snp PORT_UNLOCK(pi); 988218792Snp } 989218792Snp } 990218792Snp if (mask & IFCAP_VLAN_MTU) { 991218792Snp ifp->if_capenable ^= IFCAP_VLAN_MTU; 992218792Snp 993218792Snp /* Need to find out how to disable auto-mtu-inflation */ 994218792Snp } 995218792Snp if (mask & IFCAP_VLAN_HWTSO) 996218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 997218792Snp if (mask & IFCAP_VLAN_HWCSUM) 998218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 999218792Snp 1000218792Snp#ifdef VLAN_CAPABILITIES 1001218792Snp VLAN_CAPABILITIES(ifp); 1002218792Snp#endif 1003218792Snp ADAPTER_UNLOCK(sc); 1004218792Snp break; 1005218792Snp 1006218792Snp case SIOCSIFMEDIA: 1007218792Snp case SIOCGIFMEDIA: 1008218792Snp ifmedia_ioctl(ifp, ifr, &pi->media, cmd); 1009218792Snp break; 1010218792Snp 1011218792Snp default: 1012218792Snp rc = ether_ioctl(ifp, cmd, data); 1013218792Snp } 1014218792Snp 1015218792Snp return (rc); 1016218792Snp} 1017218792Snp 1018218792Snpstatic void 1019218792Snpcxgbe_start(struct ifnet *ifp) 1020218792Snp{ 1021218792Snp struct port_info *pi = ifp->if_softc; 1022218792Snp struct sge_txq *txq; 1023218792Snp int i; 1024218792Snp 1025218792Snp for_each_txq(pi, i, txq) { 1026218792Snp if (TXQ_TRYLOCK(txq)) { 1027219286Snp txq_start(ifp, txq); 1028218792Snp TXQ_UNLOCK(txq); 1029218792Snp } 1030218792Snp } 1031218792Snp} 1032218792Snp 1033218792Snpstatic int 1034218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m) 1035218792Snp{ 1036218792Snp struct port_info *pi = ifp->if_softc; 1037218792Snp struct adapter *sc = pi->adapter; 1038218792Snp struct sge_txq *txq = &sc->sge.txq[pi->first_txq]; 1039218792Snp struct buf_ring *br; 1040218792Snp int rc; 1041218792Snp 1042218792Snp M_ASSERTPKTHDR(m); 1043218792Snp 1044218792Snp if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1045218792Snp m_freem(m); 1046218792Snp return (0); 1047218792Snp } 1048218792Snp 1049218792Snp if (m->m_flags & M_FLOWID) 1050218792Snp txq += (m->m_pkthdr.flowid % pi->ntxq); 1051220873Snp br = txq->br; 1052218792Snp 1053218792Snp if (TXQ_TRYLOCK(txq) == 0) { 1054218792Snp /* 1055218792Snp * XXX: make sure that this packet really is sent out. There is 1056218792Snp * a small race where t4_eth_tx may stop draining the drbr and 1057218792Snp * goes away, just before we enqueued this mbuf. 1058218792Snp */ 1059218792Snp 1060218792Snp return (drbr_enqueue(ifp, br, m)); 1061218792Snp } 1062218792Snp 1063218792Snp /* 1064218792Snp * txq->m is the mbuf that is held up due to a temporary shortage of 1065218792Snp * resources and it should be put on the wire first. Then what's in 1066218792Snp * drbr and finally the mbuf that was just passed in to us. 1067218792Snp * 1068218792Snp * Return code should indicate the fate of the mbuf that was passed in 1069218792Snp * this time. 1070218792Snp */ 1071218792Snp 1072218792Snp TXQ_LOCK_ASSERT_OWNED(txq); 1073218792Snp if (drbr_needs_enqueue(ifp, br) || txq->m) { 1074218792Snp 1075218792Snp /* Queued for transmission. */ 1076218792Snp 1077218792Snp rc = drbr_enqueue(ifp, br, m); 1078218792Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 1079218792Snp (void) t4_eth_tx(ifp, txq, m); 1080218792Snp TXQ_UNLOCK(txq); 1081218792Snp return (rc); 1082218792Snp } 1083218792Snp 1084218792Snp /* Direct transmission. */ 1085218792Snp rc = t4_eth_tx(ifp, txq, m); 1086218792Snp if (rc != 0 && txq->m) 1087218792Snp rc = 0; /* held, will be transmitted soon (hopefully) */ 1088218792Snp 1089218792Snp TXQ_UNLOCK(txq); 1090218792Snp return (rc); 1091218792Snp} 1092218792Snp 1093218792Snpstatic void 1094218792Snpcxgbe_qflush(struct ifnet *ifp) 1095218792Snp{ 1096218792Snp struct port_info *pi = ifp->if_softc; 1097220649Snp struct sge_txq *txq; 1098220649Snp int i; 1099220649Snp struct mbuf *m; 1100218792Snp 1101220649Snp /* queues do not exist if !IFF_DRV_RUNNING. */ 1102220649Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1103220649Snp for_each_txq(pi, i, txq) { 1104220649Snp TXQ_LOCK(txq); 1105220649Snp m_freem(txq->m); 1106220873Snp while ((m = buf_ring_dequeue_sc(txq->br)) != NULL) 1107220649Snp m_freem(m); 1108220649Snp TXQ_UNLOCK(txq); 1109220649Snp } 1110220649Snp } 1111220649Snp if_qflush(ifp); 1112218792Snp} 1113218792Snp 1114218792Snpstatic int 1115218792Snpcxgbe_media_change(struct ifnet *ifp) 1116218792Snp{ 1117218792Snp struct port_info *pi = ifp->if_softc; 1118218792Snp 1119218792Snp device_printf(pi->dev, "%s unimplemented.\n", __func__); 1120218792Snp 1121218792Snp return (EOPNOTSUPP); 1122218792Snp} 1123218792Snp 1124218792Snpstatic void 1125218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1126218792Snp{ 1127218792Snp struct port_info *pi = ifp->if_softc; 1128218792Snp struct ifmedia_entry *cur = pi->media.ifm_cur; 1129218792Snp int speed = pi->link_cfg.speed; 1130218792Snp int data = (pi->port_type << 8) | pi->mod_type; 1131218792Snp 1132218792Snp if (cur->ifm_data != data) { 1133218792Snp build_medialist(pi); 1134218792Snp cur = pi->media.ifm_cur; 1135218792Snp } 1136218792Snp 1137218792Snp ifmr->ifm_status = IFM_AVALID; 1138218792Snp if (!pi->link_cfg.link_ok) 1139218792Snp return; 1140218792Snp 1141218792Snp ifmr->ifm_status |= IFM_ACTIVE; 1142218792Snp 1143218792Snp /* active and current will differ iff current media is autoselect. */ 1144218792Snp if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO) 1145218792Snp return; 1146218792Snp 1147218792Snp ifmr->ifm_active = IFM_ETHER | IFM_FDX; 1148218792Snp if (speed == SPEED_10000) 1149218792Snp ifmr->ifm_active |= IFM_10G_T; 1150218792Snp else if (speed == SPEED_1000) 1151218792Snp ifmr->ifm_active |= IFM_1000_T; 1152218792Snp else if (speed == SPEED_100) 1153218792Snp ifmr->ifm_active |= IFM_100_TX; 1154218792Snp else if (speed == SPEED_10) 1155218792Snp ifmr->ifm_active |= IFM_10_T; 1156218792Snp else 1157218792Snp KASSERT(0, ("%s: link up but speed unknown (%u)", __func__, 1158218792Snp speed)); 1159218792Snp} 1160218792Snp 1161218792Snpvoid 1162218792Snpt4_fatal_err(struct adapter *sc) 1163218792Snp{ 1164218792Snp t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0); 1165218792Snp t4_intr_disable(sc); 1166218792Snp log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n", 1167218792Snp device_get_nameunit(sc->dev)); 1168218792Snp} 1169218792Snp 1170218792Snpstatic int 1171218792Snpmap_bars(struct adapter *sc) 1172218792Snp{ 1173218792Snp sc->regs_rid = PCIR_BAR(0); 1174218792Snp sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1175218792Snp &sc->regs_rid, RF_ACTIVE); 1176218792Snp if (sc->regs_res == NULL) { 1177218792Snp device_printf(sc->dev, "cannot map registers.\n"); 1178218792Snp return (ENXIO); 1179218792Snp } 1180218792Snp sc->bt = rman_get_bustag(sc->regs_res); 1181218792Snp sc->bh = rman_get_bushandle(sc->regs_res); 1182218792Snp sc->mmio_len = rman_get_size(sc->regs_res); 1183218792Snp 1184218792Snp sc->msix_rid = PCIR_BAR(4); 1185218792Snp sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1186218792Snp &sc->msix_rid, RF_ACTIVE); 1187218792Snp if (sc->msix_res == NULL) { 1188218792Snp device_printf(sc->dev, "cannot map MSI-X BAR.\n"); 1189218792Snp return (ENXIO); 1190218792Snp } 1191218792Snp 1192218792Snp return (0); 1193218792Snp} 1194218792Snp 1195218792Snpstatic void 1196218792Snpsetup_memwin(struct adapter *sc) 1197218792Snp{ 1198218792Snp u_long bar0; 1199218792Snp 1200218792Snp bar0 = rman_get_start(sc->regs_res); 1201218792Snp 1202218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 0), 1203218792Snp (bar0 + MEMWIN0_BASE) | V_BIR(0) | 1204218792Snp V_WINDOW(ilog2(MEMWIN0_APERTURE) - 10)); 1205218792Snp 1206218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 1), 1207218792Snp (bar0 + MEMWIN1_BASE) | V_BIR(0) | 1208218792Snp V_WINDOW(ilog2(MEMWIN1_APERTURE) - 10)); 1209218792Snp 1210218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2), 1211218792Snp (bar0 + MEMWIN2_BASE) | V_BIR(0) | 1212218792Snp V_WINDOW(ilog2(MEMWIN2_APERTURE) - 10)); 1213218792Snp} 1214218792Snp 1215218792Snpstatic int 1216218792Snpcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g, 1217218792Snp struct intrs_and_queues *iaq) 1218218792Snp{ 1219218792Snp int rc, itype, navail, nc, nrxq10g, nrxq1g; 1220218792Snp 1221218792Snp bzero(iaq, sizeof(*iaq)); 1222218792Snp nc = mp_ncpus; /* our snapshot of the number of CPUs */ 1223218792Snp 1224219944Snp for (itype = INTR_MSIX; itype; itype >>= 1) { 1225218792Snp 1226218792Snp if ((itype & intr_types) == 0) 1227218792Snp continue; /* not allowed */ 1228218792Snp 1229219944Snp if (itype == INTR_MSIX) 1230218792Snp navail = pci_msix_count(sc->dev); 1231219944Snp else if (itype == INTR_MSI) 1232218792Snp navail = pci_msi_count(sc->dev); 1233218792Snp else 1234218792Snp navail = 1; 1235218792Snp 1236218792Snp if (navail == 0) 1237218792Snp continue; 1238218792Snp 1239218792Snp iaq->intr_type = itype; 1240218792Snp 1241218792Snp iaq->ntxq10g = min(nc, max_ntxq_10g); 1242218792Snp iaq->ntxq1g = min(nc, max_ntxq_1g); 1243218792Snp 1244218792Snp nrxq10g = min(nc, max_nrxq_10g); 1245218792Snp nrxq1g = min(nc, max_nrxq_1g); 1246218792Snp 1247222510Snp iaq->nirq = n10g * nrxq10g + n1g * nrxq1g + T4_EXTRA_INTR; 1248222510Snp if (iaq->nirq <= navail && intr_shared == 0) { 1249218792Snp 1250219944Snp if (itype == INTR_MSI && !powerof2(iaq->nirq)) 1251222510Snp goto share; 1252219944Snp 1253218792Snp /* One for err, one for fwq, and one for each rxq */ 1254218792Snp 1255222510Snp iaq->intr_shared = 0; 1256218792Snp iaq->nrxq10g = nrxq10g; 1257218792Snp iaq->nrxq1g = nrxq1g; 1258219944Snp 1259218792Snp } else { 1260222510Snpshare: 1261222510Snp iaq->intr_shared = 1; 1262218792Snp 1263222510Snp if (navail >= nc + T4_EXTRA_INTR) { 1264219944Snp if (itype == INTR_MSIX) 1265222510Snp navail = nc + T4_EXTRA_INTR; 1266219944Snp 1267219944Snp /* navail is and must remain a pow2 for MSI */ 1268219944Snp if (itype == INTR_MSI) { 1269219944Snp KASSERT(powerof2(navail), 1270219944Snp ("%d not power of 2", navail)); 1271219944Snp 1272222510Snp while (navail / 2 >= nc + T4_EXTRA_INTR) 1273219944Snp navail /= 2; 1274219944Snp } 1275219944Snp } 1276219944Snp iaq->nirq = navail; /* total # of interrupts */ 1277219944Snp 1278218792Snp /* 1279218792Snp * If we have multiple vectors available reserve one 1280218792Snp * exclusively for errors. The rest will be shared by 1281218792Snp * the fwq and data. 1282218792Snp */ 1283219944Snp if (navail > 1) 1284218792Snp navail--; 1285218792Snp iaq->nrxq10g = min(nrxq10g, navail); 1286218792Snp iaq->nrxq1g = min(nrxq1g, navail); 1287218792Snp } 1288218792Snp 1289218792Snp navail = iaq->nirq; 1290218792Snp rc = 0; 1291219944Snp if (itype == INTR_MSIX) 1292218792Snp rc = pci_alloc_msix(sc->dev, &navail); 1293219944Snp else if (itype == INTR_MSI) 1294218792Snp rc = pci_alloc_msi(sc->dev, &navail); 1295218792Snp 1296218792Snp if (rc == 0) { 1297218792Snp if (navail == iaq->nirq) 1298218792Snp return (0); 1299218792Snp 1300218792Snp /* 1301218792Snp * Didn't get the number requested. Use whatever number 1302218792Snp * the kernel is willing to allocate (it's in navail). 1303218792Snp */ 1304218792Snp pci_release_msi(sc->dev); 1305222510Snp goto share; 1306218792Snp } 1307218792Snp 1308218792Snp device_printf(sc->dev, 1309218792Snp "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n", 1310218792Snp itype, rc, iaq->nirq, navail); 1311218792Snp } 1312218792Snp 1313218792Snp device_printf(sc->dev, 1314218792Snp "failed to find a usable interrupt type. " 1315218792Snp "allowed=%d, msi-x=%d, msi=%d, intx=1", intr_types, 1316218792Snp pci_msix_count(sc->dev), pci_msi_count(sc->dev)); 1317218792Snp 1318218792Snp return (ENXIO); 1319218792Snp} 1320218792Snp 1321218792Snp/* 1322218792Snp * Install a compatible firmware (if required), establish contact with it, 1323218792Snp * become the master, and reset the device. 1324218792Snp */ 1325218792Snpstatic int 1326218792Snpprep_firmware(struct adapter *sc) 1327218792Snp{ 1328218792Snp const struct firmware *fw; 1329218792Snp int rc; 1330218792Snp enum dev_state state; 1331218792Snp 1332218792Snp /* Check firmware version and install a different one if necessary */ 1333218792Snp rc = t4_check_fw_version(sc); 1334218792Snp if (rc != 0 || force_firmware_install) { 1335219287Snp uint32_t v = 0; 1336218792Snp 1337218792Snp fw = firmware_get(T4_FWNAME); 1338219287Snp if (fw != NULL) { 1339219287Snp const struct fw_hdr *hdr = (const void *)fw->data; 1340219287Snp 1341219287Snp v = ntohl(hdr->fw_ver); 1342219287Snp 1343219287Snp /* 1344219287Snp * The firmware module will not be used if it isn't the 1345219287Snp * same major version as what the driver was compiled 1346219287Snp * with. This check trumps force_firmware_install. 1347219287Snp */ 1348219287Snp if (G_FW_HDR_FW_VER_MAJOR(v) != FW_VERSION_MAJOR) { 1349219287Snp device_printf(sc->dev, 1350219287Snp "Found firmware image but version %d " 1351219287Snp "can not be used with this driver (%d)\n", 1352219287Snp G_FW_HDR_FW_VER_MAJOR(v), FW_VERSION_MAJOR); 1353219287Snp 1354219287Snp firmware_put(fw, FIRMWARE_UNLOAD); 1355219287Snp fw = NULL; 1356219287Snp } 1357218792Snp } 1358218792Snp 1359219287Snp if (fw == NULL && (rc < 0 || force_firmware_install)) { 1360219287Snp device_printf(sc->dev, "No usable firmware. " 1361219287Snp "card has %d.%d.%d, driver compiled with %d.%d.%d, " 1362219287Snp "force_firmware_install%s set", 1363219287Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1364219287Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1365219287Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1366219287Snp FW_VERSION_MAJOR, FW_VERSION_MINOR, 1367219287Snp FW_VERSION_MICRO, 1368219287Snp force_firmware_install ? "" : " not"); 1369219287Snp return (EAGAIN); 1370219287Snp } 1371219287Snp 1372219287Snp /* 1373219287Snp * Always upgrade, even for minor/micro/build mismatches. 1374219287Snp * Downgrade only for a major version mismatch or if 1375219287Snp * force_firmware_install was specified. 1376219287Snp */ 1377219287Snp if (fw != NULL && (rc < 0 || force_firmware_install || 1378219287Snp v > sc->params.fw_vers)) { 1379218792Snp device_printf(sc->dev, 1380219287Snp "installing firmware %d.%d.%d.%d on card.\n", 1381219287Snp G_FW_HDR_FW_VER_MAJOR(v), G_FW_HDR_FW_VER_MINOR(v), 1382219287Snp G_FW_HDR_FW_VER_MICRO(v), G_FW_HDR_FW_VER_BUILD(v)); 1383219287Snp 1384219287Snp rc = -t4_load_fw(sc, fw->data, fw->datasize); 1385219287Snp if (rc != 0) { 1386219287Snp device_printf(sc->dev, 1387219287Snp "failed to install firmware: %d\n", rc); 1388219287Snp firmware_put(fw, FIRMWARE_UNLOAD); 1389219287Snp return (rc); 1390219287Snp } else { 1391219287Snp /* refresh */ 1392219287Snp (void) t4_check_fw_version(sc); 1393219287Snp } 1394218792Snp } 1395218792Snp 1396219287Snp if (fw != NULL) 1397219287Snp firmware_put(fw, FIRMWARE_UNLOAD); 1398218792Snp } 1399218792Snp 1400218792Snp /* Contact firmware, request master */ 1401218792Snp rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MUST, &state); 1402218792Snp if (rc < 0) { 1403218792Snp rc = -rc; 1404218792Snp device_printf(sc->dev, 1405218792Snp "failed to connect to the firmware: %d.\n", rc); 1406218792Snp return (rc); 1407218792Snp } 1408218792Snp 1409218792Snp /* Reset device */ 1410218792Snp rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST); 1411218792Snp if (rc != 0) { 1412218792Snp device_printf(sc->dev, "firmware reset failed: %d.\n", rc); 1413218792Snp if (rc != ETIMEDOUT && rc != EIO) 1414218792Snp t4_fw_bye(sc, sc->mbox); 1415218792Snp return (rc); 1416218792Snp } 1417218792Snp 1418218792Snp snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u", 1419218792Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1420218792Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1421218792Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1422218792Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 1423218792Snp sc->flags |= FW_OK; 1424218792Snp 1425218792Snp return (0); 1426218792Snp} 1427218792Snp 1428218792Snpstatic int 1429222551Snpget_devlog_params(struct adapter *sc, struct devlog_params *dlog) 1430222551Snp{ 1431222551Snp struct fw_devlog_cmd devlog_cmd; 1432222551Snp uint32_t meminfo; 1433222551Snp int rc; 1434222551Snp 1435222551Snp bzero(&devlog_cmd, sizeof(devlog_cmd)); 1436222551Snp devlog_cmd.op_to_write = htobe32(V_FW_CMD_OP(FW_DEVLOG_CMD) | 1437222551Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1438222551Snp devlog_cmd.retval_len16 = htobe32(FW_LEN16(devlog_cmd)); 1439222551Snp rc = -t4_wr_mbox(sc, sc->mbox, &devlog_cmd, sizeof(devlog_cmd), 1440222551Snp &devlog_cmd); 1441222551Snp if (rc != 0) { 1442222551Snp device_printf(sc->dev, 1443222551Snp "failed to get devlog parameters: %d.\n", rc); 1444222551Snp bzero(dlog, sizeof (*dlog)); 1445222551Snp return (rc); 1446222551Snp } 1447222551Snp 1448222551Snp meminfo = be32toh(devlog_cmd.memtype_devlog_memaddr16_devlog); 1449222551Snp dlog->memtype = G_FW_DEVLOG_CMD_MEMTYPE_DEVLOG(meminfo); 1450222551Snp dlog->start = G_FW_DEVLOG_CMD_MEMADDR16_DEVLOG(meminfo) << 4; 1451222551Snp dlog->size = be32toh(devlog_cmd.memsize_devlog); 1452222551Snp 1453222551Snp return (0); 1454222551Snp} 1455222551Snp 1456222551Snpstatic int 1457218792Snpget_capabilities(struct adapter *sc, struct fw_caps_config_cmd *caps) 1458218792Snp{ 1459218792Snp int rc; 1460218792Snp 1461218792Snp bzero(caps, sizeof(*caps)); 1462218792Snp caps->op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1463218792Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1464218792Snp caps->retval_len16 = htobe32(FW_LEN16(*caps)); 1465218792Snp 1466218792Snp rc = -t4_wr_mbox(sc, sc->mbox, caps, sizeof(*caps), caps); 1467218792Snp if (rc != 0) 1468218792Snp return (rc); 1469218792Snp 1470218792Snp if (caps->niccaps & htobe16(FW_CAPS_CONFIG_NIC_VM)) 1471218792Snp caps->niccaps ^= htobe16(FW_CAPS_CONFIG_NIC_VM); 1472218792Snp 1473218792Snp caps->op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1474218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE); 1475218792Snp rc = -t4_wr_mbox(sc, sc->mbox, caps, sizeof(*caps), NULL); 1476218792Snp 1477218792Snp return (rc); 1478218792Snp} 1479218792Snp 1480218792Snpstatic int 1481218792Snpget_params(struct adapter *sc, struct fw_caps_config_cmd *caps) 1482218792Snp{ 1483218792Snp int rc; 1484218792Snp uint32_t params[7], val[7]; 1485218792Snp 1486218792Snp#define FW_PARAM_DEV(param) \ 1487218792Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ 1488218792Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) 1489218792Snp#define FW_PARAM_PFVF(param) \ 1490218792Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ 1491218792Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)) 1492218792Snp 1493218792Snp params[0] = FW_PARAM_DEV(PORTVEC); 1494218792Snp params[1] = FW_PARAM_PFVF(IQFLINT_START); 1495218792Snp params[2] = FW_PARAM_PFVF(EQ_START); 1496218792Snp params[3] = FW_PARAM_PFVF(FILTER_START); 1497218792Snp params[4] = FW_PARAM_PFVF(FILTER_END); 1498218792Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 5, params, val); 1499218792Snp if (rc != 0) { 1500218792Snp device_printf(sc->dev, 1501218792Snp "failed to query parameters: %d.\n", rc); 1502218792Snp goto done; 1503218792Snp } 1504218792Snp 1505218792Snp sc->params.portvec = val[0]; 1506218792Snp sc->params.nports = 0; 1507218792Snp while (val[0]) { 1508218792Snp sc->params.nports++; 1509218792Snp val[0] &= val[0] - 1; 1510218792Snp } 1511218792Snp 1512218792Snp sc->sge.iq_start = val[1]; 1513218792Snp sc->sge.eq_start = val[2]; 1514218792Snp sc->tids.ftid_base = val[3]; 1515218792Snp sc->tids.nftids = val[4] - val[3] + 1; 1516218792Snp 1517218792Snp if (caps->toecaps) { 1518218792Snp /* query offload-related parameters */ 1519218792Snp params[0] = FW_PARAM_DEV(NTID); 1520218792Snp params[1] = FW_PARAM_PFVF(SERVER_START); 1521218792Snp params[2] = FW_PARAM_PFVF(SERVER_END); 1522218792Snp params[3] = FW_PARAM_PFVF(TDDP_START); 1523218792Snp params[4] = FW_PARAM_PFVF(TDDP_END); 1524218792Snp params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 1525218792Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, params, val); 1526218792Snp if (rc != 0) { 1527218792Snp device_printf(sc->dev, 1528218792Snp "failed to query TOE parameters: %d.\n", rc); 1529218792Snp goto done; 1530218792Snp } 1531218792Snp sc->tids.ntids = val[0]; 1532218792Snp sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS); 1533218792Snp sc->tids.stid_base = val[1]; 1534218792Snp sc->tids.nstids = val[2] - val[1] + 1; 1535218792Snp sc->vres.ddp.start = val[3]; 1536218792Snp sc->vres.ddp.size = val[4] - val[3] + 1; 1537218792Snp sc->params.ofldq_wr_cred = val[5]; 1538218792Snp sc->params.offload = 1; 1539218792Snp } 1540218792Snp if (caps->rdmacaps) { 1541218792Snp params[0] = FW_PARAM_PFVF(STAG_START); 1542218792Snp params[1] = FW_PARAM_PFVF(STAG_END); 1543218792Snp params[2] = FW_PARAM_PFVF(RQ_START); 1544218792Snp params[3] = FW_PARAM_PFVF(RQ_END); 1545218792Snp params[4] = FW_PARAM_PFVF(PBL_START); 1546218792Snp params[5] = FW_PARAM_PFVF(PBL_END); 1547218792Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, params, val); 1548218792Snp if (rc != 0) { 1549218792Snp device_printf(sc->dev, 1550218792Snp "failed to query RDMA parameters: %d.\n", rc); 1551218792Snp goto done; 1552218792Snp } 1553218792Snp sc->vres.stag.start = val[0]; 1554218792Snp sc->vres.stag.size = val[1] - val[0] + 1; 1555218792Snp sc->vres.rq.start = val[2]; 1556218792Snp sc->vres.rq.size = val[3] - val[2] + 1; 1557218792Snp sc->vres.pbl.start = val[4]; 1558218792Snp sc->vres.pbl.size = val[5] - val[4] + 1; 1559218792Snp } 1560218792Snp if (caps->iscsicaps) { 1561218792Snp params[0] = FW_PARAM_PFVF(ISCSI_START); 1562218792Snp params[1] = FW_PARAM_PFVF(ISCSI_END); 1563218792Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, params, val); 1564218792Snp if (rc != 0) { 1565218792Snp device_printf(sc->dev, 1566218792Snp "failed to query iSCSI parameters: %d.\n", rc); 1567218792Snp goto done; 1568218792Snp } 1569218792Snp sc->vres.iscsi.start = val[0]; 1570218792Snp sc->vres.iscsi.size = val[1] - val[0] + 1; 1571218792Snp } 1572218792Snp#undef FW_PARAM_PFVF 1573218792Snp#undef FW_PARAM_DEV 1574218792Snp 1575218792Snpdone: 1576218792Snp return (rc); 1577218792Snp} 1578218792Snp 1579218792Snpstatic void 1580218792Snpt4_set_desc(struct adapter *sc) 1581218792Snp{ 1582218792Snp char buf[128]; 1583218792Snp struct adapter_params *p = &sc->params; 1584218792Snp 1585218792Snp snprintf(buf, sizeof(buf), 1586219944Snp "Chelsio %s (rev %d) %d port %sNIC PCIe-x%d %d %s, S/N:%s, E/C:%s", 1587218792Snp p->vpd.id, p->rev, p->nports, is_offload(sc) ? "R" : "", 1588219944Snp p->pci.width, sc->intr_count, sc->intr_type == INTR_MSIX ? "MSI-X" : 1589219944Snp (sc->intr_type == INTR_MSI ? "MSI" : "INTx"), p->vpd.sn, p->vpd.ec); 1590218792Snp 1591218792Snp device_set_desc_copy(sc->dev, buf); 1592218792Snp} 1593218792Snp 1594218792Snpstatic void 1595218792Snpbuild_medialist(struct port_info *pi) 1596218792Snp{ 1597218792Snp struct ifmedia *media = &pi->media; 1598218792Snp int data, m; 1599218792Snp 1600218792Snp PORT_LOCK(pi); 1601218792Snp 1602218792Snp ifmedia_removeall(media); 1603218792Snp 1604218792Snp m = IFM_ETHER | IFM_FDX; 1605218792Snp data = (pi->port_type << 8) | pi->mod_type; 1606218792Snp 1607218792Snp switch(pi->port_type) { 1608218792Snp case FW_PORT_TYPE_BT_XFI: 1609218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 1610218792Snp break; 1611218792Snp 1612218792Snp case FW_PORT_TYPE_BT_XAUI: 1613218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 1614218792Snp /* fall through */ 1615218792Snp 1616218792Snp case FW_PORT_TYPE_BT_SGMII: 1617218792Snp ifmedia_add(media, m | IFM_1000_T, data, NULL); 1618218792Snp ifmedia_add(media, m | IFM_100_TX, data, NULL); 1619218792Snp ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL); 1620218792Snp ifmedia_set(media, IFM_ETHER | IFM_AUTO); 1621218792Snp break; 1622218792Snp 1623218792Snp case FW_PORT_TYPE_CX4: 1624218792Snp ifmedia_add(media, m | IFM_10G_CX4, data, NULL); 1625218792Snp ifmedia_set(media, m | IFM_10G_CX4); 1626218792Snp break; 1627218792Snp 1628218792Snp case FW_PORT_TYPE_SFP: 1629218792Snp case FW_PORT_TYPE_FIBER_XFI: 1630218792Snp case FW_PORT_TYPE_FIBER_XAUI: 1631218792Snp switch (pi->mod_type) { 1632218792Snp 1633218792Snp case FW_PORT_MOD_TYPE_LR: 1634218792Snp ifmedia_add(media, m | IFM_10G_LR, data, NULL); 1635218792Snp ifmedia_set(media, m | IFM_10G_LR); 1636218792Snp break; 1637218792Snp 1638218792Snp case FW_PORT_MOD_TYPE_SR: 1639218792Snp ifmedia_add(media, m | IFM_10G_SR, data, NULL); 1640218792Snp ifmedia_set(media, m | IFM_10G_SR); 1641218792Snp break; 1642218792Snp 1643218792Snp case FW_PORT_MOD_TYPE_LRM: 1644218792Snp ifmedia_add(media, m | IFM_10G_LRM, data, NULL); 1645218792Snp ifmedia_set(media, m | IFM_10G_LRM); 1646218792Snp break; 1647218792Snp 1648218792Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 1649218792Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 1650218792Snp ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL); 1651218792Snp ifmedia_set(media, m | IFM_10G_TWINAX); 1652218792Snp break; 1653218792Snp 1654218792Snp case FW_PORT_MOD_TYPE_NONE: 1655218792Snp m &= ~IFM_FDX; 1656218792Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 1657218792Snp ifmedia_set(media, m | IFM_NONE); 1658218792Snp break; 1659218792Snp 1660218792Snp case FW_PORT_MOD_TYPE_NA: 1661218792Snp case FW_PORT_MOD_TYPE_ER: 1662218792Snp default: 1663218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 1664218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 1665218792Snp break; 1666218792Snp } 1667218792Snp break; 1668218792Snp 1669218792Snp case FW_PORT_TYPE_KX4: 1670218792Snp case FW_PORT_TYPE_KX: 1671218792Snp case FW_PORT_TYPE_KR: 1672218792Snp default: 1673218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 1674218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 1675218792Snp break; 1676218792Snp } 1677218792Snp 1678218792Snp PORT_UNLOCK(pi); 1679218792Snp} 1680218792Snp 1681218792Snp/* 1682218792Snp * Program the port's XGMAC based on parameters in ifnet. The caller also 1683218792Snp * indicates which parameters should be programmed (the rest are left alone). 1684218792Snp */ 1685218792Snpstatic int 1686218792Snpupdate_mac_settings(struct port_info *pi, int flags) 1687218792Snp{ 1688218792Snp int rc; 1689218792Snp struct ifnet *ifp = pi->ifp; 1690218792Snp struct adapter *sc = pi->adapter; 1691218792Snp int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1; 1692218792Snp 1693218792Snp PORT_LOCK_ASSERT_OWNED(pi); 1694218792Snp KASSERT(flags, ("%s: not told what to update.", __func__)); 1695218792Snp 1696218792Snp if (flags & XGMAC_MTU) 1697218792Snp mtu = ifp->if_mtu; 1698218792Snp 1699218792Snp if (flags & XGMAC_PROMISC) 1700218792Snp promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0; 1701218792Snp 1702218792Snp if (flags & XGMAC_ALLMULTI) 1703218792Snp allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0; 1704218792Snp 1705218792Snp if (flags & XGMAC_VLANEX) 1706218792Snp vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0; 1707218792Snp 1708218792Snp rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, mtu, promisc, allmulti, 1, 1709218792Snp vlanex, false); 1710218792Snp if (rc) { 1711218792Snp if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, rc); 1712218792Snp return (rc); 1713218792Snp } 1714218792Snp 1715218792Snp if (flags & XGMAC_UCADDR) { 1716218792Snp uint8_t ucaddr[ETHER_ADDR_LEN]; 1717218792Snp 1718218792Snp bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr)); 1719218792Snp rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, 1720218792Snp ucaddr, true, true); 1721218792Snp if (rc < 0) { 1722218792Snp rc = -rc; 1723218792Snp if_printf(ifp, "change_mac failed: %d\n", rc); 1724218792Snp return (rc); 1725218792Snp } else { 1726218792Snp pi->xact_addr_filt = rc; 1727218792Snp rc = 0; 1728218792Snp } 1729218792Snp } 1730218792Snp 1731218792Snp if (flags & XGMAC_MCADDRS) { 1732218792Snp const uint8_t *mcaddr; 1733218792Snp int del = 1; 1734218792Snp uint64_t hash = 0; 1735218792Snp struct ifmultiaddr *ifma; 1736218792Snp 1737218792Snp if_maddr_rlock(ifp); 1738218792Snp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1739218792Snp if (ifma->ifma_addr->sa_family != AF_LINK) 1740218792Snp continue; 1741218792Snp mcaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 1742218792Snp 1743218792Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, del, 1, 1744218792Snp &mcaddr, NULL, &hash, 0); 1745218792Snp if (rc < 0) { 1746218792Snp rc = -rc; 1747218792Snp if_printf(ifp, "failed to add mc address" 1748218792Snp " %02x:%02x:%02x:%02x:%02x:%02x rc=%d\n", 1749218792Snp mcaddr[0], mcaddr[1], mcaddr[2], mcaddr[3], 1750218792Snp mcaddr[4], mcaddr[5], rc); 1751218792Snp goto mcfail; 1752218792Snp } 1753218792Snp del = 0; 1754218792Snp } 1755218792Snp 1756218792Snp rc = -t4_set_addr_hash(sc, sc->mbox, pi->viid, 0, hash, 0); 1757218792Snp if (rc != 0) 1758218792Snp if_printf(ifp, "failed to set mc address hash: %d", rc); 1759218792Snpmcfail: 1760218792Snp if_maddr_runlock(ifp); 1761218792Snp } 1762218792Snp 1763218792Snp return (rc); 1764218792Snp} 1765218792Snp 1766218792Snpstatic int 1767218792Snpcxgbe_init_locked(struct port_info *pi) 1768218792Snp{ 1769218792Snp struct adapter *sc = pi->adapter; 1770218792Snp int rc = 0; 1771218792Snp 1772218792Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 1773218792Snp 1774218792Snp while (!IS_DOOMED(pi) && IS_BUSY(sc)) { 1775218792Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4init", 0)) { 1776218792Snp rc = EINTR; 1777218792Snp goto done; 1778218792Snp } 1779218792Snp } 1780218792Snp if (IS_DOOMED(pi)) { 1781218792Snp rc = ENXIO; 1782218792Snp goto done; 1783218792Snp } 1784218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 1785218792Snp 1786218792Snp /* Give up the adapter lock, port init code can sleep. */ 1787218792Snp SET_BUSY(sc); 1788218792Snp ADAPTER_UNLOCK(sc); 1789218792Snp 1790218792Snp rc = cxgbe_init_synchronized(pi); 1791218792Snp 1792218792Snpdone: 1793218792Snp ADAPTER_LOCK(sc); 1794218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 1795218792Snp CLR_BUSY(sc); 1796218792Snp wakeup_one(&sc->flags); 1797218792Snp ADAPTER_UNLOCK(sc); 1798218792Snp return (rc); 1799218792Snp} 1800218792Snp 1801218792Snpstatic int 1802218792Snpcxgbe_init_synchronized(struct port_info *pi) 1803218792Snp{ 1804218792Snp struct adapter *sc = pi->adapter; 1805218792Snp struct ifnet *ifp = pi->ifp; 1806218792Snp int rc = 0, i; 1807218792Snp uint16_t *rss; 1808218792Snp struct sge_rxq *rxq; 1809218792Snp 1810218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 1811218792Snp 1812218792Snp if (isset(&sc->open_device_map, pi->port_id)) { 1813218792Snp KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, 1814218792Snp ("mismatch between open_device_map and if_drv_flags")); 1815218792Snp return (0); /* already running */ 1816218792Snp } 1817218792Snp 1818218792Snp if (sc->open_device_map == 0 && ((rc = first_port_up(sc)) != 0)) 1819218792Snp return (rc); /* error message displayed already */ 1820218792Snp 1821218792Snp /* 1822218792Snp * Allocate tx/rx/fl queues for this port. 1823218792Snp */ 1824218792Snp rc = t4_setup_eth_queues(pi); 1825218792Snp if (rc != 0) 1826218792Snp goto done; /* error message displayed already */ 1827218792Snp 1828218792Snp /* 1829218792Snp * Setup RSS for this port. 1830218792Snp */ 1831218792Snp rss = malloc(pi->nrxq * sizeof (*rss), M_CXGBE, M_ZERO | M_WAITOK); 1832218792Snp for_each_rxq(pi, i, rxq) { 1833218792Snp rss[i] = rxq->iq.abs_id; 1834218792Snp } 1835218792Snp rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, pi->rss_size, rss, 1836218792Snp pi->nrxq); 1837218792Snp free(rss, M_CXGBE); 1838218792Snp if (rc != 0) { 1839218792Snp if_printf(ifp, "rss_config failed: %d\n", rc); 1840218792Snp goto done; 1841218792Snp } 1842218792Snp 1843218792Snp PORT_LOCK(pi); 1844218792Snp rc = update_mac_settings(pi, XGMAC_ALL); 1845218792Snp PORT_UNLOCK(pi); 1846218792Snp if (rc) 1847218792Snp goto done; /* error message displayed already */ 1848218792Snp 1849218792Snp rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg); 1850218792Snp if (rc != 0) { 1851218792Snp if_printf(ifp, "start_link failed: %d\n", rc); 1852218792Snp goto done; 1853218792Snp } 1854218792Snp 1855218792Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true); 1856218792Snp if (rc != 0) { 1857218792Snp if_printf(ifp, "enable_vi failed: %d\n", rc); 1858218792Snp goto done; 1859218792Snp } 1860218792Snp pi->flags |= VI_ENABLED; 1861218792Snp 1862218792Snp /* all ok */ 1863218792Snp setbit(&sc->open_device_map, pi->port_id); 1864218792Snp ifp->if_drv_flags |= IFF_DRV_RUNNING; 1865218792Snp ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1866218792Snp 1867218792Snp callout_reset(&pi->tick, hz, cxgbe_tick, pi); 1868218792Snpdone: 1869218792Snp if (rc != 0) 1870218792Snp cxgbe_uninit_synchronized(pi); 1871218792Snp 1872218792Snp return (rc); 1873218792Snp} 1874218792Snp 1875218792Snpstatic int 1876218792Snpcxgbe_uninit_locked(struct port_info *pi) 1877218792Snp{ 1878218792Snp struct adapter *sc = pi->adapter; 1879218792Snp int rc; 1880218792Snp 1881218792Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 1882218792Snp 1883218792Snp while (!IS_DOOMED(pi) && IS_BUSY(sc)) { 1884218792Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4uninit", 0)) { 1885218792Snp rc = EINTR; 1886218792Snp goto done; 1887218792Snp } 1888218792Snp } 1889218792Snp if (IS_DOOMED(pi)) { 1890218792Snp rc = ENXIO; 1891218792Snp goto done; 1892218792Snp } 1893218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 1894218792Snp SET_BUSY(sc); 1895218792Snp ADAPTER_UNLOCK(sc); 1896218792Snp 1897218792Snp rc = cxgbe_uninit_synchronized(pi); 1898218792Snp 1899218792Snp ADAPTER_LOCK(sc); 1900218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 1901218792Snp CLR_BUSY(sc); 1902218792Snp wakeup_one(&sc->flags); 1903218792Snpdone: 1904218792Snp ADAPTER_UNLOCK(sc); 1905218792Snp return (rc); 1906218792Snp} 1907218792Snp 1908218792Snp/* 1909218792Snp * Idempotent. 1910218792Snp */ 1911218792Snpstatic int 1912218792Snpcxgbe_uninit_synchronized(struct port_info *pi) 1913218792Snp{ 1914218792Snp struct adapter *sc = pi->adapter; 1915218792Snp struct ifnet *ifp = pi->ifp; 1916218792Snp int rc; 1917218792Snp 1918218792Snp /* 1919218792Snp * taskqueue_drain may cause a deadlock if the adapter lock is held. 1920218792Snp */ 1921218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 1922218792Snp 1923218792Snp /* 1924218792Snp * Clear this port's bit from the open device map, and then drain 1925218792Snp * tasks and callouts. 1926218792Snp */ 1927218792Snp clrbit(&sc->open_device_map, pi->port_id); 1928218792Snp 1929218792Snp PORT_LOCK(pi); 1930218792Snp ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1931218792Snp callout_stop(&pi->tick); 1932218792Snp PORT_UNLOCK(pi); 1933218792Snp callout_drain(&pi->tick); 1934218792Snp 1935218792Snp /* 1936218792Snp * Stop and then free the queues' resources, including the queues 1937218792Snp * themselves. 1938218792Snp * 1939218792Snp * XXX: we could just stop the queues here (on ifconfig down) and free 1940218792Snp * them later (on port detach), but having up/down go through the entire 1941218792Snp * allocate/activate/deactivate/free sequence is a good way to find 1942218792Snp * leaks and bugs. 1943218792Snp */ 1944218792Snp rc = t4_teardown_eth_queues(pi); 1945218792Snp if (rc != 0) 1946218792Snp if_printf(ifp, "teardown failed: %d\n", rc); 1947218792Snp 1948218792Snp if (pi->flags & VI_ENABLED) { 1949218792Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false); 1950218792Snp if (rc) 1951218792Snp if_printf(ifp, "disable_vi failed: %d\n", rc); 1952218792Snp else 1953218792Snp pi->flags &= ~VI_ENABLED; 1954218792Snp } 1955218792Snp 1956218792Snp pi->link_cfg.link_ok = 0; 1957218792Snp pi->link_cfg.speed = 0; 1958218792Snp t4_os_link_changed(sc, pi->port_id, 0); 1959218792Snp 1960218792Snp if (sc->open_device_map == 0) 1961218792Snp last_port_down(sc); 1962218792Snp 1963218792Snp return (0); 1964218792Snp} 1965218792Snp 1966222510Snp#define T4_ALLOC_IRQ(sc, irq, rid, handler, arg, name) do { \ 1967222510Snp rc = t4_alloc_irq(sc, irq, rid, handler, arg, name); \ 1968218792Snp if (rc != 0) \ 1969218792Snp goto done; \ 1970218792Snp} while (0) 1971218792Snpstatic int 1972218792Snpfirst_port_up(struct adapter *sc) 1973218792Snp{ 1974222510Snp int rc, i, rid, p, q; 1975222510Snp char s[8]; 1976222510Snp struct irq *irq; 1977222510Snp struct sge_iq *intrq; 1978218792Snp 1979218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 1980218792Snp 1981218792Snp /* 1982220873Snp * queues that belong to the adapter (not any particular port). 1983218792Snp */ 1984220873Snp rc = t4_setup_adapter_queues(sc); 1985218792Snp if (rc != 0) 1986218792Snp goto done; 1987218792Snp 1988218792Snp /* 1989218792Snp * Setup interrupts. 1990218792Snp */ 1991222510Snp irq = &sc->irq[0]; 1992222510Snp rid = sc->intr_type == INTR_INTX ? 0 : 1; 1993218792Snp if (sc->intr_count == 1) { 1994222510Snp KASSERT(sc->flags & INTR_SHARED, 1995222510Snp ("%s: single interrupt but not shared?", __func__)); 1996222510Snp 1997222510Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr_all, sc, "all"); 1998218792Snp } else { 1999218792Snp /* Multiple interrupts. The first one is always error intr */ 2000222510Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr_err, sc, "err"); 2001222510Snp irq++; 2002222510Snp rid++; 2003218792Snp 2004222510Snp /* Firmware event queue normally has an interrupt of its own */ 2005222510Snp if (sc->intr_count > T4_EXTRA_INTR) { 2006222510Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr_evt, &sc->sge.fwq, 2007222510Snp "evt"); 2008222510Snp irq++; 2009222510Snp rid++; 2010222510Snp } 2011222510Snp 2012222510Snp intrq = &sc->sge.intrq[0]; 2013222510Snp if (sc->flags & INTR_SHARED) { 2014222510Snp 2015222510Snp /* All ports share these interrupt queues */ 2016222510Snp 2017222510Snp for (i = 0; i < NINTRQ(sc); i++) { 2018222510Snp snprintf(s, sizeof(s), "*.%d", i); 2019222510Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr, intrq, s); 2020222510Snp irq++; 2021222510Snp rid++; 2022222510Snp intrq++; 2023218792Snp } 2024218792Snp } else { 2025218792Snp 2026222510Snp /* Each port has its own set of interrupt queues */ 2027218792Snp 2028222510Snp for (p = 0; p < sc->params.nports; p++) { 2029222510Snp for (q = 0; q < sc->port[p]->nrxq; q++) { 2030222510Snp snprintf(s, sizeof(s), "%d.%d", p, q); 2031222510Snp T4_ALLOC_IRQ(sc, irq, rid, t4_intr, 2032222510Snp intrq, s); 2033222510Snp irq++; 2034222510Snp rid++; 2035222510Snp intrq++; 2036218792Snp } 2037218792Snp } 2038218792Snp } 2039218792Snp } 2040218792Snp 2041218792Snp t4_intr_enable(sc); 2042218792Snp sc->flags |= FULL_INIT_DONE; 2043218792Snp 2044218792Snpdone: 2045218792Snp if (rc != 0) 2046218792Snp last_port_down(sc); 2047218792Snp 2048218792Snp return (rc); 2049218792Snp} 2050218792Snp#undef T4_ALLOC_IRQ 2051218792Snp 2052218792Snp/* 2053218792Snp * Idempotent. 2054218792Snp */ 2055218792Snpstatic int 2056218792Snplast_port_down(struct adapter *sc) 2057218792Snp{ 2058218792Snp int i; 2059218792Snp 2060218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 2061218792Snp 2062218792Snp t4_intr_disable(sc); 2063218792Snp 2064220873Snp t4_teardown_adapter_queues(sc); 2065218792Snp 2066218792Snp for (i = 0; i < sc->intr_count; i++) 2067218792Snp t4_free_irq(sc, &sc->irq[i]); 2068218792Snp 2069218792Snp sc->flags &= ~FULL_INIT_DONE; 2070218792Snp 2071218792Snp return (0); 2072218792Snp} 2073218792Snp 2074218792Snpstatic int 2075218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid, 2076218792Snp iq_intr_handler_t *handler, void *arg, char *name) 2077218792Snp{ 2078218792Snp int rc; 2079218792Snp 2080218792Snp irq->rid = rid; 2081218792Snp irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid, 2082218792Snp RF_SHAREABLE | RF_ACTIVE); 2083218792Snp if (irq->res == NULL) { 2084218792Snp device_printf(sc->dev, 2085218792Snp "failed to allocate IRQ for rid %d, name %s.\n", rid, name); 2086218792Snp return (ENOMEM); 2087218792Snp } 2088218792Snp 2089218792Snp rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET, 2090218792Snp NULL, handler, arg, &irq->tag); 2091218792Snp if (rc != 0) { 2092218792Snp device_printf(sc->dev, 2093218792Snp "failed to setup interrupt for rid %d, name %s: %d\n", 2094218792Snp rid, name, rc); 2095218792Snp } else if (name) 2096218792Snp bus_describe_intr(sc->dev, irq->res, irq->tag, name); 2097218792Snp 2098218792Snp return (rc); 2099218792Snp} 2100218792Snp 2101218792Snpstatic int 2102218792Snpt4_free_irq(struct adapter *sc, struct irq *irq) 2103218792Snp{ 2104218792Snp if (irq->tag) 2105218792Snp bus_teardown_intr(sc->dev, irq->res, irq->tag); 2106218792Snp if (irq->res) 2107218792Snp bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res); 2108218792Snp 2109218792Snp bzero(irq, sizeof(*irq)); 2110218792Snp 2111218792Snp return (0); 2112218792Snp} 2113218792Snp 2114218792Snpstatic void 2115218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start, 2116218792Snp unsigned int end) 2117218792Snp{ 2118218792Snp uint32_t *p = (uint32_t *)(buf + start); 2119218792Snp 2120218792Snp for ( ; start <= end; start += sizeof(uint32_t)) 2121218792Snp *p++ = t4_read_reg(sc, start); 2122218792Snp} 2123218792Snp 2124218792Snpstatic void 2125218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf) 2126218792Snp{ 2127218792Snp int i; 2128218792Snp static const unsigned int reg_ranges[] = { 2129218792Snp 0x1008, 0x1108, 2130218792Snp 0x1180, 0x11b4, 2131218792Snp 0x11fc, 0x123c, 2132218792Snp 0x1300, 0x173c, 2133218792Snp 0x1800, 0x18fc, 2134218792Snp 0x3000, 0x30d8, 2135218792Snp 0x30e0, 0x5924, 2136218792Snp 0x5960, 0x59d4, 2137218792Snp 0x5a00, 0x5af8, 2138218792Snp 0x6000, 0x6098, 2139218792Snp 0x6100, 0x6150, 2140218792Snp 0x6200, 0x6208, 2141218792Snp 0x6240, 0x6248, 2142218792Snp 0x6280, 0x6338, 2143218792Snp 0x6370, 0x638c, 2144218792Snp 0x6400, 0x643c, 2145218792Snp 0x6500, 0x6524, 2146218792Snp 0x6a00, 0x6a38, 2147218792Snp 0x6a60, 0x6a78, 2148218792Snp 0x6b00, 0x6b84, 2149218792Snp 0x6bf0, 0x6c84, 2150218792Snp 0x6cf0, 0x6d84, 2151218792Snp 0x6df0, 0x6e84, 2152218792Snp 0x6ef0, 0x6f84, 2153218792Snp 0x6ff0, 0x7084, 2154218792Snp 0x70f0, 0x7184, 2155218792Snp 0x71f0, 0x7284, 2156218792Snp 0x72f0, 0x7384, 2157218792Snp 0x73f0, 0x7450, 2158218792Snp 0x7500, 0x7530, 2159218792Snp 0x7600, 0x761c, 2160218792Snp 0x7680, 0x76cc, 2161218792Snp 0x7700, 0x7798, 2162218792Snp 0x77c0, 0x77fc, 2163218792Snp 0x7900, 0x79fc, 2164218792Snp 0x7b00, 0x7c38, 2165218792Snp 0x7d00, 0x7efc, 2166218792Snp 0x8dc0, 0x8e1c, 2167218792Snp 0x8e30, 0x8e78, 2168218792Snp 0x8ea0, 0x8f6c, 2169218792Snp 0x8fc0, 0x9074, 2170218792Snp 0x90fc, 0x90fc, 2171218792Snp 0x9400, 0x9458, 2172218792Snp 0x9600, 0x96bc, 2173218792Snp 0x9800, 0x9808, 2174218792Snp 0x9820, 0x983c, 2175218792Snp 0x9850, 0x9864, 2176218792Snp 0x9c00, 0x9c6c, 2177218792Snp 0x9c80, 0x9cec, 2178218792Snp 0x9d00, 0x9d6c, 2179218792Snp 0x9d80, 0x9dec, 2180218792Snp 0x9e00, 0x9e6c, 2181218792Snp 0x9e80, 0x9eec, 2182218792Snp 0x9f00, 0x9f6c, 2183218792Snp 0x9f80, 0x9fec, 2184218792Snp 0xd004, 0xd03c, 2185218792Snp 0xdfc0, 0xdfe0, 2186218792Snp 0xe000, 0xea7c, 2187218792Snp 0xf000, 0x11190, 2188218792Snp 0x19040, 0x19124, 2189218792Snp 0x19150, 0x191b0, 2190218792Snp 0x191d0, 0x191e8, 2191218792Snp 0x19238, 0x1924c, 2192218792Snp 0x193f8, 0x19474, 2193218792Snp 0x19490, 0x194f8, 2194218792Snp 0x19800, 0x19f30, 2195218792Snp 0x1a000, 0x1a06c, 2196218792Snp 0x1a0b0, 0x1a120, 2197218792Snp 0x1a128, 0x1a138, 2198218792Snp 0x1a190, 0x1a1c4, 2199218792Snp 0x1a1fc, 0x1a1fc, 2200218792Snp 0x1e040, 0x1e04c, 2201218792Snp 0x1e240, 0x1e28c, 2202218792Snp 0x1e2c0, 0x1e2c0, 2203218792Snp 0x1e2e0, 0x1e2e0, 2204218792Snp 0x1e300, 0x1e384, 2205218792Snp 0x1e3c0, 0x1e3c8, 2206218792Snp 0x1e440, 0x1e44c, 2207218792Snp 0x1e640, 0x1e68c, 2208218792Snp 0x1e6c0, 0x1e6c0, 2209218792Snp 0x1e6e0, 0x1e6e0, 2210218792Snp 0x1e700, 0x1e784, 2211218792Snp 0x1e7c0, 0x1e7c8, 2212218792Snp 0x1e840, 0x1e84c, 2213218792Snp 0x1ea40, 0x1ea8c, 2214218792Snp 0x1eac0, 0x1eac0, 2215218792Snp 0x1eae0, 0x1eae0, 2216218792Snp 0x1eb00, 0x1eb84, 2217218792Snp 0x1ebc0, 0x1ebc8, 2218218792Snp 0x1ec40, 0x1ec4c, 2219218792Snp 0x1ee40, 0x1ee8c, 2220218792Snp 0x1eec0, 0x1eec0, 2221218792Snp 0x1eee0, 0x1eee0, 2222218792Snp 0x1ef00, 0x1ef84, 2223218792Snp 0x1efc0, 0x1efc8, 2224218792Snp 0x1f040, 0x1f04c, 2225218792Snp 0x1f240, 0x1f28c, 2226218792Snp 0x1f2c0, 0x1f2c0, 2227218792Snp 0x1f2e0, 0x1f2e0, 2228218792Snp 0x1f300, 0x1f384, 2229218792Snp 0x1f3c0, 0x1f3c8, 2230218792Snp 0x1f440, 0x1f44c, 2231218792Snp 0x1f640, 0x1f68c, 2232218792Snp 0x1f6c0, 0x1f6c0, 2233218792Snp 0x1f6e0, 0x1f6e0, 2234218792Snp 0x1f700, 0x1f784, 2235218792Snp 0x1f7c0, 0x1f7c8, 2236218792Snp 0x1f840, 0x1f84c, 2237218792Snp 0x1fa40, 0x1fa8c, 2238218792Snp 0x1fac0, 0x1fac0, 2239218792Snp 0x1fae0, 0x1fae0, 2240218792Snp 0x1fb00, 0x1fb84, 2241218792Snp 0x1fbc0, 0x1fbc8, 2242218792Snp 0x1fc40, 0x1fc4c, 2243218792Snp 0x1fe40, 0x1fe8c, 2244218792Snp 0x1fec0, 0x1fec0, 2245218792Snp 0x1fee0, 0x1fee0, 2246218792Snp 0x1ff00, 0x1ff84, 2247218792Snp 0x1ffc0, 0x1ffc8, 2248218792Snp 0x20000, 0x2002c, 2249218792Snp 0x20100, 0x2013c, 2250218792Snp 0x20190, 0x201c8, 2251218792Snp 0x20200, 0x20318, 2252218792Snp 0x20400, 0x20528, 2253218792Snp 0x20540, 0x20614, 2254218792Snp 0x21000, 0x21040, 2255218792Snp 0x2104c, 0x21060, 2256218792Snp 0x210c0, 0x210ec, 2257218792Snp 0x21200, 0x21268, 2258218792Snp 0x21270, 0x21284, 2259218792Snp 0x212fc, 0x21388, 2260218792Snp 0x21400, 0x21404, 2261218792Snp 0x21500, 0x21518, 2262218792Snp 0x2152c, 0x2153c, 2263218792Snp 0x21550, 0x21554, 2264218792Snp 0x21600, 0x21600, 2265218792Snp 0x21608, 0x21628, 2266218792Snp 0x21630, 0x2163c, 2267218792Snp 0x21700, 0x2171c, 2268218792Snp 0x21780, 0x2178c, 2269218792Snp 0x21800, 0x21c38, 2270218792Snp 0x21c80, 0x21d7c, 2271218792Snp 0x21e00, 0x21e04, 2272218792Snp 0x22000, 0x2202c, 2273218792Snp 0x22100, 0x2213c, 2274218792Snp 0x22190, 0x221c8, 2275218792Snp 0x22200, 0x22318, 2276218792Snp 0x22400, 0x22528, 2277218792Snp 0x22540, 0x22614, 2278218792Snp 0x23000, 0x23040, 2279218792Snp 0x2304c, 0x23060, 2280218792Snp 0x230c0, 0x230ec, 2281218792Snp 0x23200, 0x23268, 2282218792Snp 0x23270, 0x23284, 2283218792Snp 0x232fc, 0x23388, 2284218792Snp 0x23400, 0x23404, 2285218792Snp 0x23500, 0x23518, 2286218792Snp 0x2352c, 0x2353c, 2287218792Snp 0x23550, 0x23554, 2288218792Snp 0x23600, 0x23600, 2289218792Snp 0x23608, 0x23628, 2290218792Snp 0x23630, 0x2363c, 2291218792Snp 0x23700, 0x2371c, 2292218792Snp 0x23780, 0x2378c, 2293218792Snp 0x23800, 0x23c38, 2294218792Snp 0x23c80, 0x23d7c, 2295218792Snp 0x23e00, 0x23e04, 2296218792Snp 0x24000, 0x2402c, 2297218792Snp 0x24100, 0x2413c, 2298218792Snp 0x24190, 0x241c8, 2299218792Snp 0x24200, 0x24318, 2300218792Snp 0x24400, 0x24528, 2301218792Snp 0x24540, 0x24614, 2302218792Snp 0x25000, 0x25040, 2303218792Snp 0x2504c, 0x25060, 2304218792Snp 0x250c0, 0x250ec, 2305218792Snp 0x25200, 0x25268, 2306218792Snp 0x25270, 0x25284, 2307218792Snp 0x252fc, 0x25388, 2308218792Snp 0x25400, 0x25404, 2309218792Snp 0x25500, 0x25518, 2310218792Snp 0x2552c, 0x2553c, 2311218792Snp 0x25550, 0x25554, 2312218792Snp 0x25600, 0x25600, 2313218792Snp 0x25608, 0x25628, 2314218792Snp 0x25630, 0x2563c, 2315218792Snp 0x25700, 0x2571c, 2316218792Snp 0x25780, 0x2578c, 2317218792Snp 0x25800, 0x25c38, 2318218792Snp 0x25c80, 0x25d7c, 2319218792Snp 0x25e00, 0x25e04, 2320218792Snp 0x26000, 0x2602c, 2321218792Snp 0x26100, 0x2613c, 2322218792Snp 0x26190, 0x261c8, 2323218792Snp 0x26200, 0x26318, 2324218792Snp 0x26400, 0x26528, 2325218792Snp 0x26540, 0x26614, 2326218792Snp 0x27000, 0x27040, 2327218792Snp 0x2704c, 0x27060, 2328218792Snp 0x270c0, 0x270ec, 2329218792Snp 0x27200, 0x27268, 2330218792Snp 0x27270, 0x27284, 2331218792Snp 0x272fc, 0x27388, 2332218792Snp 0x27400, 0x27404, 2333218792Snp 0x27500, 0x27518, 2334218792Snp 0x2752c, 0x2753c, 2335218792Snp 0x27550, 0x27554, 2336218792Snp 0x27600, 0x27600, 2337218792Snp 0x27608, 0x27628, 2338218792Snp 0x27630, 0x2763c, 2339218792Snp 0x27700, 0x2771c, 2340218792Snp 0x27780, 0x2778c, 2341218792Snp 0x27800, 0x27c38, 2342218792Snp 0x27c80, 0x27d7c, 2343218792Snp 0x27e00, 0x27e04 2344218792Snp }; 2345218792Snp 2346218792Snp regs->version = 4 | (sc->params.rev << 10); 2347218792Snp for (i = 0; i < ARRAY_SIZE(reg_ranges); i += 2) 2348218792Snp reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]); 2349218792Snp} 2350218792Snp 2351218792Snpstatic void 2352218792Snpcxgbe_tick(void *arg) 2353218792Snp{ 2354218792Snp struct port_info *pi = arg; 2355218792Snp struct ifnet *ifp = pi->ifp; 2356218792Snp struct sge_txq *txq; 2357218792Snp int i, drops; 2358218792Snp struct port_stats *s = &pi->stats; 2359218792Snp 2360218792Snp PORT_LOCK(pi); 2361218792Snp if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2362218792Snp PORT_UNLOCK(pi); 2363218792Snp return; /* without scheduling another callout */ 2364218792Snp } 2365218792Snp 2366218792Snp t4_get_port_stats(pi->adapter, pi->tx_chan, s); 2367218792Snp 2368218792Snp ifp->if_opackets = s->tx_frames; 2369218792Snp ifp->if_ipackets = s->rx_frames; 2370218792Snp ifp->if_obytes = s->tx_octets; 2371218792Snp ifp->if_ibytes = s->rx_octets; 2372218792Snp ifp->if_omcasts = s->tx_mcast_frames; 2373218792Snp ifp->if_imcasts = s->rx_mcast_frames; 2374218792Snp ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 + 2375218792Snp s->rx_ovflow3; 2376218792Snp 2377218792Snp drops = s->tx_drop; 2378218792Snp for_each_txq(pi, i, txq) 2379220873Snp drops += txq->br->br_drops; 2380218792Snp ifp->if_snd.ifq_drops = drops; 2381218792Snp 2382218792Snp ifp->if_oerrors = s->tx_error_frames; 2383218792Snp ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long + 2384218792Snp s->rx_fcs_err + s->rx_len_err; 2385218792Snp 2386218792Snp callout_schedule(&pi->tick, hz); 2387218792Snp PORT_UNLOCK(pi); 2388218792Snp} 2389218792Snp 2390218792Snpstatic int 2391218792Snpt4_sysctls(struct adapter *sc) 2392218792Snp{ 2393218792Snp struct sysctl_ctx_list *ctx; 2394218792Snp struct sysctl_oid *oid; 2395218792Snp struct sysctl_oid_list *children; 2396218792Snp 2397218792Snp ctx = device_get_sysctl_ctx(sc->dev); 2398218792Snp oid = device_get_sysctl_tree(sc->dev); 2399218792Snp children = SYSCTL_CHILDREN(oid); 2400218792Snp 2401218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, 2402218792Snp &sc->params.nports, 0, "# of ports"); 2403218792Snp 2404218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD, 2405218792Snp &sc->params.rev, 0, "chip hardware revision"); 2406218792Snp 2407218792Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 2408218792Snp CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 2409218792Snp 2410218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "TOE", CTLFLAG_RD, 2411218792Snp &sc->params.offload, 0, "hardware is capable of TCP offload"); 2412218792Snp 2413218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, 2414218792Snp &sc->params.vpd.cclk, 0, "core clock frequency (in KHz)"); 2415218792Snp 2416219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers", 2417219436Snp CTLTYPE_STRING | CTLFLAG_RD, &intr_timer, sizeof(intr_timer), 2418219436Snp sysctl_int_array, "A", "interrupt holdoff timer values (us)"); 2419218792Snp 2420219436Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts", 2421219436Snp CTLTYPE_STRING | CTLFLAG_RD, &intr_pktcount, sizeof(intr_pktcount), 2422219436Snp sysctl_int_array, "A", "interrupt holdoff packet counter values"); 2423218792Snp 2424222551Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "devlog", 2425222551Snp CTLTYPE_STRING | CTLFLAG_RD, sc, 0, 2426222551Snp sysctl_devlog, "A", "device log"); 2427222551Snp 2428218792Snp return (0); 2429218792Snp} 2430218792Snp 2431218792Snpstatic int 2432218792Snpcxgbe_sysctls(struct port_info *pi) 2433218792Snp{ 2434218792Snp struct sysctl_ctx_list *ctx; 2435218792Snp struct sysctl_oid *oid; 2436218792Snp struct sysctl_oid_list *children; 2437218792Snp 2438218792Snp ctx = device_get_sysctl_ctx(pi->dev); 2439218792Snp 2440218792Snp /* 2441218792Snp * dev.cxgbe.X. 2442218792Snp */ 2443218792Snp oid = device_get_sysctl_tree(pi->dev); 2444218792Snp children = SYSCTL_CHILDREN(oid); 2445218792Snp 2446218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD, 2447218792Snp &pi->nrxq, 0, "# of rx queues"); 2448218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD, 2449218792Snp &pi->ntxq, 0, "# of tx queues"); 2450218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD, 2451218792Snp &pi->first_rxq, 0, "index of first rx queue"); 2452218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD, 2453218792Snp &pi->first_txq, 0, "index of first tx queue"); 2454218792Snp 2455218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx", 2456218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I", 2457218792Snp "holdoff timer index"); 2458218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx", 2459218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I", 2460218792Snp "holdoff packet counter index"); 2461218792Snp 2462218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq", 2463218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I", 2464218792Snp "rx queue size"); 2465218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq", 2466218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I", 2467218792Snp "tx queue size"); 2468218792Snp 2469218792Snp /* 2470218792Snp * dev.cxgbe.X.stats. 2471218792Snp */ 2472218792Snp oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, 2473218792Snp NULL, "port statistics"); 2474218792Snp children = SYSCTL_CHILDREN(oid); 2475218792Snp 2476218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \ 2477218792Snp SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \ 2478218792Snp CTLTYPE_U64 | CTLFLAG_RD, pi->adapter, reg, \ 2479218792Snp sysctl_handle_t4_reg64, "QU", desc) 2480218792Snp 2481218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames", 2482218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L)); 2483218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames", 2484218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L)); 2485218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames", 2486218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L)); 2487218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames", 2488218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L)); 2489218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames", 2490218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L)); 2491218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames", 2492218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L)); 2493218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_64", 2494218792Snp "# of tx frames in this range", 2495218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L)); 2496218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127", 2497218792Snp "# of tx frames in this range", 2498218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L)); 2499218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255", 2500218792Snp "# of tx frames in this range", 2501218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L)); 2502218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511", 2503218792Snp "# of tx frames in this range", 2504218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L)); 2505218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023", 2506218792Snp "# of tx frames in this range", 2507218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L)); 2508218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518", 2509218792Snp "# of tx frames in this range", 2510218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L)); 2511218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max", 2512218792Snp "# of tx frames in this range", 2513218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L)); 2514218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames", 2515218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L)); 2516218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted", 2517218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L)); 2518218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted", 2519218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L)); 2520218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted", 2521218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L)); 2522218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted", 2523218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L)); 2524218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted", 2525218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L)); 2526218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted", 2527218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L)); 2528218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted", 2529218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L)); 2530218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted", 2531218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L)); 2532218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted", 2533218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L)); 2534218792Snp 2535218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames", 2536218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L)); 2537218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames", 2538218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L)); 2539218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames", 2540218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L)); 2541218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames", 2542218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L)); 2543218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames", 2544218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L)); 2545218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU", 2546218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L)); 2547218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames", 2548218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L)); 2549218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err", 2550218792Snp "# of frames received with bad FCS", 2551218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L)); 2552218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_len_err", 2553218792Snp "# of frames received with length error", 2554218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L)); 2555218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors", 2556218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L)); 2557218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received", 2558218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L)); 2559218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_64", 2560218792Snp "# of rx frames in this range", 2561218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L)); 2562218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127", 2563218792Snp "# of rx frames in this range", 2564218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L)); 2565218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255", 2566218792Snp "# of rx frames in this range", 2567218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L)); 2568218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511", 2569218792Snp "# of rx frames in this range", 2570218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L)); 2571218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023", 2572218792Snp "# of rx frames in this range", 2573218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L)); 2574218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518", 2575218792Snp "# of rx frames in this range", 2576218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L)); 2577218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max", 2578218792Snp "# of rx frames in this range", 2579218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L)); 2580218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received", 2581218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L)); 2582218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received", 2583218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L)); 2584218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received", 2585218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L)); 2586218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received", 2587218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L)); 2588218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received", 2589218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L)); 2590218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received", 2591218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L)); 2592218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received", 2593218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L)); 2594218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received", 2595218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L)); 2596218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received", 2597218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L)); 2598218792Snp 2599218792Snp#undef SYSCTL_ADD_T4_REG64 2600218792Snp 2601218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \ 2602218792Snp SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \ 2603218792Snp &pi->stats.name, desc) 2604218792Snp 2605218792Snp /* We get these from port_stats and they may be stale by upto 1s */ 2606218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0, 2607218792Snp "# drops due to buffer-group 0 overflows"); 2608218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1, 2609218792Snp "# drops due to buffer-group 1 overflows"); 2610218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2, 2611218792Snp "# drops due to buffer-group 2 overflows"); 2612218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3, 2613218792Snp "# drops due to buffer-group 3 overflows"); 2614218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc0, 2615218792Snp "# of buffer-group 0 truncated packets"); 2616218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc1, 2617218792Snp "# of buffer-group 1 truncated packets"); 2618218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc2, 2619218792Snp "# of buffer-group 2 truncated packets"); 2620218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc3, 2621218792Snp "# of buffer-group 3 truncated packets"); 2622218792Snp 2623218792Snp#undef SYSCTL_ADD_T4_PORTSTAT 2624218792Snp 2625218792Snp return (0); 2626218792Snp} 2627218792Snp 2628218792Snpstatic int 2629219436Snpsysctl_int_array(SYSCTL_HANDLER_ARGS) 2630219436Snp{ 2631219436Snp int rc, *i; 2632219436Snp struct sbuf sb; 2633219436Snp 2634219436Snp sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND); 2635219436Snp for (i = arg1; arg2; arg2 -= sizeof(int), i++) 2636219436Snp sbuf_printf(&sb, "%d ", *i); 2637219436Snp sbuf_trim(&sb); 2638219436Snp sbuf_finish(&sb); 2639219436Snp rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); 2640219436Snp sbuf_delete(&sb); 2641219436Snp return (rc); 2642219436Snp} 2643219436Snp 2644219436Snpstatic int 2645218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS) 2646218792Snp{ 2647218792Snp struct port_info *pi = arg1; 2648218792Snp struct adapter *sc = pi->adapter; 2649218792Snp struct sge_rxq *rxq; 2650218792Snp int idx, rc, i; 2651218792Snp 2652218792Snp idx = pi->tmr_idx; 2653218792Snp 2654218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 2655218792Snp if (rc != 0 || req->newptr == NULL) 2656218792Snp return (rc); 2657218792Snp 2658218792Snp if (idx < 0 || idx >= SGE_NTIMERS) 2659218792Snp return (EINVAL); 2660218792Snp 2661218792Snp ADAPTER_LOCK(sc); 2662218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 2663218792Snp if (rc == 0) { 2664218792Snp for_each_rxq(pi, i, rxq) { 2665218792Snp rxq->iq.intr_params = V_QINTR_TIMER_IDX(idx) | 2666218792Snp V_QINTR_CNT_EN(pi->pktc_idx != -1); 2667218792Snp } 2668218792Snp pi->tmr_idx = idx; 2669218792Snp } 2670218792Snp 2671218792Snp ADAPTER_UNLOCK(sc); 2672218792Snp return (rc); 2673218792Snp} 2674218792Snp 2675218792Snpstatic int 2676218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS) 2677218792Snp{ 2678218792Snp struct port_info *pi = arg1; 2679218792Snp struct adapter *sc = pi->adapter; 2680218792Snp int idx, rc; 2681218792Snp 2682218792Snp idx = pi->pktc_idx; 2683218792Snp 2684218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 2685218792Snp if (rc != 0 || req->newptr == NULL) 2686218792Snp return (rc); 2687218792Snp 2688218792Snp if (idx < -1 || idx >= SGE_NCOUNTERS) 2689218792Snp return (EINVAL); 2690218792Snp 2691218792Snp ADAPTER_LOCK(sc); 2692218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 2693218792Snp if (rc == 0 && pi->ifp->if_drv_flags & IFF_DRV_RUNNING) 2694218792Snp rc = EBUSY; /* can be changed only when port is down */ 2695218792Snp 2696218792Snp if (rc == 0) 2697218792Snp pi->pktc_idx = idx; 2698218792Snp 2699218792Snp ADAPTER_UNLOCK(sc); 2700218792Snp return (rc); 2701218792Snp} 2702218792Snp 2703218792Snpstatic int 2704218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS) 2705218792Snp{ 2706218792Snp struct port_info *pi = arg1; 2707218792Snp struct adapter *sc = pi->adapter; 2708218792Snp int qsize, rc; 2709218792Snp 2710218792Snp qsize = pi->qsize_rxq; 2711218792Snp 2712218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 2713218792Snp if (rc != 0 || req->newptr == NULL) 2714218792Snp return (rc); 2715218792Snp 2716218792Snp if (qsize < 128 || (qsize & 7)) 2717218792Snp return (EINVAL); 2718218792Snp 2719218792Snp ADAPTER_LOCK(sc); 2720218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 2721218792Snp if (rc == 0 && pi->ifp->if_drv_flags & IFF_DRV_RUNNING) 2722218792Snp rc = EBUSY; /* can be changed only when port is down */ 2723218792Snp 2724218792Snp if (rc == 0) 2725218792Snp pi->qsize_rxq = qsize; 2726218792Snp 2727218792Snp ADAPTER_UNLOCK(sc); 2728218792Snp return (rc); 2729218792Snp} 2730218792Snp 2731218792Snpstatic int 2732218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS) 2733218792Snp{ 2734218792Snp struct port_info *pi = arg1; 2735218792Snp struct adapter *sc = pi->adapter; 2736218792Snp int qsize, rc; 2737218792Snp 2738218792Snp qsize = pi->qsize_txq; 2739218792Snp 2740218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 2741218792Snp if (rc != 0 || req->newptr == NULL) 2742218792Snp return (rc); 2743218792Snp 2744218792Snp if (qsize < 128) 2745218792Snp return (EINVAL); 2746218792Snp 2747218792Snp ADAPTER_LOCK(sc); 2748218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 2749218792Snp if (rc == 0 && pi->ifp->if_drv_flags & IFF_DRV_RUNNING) 2750218792Snp rc = EBUSY; /* can be changed only when port is down */ 2751218792Snp 2752218792Snp if (rc == 0) 2753218792Snp pi->qsize_txq = qsize; 2754218792Snp 2755218792Snp ADAPTER_UNLOCK(sc); 2756218792Snp return (rc); 2757218792Snp} 2758218792Snp 2759218792Snpstatic int 2760218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS) 2761218792Snp{ 2762218792Snp struct adapter *sc = arg1; 2763218792Snp int reg = arg2; 2764218792Snp uint64_t val; 2765218792Snp 2766218792Snp val = t4_read_reg64(sc, reg); 2767218792Snp 2768218792Snp return (sysctl_handle_64(oidp, &val, 0, req)); 2769218792Snp} 2770218792Snp 2771222551Snpconst char *devlog_level_strings[] = { 2772222551Snp [FW_DEVLOG_LEVEL_EMERG] = "EMERG", 2773222551Snp [FW_DEVLOG_LEVEL_CRIT] = "CRIT", 2774222551Snp [FW_DEVLOG_LEVEL_ERR] = "ERR", 2775222551Snp [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE", 2776222551Snp [FW_DEVLOG_LEVEL_INFO] = "INFO", 2777222551Snp [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG" 2778222551Snp}; 2779222551Snp 2780222551Snpconst char *devlog_facility_strings[] = { 2781222551Snp [FW_DEVLOG_FACILITY_CORE] = "CORE", 2782222551Snp [FW_DEVLOG_FACILITY_SCHED] = "SCHED", 2783222551Snp [FW_DEVLOG_FACILITY_TIMER] = "TIMER", 2784222551Snp [FW_DEVLOG_FACILITY_RES] = "RES", 2785222551Snp [FW_DEVLOG_FACILITY_HW] = "HW", 2786222551Snp [FW_DEVLOG_FACILITY_FLR] = "FLR", 2787222551Snp [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ", 2788222551Snp [FW_DEVLOG_FACILITY_PHY] = "PHY", 2789222551Snp [FW_DEVLOG_FACILITY_MAC] = "MAC", 2790222551Snp [FW_DEVLOG_FACILITY_PORT] = "PORT", 2791222551Snp [FW_DEVLOG_FACILITY_VI] = "VI", 2792222551Snp [FW_DEVLOG_FACILITY_FILTER] = "FILTER", 2793222551Snp [FW_DEVLOG_FACILITY_ACL] = "ACL", 2794222551Snp [FW_DEVLOG_FACILITY_TM] = "TM", 2795222551Snp [FW_DEVLOG_FACILITY_QFC] = "QFC", 2796222551Snp [FW_DEVLOG_FACILITY_DCB] = "DCB", 2797222551Snp [FW_DEVLOG_FACILITY_ETH] = "ETH", 2798222551Snp [FW_DEVLOG_FACILITY_OFLD] = "OFLD", 2799222551Snp [FW_DEVLOG_FACILITY_RI] = "RI", 2800222551Snp [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI", 2801222551Snp [FW_DEVLOG_FACILITY_FCOE] = "FCOE", 2802222551Snp [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI", 2803222551Snp [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE" 2804222551Snp}; 2805222551Snp 2806222551Snpstatic int 2807222551Snpsysctl_devlog(SYSCTL_HANDLER_ARGS) 2808222551Snp{ 2809222551Snp struct adapter *sc = arg1; 2810222551Snp struct devlog_params *dparams = &sc->params.devlog; 2811222551Snp struct fw_devlog_e *buf, *e; 2812222551Snp int i, j, rc, nentries, first = 0; 2813222551Snp struct sbuf *sb; 2814222551Snp uint64_t ftstamp = UINT64_MAX; 2815222551Snp 2816222551Snp if (dparams->start == 0) 2817222551Snp return (ENXIO); 2818222551Snp 2819222551Snp nentries = dparams->size / sizeof(struct fw_devlog_e); 2820222551Snp 2821222551Snp buf = malloc(dparams->size, M_CXGBE, M_NOWAIT); 2822222551Snp if (buf == NULL) 2823222551Snp return (ENOMEM); 2824222551Snp 2825222551Snp rc = -t4_mem_read(sc, dparams->memtype, dparams->start, dparams->size, 2826222551Snp (void *)buf); 2827222551Snp if (rc != 0) 2828222551Snp goto done; 2829222551Snp 2830222551Snp for (i = 0; i < nentries; i++) { 2831222551Snp e = &buf[i]; 2832222551Snp 2833222551Snp if (e->timestamp == 0) 2834222551Snp break; /* end */ 2835222551Snp 2836222551Snp e->timestamp = be64toh(e->timestamp); 2837222551Snp e->seqno = be32toh(e->seqno); 2838222551Snp for (j = 0; j < 8; j++) 2839222551Snp e->params[j] = be32toh(e->params[j]); 2840222551Snp 2841222551Snp if (e->timestamp < ftstamp) { 2842222551Snp ftstamp = e->timestamp; 2843222551Snp first = i; 2844222551Snp } 2845222551Snp } 2846222551Snp 2847222551Snp if (buf[first].timestamp == 0) 2848222551Snp goto done; /* nothing in the log */ 2849222551Snp 2850222551Snp rc = sysctl_wire_old_buffer(req, 0); 2851222551Snp if (rc != 0) 2852222551Snp goto done; 2853222551Snp 2854222551Snp sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 2855222551Snp sbuf_printf(sb, "\n%10s %15s %8s %8s %s\n", 2856222551Snp "Seq#", "Tstamp", "Level", "Facility", "Message"); 2857222551Snp 2858222551Snp i = first; 2859222551Snp do { 2860222551Snp e = &buf[i]; 2861222551Snp if (e->timestamp == 0) 2862222551Snp break; /* end */ 2863222551Snp 2864222551Snp sbuf_printf(sb, "%10d %15ju %8s %8s ", 2865222551Snp e->seqno, e->timestamp, 2866222551Snp (e->level < ARRAY_SIZE(devlog_level_strings) ? 2867222551Snp devlog_level_strings[e->level] : "UNKNOWN"), 2868222551Snp (e->facility < ARRAY_SIZE(devlog_facility_strings) ? 2869222551Snp devlog_facility_strings[e->facility] : "UNKNOWN")); 2870222551Snp sbuf_printf(sb, e->fmt, e->params[0], e->params[1], 2871222551Snp e->params[2], e->params[3], e->params[4], 2872222551Snp e->params[5], e->params[6], e->params[7]); 2873222551Snp 2874222551Snp if (++i == nentries) 2875222551Snp i = 0; 2876222551Snp } while (i != first); 2877222551Snp 2878222551Snp rc = sbuf_finish(sb); 2879222551Snp sbuf_delete(sb); 2880222551Snpdone: 2881222551Snp free(buf, M_CXGBE); 2882222551Snp return (rc); 2883222551Snp} 2884222551Snp 2885219286Snpstatic inline void 2886219286Snptxq_start(struct ifnet *ifp, struct sge_txq *txq) 2887219286Snp{ 2888219286Snp struct buf_ring *br; 2889219286Snp struct mbuf *m; 2890219286Snp 2891219286Snp TXQ_LOCK_ASSERT_OWNED(txq); 2892219286Snp 2893220873Snp br = txq->br; 2894219286Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 2895219286Snp if (m) 2896219286Snp t4_eth_tx(ifp, txq, m); 2897219286Snp} 2898219286Snp 2899219286Snpvoid 2900219286Snpcxgbe_txq_start(void *arg, int count) 2901219286Snp{ 2902219286Snp struct sge_txq *txq = arg; 2903219286Snp 2904219286Snp TXQ_LOCK(txq); 2905220649Snp if (txq->eq.flags & EQ_CRFLUSHED) { 2906220649Snp txq->eq.flags &= ~EQ_CRFLUSHED; 2907220649Snp txq_start(txq->ifp, txq); 2908220649Snp } else 2909220649Snp wakeup_one(txq); /* txq is going away, wakeup free_txq */ 2910219286Snp TXQ_UNLOCK(txq); 2911219286Snp} 2912219286Snp 2913221474Snpstatic uint32_t 2914221474Snpfconf_to_mode(uint32_t fconf) 2915221474Snp{ 2916221474Snp uint32_t mode; 2917221474Snp 2918221474Snp mode = T4_FILTER_IPv4 | T4_FILTER_IPv6 | T4_FILTER_IP_SADDR | 2919221474Snp T4_FILTER_IP_DADDR | T4_FILTER_IP_SPORT | T4_FILTER_IP_DPORT; 2920221474Snp 2921221474Snp if (fconf & F_FRAGMENTATION) 2922221474Snp mode |= T4_FILTER_IP_FRAGMENT; 2923221474Snp 2924221474Snp if (fconf & F_MPSHITTYPE) 2925221474Snp mode |= T4_FILTER_MPS_HIT_TYPE; 2926221474Snp 2927221474Snp if (fconf & F_MACMATCH) 2928221474Snp mode |= T4_FILTER_MAC_IDX; 2929221474Snp 2930221474Snp if (fconf & F_ETHERTYPE) 2931221474Snp mode |= T4_FILTER_ETH_TYPE; 2932221474Snp 2933221474Snp if (fconf & F_PROTOCOL) 2934221474Snp mode |= T4_FILTER_IP_PROTO; 2935221474Snp 2936221474Snp if (fconf & F_TOS) 2937221474Snp mode |= T4_FILTER_IP_TOS; 2938221474Snp 2939221474Snp if (fconf & F_VLAN) 2940221474Snp mode |= T4_FILTER_IVLAN; 2941221474Snp 2942221474Snp if (fconf & F_VNIC_ID) 2943221474Snp mode |= T4_FILTER_OVLAN; 2944221474Snp 2945221474Snp if (fconf & F_PORT) 2946221474Snp mode |= T4_FILTER_PORT; 2947221474Snp 2948221474Snp if (fconf & F_FCOE) 2949221474Snp mode |= T4_FILTER_FCoE; 2950221474Snp 2951221474Snp return (mode); 2952221474Snp} 2953221474Snp 2954221474Snpstatic uint32_t 2955221474Snpmode_to_fconf(uint32_t mode) 2956221474Snp{ 2957221474Snp uint32_t fconf = 0; 2958221474Snp 2959221474Snp if (mode & T4_FILTER_IP_FRAGMENT) 2960221474Snp fconf |= F_FRAGMENTATION; 2961221474Snp 2962221474Snp if (mode & T4_FILTER_MPS_HIT_TYPE) 2963221474Snp fconf |= F_MPSHITTYPE; 2964221474Snp 2965221474Snp if (mode & T4_FILTER_MAC_IDX) 2966221474Snp fconf |= F_MACMATCH; 2967221474Snp 2968221474Snp if (mode & T4_FILTER_ETH_TYPE) 2969221474Snp fconf |= F_ETHERTYPE; 2970221474Snp 2971221474Snp if (mode & T4_FILTER_IP_PROTO) 2972221474Snp fconf |= F_PROTOCOL; 2973221474Snp 2974221474Snp if (mode & T4_FILTER_IP_TOS) 2975221474Snp fconf |= F_TOS; 2976221474Snp 2977221474Snp if (mode & T4_FILTER_IVLAN) 2978221474Snp fconf |= F_VLAN; 2979221474Snp 2980221474Snp if (mode & T4_FILTER_OVLAN) 2981221474Snp fconf |= F_VNIC_ID; 2982221474Snp 2983221474Snp if (mode & T4_FILTER_PORT) 2984221474Snp fconf |= F_PORT; 2985221474Snp 2986221474Snp if (mode & T4_FILTER_FCoE) 2987221474Snp fconf |= F_FCOE; 2988221474Snp 2989221474Snp return (fconf); 2990221474Snp} 2991221474Snp 2992221474Snpstatic uint32_t 2993221474Snpfspec_to_fconf(struct t4_filter_specification *fs) 2994221474Snp{ 2995221474Snp uint32_t fconf = 0; 2996221474Snp 2997221474Snp if (fs->val.frag || fs->mask.frag) 2998221474Snp fconf |= F_FRAGMENTATION; 2999221474Snp 3000221474Snp if (fs->val.matchtype || fs->mask.matchtype) 3001221474Snp fconf |= F_MPSHITTYPE; 3002221474Snp 3003221474Snp if (fs->val.macidx || fs->mask.macidx) 3004221474Snp fconf |= F_MACMATCH; 3005221474Snp 3006221474Snp if (fs->val.ethtype || fs->mask.ethtype) 3007221474Snp fconf |= F_ETHERTYPE; 3008221474Snp 3009221474Snp if (fs->val.proto || fs->mask.proto) 3010221474Snp fconf |= F_PROTOCOL; 3011221474Snp 3012221474Snp if (fs->val.tos || fs->mask.tos) 3013221474Snp fconf |= F_TOS; 3014221474Snp 3015221474Snp if (fs->val.ivlan_vld || fs->mask.ivlan_vld) 3016221474Snp fconf |= F_VLAN; 3017221474Snp 3018221474Snp if (fs->val.ovlan_vld || fs->mask.ovlan_vld) 3019221474Snp fconf |= F_VNIC_ID; 3020221474Snp 3021221474Snp if (fs->val.iport || fs->mask.iport) 3022221474Snp fconf |= F_PORT; 3023221474Snp 3024221474Snp if (fs->val.fcoe || fs->mask.fcoe) 3025221474Snp fconf |= F_FCOE; 3026221474Snp 3027221474Snp return (fconf); 3028221474Snp} 3029221474Snp 3030221474Snpstatic int 3031221474Snpget_filter_mode(struct adapter *sc, uint32_t *mode) 3032221474Snp{ 3033221474Snp uint32_t fconf; 3034221474Snp 3035221474Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1, 3036221474Snp A_TP_VLAN_PRI_MAP); 3037221474Snp 3038221474Snp *mode = fconf_to_mode(fconf); 3039221474Snp 3040221474Snp return (0); 3041221474Snp} 3042221474Snp 3043221474Snpstatic int 3044221474Snpset_filter_mode(struct adapter *sc, uint32_t mode) 3045221474Snp{ 3046221474Snp uint32_t fconf; 3047221474Snp int rc; 3048221474Snp 3049221474Snp fconf = mode_to_fconf(mode); 3050221474Snp 3051221474Snp ADAPTER_LOCK(sc); 3052221474Snp if (IS_BUSY(sc)) { 3053221474Snp rc = EAGAIN; 3054221474Snp goto done; 3055221474Snp } 3056221474Snp 3057221474Snp if (sc->tids.ftids_in_use > 0) { 3058221474Snp rc = EBUSY; 3059221474Snp goto done; 3060221474Snp } 3061221474Snp 3062221474Snp rc = -t4_set_filter_mode(sc, fconf); 3063221474Snpdone: 3064221474Snp ADAPTER_UNLOCK(sc); 3065221474Snp return (rc); 3066221474Snp} 3067221474Snp 3068222552Snpstatic inline uint64_t 3069222552Snpget_filter_hits(struct adapter *sc, uint32_t fid) 3070222552Snp{ 3071222552Snp uint32_t tcb_base = t4_read_reg(sc, A_TP_CMM_TCB_BASE); 3072222552Snp uint64_t hits; 3073222552Snp 3074222552Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0), 3075222552Snp tcb_base + (fid + sc->tids.ftid_base) * TCB_SIZE); 3076222552Snp t4_read_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_OFFSET, 0)); 3077222552Snp hits = t4_read_reg64(sc, MEMWIN0_BASE + 16); 3078222552Snp 3079222552Snp return (be64toh(hits)); 3080222552Snp} 3081222552Snp 3082221474Snpstatic int 3083221474Snpget_filter(struct adapter *sc, struct t4_filter *t) 3084221474Snp{ 3085221474Snp int i, nfilters = sc->tids.nftids; 3086221474Snp struct filter_entry *f; 3087221474Snp 3088221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 3089221474Snp 3090221474Snp if (IS_BUSY(sc)) 3091221474Snp return (EAGAIN); 3092221474Snp 3093221474Snp if (sc->tids.ftids_in_use == 0 || sc->tids.ftid_tab == NULL || 3094221474Snp t->idx >= nfilters) { 3095221474Snp t->idx = 0xffffffff; 3096221474Snp return (0); 3097221474Snp } 3098221474Snp 3099221474Snp f = &sc->tids.ftid_tab[t->idx]; 3100221474Snp for (i = t->idx; i < nfilters; i++, f++) { 3101221474Snp if (f->valid) { 3102221474Snp t->idx = i; 3103222509Snp t->l2tidx = f->l2t ? f->l2t->idx : 0; 3104222509Snp t->smtidx = f->smtidx; 3105222552Snp if (f->fs.hitcnts) 3106222552Snp t->hits = get_filter_hits(sc, t->idx); 3107222552Snp else 3108222552Snp t->hits = UINT64_MAX; 3109221474Snp t->fs = f->fs; 3110221474Snp 3111221474Snp return (0); 3112221474Snp } 3113221474Snp } 3114221474Snp 3115221474Snp t->idx = 0xffffffff; 3116221474Snp return (0); 3117221474Snp} 3118221474Snp 3119221474Snpstatic int 3120221474Snpset_filter(struct adapter *sc, struct t4_filter *t) 3121221474Snp{ 3122221474Snp uint32_t fconf; 3123221474Snp unsigned int nfilters, nports; 3124221474Snp struct filter_entry *f; 3125221474Snp int i; 3126221474Snp 3127221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 3128221474Snp 3129221474Snp nfilters = sc->tids.nftids; 3130221474Snp nports = sc->params.nports; 3131221474Snp 3132221474Snp if (nfilters == 0) 3133221474Snp return (ENOTSUP); 3134221474Snp 3135221474Snp if (!(sc->flags & FULL_INIT_DONE)) 3136221474Snp return (EAGAIN); 3137221474Snp 3138221474Snp if (t->idx >= nfilters) 3139221474Snp return (EINVAL); 3140221474Snp 3141221474Snp /* Validate against the global filter mode */ 3142221474Snp t4_read_indirect(sc, A_TP_PIO_ADDR, A_TP_PIO_DATA, &fconf, 1, 3143221474Snp A_TP_VLAN_PRI_MAP); 3144221474Snp if ((fconf | fspec_to_fconf(&t->fs)) != fconf) 3145221474Snp return (E2BIG); 3146221474Snp 3147221474Snp if (t->fs.action == FILTER_SWITCH && t->fs.eport >= nports) 3148221474Snp return (EINVAL); 3149221474Snp 3150221474Snp if (t->fs.val.iport >= nports) 3151221474Snp return (EINVAL); 3152221474Snp 3153221474Snp /* Can't specify an iq if not steering to it */ 3154221474Snp if (!t->fs.dirsteer && t->fs.iq) 3155221474Snp return (EINVAL); 3156221474Snp 3157221474Snp /* IPv6 filter idx must be 4 aligned */ 3158221474Snp if (t->fs.type == 1 && 3159221474Snp ((t->idx & 0x3) || t->idx + 4 >= nfilters)) 3160221474Snp return (EINVAL); 3161221474Snp 3162221474Snp if (sc->tids.ftid_tab == NULL) { 3163221474Snp KASSERT(sc->tids.ftids_in_use == 0, 3164221474Snp ("%s: no memory allocated but filters_in_use > 0", 3165221474Snp __func__)); 3166221474Snp 3167221474Snp sc->tids.ftid_tab = malloc(sizeof (struct filter_entry) * 3168221474Snp nfilters, M_CXGBE, M_NOWAIT | M_ZERO); 3169221474Snp if (sc->tids.ftid_tab == NULL) 3170221474Snp return (ENOMEM); 3171221474Snp } 3172221474Snp 3173221474Snp for (i = 0; i < 4; i++) { 3174221474Snp f = &sc->tids.ftid_tab[t->idx + i]; 3175221474Snp 3176221474Snp if (f->pending || f->valid) 3177221474Snp return (EBUSY); 3178221474Snp if (f->locked) 3179221474Snp return (EPERM); 3180221474Snp 3181221474Snp if (t->fs.type == 0) 3182221474Snp break; 3183221474Snp } 3184221474Snp 3185221474Snp f = &sc->tids.ftid_tab[t->idx]; 3186221474Snp f->fs = t->fs; 3187221474Snp 3188221474Snp return set_filter_wr(sc, t->idx); 3189221474Snp} 3190221474Snp 3191221474Snpstatic int 3192221474Snpdel_filter(struct adapter *sc, struct t4_filter *t) 3193221474Snp{ 3194221474Snp unsigned int nfilters; 3195221474Snp struct filter_entry *f; 3196221474Snp 3197221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 3198221474Snp 3199221474Snp if (IS_BUSY(sc)) 3200221474Snp return (EAGAIN); 3201221474Snp 3202221474Snp nfilters = sc->tids.nftids; 3203221474Snp 3204221474Snp if (nfilters == 0) 3205221474Snp return (ENOTSUP); 3206221474Snp 3207221474Snp if (sc->tids.ftid_tab == NULL || sc->tids.ftids_in_use == 0 || 3208221474Snp t->idx >= nfilters) 3209221474Snp return (EINVAL); 3210221474Snp 3211221474Snp if (!(sc->flags & FULL_INIT_DONE)) 3212221474Snp return (EAGAIN); 3213221474Snp 3214221474Snp f = &sc->tids.ftid_tab[t->idx]; 3215221474Snp 3216221474Snp if (f->pending) 3217221474Snp return (EBUSY); 3218221474Snp if (f->locked) 3219221474Snp return (EPERM); 3220221474Snp 3221221474Snp if (f->valid) { 3222221474Snp t->fs = f->fs; /* extra info for the caller */ 3223221474Snp return del_filter_wr(sc, t->idx); 3224221474Snp } 3225221474Snp 3226221474Snp return (0); 3227221474Snp} 3228221474Snp 3229221474Snpstatic void 3230222509Snpclear_filter(struct filter_entry *f) 3231221474Snp{ 3232222509Snp if (f->l2t) 3233222509Snp t4_l2t_release(f->l2t); 3234222509Snp 3235221474Snp bzero(f, sizeof (*f)); 3236221474Snp} 3237221474Snp 3238221474Snpstatic int 3239221474Snpset_filter_wr(struct adapter *sc, int fidx) 3240221474Snp{ 3241221474Snp int rc; 3242221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 3243221474Snp struct mbuf *m; 3244221474Snp struct fw_filter_wr *fwr; 3245221474Snp unsigned int ftid; 3246221474Snp 3247221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 3248221474Snp 3249222509Snp if (f->fs.newdmac || f->fs.newvlan) { 3250222509Snp /* This filter needs an L2T entry; allocate one. */ 3251222509Snp f->l2t = t4_l2t_alloc_switching(sc->l2t); 3252222509Snp if (f->l2t == NULL) 3253222509Snp return (EAGAIN); 3254222509Snp if (t4_l2t_set_switching(sc, f->l2t, f->fs.vlan, f->fs.eport, 3255222509Snp f->fs.dmac)) { 3256222509Snp t4_l2t_release(f->l2t); 3257222509Snp f->l2t = NULL; 3258222509Snp return (ENOMEM); 3259222509Snp } 3260222509Snp } 3261221474Snp 3262221474Snp ftid = sc->tids.ftid_base + fidx; 3263221474Snp 3264221474Snp m = m_gethdr(M_NOWAIT, MT_DATA); 3265221474Snp if (m == NULL) 3266221474Snp return (ENOMEM); 3267221474Snp 3268221474Snp fwr = mtod(m, struct fw_filter_wr *); 3269221474Snp m->m_len = m->m_pkthdr.len = sizeof(*fwr); 3270221474Snp bzero(fwr, sizeof (*fwr)); 3271221474Snp 3272221474Snp fwr->op_pkd = htobe32(V_FW_WR_OP(FW_FILTER_WR)); 3273221474Snp fwr->len16_pkd = htobe32(FW_LEN16(*fwr)); 3274221474Snp fwr->tid_to_iq = 3275221474Snp htobe32(V_FW_FILTER_WR_TID(ftid) | 3276221474Snp V_FW_FILTER_WR_RQTYPE(f->fs.type) | 3277221474Snp V_FW_FILTER_WR_NOREPLY(0) | 3278221474Snp V_FW_FILTER_WR_IQ(f->fs.iq)); 3279221474Snp fwr->del_filter_to_l2tix = 3280221474Snp htobe32(V_FW_FILTER_WR_RPTTID(f->fs.rpttid) | 3281221474Snp V_FW_FILTER_WR_DROP(f->fs.action == FILTER_DROP) | 3282221474Snp V_FW_FILTER_WR_DIRSTEER(f->fs.dirsteer) | 3283221474Snp V_FW_FILTER_WR_MASKHASH(f->fs.maskhash) | 3284221474Snp V_FW_FILTER_WR_DIRSTEERHASH(f->fs.dirsteerhash) | 3285221474Snp V_FW_FILTER_WR_LPBK(f->fs.action == FILTER_SWITCH) | 3286221474Snp V_FW_FILTER_WR_DMAC(f->fs.newdmac) | 3287221474Snp V_FW_FILTER_WR_SMAC(f->fs.newsmac) | 3288221474Snp V_FW_FILTER_WR_INSVLAN(f->fs.newvlan == VLAN_INSERT || 3289221474Snp f->fs.newvlan == VLAN_REWRITE) | 3290221474Snp V_FW_FILTER_WR_RMVLAN(f->fs.newvlan == VLAN_REMOVE || 3291221474Snp f->fs.newvlan == VLAN_REWRITE) | 3292221474Snp V_FW_FILTER_WR_HITCNTS(f->fs.hitcnts) | 3293221474Snp V_FW_FILTER_WR_TXCHAN(f->fs.eport) | 3294221474Snp V_FW_FILTER_WR_PRIO(f->fs.prio) | 3295222509Snp V_FW_FILTER_WR_L2TIX(f->l2t ? f->l2t->idx : 0)); 3296221474Snp fwr->ethtype = htobe16(f->fs.val.ethtype); 3297221474Snp fwr->ethtypem = htobe16(f->fs.mask.ethtype); 3298221474Snp fwr->frag_to_ovlan_vldm = 3299221474Snp (V_FW_FILTER_WR_FRAG(f->fs.val.frag) | 3300221474Snp V_FW_FILTER_WR_FRAGM(f->fs.mask.frag) | 3301221474Snp V_FW_FILTER_WR_IVLAN_VLD(f->fs.val.ivlan_vld) | 3302221474Snp V_FW_FILTER_WR_OVLAN_VLD(f->fs.val.ovlan_vld) | 3303221474Snp V_FW_FILTER_WR_IVLAN_VLDM(f->fs.mask.ivlan_vld) | 3304221474Snp V_FW_FILTER_WR_OVLAN_VLDM(f->fs.mask.ovlan_vld)); 3305221474Snp fwr->smac_sel = 0; 3306221474Snp fwr->rx_chan_rx_rpl_iq = htobe16(V_FW_FILTER_WR_RX_CHAN(0) | 3307222510Snp V_FW_FILTER_WR_RX_RPL_IQ(sc->sge.intrq[0].abs_id)); 3308221474Snp fwr->maci_to_matchtypem = 3309221474Snp htobe32(V_FW_FILTER_WR_MACI(f->fs.val.macidx) | 3310221474Snp V_FW_FILTER_WR_MACIM(f->fs.mask.macidx) | 3311221474Snp V_FW_FILTER_WR_FCOE(f->fs.val.fcoe) | 3312221474Snp V_FW_FILTER_WR_FCOEM(f->fs.mask.fcoe) | 3313221474Snp V_FW_FILTER_WR_PORT(f->fs.val.iport) | 3314221474Snp V_FW_FILTER_WR_PORTM(f->fs.mask.iport) | 3315221474Snp V_FW_FILTER_WR_MATCHTYPE(f->fs.val.matchtype) | 3316221474Snp V_FW_FILTER_WR_MATCHTYPEM(f->fs.mask.matchtype)); 3317221474Snp fwr->ptcl = f->fs.val.proto; 3318221474Snp fwr->ptclm = f->fs.mask.proto; 3319221474Snp fwr->ttyp = f->fs.val.tos; 3320221474Snp fwr->ttypm = f->fs.mask.tos; 3321221474Snp fwr->ivlan = htobe16(f->fs.val.ivlan); 3322221474Snp fwr->ivlanm = htobe16(f->fs.mask.ivlan); 3323221474Snp fwr->ovlan = htobe16(f->fs.val.ovlan); 3324221474Snp fwr->ovlanm = htobe16(f->fs.mask.ovlan); 3325221474Snp bcopy(f->fs.val.dip, fwr->lip, sizeof (fwr->lip)); 3326221474Snp bcopy(f->fs.mask.dip, fwr->lipm, sizeof (fwr->lipm)); 3327221474Snp bcopy(f->fs.val.sip, fwr->fip, sizeof (fwr->fip)); 3328221474Snp bcopy(f->fs.mask.sip, fwr->fipm, sizeof (fwr->fipm)); 3329221474Snp fwr->lp = htobe16(f->fs.val.dport); 3330221474Snp fwr->lpm = htobe16(f->fs.mask.dport); 3331221474Snp fwr->fp = htobe16(f->fs.val.sport); 3332221474Snp fwr->fpm = htobe16(f->fs.mask.sport); 3333221474Snp if (f->fs.newsmac) 3334221474Snp bcopy(f->fs.smac, fwr->sma, sizeof (fwr->sma)); 3335221474Snp 3336221474Snp f->pending = 1; 3337221474Snp sc->tids.ftids_in_use++; 3338221474Snp rc = t4_mgmt_tx(sc, m); 3339221474Snp if (rc != 0) { 3340221474Snp sc->tids.ftids_in_use--; 3341221474Snp m_freem(m); 3342222509Snp clear_filter(f); 3343221474Snp } 3344221474Snp return (rc); 3345221474Snp} 3346221474Snp 3347221474Snpstatic int 3348221474Snpdel_filter_wr(struct adapter *sc, int fidx) 3349221474Snp{ 3350221474Snp struct filter_entry *f = &sc->tids.ftid_tab[fidx]; 3351221474Snp struct mbuf *m; 3352221474Snp struct fw_filter_wr *fwr; 3353221474Snp unsigned int rc, ftid; 3354221474Snp 3355221474Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 3356221474Snp 3357221474Snp ftid = sc->tids.ftid_base + fidx; 3358221474Snp 3359221474Snp m = m_gethdr(M_NOWAIT, MT_DATA); 3360221474Snp if (m == NULL) 3361221474Snp return (ENOMEM); 3362221474Snp 3363221474Snp fwr = mtod(m, struct fw_filter_wr *); 3364221474Snp m->m_len = m->m_pkthdr.len = sizeof(*fwr); 3365221474Snp bzero(fwr, sizeof (*fwr)); 3366221474Snp 3367222510Snp t4_mk_filtdelwr(ftid, fwr, sc->sge.intrq[0].abs_id); 3368221474Snp 3369221474Snp f->pending = 1; 3370221474Snp rc = t4_mgmt_tx(sc, m); 3371221474Snp if (rc != 0) { 3372221474Snp f->pending = 0; 3373221474Snp m_freem(m); 3374221474Snp } 3375221474Snp return (rc); 3376221474Snp} 3377221474Snp 3378221474Snp/* XXX move intr handlers to main.c and make this static */ 3379221474Snpvoid 3380221474Snpfilter_rpl(struct adapter *sc, const struct cpl_set_tcb_rpl *rpl) 3381221474Snp{ 3382221474Snp unsigned int idx = GET_TID(rpl); 3383221474Snp 3384221474Snp if (idx >= sc->tids.ftid_base && 3385221474Snp (idx -= sc->tids.ftid_base) < sc->tids.nftids) { 3386221474Snp unsigned int rc = G_COOKIE(rpl->cookie); 3387221474Snp struct filter_entry *f = &sc->tids.ftid_tab[idx]; 3388221474Snp 3389221474Snp if (rc == FW_FILTER_WR_FLT_DELETED) { 3390221474Snp /* 3391221474Snp * Clear the filter when we get confirmation from the 3392221474Snp * hardware that the filter has been deleted. 3393221474Snp */ 3394222509Snp clear_filter(f); 3395221474Snp sc->tids.ftids_in_use--; 3396221474Snp } else if (rc == FW_FILTER_WR_SMT_TBL_FULL) { 3397221474Snp device_printf(sc->dev, 3398221474Snp "filter %u setup failed due to full SMT\n", idx); 3399222509Snp clear_filter(f); 3400221474Snp sc->tids.ftids_in_use--; 3401221474Snp } else if (rc == FW_FILTER_WR_FLT_ADDED) { 3402221474Snp f->smtidx = (be64toh(rpl->oldval) >> 24) & 0xff; 3403221474Snp f->pending = 0; /* asynchronous setup completed */ 3404221474Snp f->valid = 1; 3405221474Snp } else { 3406221474Snp /* 3407221474Snp * Something went wrong. Issue a warning about the 3408221474Snp * problem and clear everything out. 3409221474Snp */ 3410221474Snp device_printf(sc->dev, 3411221474Snp "filter %u setup failed with error %u\n", idx, rc); 3412222509Snp clear_filter(f); 3413221474Snp sc->tids.ftids_in_use--; 3414221474Snp } 3415221474Snp } 3416221474Snp} 3417221474Snp 3418222973Snpstatic int 3419222973Snpget_sge_context(struct adapter *sc, struct t4_sge_context *cntxt) 3420222973Snp{ 3421222973Snp int rc = EINVAL; 3422222973Snp 3423222973Snp if (cntxt->cid > M_CTXTQID) 3424222973Snp return (rc); 3425222973Snp 3426222973Snp if (cntxt->mem_id != CTXT_EGRESS && cntxt->mem_id != CTXT_INGRESS && 3427222973Snp cntxt->mem_id != CTXT_FLM && cntxt->mem_id != CTXT_CNM) 3428222973Snp return (rc); 3429222973Snp 3430222973Snp if (sc->flags & FW_OK) { 3431222973Snp ADAPTER_LOCK(sc); /* Avoid parallel t4_wr_mbox */ 3432222973Snp rc = -t4_sge_ctxt_rd(sc, sc->mbox, cntxt->cid, cntxt->mem_id, 3433222973Snp &cntxt->data[0]); 3434222973Snp ADAPTER_UNLOCK(sc); 3435222973Snp } 3436222973Snp 3437222973Snp if (rc != 0) { 3438222973Snp /* Read via firmware failed or wasn't even attempted */ 3439222973Snp 3440222973Snp rc = -t4_sge_ctxt_rd_bd(sc, cntxt->cid, cntxt->mem_id, 3441222973Snp &cntxt->data[0]); 3442222973Snp } 3443222973Snp 3444222973Snp return (rc); 3445222973Snp} 3446222973Snp 3447218792Snpint 3448218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap) 3449218792Snp{ 3450222102Snp int i; 3451218792Snp 3452222102Snp return (pci_find_cap(sc->dev, cap, &i) == 0 ? i : 0); 3453218792Snp} 3454218792Snp 3455218792Snpint 3456218792Snpt4_os_pci_save_state(struct adapter *sc) 3457218792Snp{ 3458218792Snp device_t dev; 3459218792Snp struct pci_devinfo *dinfo; 3460218792Snp 3461218792Snp dev = sc->dev; 3462218792Snp dinfo = device_get_ivars(dev); 3463218792Snp 3464218792Snp pci_cfg_save(dev, dinfo, 0); 3465218792Snp return (0); 3466218792Snp} 3467218792Snp 3468218792Snpint 3469218792Snpt4_os_pci_restore_state(struct adapter *sc) 3470218792Snp{ 3471218792Snp device_t dev; 3472218792Snp struct pci_devinfo *dinfo; 3473218792Snp 3474218792Snp dev = sc->dev; 3475218792Snp dinfo = device_get_ivars(dev); 3476218792Snp 3477218792Snp pci_cfg_restore(dev, dinfo); 3478218792Snp return (0); 3479218792Snp} 3480219299Snp 3481218792Snpvoid 3482218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx) 3483218792Snp{ 3484218792Snp struct port_info *pi = sc->port[idx]; 3485218792Snp static const char *mod_str[] = { 3486220232Snp NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX", "LRM" 3487218792Snp }; 3488218792Snp 3489218792Snp if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 3490218792Snp if_printf(pi->ifp, "transceiver unplugged.\n"); 3491220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_UNKNOWN) 3492220232Snp if_printf(pi->ifp, "unknown transceiver inserted.\n"); 3493220232Snp else if (pi->mod_type == FW_PORT_MOD_TYPE_NOTSUPPORTED) 3494220232Snp if_printf(pi->ifp, "unsupported transceiver inserted.\n"); 3495219299Snp else if (pi->mod_type > 0 && pi->mod_type < ARRAY_SIZE(mod_str)) { 3496218792Snp if_printf(pi->ifp, "%s transceiver inserted.\n", 3497218792Snp mod_str[pi->mod_type]); 3498219299Snp } else { 3499219299Snp if_printf(pi->ifp, "transceiver (type %d) inserted.\n", 3500219299Snp pi->mod_type); 3501219299Snp } 3502218792Snp} 3503218792Snp 3504218792Snpvoid 3505218792Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat) 3506218792Snp{ 3507218792Snp struct port_info *pi = sc->port[idx]; 3508218792Snp struct ifnet *ifp = pi->ifp; 3509218792Snp 3510218792Snp if (link_stat) { 3511218792Snp ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed); 3512218792Snp if_link_state_change(ifp, LINK_STATE_UP); 3513218792Snp } else 3514218792Snp if_link_state_change(ifp, LINK_STATE_DOWN); 3515218792Snp} 3516218792Snp 3517218792Snpstatic int 3518218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td) 3519218792Snp{ 3520218792Snp return (0); 3521218792Snp} 3522218792Snp 3523218792Snpstatic int 3524218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td) 3525218792Snp{ 3526218792Snp return (0); 3527218792Snp} 3528218792Snp 3529218792Snpstatic int 3530218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag, 3531218792Snp struct thread *td) 3532218792Snp{ 3533218792Snp int rc; 3534218792Snp struct adapter *sc = dev->si_drv1; 3535218792Snp 3536218792Snp rc = priv_check(td, PRIV_DRIVER); 3537218792Snp if (rc != 0) 3538218792Snp return (rc); 3539218792Snp 3540218792Snp switch (cmd) { 3541220410Snp case CHELSIO_T4_GETREG: { 3542220410Snp struct t4_reg *edata = (struct t4_reg *)data; 3543220410Snp 3544218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 3545218792Snp return (EFAULT); 3546220410Snp 3547220410Snp if (edata->size == 4) 3548220410Snp edata->val = t4_read_reg(sc, edata->addr); 3549220410Snp else if (edata->size == 8) 3550220410Snp edata->val = t4_read_reg64(sc, edata->addr); 3551220410Snp else 3552220410Snp return (EINVAL); 3553220410Snp 3554218792Snp break; 3555218792Snp } 3556220410Snp case CHELSIO_T4_SETREG: { 3557220410Snp struct t4_reg *edata = (struct t4_reg *)data; 3558220410Snp 3559218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 3560218792Snp return (EFAULT); 3561220410Snp 3562220410Snp if (edata->size == 4) { 3563220410Snp if (edata->val & 0xffffffff00000000) 3564220410Snp return (EINVAL); 3565220410Snp t4_write_reg(sc, edata->addr, (uint32_t) edata->val); 3566220410Snp } else if (edata->size == 8) 3567220410Snp t4_write_reg64(sc, edata->addr, edata->val); 3568220410Snp else 3569220410Snp return (EINVAL); 3570218792Snp break; 3571218792Snp } 3572218792Snp case CHELSIO_T4_REGDUMP: { 3573218792Snp struct t4_regdump *regs = (struct t4_regdump *)data; 3574218792Snp int reglen = T4_REGDUMP_SIZE; 3575218792Snp uint8_t *buf; 3576218792Snp 3577218792Snp if (regs->len < reglen) { 3578218792Snp regs->len = reglen; /* hint to the caller */ 3579218792Snp return (ENOBUFS); 3580218792Snp } 3581218792Snp 3582218792Snp regs->len = reglen; 3583218792Snp buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO); 3584218792Snp t4_get_regs(sc, regs, buf); 3585218792Snp rc = copyout(buf, regs->data, reglen); 3586218792Snp free(buf, M_CXGBE); 3587218792Snp break; 3588218792Snp } 3589221474Snp case CHELSIO_T4_GET_FILTER_MODE: 3590221474Snp rc = get_filter_mode(sc, (uint32_t *)data); 3591221474Snp break; 3592221474Snp case CHELSIO_T4_SET_FILTER_MODE: 3593221474Snp rc = set_filter_mode(sc, *(uint32_t *)data); 3594221474Snp break; 3595221474Snp case CHELSIO_T4_GET_FILTER: 3596221474Snp ADAPTER_LOCK(sc); 3597221474Snp rc = get_filter(sc, (struct t4_filter *)data); 3598221474Snp ADAPTER_UNLOCK(sc); 3599221474Snp break; 3600221474Snp case CHELSIO_T4_SET_FILTER: 3601221474Snp ADAPTER_LOCK(sc); 3602221474Snp rc = set_filter(sc, (struct t4_filter *)data); 3603221474Snp ADAPTER_UNLOCK(sc); 3604221474Snp break; 3605221474Snp case CHELSIO_T4_DEL_FILTER: 3606221474Snp ADAPTER_LOCK(sc); 3607221474Snp rc = del_filter(sc, (struct t4_filter *)data); 3608221474Snp ADAPTER_UNLOCK(sc); 3609221474Snp break; 3610222973Snp case CHELSIO_T4_GET_SGE_CONTEXT: 3611222973Snp rc = get_sge_context(sc, (struct t4_sge_context *)data); 3612222973Snp break; 3613218792Snp default: 3614218792Snp rc = EINVAL; 3615218792Snp } 3616218792Snp 3617218792Snp return (rc); 3618218792Snp} 3619218792Snp 3620219392Snpstatic int 3621219392Snpt4_mod_event(module_t mod, int cmd, void *arg) 3622219392Snp{ 3623219392Snp 3624219392Snp if (cmd == MOD_LOAD) 3625219392Snp t4_sge_modload(); 3626219392Snp 3627219392Snp return (0); 3628219392Snp} 3629219392Snp 3630218792Snpstatic devclass_t t4_devclass; 3631218792Snpstatic devclass_t cxgbe_devclass; 3632218792Snp 3633219392SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, t4_mod_event, 0); 3634218792SnpMODULE_VERSION(t4nex, 1); 3635218792Snp 3636218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0); 3637218792SnpMODULE_VERSION(cxgbe, 1); 3638