t4_main.c revision 218792
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 218792 2011-02-18 08:00:26Z np $"); 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> 39218792Snp#include <sys/pciio.h> 40218792Snp#include <dev/pci/pcireg.h> 41218792Snp#include <dev/pci/pcivar.h> 42218792Snp#include <dev/pci/pci_private.h> 43218792Snp#include <sys/firmware.h> 44218792Snp#include <sys/smp.h> 45218792Snp#include <sys/socket.h> 46218792Snp#include <sys/sockio.h> 47218792Snp#include <sys/sysctl.h> 48218792Snp#include <net/ethernet.h> 49218792Snp#include <net/if.h> 50218792Snp#include <net/if_types.h> 51218792Snp#include <net/if_dl.h> 52218792Snp 53218792Snp#include "common/t4_hw.h" 54218792Snp#include "common/common.h" 55218792Snp#include "common/t4_regs.h" 56218792Snp#include "common/t4_regs_values.h" 57218792Snp#include "common/t4fw_interface.h" 58218792Snp#include "t4_ioctl.h" 59218792Snp 60218792Snp/* T4 bus driver interface */ 61218792Snpstatic int t4_probe(device_t); 62218792Snpstatic int t4_attach(device_t); 63218792Snpstatic int t4_detach(device_t); 64218792Snpstatic device_method_t t4_methods[] = { 65218792Snp DEVMETHOD(device_probe, t4_probe), 66218792Snp DEVMETHOD(device_attach, t4_attach), 67218792Snp DEVMETHOD(device_detach, t4_detach), 68218792Snp 69218792Snp /* bus interface */ 70218792Snp DEVMETHOD(bus_print_child, bus_generic_print_child), 71218792Snp DEVMETHOD(bus_driver_added, bus_generic_driver_added), 72218792Snp 73218792Snp { 0, 0 } 74218792Snp}; 75218792Snpstatic driver_t t4_driver = { 76218792Snp "t4nex", 77218792Snp t4_methods, 78218792Snp sizeof(struct adapter) 79218792Snp}; 80218792Snp 81218792Snp 82218792Snp/* T4 port (cxgbe) interface */ 83218792Snpstatic int cxgbe_probe(device_t); 84218792Snpstatic int cxgbe_attach(device_t); 85218792Snpstatic int cxgbe_detach(device_t); 86218792Snpstatic device_method_t cxgbe_methods[] = { 87218792Snp DEVMETHOD(device_probe, cxgbe_probe), 88218792Snp DEVMETHOD(device_attach, cxgbe_attach), 89218792Snp DEVMETHOD(device_detach, cxgbe_detach), 90218792Snp { 0, 0 } 91218792Snp}; 92218792Snpstatic driver_t cxgbe_driver = { 93218792Snp "cxgbe", 94218792Snp cxgbe_methods, 95218792Snp sizeof(struct port_info) 96218792Snp}; 97218792Snp 98218792Snpstatic d_ioctl_t t4_ioctl; 99218792Snpstatic d_open_t t4_open; 100218792Snpstatic d_close_t t4_close; 101218792Snp 102218792Snpstatic struct cdevsw t4_cdevsw = { 103218792Snp .d_version = D_VERSION, 104218792Snp .d_flags = 0, 105218792Snp .d_open = t4_open, 106218792Snp .d_close = t4_close, 107218792Snp .d_ioctl = t4_ioctl, 108218792Snp .d_name = "t4nex", 109218792Snp}; 110218792Snp 111218792Snp/* ifnet + media interface */ 112218792Snpstatic void cxgbe_init(void *); 113218792Snpstatic int cxgbe_ioctl(struct ifnet *, unsigned long, caddr_t); 114218792Snpstatic void cxgbe_start(struct ifnet *); 115218792Snpstatic int cxgbe_transmit(struct ifnet *, struct mbuf *); 116218792Snpstatic void cxgbe_qflush(struct ifnet *); 117218792Snpstatic int cxgbe_media_change(struct ifnet *); 118218792Snpstatic void cxgbe_media_status(struct ifnet *, struct ifmediareq *); 119218792Snp 120218792SnpMALLOC_DEFINE(M_CXGBE, "cxgbe", "Chelsio T4 Ethernet driver and services"); 121218792Snp 122218792Snp/* 123218792Snp * Tunables. 124218792Snp */ 125218792SnpSYSCTL_NODE(_hw, OID_AUTO, cxgbe, CTLFLAG_RD, 0, "cxgbe driver parameters"); 126218792Snp 127218792Snpstatic int force_firmware_install = 0; 128218792SnpTUNABLE_INT("hw.cxgbe.force_firmware_install", &force_firmware_install); 129218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, force_firmware_install, CTLFLAG_RDTUN, 130218792Snp &force_firmware_install, 0, "install firmware on every attach."); 131218792Snp 132218792Snp/* 133218792Snp * Holdoff timer and packet counter values. 134218792Snp */ 135218792Snpstatic unsigned int intr_timer[SGE_NTIMERS] = {1, 5, 10, 50, 100, 200}; 136218792Snpstatic unsigned int intr_pktcount[SGE_NCOUNTERS] = {1, 8, 16, 32}; /* 63 max */ 137218792Snp 138218792Snp/* 139218792Snp * Max # of tx and rx queues to use for each 10G and 1G port. 140218792Snp */ 141218792Snpstatic unsigned int max_ntxq_10g = 8; 142218792SnpTUNABLE_INT("hw.cxgbe.max_ntxq_10G_port", &max_ntxq_10g); 143218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_ntxq_10G_port, CTLFLAG_RDTUN, 144218792Snp &max_ntxq_10g, 0, "maximum number of tx queues per 10G port."); 145218792Snp 146218792Snpstatic unsigned int max_nrxq_10g = 8; 147218792SnpTUNABLE_INT("hw.cxgbe.max_nrxq_10G_port", &max_nrxq_10g); 148218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_nrxq_10G_port, CTLFLAG_RDTUN, 149218792Snp &max_nrxq_10g, 0, "maximum number of rxq's (per 10G port)."); 150218792Snp 151218792Snpstatic unsigned int max_ntxq_1g = 2; 152218792SnpTUNABLE_INT("hw.cxgbe.max_ntxq_1G_port", &max_ntxq_1g); 153218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_ntxq_1G_port, CTLFLAG_RDTUN, 154218792Snp &max_ntxq_1g, 0, "maximum number of tx queues per 1G port."); 155218792Snp 156218792Snpstatic unsigned int max_nrxq_1g = 2; 157218792SnpTUNABLE_INT("hw.cxgbe.max_nrxq_1G_port", &max_nrxq_1g); 158218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, max_nrxq_1G_port, CTLFLAG_RDTUN, 159218792Snp &max_nrxq_1g, 0, "maximum number of rxq's (per 1G port)."); 160218792Snp 161218792Snp/* 162218792Snp * Holdoff parameters for 10G and 1G ports. 163218792Snp */ 164218792Snpstatic unsigned int tmr_idx_10g = 1; 165218792SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_10G", &tmr_idx_10g); 166218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_timer_idx_10G, CTLFLAG_RDTUN, 167218792Snp &tmr_idx_10g, 0, 168218792Snp "default timer index for interrupt holdoff (10G ports)."); 169218792Snp 170218792Snpstatic int pktc_idx_10g = 2; 171218792SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_10G", &pktc_idx_10g); 172218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_pktc_idx_10G, CTLFLAG_RDTUN, 173218792Snp &pktc_idx_10g, 0, 174218792Snp "default pkt counter index for interrupt holdoff (10G ports)."); 175218792Snp 176218792Snpstatic unsigned int tmr_idx_1g = 1; 177218792SnpTUNABLE_INT("hw.cxgbe.holdoff_timer_idx_1G", &tmr_idx_1g); 178218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_timer_idx_1G, CTLFLAG_RDTUN, 179218792Snp &tmr_idx_1g, 0, 180218792Snp "default timer index for interrupt holdoff (1G ports)."); 181218792Snp 182218792Snpstatic int pktc_idx_1g = 2; 183218792SnpTUNABLE_INT("hw.cxgbe.holdoff_pktc_idx_1G", &pktc_idx_1g); 184218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, holdoff_pktc_idx_1G, CTLFLAG_RDTUN, 185218792Snp &pktc_idx_1g, 0, 186218792Snp "default pkt counter index for interrupt holdoff (1G ports)."); 187218792Snp 188218792Snp/* 189218792Snp * Size (# of entries) of each tx and rx queue. 190218792Snp */ 191218792Snpstatic unsigned int qsize_txq = TX_EQ_QSIZE; 192218792SnpTUNABLE_INT("hw.cxgbe.qsize_txq", &qsize_txq); 193218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, qsize_txq, CTLFLAG_RDTUN, 194218792Snp &qsize_txq, 0, "default queue size of NIC tx queues."); 195218792Snp 196218792Snpstatic unsigned int qsize_rxq = RX_IQ_QSIZE; 197218792SnpTUNABLE_INT("hw.cxgbe.qsize_rxq", &qsize_rxq); 198218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, qsize_rxq, CTLFLAG_RDTUN, 199218792Snp &qsize_rxq, 0, "default queue size of NIC rx queues."); 200218792Snp 201218792Snp/* 202218792Snp * Interrupt types allowed. 203218792Snp */ 204218792Snpstatic int intr_types = 7; 205218792SnpTUNABLE_INT("hw.cxgbe.interrupt_types", &intr_types); 206218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, interrupt_types, CTLFLAG_RDTUN, &intr_types, 0, 207218792Snp "interrupt types allowed (bits 0, 1, 2 = INTx, MSI, MSI-X respectively)"); 208218792Snp 209218792Snp/* 210218792Snp * Force the driver to use interrupt forwarding. 211218792Snp */ 212218792Snpstatic int intr_fwd = 0; 213218792SnpTUNABLE_INT("hw.cxgbe.interrupt_forwarding", &intr_fwd); 214218792SnpSYSCTL_UINT(_hw_cxgbe, OID_AUTO, interrupt_forwarding, CTLFLAG_RDTUN, 215218792Snp &intr_fwd, 0, "always use forwarded interrupts"); 216218792Snp 217218792Snpstruct intrs_and_queues { 218218792Snp int intr_type; /* 1, 2, or 4 for INTx, MSI, or MSI-X */ 219218792Snp int nirq; /* Number of vectors */ 220218792Snp int intr_fwd; /* Interrupts forwarded */ 221218792Snp int ntxq10g; /* # of NIC txq's for each 10G port */ 222218792Snp int nrxq10g; /* # of NIC rxq's for each 10G port */ 223218792Snp int ntxq1g; /* # of NIC txq's for each 1G port */ 224218792Snp int nrxq1g; /* # of NIC rxq's for each 1G port */ 225218792Snp}; 226218792Snp 227218792Snpenum { 228218792Snp MEMWIN0_APERTURE = 2048, 229218792Snp MEMWIN0_BASE = 0x1b800, 230218792Snp MEMWIN1_APERTURE = 32768, 231218792Snp MEMWIN1_BASE = 0x28000, 232218792Snp MEMWIN2_APERTURE = 65536, 233218792Snp MEMWIN2_BASE = 0x30000, 234218792Snp}; 235218792Snp 236218792Snpenum { 237218792Snp XGMAC_MTU = (1 << 0), 238218792Snp XGMAC_PROMISC = (1 << 1), 239218792Snp XGMAC_ALLMULTI = (1 << 2), 240218792Snp XGMAC_VLANEX = (1 << 3), 241218792Snp XGMAC_UCADDR = (1 << 4), 242218792Snp XGMAC_MCADDRS = (1 << 5), 243218792Snp 244218792Snp XGMAC_ALL = 0xffff 245218792Snp}; 246218792Snp 247218792Snpstatic int map_bars(struct adapter *); 248218792Snpstatic void setup_memwin(struct adapter *); 249218792Snpstatic int cfg_itype_and_nqueues(struct adapter *, int, int, 250218792Snp struct intrs_and_queues *); 251218792Snpstatic int prep_firmware(struct adapter *); 252218792Snpstatic int get_capabilities(struct adapter *, struct fw_caps_config_cmd *); 253218792Snpstatic int get_params(struct adapter *, struct fw_caps_config_cmd *); 254218792Snpstatic void t4_set_desc(struct adapter *); 255218792Snpstatic void build_medialist(struct port_info *); 256218792Snpstatic int update_mac_settings(struct port_info *, int); 257218792Snpstatic int cxgbe_init_locked(struct port_info *); 258218792Snpstatic int cxgbe_init_synchronized(struct port_info *); 259218792Snpstatic int cxgbe_uninit_locked(struct port_info *); 260218792Snpstatic int cxgbe_uninit_synchronized(struct port_info *); 261218792Snpstatic int first_port_up(struct adapter *); 262218792Snpstatic int last_port_down(struct adapter *); 263218792Snpstatic int t4_alloc_irq(struct adapter *, struct irq *, int rid, 264218792Snp iq_intr_handler_t *, void *, char *); 265218792Snpstatic int t4_free_irq(struct adapter *, struct irq *); 266218792Snpstatic void reg_block_dump(struct adapter *, uint8_t *, unsigned int, 267218792Snp unsigned int); 268218792Snpstatic void t4_get_regs(struct adapter *, struct t4_regdump *, uint8_t *); 269218792Snpstatic void cxgbe_tick(void *); 270218792Snpstatic int t4_sysctls(struct adapter *); 271218792Snpstatic int cxgbe_sysctls(struct port_info *); 272218792Snpstatic int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS); 273218792Snpstatic int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS); 274218792Snpstatic int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS); 275218792Snpstatic int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS); 276218792Snpstatic int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS); 277218792Snp 278218792Snp 279218792Snpstruct t4_pciids { 280218792Snp uint16_t device; 281218792Snp uint8_t mpf; 282218792Snp char *desc; 283218792Snp} t4_pciids[] = { 284218792Snp {0xa000, 0, "Chelsio Terminator 4 FPGA"}, 285218792Snp {0x4400, 4, "Chelsio T440-dbg"}, 286218792Snp {0x4401, 4, "Chelsio T420-CR"}, 287218792Snp {0x4402, 4, "Chelsio T422-CR"}, 288218792Snp {0x4403, 4, "Chelsio T440-CR"}, 289218792Snp {0x4404, 4, "Chelsio T420-BCH"}, 290218792Snp {0x4405, 4, "Chelsio T440-BCH"}, 291218792Snp {0x4406, 4, "Chelsio T440-CH"}, 292218792Snp {0x4407, 4, "Chelsio T420-SO"}, 293218792Snp {0x4408, 4, "Chelsio T420-CX"}, 294218792Snp {0x4409, 4, "Chelsio T420-BT"}, 295218792Snp {0x440a, 4, "Chelsio T404-BT"}, 296218792Snp}; 297218792Snp 298218792Snpstatic int 299218792Snpt4_probe(device_t dev) 300218792Snp{ 301218792Snp int i; 302218792Snp uint16_t v = pci_get_vendor(dev); 303218792Snp uint16_t d = pci_get_device(dev); 304218792Snp 305218792Snp if (v != PCI_VENDOR_ID_CHELSIO) 306218792Snp return (ENXIO); 307218792Snp 308218792Snp for (i = 0; i < ARRAY_SIZE(t4_pciids); i++) { 309218792Snp if (d == t4_pciids[i].device && 310218792Snp pci_get_function(dev) == t4_pciids[i].mpf) { 311218792Snp device_set_desc(dev, t4_pciids[i].desc); 312218792Snp return (BUS_PROBE_DEFAULT); 313218792Snp } 314218792Snp } 315218792Snp 316218792Snp return (ENXIO); 317218792Snp} 318218792Snp 319218792Snpstatic int 320218792Snpt4_attach(device_t dev) 321218792Snp{ 322218792Snp struct adapter *sc; 323218792Snp int rc = 0, i, n10g, n1g, rqidx, tqidx; 324218792Snp struct fw_caps_config_cmd caps; 325218792Snp uint32_t p, v; 326218792Snp struct intrs_and_queues iaq; 327218792Snp struct sge *s; 328218792Snp 329218792Snp sc = device_get_softc(dev); 330218792Snp sc->dev = dev; 331218792Snp sc->pf = pci_get_function(dev); 332218792Snp sc->mbox = sc->pf; 333218792Snp 334218792Snp pci_enable_busmaster(dev); 335218792Snp pci_set_max_read_req(dev, 4096); 336218792Snp snprintf(sc->lockname, sizeof(sc->lockname), "%s", 337218792Snp device_get_nameunit(dev)); 338218792Snp mtx_init(&sc->sc_lock, sc->lockname, 0, MTX_DEF); 339218792Snp 340218792Snp rc = map_bars(sc); 341218792Snp if (rc != 0) 342218792Snp goto done; /* error message displayed already */ 343218792Snp 344218792Snp memset(sc->chan_map, 0xff, sizeof(sc->chan_map)); 345218792Snp 346218792Snp /* Prepare the adapter for operation */ 347218792Snp rc = -t4_prep_adapter(sc); 348218792Snp if (rc != 0) { 349218792Snp device_printf(dev, "failed to prepare adapter: %d.\n", rc); 350218792Snp goto done; 351218792Snp } 352218792Snp 353218792Snp /* Do this really early */ 354218792Snp sc->cdev = make_dev(&t4_cdevsw, device_get_unit(dev), UID_ROOT, 355218792Snp GID_WHEEL, 0600, "%s", device_get_nameunit(dev)); 356218792Snp sc->cdev->si_drv1 = sc; 357218792Snp 358218792Snp /* Prepare the firmware for operation */ 359218792Snp rc = prep_firmware(sc); 360218792Snp if (rc != 0) 361218792Snp goto done; /* error message displayed already */ 362218792Snp 363218792Snp /* Get device capabilities and select which ones we'll use */ 364218792Snp rc = get_capabilities(sc, &caps); 365218792Snp if (rc != 0) { 366218792Snp device_printf(dev, 367218792Snp "failed to initialize adapter capabilities: %d.\n", rc); 368218792Snp goto done; 369218792Snp } 370218792Snp 371218792Snp /* Choose the global RSS mode. */ 372218792Snp rc = -t4_config_glbl_rss(sc, sc->mbox, 373218792Snp FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL, 374218792Snp F_FW_RSS_GLB_CONFIG_CMD_TNLMAPEN | 375218792Snp F_FW_RSS_GLB_CONFIG_CMD_TNLALLLKP); 376218792Snp if (rc != 0) { 377218792Snp device_printf(dev, 378218792Snp "failed to select global RSS mode: %d.\n", rc); 379218792Snp goto done; 380218792Snp } 381218792Snp 382218792Snp /* These are total (sum of all ports) limits for a bus driver */ 383218792Snp rc = -t4_cfg_pfvf(sc, sc->mbox, sc->pf, 0, 384218792Snp 64, /* max # of egress queues */ 385218792Snp 64, /* max # of egress Ethernet or control queues */ 386218792Snp 64, /* max # of ingress queues with fl/interrupt */ 387218792Snp 0, /* max # of ingress queues without interrupt */ 388218792Snp 0, /* PCIe traffic class */ 389218792Snp 4, /* max # of virtual interfaces */ 390218792Snp M_FW_PFVF_CMD_CMASK, M_FW_PFVF_CMD_PMASK, 16, 391218792Snp FW_CMD_CAP_PF, FW_CMD_CAP_PF); 392218792Snp if (rc != 0) { 393218792Snp device_printf(dev, 394218792Snp "failed to configure pf/vf resources: %d.\n", rc); 395218792Snp goto done; 396218792Snp } 397218792Snp 398218792Snp /* Need this before sge_init */ 399218792Snp for (i = 0; i < SGE_NTIMERS; i++) 400218792Snp sc->sge.timer_val[i] = min(intr_timer[i], 200U); 401218792Snp for (i = 0; i < SGE_NCOUNTERS; i++) 402218792Snp sc->sge.counter_val[i] = min(intr_pktcount[i], M_THRESHOLD_0); 403218792Snp 404218792Snp /* Also need the cooked value of cclk before sge_init */ 405218792Snp p = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | 406218792Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_CCLK)); 407218792Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 1, &p, &v); 408218792Snp if (rc != 0) { 409218792Snp device_printf(sc->dev, 410218792Snp "failed to obtain core clock value: %d.\n", rc); 411218792Snp goto done; 412218792Snp } 413218792Snp sc->params.vpd.cclk = v; 414218792Snp 415218792Snp t4_sge_init(sc); 416218792Snp 417218792Snp /* 418218792Snp * XXX: This is the place to call t4_set_filter_mode() 419218792Snp */ 420218792Snp 421218792Snp /* get basic stuff going */ 422218792Snp rc = -t4_early_init(sc, sc->mbox); 423218792Snp if (rc != 0) { 424218792Snp device_printf(dev, "early init failed: %d.\n", rc); 425218792Snp goto done; 426218792Snp } 427218792Snp 428218792Snp rc = get_params(sc, &caps); 429218792Snp if (rc != 0) 430218792Snp goto done; /* error message displayed already */ 431218792Snp 432218792Snp /* These are finalized by FW initialization, load their values now */ 433218792Snp v = t4_read_reg(sc, A_TP_TIMER_RESOLUTION); 434218792Snp sc->params.tp.tre = G_TIMERRESOLUTION(v); 435218792Snp sc->params.tp.dack_re = G_DELAYEDACKRESOLUTION(v); 436218792Snp t4_read_mtu_tbl(sc, sc->params.mtus, NULL); 437218792Snp 438218792Snp /* tweak some settings */ 439218792Snp t4_write_reg(sc, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) | V_RXTSHIFTMAXR1(4) | 440218792Snp V_RXTSHIFTMAXR2(15) | V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) | 441218792Snp V_KEEPALIVEMAXR1(4) | V_KEEPALIVEMAXR2(9)); 442218792Snp t4_write_reg(sc, A_ULP_RX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12)); 443218792Snp 444218792Snp setup_memwin(sc); 445218792Snp 446218792Snp rc = t4_create_dma_tag(sc); 447218792Snp if (rc != 0) 448218792Snp goto done; /* error message displayed already */ 449218792Snp 450218792Snp /* 451218792Snp * First pass over all the ports - allocate VIs and initialize some 452218792Snp * basic parameters like mac address, port type, etc. We also figure 453218792Snp * out whether a port is 10G or 1G and use that information when 454218792Snp * calculating how many interrupts to attempt to allocate. 455218792Snp */ 456218792Snp n10g = n1g = 0; 457218792Snp for_each_port(sc, i) { 458218792Snp struct port_info *pi; 459218792Snp 460218792Snp pi = malloc(sizeof(*pi), M_CXGBE, M_ZERO | M_WAITOK); 461218792Snp sc->port[i] = pi; 462218792Snp 463218792Snp /* These must be set before t4_port_init */ 464218792Snp pi->adapter = sc; 465218792Snp pi->port_id = i; 466218792Snp 467218792Snp /* Allocate the vi and initialize parameters like mac addr */ 468218792Snp rc = -t4_port_init(pi, sc->mbox, sc->pf, 0); 469218792Snp if (rc != 0) { 470218792Snp device_printf(dev, "unable to initialize port %d: %d\n", 471218792Snp i, rc); 472218792Snp free(pi, M_CXGBE); 473218792Snp sc->port[i] = NULL; /* indicates init failed */ 474218792Snp continue; 475218792Snp } 476218792Snp 477218792Snp snprintf(pi->lockname, sizeof(pi->lockname), "%sp%d", 478218792Snp device_get_nameunit(dev), i); 479218792Snp mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF); 480218792Snp 481218792Snp if (is_10G_port(pi)) { 482218792Snp n10g++; 483218792Snp pi->tmr_idx = tmr_idx_10g; 484218792Snp pi->pktc_idx = pktc_idx_10g; 485218792Snp } else { 486218792Snp n1g++; 487218792Snp pi->tmr_idx = tmr_idx_1g; 488218792Snp pi->pktc_idx = pktc_idx_1g; 489218792Snp } 490218792Snp 491218792Snp pi->xact_addr_filt = -1; 492218792Snp 493218792Snp pi->qsize_rxq = max(qsize_rxq, 128); 494218792Snp while (pi->qsize_rxq & 7) 495218792Snp pi->qsize_rxq++; 496218792Snp pi->qsize_txq = max(qsize_txq, 128); 497218792Snp 498218792Snp if (pi->qsize_rxq != qsize_rxq) { 499218792Snp device_printf(dev, 500218792Snp "using %d instead of %d as the rx queue size.\n", 501218792Snp pi->qsize_rxq, qsize_rxq); 502218792Snp } 503218792Snp if (pi->qsize_txq != qsize_txq) { 504218792Snp device_printf(dev, 505218792Snp "using %d instead of %d as the tx queue size.\n", 506218792Snp pi->qsize_txq, qsize_txq); 507218792Snp } 508218792Snp 509218792Snp pi->dev = device_add_child(dev, "cxgbe", -1); 510218792Snp if (pi->dev == NULL) { 511218792Snp device_printf(dev, 512218792Snp "failed to add device for port %d.\n", i); 513218792Snp rc = ENXIO; 514218792Snp goto done; 515218792Snp } 516218792Snp device_set_softc(pi->dev, pi); 517218792Snp 518218792Snp setbit(&sc->registered_device_map, i); 519218792Snp } 520218792Snp 521218792Snp if (sc->registered_device_map == 0) { 522218792Snp device_printf(dev, "no usable ports\n"); 523218792Snp rc = ENXIO; 524218792Snp goto done; 525218792Snp } 526218792Snp 527218792Snp /* 528218792Snp * Interrupt type, # of interrupts, # of rx/tx queues, etc. 529218792Snp */ 530218792Snp rc = cfg_itype_and_nqueues(sc, n10g, n1g, &iaq); 531218792Snp if (rc != 0) 532218792Snp goto done; /* error message displayed already */ 533218792Snp 534218792Snp sc->intr_type = iaq.intr_type; 535218792Snp sc->intr_count = iaq.nirq; 536218792Snp 537218792Snp s = &sc->sge; 538218792Snp s->nrxq = n10g * iaq.nrxq10g + n1g * iaq.nrxq1g; 539218792Snp s->ntxq = n10g * iaq.ntxq10g + n1g * iaq.ntxq1g; 540218792Snp s->neq = s->ntxq + s->nrxq; /* the fl in an rxq is an eq */ 541218792Snp s->niq = s->nrxq + 1; /* 1 extra for firmware event queue */ 542218792Snp if (iaq.intr_fwd) { 543218792Snp sc->flags |= INTR_FWD; 544218792Snp s->niq += NFIQ(sc); /* forwarded interrupt queues */ 545218792Snp s->fiq = malloc(NFIQ(sc) * sizeof(struct sge_iq), M_CXGBE, 546218792Snp M_ZERO | M_WAITOK); 547218792Snp } 548218792Snp s->rxq = malloc(s->nrxq * sizeof(struct sge_rxq), M_CXGBE, 549218792Snp M_ZERO | M_WAITOK); 550218792Snp s->txq = malloc(s->ntxq * sizeof(struct sge_txq), M_CXGBE, 551218792Snp M_ZERO | M_WAITOK); 552218792Snp s->iqmap = malloc(s->niq * sizeof(struct sge_iq *), M_CXGBE, 553218792Snp M_ZERO | M_WAITOK); 554218792Snp s->eqmap = malloc(s->neq * sizeof(struct sge_eq *), M_CXGBE, 555218792Snp M_ZERO | M_WAITOK); 556218792Snp 557218792Snp sc->irq = malloc(sc->intr_count * sizeof(struct irq), M_CXGBE, 558218792Snp M_ZERO | M_WAITOK); 559218792Snp 560218792Snp t4_sysctls(sc); 561218792Snp 562218792Snp /* 563218792Snp * Second pass over the ports. This time we know the number of rx and 564218792Snp * tx queues that each port should get. 565218792Snp */ 566218792Snp rqidx = tqidx = 0; 567218792Snp for_each_port(sc, i) { 568218792Snp struct port_info *pi = sc->port[i]; 569218792Snp 570218792Snp if (pi == NULL) 571218792Snp continue; 572218792Snp 573218792Snp pi->first_rxq = rqidx; 574218792Snp pi->nrxq = is_10G_port(pi) ? iaq.nrxq10g : iaq.nrxq1g; 575218792Snp 576218792Snp pi->first_txq = tqidx; 577218792Snp pi->ntxq = is_10G_port(pi) ? iaq.ntxq10g : iaq.ntxq1g; 578218792Snp 579218792Snp rqidx += pi->nrxq; 580218792Snp tqidx += pi->ntxq; 581218792Snp } 582218792Snp 583218792Snp rc = bus_generic_attach(dev); 584218792Snp if (rc != 0) { 585218792Snp device_printf(dev, 586218792Snp "failed to attach all child ports: %d\n", rc); 587218792Snp goto done; 588218792Snp } 589218792Snp 590218792Snp#ifdef INVARIANTS 591218792Snp device_printf(dev, 592218792Snp "%p, %d ports (0x%x), %d intr_type, %d intr_count\n", 593218792Snp sc, sc->params.nports, sc->params.portvec, 594218792Snp sc->intr_type, sc->intr_count); 595218792Snp#endif 596218792Snp t4_set_desc(sc); 597218792Snp 598218792Snpdone: 599218792Snp if (rc != 0) 600218792Snp t4_detach(dev); 601218792Snp 602218792Snp return (rc); 603218792Snp} 604218792Snp 605218792Snp/* 606218792Snp * Idempotent 607218792Snp */ 608218792Snpstatic int 609218792Snpt4_detach(device_t dev) 610218792Snp{ 611218792Snp struct adapter *sc; 612218792Snp struct port_info *pi; 613218792Snp int i; 614218792Snp 615218792Snp sc = device_get_softc(dev); 616218792Snp 617218792Snp if (sc->cdev) 618218792Snp destroy_dev(sc->cdev); 619218792Snp 620218792Snp bus_generic_detach(dev); 621218792Snp for (i = 0; i < MAX_NPORTS; i++) { 622218792Snp pi = sc->port[i]; 623218792Snp if (pi) { 624218792Snp t4_free_vi(pi->adapter, sc->mbox, sc->pf, 0, pi->viid); 625218792Snp if (pi->dev) 626218792Snp device_delete_child(dev, pi->dev); 627218792Snp 628218792Snp mtx_destroy(&pi->pi_lock); 629218792Snp free(pi, M_CXGBE); 630218792Snp } 631218792Snp } 632218792Snp 633218792Snp if (sc->flags & FW_OK) 634218792Snp t4_fw_bye(sc, sc->mbox); 635218792Snp 636218792Snp if (sc->intr_type == 2 || sc->intr_type == 4) 637218792Snp pci_release_msi(dev); 638218792Snp 639218792Snp if (sc->regs_res) 640218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->regs_rid, 641218792Snp sc->regs_res); 642218792Snp 643218792Snp if (sc->msix_res) 644218792Snp bus_release_resource(dev, SYS_RES_MEMORY, sc->msix_rid, 645218792Snp sc->msix_res); 646218792Snp 647218792Snp free(sc->irq, M_CXGBE); 648218792Snp free(sc->sge.rxq, M_CXGBE); 649218792Snp free(sc->sge.txq, M_CXGBE); 650218792Snp free(sc->sge.fiq, M_CXGBE); 651218792Snp free(sc->sge.iqmap, M_CXGBE); 652218792Snp free(sc->sge.eqmap, M_CXGBE); 653218792Snp t4_destroy_dma_tag(sc); 654218792Snp mtx_destroy(&sc->sc_lock); 655218792Snp 656218792Snp bzero(sc, sizeof(*sc)); 657218792Snp 658218792Snp return (0); 659218792Snp} 660218792Snp 661218792Snp 662218792Snpstatic int 663218792Snpcxgbe_probe(device_t dev) 664218792Snp{ 665218792Snp char buf[128]; 666218792Snp struct port_info *pi = device_get_softc(dev); 667218792Snp 668218792Snp snprintf(buf, sizeof(buf), "Port %d", pi->port_id); 669218792Snp device_set_desc_copy(dev, buf); 670218792Snp 671218792Snp return (BUS_PROBE_DEFAULT); 672218792Snp} 673218792Snp 674218792Snp#define T4_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | \ 675218792Snp IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO | \ 676218792Snp IFCAP_VLAN_HWTSO) 677218792Snp#define T4_CAP_ENABLE (T4_CAP & ~IFCAP_TSO6) 678218792Snp 679218792Snpstatic int 680218792Snpcxgbe_attach(device_t dev) 681218792Snp{ 682218792Snp struct port_info *pi = device_get_softc(dev); 683218792Snp struct ifnet *ifp; 684218792Snp 685218792Snp /* Allocate an ifnet and set it up */ 686218792Snp ifp = if_alloc(IFT_ETHER); 687218792Snp if (ifp == NULL) { 688218792Snp device_printf(dev, "Cannot allocate ifnet\n"); 689218792Snp return (ENOMEM); 690218792Snp } 691218792Snp pi->ifp = ifp; 692218792Snp ifp->if_softc = pi; 693218792Snp 694218792Snp callout_init(&pi->tick, CALLOUT_MPSAFE); 695218792Snp 696218792Snp if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 697218792Snp ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 698218792Snp 699218792Snp ifp->if_init = cxgbe_init; 700218792Snp ifp->if_ioctl = cxgbe_ioctl; 701218792Snp ifp->if_start = cxgbe_start; 702218792Snp ifp->if_transmit = cxgbe_transmit; 703218792Snp ifp->if_qflush = cxgbe_qflush; 704218792Snp 705218792Snp ifp->if_snd.ifq_drv_maxlen = 1024; 706218792Snp IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 707218792Snp IFQ_SET_READY(&ifp->if_snd); 708218792Snp 709218792Snp ifp->if_capabilities = T4_CAP; 710218792Snp ifp->if_capenable = T4_CAP_ENABLE; 711218792Snp ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO; 712218792Snp 713218792Snp /* Initialize ifmedia for this port */ 714218792Snp ifmedia_init(&pi->media, IFM_IMASK, cxgbe_media_change, 715218792Snp cxgbe_media_status); 716218792Snp build_medialist(pi); 717218792Snp 718218792Snp ether_ifattach(ifp, pi->hw_addr); 719218792Snp 720218792Snp#ifdef INVARIANTS 721218792Snp device_printf(dev, "%p, %d txq, %d rxq\n", pi, pi->ntxq, pi->nrxq); 722218792Snp#endif 723218792Snp 724218792Snp cxgbe_sysctls(pi); 725218792Snp 726218792Snp return (0); 727218792Snp} 728218792Snp 729218792Snpstatic int 730218792Snpcxgbe_detach(device_t dev) 731218792Snp{ 732218792Snp struct port_info *pi = device_get_softc(dev); 733218792Snp struct adapter *sc = pi->adapter; 734218792Snp int rc; 735218792Snp 736218792Snp /* Tell if_ioctl and if_init that the port is going away */ 737218792Snp ADAPTER_LOCK(sc); 738218792Snp SET_DOOMED(pi); 739218792Snp wakeup(&sc->flags); 740218792Snp while (IS_BUSY(sc)) 741218792Snp mtx_sleep(&sc->flags, &sc->sc_lock, 0, "t4detach", 0); 742218792Snp SET_BUSY(sc); 743218792Snp ADAPTER_UNLOCK(sc); 744218792Snp 745218792Snp rc = cxgbe_uninit_synchronized(pi); 746218792Snp if (rc != 0) 747218792Snp device_printf(dev, "port uninit failed: %d.\n", rc); 748218792Snp 749218792Snp ifmedia_removeall(&pi->media); 750218792Snp ether_ifdetach(pi->ifp); 751218792Snp if_free(pi->ifp); 752218792Snp 753218792Snp ADAPTER_LOCK(sc); 754218792Snp CLR_BUSY(sc); 755218792Snp wakeup_one(&sc->flags); 756218792Snp ADAPTER_UNLOCK(sc); 757218792Snp 758218792Snp return (0); 759218792Snp} 760218792Snp 761218792Snpstatic void 762218792Snpcxgbe_init(void *arg) 763218792Snp{ 764218792Snp struct port_info *pi = arg; 765218792Snp struct adapter *sc = pi->adapter; 766218792Snp 767218792Snp ADAPTER_LOCK(sc); 768218792Snp cxgbe_init_locked(pi); /* releases adapter lock */ 769218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 770218792Snp} 771218792Snp 772218792Snpstatic int 773218792Snpcxgbe_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) 774218792Snp{ 775218792Snp int rc = 0, mtu, flags; 776218792Snp struct port_info *pi = ifp->if_softc; 777218792Snp struct adapter *sc = pi->adapter; 778218792Snp struct ifreq *ifr = (struct ifreq *)data; 779218792Snp uint32_t mask; 780218792Snp 781218792Snp switch (cmd) { 782218792Snp case SIOCSIFMTU: 783218792Snp ADAPTER_LOCK(sc); 784218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 785218792Snp if (rc) { 786218792Snpfail: 787218792Snp ADAPTER_UNLOCK(sc); 788218792Snp return (rc); 789218792Snp } 790218792Snp 791218792Snp mtu = ifr->ifr_mtu; 792218792Snp if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) { 793218792Snp rc = EINVAL; 794218792Snp } else { 795218792Snp ifp->if_mtu = mtu; 796218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 797218792Snp t4_update_fl_bufsize(ifp); 798218792Snp PORT_LOCK(pi); 799218792Snp rc = update_mac_settings(pi, XGMAC_MTU); 800218792Snp PORT_UNLOCK(pi); 801218792Snp } 802218792Snp } 803218792Snp ADAPTER_UNLOCK(sc); 804218792Snp break; 805218792Snp 806218792Snp case SIOCSIFFLAGS: 807218792Snp ADAPTER_LOCK(sc); 808218792Snp if (IS_DOOMED(pi)) { 809218792Snp rc = ENXIO; 810218792Snp goto fail; 811218792Snp } 812218792Snp if (ifp->if_flags & IFF_UP) { 813218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 814218792Snp flags = pi->if_flags; 815218792Snp if ((ifp->if_flags ^ flags) & 816218792Snp (IFF_PROMISC | IFF_ALLMULTI)) { 817218792Snp if (IS_BUSY(sc)) { 818218792Snp rc = EBUSY; 819218792Snp goto fail; 820218792Snp } 821218792Snp PORT_LOCK(pi); 822218792Snp rc = update_mac_settings(pi, 823218792Snp XGMAC_PROMISC | XGMAC_ALLMULTI); 824218792Snp PORT_UNLOCK(pi); 825218792Snp } 826218792Snp ADAPTER_UNLOCK(sc); 827218792Snp } else 828218792Snp rc = cxgbe_init_locked(pi); 829218792Snp pi->if_flags = ifp->if_flags; 830218792Snp } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 831218792Snp rc = cxgbe_uninit_locked(pi); 832218792Snp else 833218792Snp ADAPTER_UNLOCK(sc); 834218792Snp 835218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 836218792Snp break; 837218792Snp 838218792Snp case SIOCADDMULTI: 839218792Snp case SIOCDELMULTI: /* these two can be called with a mutex held :-( */ 840218792Snp ADAPTER_LOCK(sc); 841218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 842218792Snp if (rc) 843218792Snp goto fail; 844218792Snp 845218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 846218792Snp PORT_LOCK(pi); 847218792Snp rc = update_mac_settings(pi, XGMAC_MCADDRS); 848218792Snp PORT_UNLOCK(pi); 849218792Snp } 850218792Snp ADAPTER_UNLOCK(sc); 851218792Snp break; 852218792Snp 853218792Snp case SIOCSIFCAP: 854218792Snp ADAPTER_LOCK(sc); 855218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 856218792Snp if (rc) 857218792Snp goto fail; 858218792Snp 859218792Snp mask = ifr->ifr_reqcap ^ ifp->if_capenable; 860218792Snp if (mask & IFCAP_TXCSUM) { 861218792Snp ifp->if_capenable ^= IFCAP_TXCSUM; 862218792Snp ifp->if_hwassist ^= (CSUM_TCP | CSUM_UDP | CSUM_IP); 863218792Snp 864218792Snp if (IFCAP_TSO & ifp->if_capenable && 865218792Snp !(IFCAP_TXCSUM & ifp->if_capenable)) { 866218792Snp ifp->if_capenable &= ~IFCAP_TSO; 867218792Snp ifp->if_hwassist &= ~CSUM_TSO; 868218792Snp if_printf(ifp, 869218792Snp "tso disabled due to -txcsum.\n"); 870218792Snp } 871218792Snp } 872218792Snp if (mask & IFCAP_RXCSUM) 873218792Snp ifp->if_capenable ^= IFCAP_RXCSUM; 874218792Snp if (mask & IFCAP_TSO4) { 875218792Snp ifp->if_capenable ^= IFCAP_TSO4; 876218792Snp 877218792Snp if (IFCAP_TSO & ifp->if_capenable) { 878218792Snp if (IFCAP_TXCSUM & ifp->if_capenable) 879218792Snp ifp->if_hwassist |= CSUM_TSO; 880218792Snp else { 881218792Snp ifp->if_capenable &= ~IFCAP_TSO; 882218792Snp ifp->if_hwassist &= ~CSUM_TSO; 883218792Snp if_printf(ifp, 884218792Snp "enable txcsum first.\n"); 885218792Snp rc = EAGAIN; 886218792Snp } 887218792Snp } else 888218792Snp ifp->if_hwassist &= ~CSUM_TSO; 889218792Snp } 890218792Snp if (mask & IFCAP_LRO) { 891218792Snp#ifdef INET 892218792Snp int i; 893218792Snp struct sge_rxq *rxq; 894218792Snp 895218792Snp ifp->if_capenable ^= IFCAP_LRO; 896218792Snp for_each_rxq(pi, i, rxq) { 897218792Snp if (ifp->if_capenable & IFCAP_LRO) 898218792Snp rxq->flags |= RXQ_LRO_ENABLED; 899218792Snp else 900218792Snp rxq->flags &= ~RXQ_LRO_ENABLED; 901218792Snp } 902218792Snp#endif 903218792Snp } 904218792Snp#ifndef TCP_OFFLOAD_DISABLE 905218792Snp if (mask & IFCAP_TOE4) { 906218792Snp rc = EOPNOTSUPP; 907218792Snp } 908218792Snp#endif 909218792Snp if (mask & IFCAP_VLAN_HWTAGGING) { 910218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 911218792Snp if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 912218792Snp PORT_LOCK(pi); 913218792Snp rc = update_mac_settings(pi, XGMAC_VLANEX); 914218792Snp PORT_UNLOCK(pi); 915218792Snp } 916218792Snp } 917218792Snp if (mask & IFCAP_VLAN_MTU) { 918218792Snp ifp->if_capenable ^= IFCAP_VLAN_MTU; 919218792Snp 920218792Snp /* Need to find out how to disable auto-mtu-inflation */ 921218792Snp } 922218792Snp if (mask & IFCAP_VLAN_HWTSO) 923218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 924218792Snp if (mask & IFCAP_VLAN_HWCSUM) 925218792Snp ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 926218792Snp 927218792Snp#ifdef VLAN_CAPABILITIES 928218792Snp VLAN_CAPABILITIES(ifp); 929218792Snp#endif 930218792Snp ADAPTER_UNLOCK(sc); 931218792Snp break; 932218792Snp 933218792Snp case SIOCSIFMEDIA: 934218792Snp case SIOCGIFMEDIA: 935218792Snp ifmedia_ioctl(ifp, ifr, &pi->media, cmd); 936218792Snp break; 937218792Snp 938218792Snp default: 939218792Snp rc = ether_ioctl(ifp, cmd, data); 940218792Snp } 941218792Snp 942218792Snp return (rc); 943218792Snp} 944218792Snp 945218792Snpstatic void 946218792Snpcxgbe_start(struct ifnet *ifp) 947218792Snp{ 948218792Snp struct port_info *pi = ifp->if_softc; 949218792Snp struct sge_txq *txq; 950218792Snp int i; 951218792Snp 952218792Snp for_each_txq(pi, i, txq) { 953218792Snp if (TXQ_TRYLOCK(txq)) { 954218792Snp struct buf_ring *br = txq->eq.br; 955218792Snp struct mbuf *m; 956218792Snp 957218792Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 958218792Snp if (m) 959218792Snp t4_eth_tx(ifp, txq, m); 960218792Snp 961218792Snp TXQ_UNLOCK(txq); 962218792Snp } 963218792Snp } 964218792Snp} 965218792Snp 966218792Snpstatic int 967218792Snpcxgbe_transmit(struct ifnet *ifp, struct mbuf *m) 968218792Snp{ 969218792Snp struct port_info *pi = ifp->if_softc; 970218792Snp struct adapter *sc = pi->adapter; 971218792Snp struct sge_txq *txq = &sc->sge.txq[pi->first_txq]; 972218792Snp struct buf_ring *br; 973218792Snp int rc; 974218792Snp 975218792Snp M_ASSERTPKTHDR(m); 976218792Snp 977218792Snp if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 978218792Snp m_freem(m); 979218792Snp return (0); 980218792Snp } 981218792Snp 982218792Snp if (m->m_flags & M_FLOWID) 983218792Snp txq += (m->m_pkthdr.flowid % pi->ntxq); 984218792Snp br = txq->eq.br; 985218792Snp 986218792Snp if (TXQ_TRYLOCK(txq) == 0) { 987218792Snp /* 988218792Snp * XXX: make sure that this packet really is sent out. There is 989218792Snp * a small race where t4_eth_tx may stop draining the drbr and 990218792Snp * goes away, just before we enqueued this mbuf. 991218792Snp */ 992218792Snp 993218792Snp return (drbr_enqueue(ifp, br, m)); 994218792Snp } 995218792Snp 996218792Snp /* 997218792Snp * txq->m is the mbuf that is held up due to a temporary shortage of 998218792Snp * resources and it should be put on the wire first. Then what's in 999218792Snp * drbr and finally the mbuf that was just passed in to us. 1000218792Snp * 1001218792Snp * Return code should indicate the fate of the mbuf that was passed in 1002218792Snp * this time. 1003218792Snp */ 1004218792Snp 1005218792Snp TXQ_LOCK_ASSERT_OWNED(txq); 1006218792Snp if (drbr_needs_enqueue(ifp, br) || txq->m) { 1007218792Snp 1008218792Snp /* Queued for transmission. */ 1009218792Snp 1010218792Snp rc = drbr_enqueue(ifp, br, m); 1011218792Snp m = txq->m ? txq->m : drbr_dequeue(ifp, br); 1012218792Snp (void) t4_eth_tx(ifp, txq, m); 1013218792Snp TXQ_UNLOCK(txq); 1014218792Snp return (rc); 1015218792Snp } 1016218792Snp 1017218792Snp /* Direct transmission. */ 1018218792Snp rc = t4_eth_tx(ifp, txq, m); 1019218792Snp if (rc != 0 && txq->m) 1020218792Snp rc = 0; /* held, will be transmitted soon (hopefully) */ 1021218792Snp 1022218792Snp TXQ_UNLOCK(txq); 1023218792Snp return (rc); 1024218792Snp} 1025218792Snp 1026218792Snpstatic void 1027218792Snpcxgbe_qflush(struct ifnet *ifp) 1028218792Snp{ 1029218792Snp struct port_info *pi = ifp->if_softc; 1030218792Snp 1031218792Snp device_printf(pi->dev, "%s unimplemented.\n", __func__); 1032218792Snp} 1033218792Snp 1034218792Snpstatic int 1035218792Snpcxgbe_media_change(struct ifnet *ifp) 1036218792Snp{ 1037218792Snp struct port_info *pi = ifp->if_softc; 1038218792Snp 1039218792Snp device_printf(pi->dev, "%s unimplemented.\n", __func__); 1040218792Snp 1041218792Snp return (EOPNOTSUPP); 1042218792Snp} 1043218792Snp 1044218792Snpstatic void 1045218792Snpcxgbe_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1046218792Snp{ 1047218792Snp struct port_info *pi = ifp->if_softc; 1048218792Snp struct ifmedia_entry *cur = pi->media.ifm_cur; 1049218792Snp int speed = pi->link_cfg.speed; 1050218792Snp int data = (pi->port_type << 8) | pi->mod_type; 1051218792Snp 1052218792Snp if (cur->ifm_data != data) { 1053218792Snp build_medialist(pi); 1054218792Snp cur = pi->media.ifm_cur; 1055218792Snp } 1056218792Snp 1057218792Snp ifmr->ifm_status = IFM_AVALID; 1058218792Snp if (!pi->link_cfg.link_ok) 1059218792Snp return; 1060218792Snp 1061218792Snp ifmr->ifm_status |= IFM_ACTIVE; 1062218792Snp 1063218792Snp /* active and current will differ iff current media is autoselect. */ 1064218792Snp if (IFM_SUBTYPE(cur->ifm_media) != IFM_AUTO) 1065218792Snp return; 1066218792Snp 1067218792Snp ifmr->ifm_active = IFM_ETHER | IFM_FDX; 1068218792Snp if (speed == SPEED_10000) 1069218792Snp ifmr->ifm_active |= IFM_10G_T; 1070218792Snp else if (speed == SPEED_1000) 1071218792Snp ifmr->ifm_active |= IFM_1000_T; 1072218792Snp else if (speed == SPEED_100) 1073218792Snp ifmr->ifm_active |= IFM_100_TX; 1074218792Snp else if (speed == SPEED_10) 1075218792Snp ifmr->ifm_active |= IFM_10_T; 1076218792Snp else 1077218792Snp KASSERT(0, ("%s: link up but speed unknown (%u)", __func__, 1078218792Snp speed)); 1079218792Snp} 1080218792Snp 1081218792Snpvoid 1082218792Snpt4_fatal_err(struct adapter *sc) 1083218792Snp{ 1084218792Snp t4_set_reg_field(sc, A_SGE_CONTROL, F_GLOBALENABLE, 0); 1085218792Snp t4_intr_disable(sc); 1086218792Snp log(LOG_EMERG, "%s: encountered fatal error, adapter stopped.\n", 1087218792Snp device_get_nameunit(sc->dev)); 1088218792Snp} 1089218792Snp 1090218792Snpstatic int 1091218792Snpmap_bars(struct adapter *sc) 1092218792Snp{ 1093218792Snp sc->regs_rid = PCIR_BAR(0); 1094218792Snp sc->regs_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1095218792Snp &sc->regs_rid, RF_ACTIVE); 1096218792Snp if (sc->regs_res == NULL) { 1097218792Snp device_printf(sc->dev, "cannot map registers.\n"); 1098218792Snp return (ENXIO); 1099218792Snp } 1100218792Snp sc->bt = rman_get_bustag(sc->regs_res); 1101218792Snp sc->bh = rman_get_bushandle(sc->regs_res); 1102218792Snp sc->mmio_len = rman_get_size(sc->regs_res); 1103218792Snp 1104218792Snp sc->msix_rid = PCIR_BAR(4); 1105218792Snp sc->msix_res = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, 1106218792Snp &sc->msix_rid, RF_ACTIVE); 1107218792Snp if (sc->msix_res == NULL) { 1108218792Snp device_printf(sc->dev, "cannot map MSI-X BAR.\n"); 1109218792Snp return (ENXIO); 1110218792Snp } 1111218792Snp 1112218792Snp return (0); 1113218792Snp} 1114218792Snp 1115218792Snpstatic void 1116218792Snpsetup_memwin(struct adapter *sc) 1117218792Snp{ 1118218792Snp u_long bar0; 1119218792Snp 1120218792Snp bar0 = rman_get_start(sc->regs_res); 1121218792Snp 1122218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 0), 1123218792Snp (bar0 + MEMWIN0_BASE) | V_BIR(0) | 1124218792Snp V_WINDOW(ilog2(MEMWIN0_APERTURE) - 10)); 1125218792Snp 1126218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 1), 1127218792Snp (bar0 + MEMWIN1_BASE) | V_BIR(0) | 1128218792Snp V_WINDOW(ilog2(MEMWIN1_APERTURE) - 10)); 1129218792Snp 1130218792Snp t4_write_reg(sc, PCIE_MEM_ACCESS_REG(A_PCIE_MEM_ACCESS_BASE_WIN, 2), 1131218792Snp (bar0 + MEMWIN2_BASE) | V_BIR(0) | 1132218792Snp V_WINDOW(ilog2(MEMWIN2_APERTURE) - 10)); 1133218792Snp} 1134218792Snp 1135218792Snpstatic int 1136218792Snpcfg_itype_and_nqueues(struct adapter *sc, int n10g, int n1g, 1137218792Snp struct intrs_and_queues *iaq) 1138218792Snp{ 1139218792Snp int rc, itype, navail, nc, nrxq10g, nrxq1g; 1140218792Snp 1141218792Snp bzero(iaq, sizeof(*iaq)); 1142218792Snp nc = mp_ncpus; /* our snapshot of the number of CPUs */ 1143218792Snp 1144218792Snp for (itype = 4; itype; itype >>= 1) { 1145218792Snp 1146218792Snp if ((itype & intr_types) == 0) 1147218792Snp continue; /* not allowed */ 1148218792Snp 1149218792Snp if (itype == 4) 1150218792Snp navail = pci_msix_count(sc->dev); 1151218792Snp else if (itype == 2) 1152218792Snp navail = pci_msi_count(sc->dev); 1153218792Snp else 1154218792Snp navail = 1; 1155218792Snp 1156218792Snp if (navail == 0) 1157218792Snp continue; 1158218792Snp 1159218792Snp iaq->intr_type = itype; 1160218792Snp 1161218792Snp iaq->ntxq10g = min(nc, max_ntxq_10g); 1162218792Snp iaq->ntxq1g = min(nc, max_ntxq_1g); 1163218792Snp 1164218792Snp nrxq10g = min(nc, max_nrxq_10g); 1165218792Snp nrxq1g = min(nc, max_nrxq_1g); 1166218792Snp 1167218792Snp /* Extra 2 is for a) error interrupt b) firmware event */ 1168218792Snp iaq->nirq = n10g * nrxq10g + n1g * nrxq1g + 2; 1169218792Snp if (iaq->nirq <= navail && intr_fwd == 0) { 1170218792Snp 1171218792Snp /* One for err, one for fwq, and one for each rxq */ 1172218792Snp 1173218792Snp iaq->intr_fwd = 0; 1174218792Snp iaq->nrxq10g = nrxq10g; 1175218792Snp iaq->nrxq1g = nrxq1g; 1176218792Snp if (itype == 2) { 1177218792Snp /* # of vectors requested must be power of 2 */ 1178218792Snp while (!powerof2(iaq->nirq)) 1179218792Snp iaq->nirq++; 1180218792Snp KASSERT(iaq->nirq <= navail, 1181218792Snp ("%s: bad MSI calculation", __func__)); 1182218792Snp } 1183218792Snp } else { 1184218792Snpfwd: 1185218792Snp iaq->intr_fwd = 1; 1186218792Snp iaq->nirq = navail; 1187218792Snp 1188218792Snp /* 1189218792Snp * If we have multiple vectors available reserve one 1190218792Snp * exclusively for errors. The rest will be shared by 1191218792Snp * the fwq and data. 1192218792Snp */ 1193218792Snp if (navail > 1) { 1194218792Snp navail--; 1195218792Snp 1196218792Snp if (navail > nc && itype == 4) 1197218792Snp iaq->nirq = nc + 1; 1198218792Snp } 1199218792Snp 1200218792Snp iaq->nrxq10g = min(nrxq10g, navail); 1201218792Snp iaq->nrxq1g = min(nrxq1g, navail); 1202218792Snp } 1203218792Snp 1204218792Snp navail = iaq->nirq; 1205218792Snp rc = 0; 1206218792Snp if (itype == 4) 1207218792Snp rc = pci_alloc_msix(sc->dev, &navail); 1208218792Snp else if (itype == 2) 1209218792Snp rc = pci_alloc_msi(sc->dev, &navail); 1210218792Snp 1211218792Snp if (rc == 0) { 1212218792Snp if (navail == iaq->nirq) 1213218792Snp return (0); 1214218792Snp 1215218792Snp /* 1216218792Snp * Didn't get the number requested. Use whatever number 1217218792Snp * the kernel is willing to allocate (it's in navail). 1218218792Snp */ 1219218792Snp pci_release_msi(sc->dev); 1220218792Snp goto fwd; 1221218792Snp } 1222218792Snp 1223218792Snp device_printf(sc->dev, 1224218792Snp "failed to allocate vectors:%d, type=%d, req=%d, rcvd=%d\n", 1225218792Snp itype, rc, iaq->nirq, navail); 1226218792Snp } 1227218792Snp 1228218792Snp device_printf(sc->dev, 1229218792Snp "failed to find a usable interrupt type. " 1230218792Snp "allowed=%d, msi-x=%d, msi=%d, intx=1", intr_types, 1231218792Snp pci_msix_count(sc->dev), pci_msi_count(sc->dev)); 1232218792Snp 1233218792Snp return (ENXIO); 1234218792Snp} 1235218792Snp 1236218792Snp/* 1237218792Snp * Install a compatible firmware (if required), establish contact with it, 1238218792Snp * become the master, and reset the device. 1239218792Snp */ 1240218792Snpstatic int 1241218792Snpprep_firmware(struct adapter *sc) 1242218792Snp{ 1243218792Snp const struct firmware *fw; 1244218792Snp int rc; 1245218792Snp enum dev_state state; 1246218792Snp 1247218792Snp /* Check firmware version and install a different one if necessary */ 1248218792Snp rc = t4_check_fw_version(sc); 1249218792Snp if (rc != 0 || force_firmware_install) { 1250218792Snp 1251218792Snp fw = firmware_get(T4_FWNAME); 1252218792Snp if (fw == NULL) { 1253218792Snp device_printf(sc->dev, 1254218792Snp "Could not find firmware image %s\n", T4_FWNAME); 1255218792Snp return (ENOENT); 1256218792Snp } 1257218792Snp 1258218792Snp device_printf(sc->dev, 1259218792Snp "installing firmware %d.%d.%d on card.\n", 1260218792Snp FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO); 1261218792Snp rc = -t4_load_fw(sc, fw->data, fw->datasize); 1262218792Snp if (rc != 0) { 1263218792Snp device_printf(sc->dev, 1264218792Snp "failed to install firmware: %d\n", rc); 1265218792Snp return (rc); 1266218792Snp } else { 1267218792Snp t4_get_fw_version(sc, &sc->params.fw_vers); 1268218792Snp t4_get_tp_version(sc, &sc->params.tp_vers); 1269218792Snp } 1270218792Snp 1271218792Snp firmware_put(fw, FIRMWARE_UNLOAD); 1272218792Snp } 1273218792Snp 1274218792Snp /* Contact firmware, request master */ 1275218792Snp rc = t4_fw_hello(sc, sc->mbox, sc->mbox, MASTER_MUST, &state); 1276218792Snp if (rc < 0) { 1277218792Snp rc = -rc; 1278218792Snp device_printf(sc->dev, 1279218792Snp "failed to connect to the firmware: %d.\n", rc); 1280218792Snp return (rc); 1281218792Snp } 1282218792Snp 1283218792Snp /* Reset device */ 1284218792Snp rc = -t4_fw_reset(sc, sc->mbox, F_PIORSTMODE | F_PIORST); 1285218792Snp if (rc != 0) { 1286218792Snp device_printf(sc->dev, "firmware reset failed: %d.\n", rc); 1287218792Snp if (rc != ETIMEDOUT && rc != EIO) 1288218792Snp t4_fw_bye(sc, sc->mbox); 1289218792Snp return (rc); 1290218792Snp } 1291218792Snp 1292218792Snp snprintf(sc->fw_version, sizeof(sc->fw_version), "%u.%u.%u.%u", 1293218792Snp G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers), 1294218792Snp G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers), 1295218792Snp G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers), 1296218792Snp G_FW_HDR_FW_VER_BUILD(sc->params.fw_vers)); 1297218792Snp sc->flags |= FW_OK; 1298218792Snp 1299218792Snp return (0); 1300218792Snp} 1301218792Snp 1302218792Snpstatic int 1303218792Snpget_capabilities(struct adapter *sc, struct fw_caps_config_cmd *caps) 1304218792Snp{ 1305218792Snp int rc; 1306218792Snp 1307218792Snp bzero(caps, sizeof(*caps)); 1308218792Snp caps->op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1309218792Snp F_FW_CMD_REQUEST | F_FW_CMD_READ); 1310218792Snp caps->retval_len16 = htobe32(FW_LEN16(*caps)); 1311218792Snp 1312218792Snp rc = -t4_wr_mbox(sc, sc->mbox, caps, sizeof(*caps), caps); 1313218792Snp if (rc != 0) 1314218792Snp return (rc); 1315218792Snp 1316218792Snp if (caps->niccaps & htobe16(FW_CAPS_CONFIG_NIC_VM)) 1317218792Snp caps->niccaps ^= htobe16(FW_CAPS_CONFIG_NIC_VM); 1318218792Snp 1319218792Snp caps->op_to_write = htobe32(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) | 1320218792Snp F_FW_CMD_REQUEST | F_FW_CMD_WRITE); 1321218792Snp rc = -t4_wr_mbox(sc, sc->mbox, caps, sizeof(*caps), NULL); 1322218792Snp 1323218792Snp return (rc); 1324218792Snp} 1325218792Snp 1326218792Snpstatic int 1327218792Snpget_params(struct adapter *sc, struct fw_caps_config_cmd *caps) 1328218792Snp{ 1329218792Snp int rc; 1330218792Snp uint32_t params[7], val[7]; 1331218792Snp 1332218792Snp#define FW_PARAM_DEV(param) \ 1333218792Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \ 1334218792Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param)) 1335218792Snp#define FW_PARAM_PFVF(param) \ 1336218792Snp (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \ 1337218792Snp V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)) 1338218792Snp 1339218792Snp params[0] = FW_PARAM_DEV(PORTVEC); 1340218792Snp params[1] = FW_PARAM_PFVF(IQFLINT_START); 1341218792Snp params[2] = FW_PARAM_PFVF(EQ_START); 1342218792Snp params[3] = FW_PARAM_PFVF(FILTER_START); 1343218792Snp params[4] = FW_PARAM_PFVF(FILTER_END); 1344218792Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 5, params, val); 1345218792Snp if (rc != 0) { 1346218792Snp device_printf(sc->dev, 1347218792Snp "failed to query parameters: %d.\n", rc); 1348218792Snp goto done; 1349218792Snp } 1350218792Snp 1351218792Snp sc->params.portvec = val[0]; 1352218792Snp sc->params.nports = 0; 1353218792Snp while (val[0]) { 1354218792Snp sc->params.nports++; 1355218792Snp val[0] &= val[0] - 1; 1356218792Snp } 1357218792Snp 1358218792Snp sc->sge.iq_start = val[1]; 1359218792Snp sc->sge.eq_start = val[2]; 1360218792Snp sc->tids.ftid_base = val[3]; 1361218792Snp sc->tids.nftids = val[4] - val[3] + 1; 1362218792Snp 1363218792Snp if (caps->toecaps) { 1364218792Snp /* query offload-related parameters */ 1365218792Snp params[0] = FW_PARAM_DEV(NTID); 1366218792Snp params[1] = FW_PARAM_PFVF(SERVER_START); 1367218792Snp params[2] = FW_PARAM_PFVF(SERVER_END); 1368218792Snp params[3] = FW_PARAM_PFVF(TDDP_START); 1369218792Snp params[4] = FW_PARAM_PFVF(TDDP_END); 1370218792Snp params[5] = FW_PARAM_DEV(FLOWC_BUFFIFO_SZ); 1371218792Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, params, val); 1372218792Snp if (rc != 0) { 1373218792Snp device_printf(sc->dev, 1374218792Snp "failed to query TOE parameters: %d.\n", rc); 1375218792Snp goto done; 1376218792Snp } 1377218792Snp sc->tids.ntids = val[0]; 1378218792Snp sc->tids.natids = min(sc->tids.ntids / 2, MAX_ATIDS); 1379218792Snp sc->tids.stid_base = val[1]; 1380218792Snp sc->tids.nstids = val[2] - val[1] + 1; 1381218792Snp sc->vres.ddp.start = val[3]; 1382218792Snp sc->vres.ddp.size = val[4] - val[3] + 1; 1383218792Snp sc->params.ofldq_wr_cred = val[5]; 1384218792Snp sc->params.offload = 1; 1385218792Snp } 1386218792Snp if (caps->rdmacaps) { 1387218792Snp params[0] = FW_PARAM_PFVF(STAG_START); 1388218792Snp params[1] = FW_PARAM_PFVF(STAG_END); 1389218792Snp params[2] = FW_PARAM_PFVF(RQ_START); 1390218792Snp params[3] = FW_PARAM_PFVF(RQ_END); 1391218792Snp params[4] = FW_PARAM_PFVF(PBL_START); 1392218792Snp params[5] = FW_PARAM_PFVF(PBL_END); 1393218792Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 6, params, val); 1394218792Snp if (rc != 0) { 1395218792Snp device_printf(sc->dev, 1396218792Snp "failed to query RDMA parameters: %d.\n", rc); 1397218792Snp goto done; 1398218792Snp } 1399218792Snp sc->vres.stag.start = val[0]; 1400218792Snp sc->vres.stag.size = val[1] - val[0] + 1; 1401218792Snp sc->vres.rq.start = val[2]; 1402218792Snp sc->vres.rq.size = val[3] - val[2] + 1; 1403218792Snp sc->vres.pbl.start = val[4]; 1404218792Snp sc->vres.pbl.size = val[5] - val[4] + 1; 1405218792Snp } 1406218792Snp if (caps->iscsicaps) { 1407218792Snp params[0] = FW_PARAM_PFVF(ISCSI_START); 1408218792Snp params[1] = FW_PARAM_PFVF(ISCSI_END); 1409218792Snp rc = -t4_query_params(sc, sc->mbox, sc->pf, 0, 2, params, val); 1410218792Snp if (rc != 0) { 1411218792Snp device_printf(sc->dev, 1412218792Snp "failed to query iSCSI parameters: %d.\n", rc); 1413218792Snp goto done; 1414218792Snp } 1415218792Snp sc->vres.iscsi.start = val[0]; 1416218792Snp sc->vres.iscsi.size = val[1] - val[0] + 1; 1417218792Snp } 1418218792Snp#undef FW_PARAM_PFVF 1419218792Snp#undef FW_PARAM_DEV 1420218792Snp 1421218792Snpdone: 1422218792Snp return (rc); 1423218792Snp} 1424218792Snp 1425218792Snpstatic void 1426218792Snpt4_set_desc(struct adapter *sc) 1427218792Snp{ 1428218792Snp char buf[128]; 1429218792Snp struct adapter_params *p = &sc->params; 1430218792Snp 1431218792Snp snprintf(buf, sizeof(buf), 1432218792Snp "Chelsio %s (rev %d) %d port %sNIC PCIe-x%d %s, S/N:%s, E/C:%s", 1433218792Snp p->vpd.id, p->rev, p->nports, is_offload(sc) ? "R" : "", 1434218792Snp p->pci.width, (sc->intr_type == 4 ) ? "MSI-X" : 1435218792Snp (sc->intr_type == 2) ? "MSI" : "INTx", p->vpd.sn, p->vpd.ec); 1436218792Snp 1437218792Snp device_set_desc_copy(sc->dev, buf); 1438218792Snp} 1439218792Snp 1440218792Snpstatic void 1441218792Snpbuild_medialist(struct port_info *pi) 1442218792Snp{ 1443218792Snp struct ifmedia *media = &pi->media; 1444218792Snp int data, m; 1445218792Snp 1446218792Snp PORT_LOCK(pi); 1447218792Snp 1448218792Snp ifmedia_removeall(media); 1449218792Snp 1450218792Snp m = IFM_ETHER | IFM_FDX; 1451218792Snp data = (pi->port_type << 8) | pi->mod_type; 1452218792Snp 1453218792Snp switch(pi->port_type) { 1454218792Snp case FW_PORT_TYPE_BT_XFI: 1455218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 1456218792Snp break; 1457218792Snp 1458218792Snp case FW_PORT_TYPE_BT_XAUI: 1459218792Snp ifmedia_add(media, m | IFM_10G_T, data, NULL); 1460218792Snp /* fall through */ 1461218792Snp 1462218792Snp case FW_PORT_TYPE_BT_SGMII: 1463218792Snp ifmedia_add(media, m | IFM_1000_T, data, NULL); 1464218792Snp ifmedia_add(media, m | IFM_100_TX, data, NULL); 1465218792Snp ifmedia_add(media, IFM_ETHER | IFM_AUTO, data, NULL); 1466218792Snp ifmedia_set(media, IFM_ETHER | IFM_AUTO); 1467218792Snp break; 1468218792Snp 1469218792Snp case FW_PORT_TYPE_CX4: 1470218792Snp ifmedia_add(media, m | IFM_10G_CX4, data, NULL); 1471218792Snp ifmedia_set(media, m | IFM_10G_CX4); 1472218792Snp break; 1473218792Snp 1474218792Snp case FW_PORT_TYPE_SFP: 1475218792Snp case FW_PORT_TYPE_FIBER_XFI: 1476218792Snp case FW_PORT_TYPE_FIBER_XAUI: 1477218792Snp switch (pi->mod_type) { 1478218792Snp 1479218792Snp case FW_PORT_MOD_TYPE_LR: 1480218792Snp ifmedia_add(media, m | IFM_10G_LR, data, NULL); 1481218792Snp ifmedia_set(media, m | IFM_10G_LR); 1482218792Snp break; 1483218792Snp 1484218792Snp case FW_PORT_MOD_TYPE_SR: 1485218792Snp ifmedia_add(media, m | IFM_10G_SR, data, NULL); 1486218792Snp ifmedia_set(media, m | IFM_10G_SR); 1487218792Snp break; 1488218792Snp 1489218792Snp case FW_PORT_MOD_TYPE_LRM: 1490218792Snp ifmedia_add(media, m | IFM_10G_LRM, data, NULL); 1491218792Snp ifmedia_set(media, m | IFM_10G_LRM); 1492218792Snp break; 1493218792Snp 1494218792Snp case FW_PORT_MOD_TYPE_TWINAX_PASSIVE: 1495218792Snp case FW_PORT_MOD_TYPE_TWINAX_ACTIVE: 1496218792Snp ifmedia_add(media, m | IFM_10G_TWINAX, data, NULL); 1497218792Snp ifmedia_set(media, m | IFM_10G_TWINAX); 1498218792Snp break; 1499218792Snp 1500218792Snp case FW_PORT_MOD_TYPE_NONE: 1501218792Snp m &= ~IFM_FDX; 1502218792Snp ifmedia_add(media, m | IFM_NONE, data, NULL); 1503218792Snp ifmedia_set(media, m | IFM_NONE); 1504218792Snp break; 1505218792Snp 1506218792Snp case FW_PORT_MOD_TYPE_NA: 1507218792Snp case FW_PORT_MOD_TYPE_ER: 1508218792Snp default: 1509218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 1510218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 1511218792Snp break; 1512218792Snp } 1513218792Snp break; 1514218792Snp 1515218792Snp case FW_PORT_TYPE_KX4: 1516218792Snp case FW_PORT_TYPE_KX: 1517218792Snp case FW_PORT_TYPE_KR: 1518218792Snp default: 1519218792Snp ifmedia_add(media, m | IFM_UNKNOWN, data, NULL); 1520218792Snp ifmedia_set(media, m | IFM_UNKNOWN); 1521218792Snp break; 1522218792Snp } 1523218792Snp 1524218792Snp PORT_UNLOCK(pi); 1525218792Snp} 1526218792Snp 1527218792Snp/* 1528218792Snp * Program the port's XGMAC based on parameters in ifnet. The caller also 1529218792Snp * indicates which parameters should be programmed (the rest are left alone). 1530218792Snp */ 1531218792Snpstatic int 1532218792Snpupdate_mac_settings(struct port_info *pi, int flags) 1533218792Snp{ 1534218792Snp int rc; 1535218792Snp struct ifnet *ifp = pi->ifp; 1536218792Snp struct adapter *sc = pi->adapter; 1537218792Snp int mtu = -1, promisc = -1, allmulti = -1, vlanex = -1; 1538218792Snp 1539218792Snp PORT_LOCK_ASSERT_OWNED(pi); 1540218792Snp KASSERT(flags, ("%s: not told what to update.", __func__)); 1541218792Snp 1542218792Snp if (flags & XGMAC_MTU) 1543218792Snp mtu = ifp->if_mtu; 1544218792Snp 1545218792Snp if (flags & XGMAC_PROMISC) 1546218792Snp promisc = ifp->if_flags & IFF_PROMISC ? 1 : 0; 1547218792Snp 1548218792Snp if (flags & XGMAC_ALLMULTI) 1549218792Snp allmulti = ifp->if_flags & IFF_ALLMULTI ? 1 : 0; 1550218792Snp 1551218792Snp if (flags & XGMAC_VLANEX) 1552218792Snp vlanex = ifp->if_capenable & IFCAP_VLAN_HWTAGGING ? 1 : 0; 1553218792Snp 1554218792Snp rc = -t4_set_rxmode(sc, sc->mbox, pi->viid, mtu, promisc, allmulti, 1, 1555218792Snp vlanex, false); 1556218792Snp if (rc) { 1557218792Snp if_printf(ifp, "set_rxmode (%x) failed: %d\n", flags, rc); 1558218792Snp return (rc); 1559218792Snp } 1560218792Snp 1561218792Snp if (flags & XGMAC_UCADDR) { 1562218792Snp uint8_t ucaddr[ETHER_ADDR_LEN]; 1563218792Snp 1564218792Snp bcopy(IF_LLADDR(ifp), ucaddr, sizeof(ucaddr)); 1565218792Snp rc = t4_change_mac(sc, sc->mbox, pi->viid, pi->xact_addr_filt, 1566218792Snp ucaddr, true, true); 1567218792Snp if (rc < 0) { 1568218792Snp rc = -rc; 1569218792Snp if_printf(ifp, "change_mac failed: %d\n", rc); 1570218792Snp return (rc); 1571218792Snp } else { 1572218792Snp pi->xact_addr_filt = rc; 1573218792Snp rc = 0; 1574218792Snp } 1575218792Snp } 1576218792Snp 1577218792Snp if (flags & XGMAC_MCADDRS) { 1578218792Snp const uint8_t *mcaddr; 1579218792Snp int del = 1; 1580218792Snp uint64_t hash = 0; 1581218792Snp struct ifmultiaddr *ifma; 1582218792Snp 1583218792Snp if_maddr_rlock(ifp); 1584218792Snp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1585218792Snp if (ifma->ifma_addr->sa_family != AF_LINK) 1586218792Snp continue; 1587218792Snp mcaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr); 1588218792Snp 1589218792Snp rc = t4_alloc_mac_filt(sc, sc->mbox, pi->viid, del, 1, 1590218792Snp &mcaddr, NULL, &hash, 0); 1591218792Snp if (rc < 0) { 1592218792Snp rc = -rc; 1593218792Snp if_printf(ifp, "failed to add mc address" 1594218792Snp " %02x:%02x:%02x:%02x:%02x:%02x rc=%d\n", 1595218792Snp mcaddr[0], mcaddr[1], mcaddr[2], mcaddr[3], 1596218792Snp mcaddr[4], mcaddr[5], rc); 1597218792Snp goto mcfail; 1598218792Snp } 1599218792Snp del = 0; 1600218792Snp } 1601218792Snp 1602218792Snp rc = -t4_set_addr_hash(sc, sc->mbox, pi->viid, 0, hash, 0); 1603218792Snp if (rc != 0) 1604218792Snp if_printf(ifp, "failed to set mc address hash: %d", rc); 1605218792Snpmcfail: 1606218792Snp if_maddr_runlock(ifp); 1607218792Snp } 1608218792Snp 1609218792Snp return (rc); 1610218792Snp} 1611218792Snp 1612218792Snpstatic int 1613218792Snpcxgbe_init_locked(struct port_info *pi) 1614218792Snp{ 1615218792Snp struct adapter *sc = pi->adapter; 1616218792Snp int rc = 0; 1617218792Snp 1618218792Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 1619218792Snp 1620218792Snp while (!IS_DOOMED(pi) && IS_BUSY(sc)) { 1621218792Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4init", 0)) { 1622218792Snp rc = EINTR; 1623218792Snp goto done; 1624218792Snp } 1625218792Snp } 1626218792Snp if (IS_DOOMED(pi)) { 1627218792Snp rc = ENXIO; 1628218792Snp goto done; 1629218792Snp } 1630218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 1631218792Snp 1632218792Snp /* Give up the adapter lock, port init code can sleep. */ 1633218792Snp SET_BUSY(sc); 1634218792Snp ADAPTER_UNLOCK(sc); 1635218792Snp 1636218792Snp rc = cxgbe_init_synchronized(pi); 1637218792Snp 1638218792Snpdone: 1639218792Snp ADAPTER_LOCK(sc); 1640218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 1641218792Snp CLR_BUSY(sc); 1642218792Snp wakeup_one(&sc->flags); 1643218792Snp ADAPTER_UNLOCK(sc); 1644218792Snp return (rc); 1645218792Snp} 1646218792Snp 1647218792Snpstatic int 1648218792Snpcxgbe_init_synchronized(struct port_info *pi) 1649218792Snp{ 1650218792Snp struct adapter *sc = pi->adapter; 1651218792Snp struct ifnet *ifp = pi->ifp; 1652218792Snp int rc = 0, i; 1653218792Snp uint16_t *rss; 1654218792Snp struct sge_rxq *rxq; 1655218792Snp 1656218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 1657218792Snp 1658218792Snp if (isset(&sc->open_device_map, pi->port_id)) { 1659218792Snp KASSERT(ifp->if_drv_flags & IFF_DRV_RUNNING, 1660218792Snp ("mismatch between open_device_map and if_drv_flags")); 1661218792Snp return (0); /* already running */ 1662218792Snp } 1663218792Snp 1664218792Snp if (sc->open_device_map == 0 && ((rc = first_port_up(sc)) != 0)) 1665218792Snp return (rc); /* error message displayed already */ 1666218792Snp 1667218792Snp /* 1668218792Snp * Allocate tx/rx/fl queues for this port. 1669218792Snp */ 1670218792Snp rc = t4_setup_eth_queues(pi); 1671218792Snp if (rc != 0) 1672218792Snp goto done; /* error message displayed already */ 1673218792Snp 1674218792Snp /* 1675218792Snp * Setup RSS for this port. 1676218792Snp */ 1677218792Snp rss = malloc(pi->nrxq * sizeof (*rss), M_CXGBE, M_ZERO | M_WAITOK); 1678218792Snp for_each_rxq(pi, i, rxq) { 1679218792Snp rss[i] = rxq->iq.abs_id; 1680218792Snp } 1681218792Snp rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, pi->rss_size, rss, 1682218792Snp pi->nrxq); 1683218792Snp free(rss, M_CXGBE); 1684218792Snp if (rc != 0) { 1685218792Snp if_printf(ifp, "rss_config failed: %d\n", rc); 1686218792Snp goto done; 1687218792Snp } 1688218792Snp 1689218792Snp PORT_LOCK(pi); 1690218792Snp rc = update_mac_settings(pi, XGMAC_ALL); 1691218792Snp PORT_UNLOCK(pi); 1692218792Snp if (rc) 1693218792Snp goto done; /* error message displayed already */ 1694218792Snp 1695218792Snp rc = -t4_link_start(sc, sc->mbox, pi->tx_chan, &pi->link_cfg); 1696218792Snp if (rc != 0) { 1697218792Snp if_printf(ifp, "start_link failed: %d\n", rc); 1698218792Snp goto done; 1699218792Snp } 1700218792Snp 1701218792Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, true, true); 1702218792Snp if (rc != 0) { 1703218792Snp if_printf(ifp, "enable_vi failed: %d\n", rc); 1704218792Snp goto done; 1705218792Snp } 1706218792Snp pi->flags |= VI_ENABLED; 1707218792Snp 1708218792Snp /* all ok */ 1709218792Snp setbit(&sc->open_device_map, pi->port_id); 1710218792Snp ifp->if_drv_flags |= IFF_DRV_RUNNING; 1711218792Snp ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1712218792Snp 1713218792Snp callout_reset(&pi->tick, hz, cxgbe_tick, pi); 1714218792Snpdone: 1715218792Snp if (rc != 0) 1716218792Snp cxgbe_uninit_synchronized(pi); 1717218792Snp 1718218792Snp return (rc); 1719218792Snp} 1720218792Snp 1721218792Snpstatic int 1722218792Snpcxgbe_uninit_locked(struct port_info *pi) 1723218792Snp{ 1724218792Snp struct adapter *sc = pi->adapter; 1725218792Snp int rc; 1726218792Snp 1727218792Snp ADAPTER_LOCK_ASSERT_OWNED(sc); 1728218792Snp 1729218792Snp while (!IS_DOOMED(pi) && IS_BUSY(sc)) { 1730218792Snp if (mtx_sleep(&sc->flags, &sc->sc_lock, PCATCH, "t4uninit", 0)) { 1731218792Snp rc = EINTR; 1732218792Snp goto done; 1733218792Snp } 1734218792Snp } 1735218792Snp if (IS_DOOMED(pi)) { 1736218792Snp rc = ENXIO; 1737218792Snp goto done; 1738218792Snp } 1739218792Snp KASSERT(!IS_BUSY(sc), ("%s: controller busy.", __func__)); 1740218792Snp SET_BUSY(sc); 1741218792Snp ADAPTER_UNLOCK(sc); 1742218792Snp 1743218792Snp rc = cxgbe_uninit_synchronized(pi); 1744218792Snp 1745218792Snp ADAPTER_LOCK(sc); 1746218792Snp KASSERT(IS_BUSY(sc), ("%s: controller not busy.", __func__)); 1747218792Snp CLR_BUSY(sc); 1748218792Snp wakeup_one(&sc->flags); 1749218792Snpdone: 1750218792Snp ADAPTER_UNLOCK(sc); 1751218792Snp return (rc); 1752218792Snp} 1753218792Snp 1754218792Snp/* 1755218792Snp * Idempotent. 1756218792Snp */ 1757218792Snpstatic int 1758218792Snpcxgbe_uninit_synchronized(struct port_info *pi) 1759218792Snp{ 1760218792Snp struct adapter *sc = pi->adapter; 1761218792Snp struct ifnet *ifp = pi->ifp; 1762218792Snp int rc; 1763218792Snp 1764218792Snp /* 1765218792Snp * taskqueue_drain may cause a deadlock if the adapter lock is held. 1766218792Snp */ 1767218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 1768218792Snp 1769218792Snp /* 1770218792Snp * Clear this port's bit from the open device map, and then drain 1771218792Snp * tasks and callouts. 1772218792Snp */ 1773218792Snp clrbit(&sc->open_device_map, pi->port_id); 1774218792Snp 1775218792Snp PORT_LOCK(pi); 1776218792Snp ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1777218792Snp callout_stop(&pi->tick); 1778218792Snp PORT_UNLOCK(pi); 1779218792Snp callout_drain(&pi->tick); 1780218792Snp 1781218792Snp /* 1782218792Snp * Stop and then free the queues' resources, including the queues 1783218792Snp * themselves. 1784218792Snp * 1785218792Snp * XXX: we could just stop the queues here (on ifconfig down) and free 1786218792Snp * them later (on port detach), but having up/down go through the entire 1787218792Snp * allocate/activate/deactivate/free sequence is a good way to find 1788218792Snp * leaks and bugs. 1789218792Snp */ 1790218792Snp rc = t4_teardown_eth_queues(pi); 1791218792Snp if (rc != 0) 1792218792Snp if_printf(ifp, "teardown failed: %d\n", rc); 1793218792Snp 1794218792Snp if (pi->flags & VI_ENABLED) { 1795218792Snp rc = -t4_enable_vi(sc, sc->mbox, pi->viid, false, false); 1796218792Snp if (rc) 1797218792Snp if_printf(ifp, "disable_vi failed: %d\n", rc); 1798218792Snp else 1799218792Snp pi->flags &= ~VI_ENABLED; 1800218792Snp } 1801218792Snp 1802218792Snp pi->link_cfg.link_ok = 0; 1803218792Snp pi->link_cfg.speed = 0; 1804218792Snp t4_os_link_changed(sc, pi->port_id, 0); 1805218792Snp 1806218792Snp if (sc->open_device_map == 0) 1807218792Snp last_port_down(sc); 1808218792Snp 1809218792Snp return (0); 1810218792Snp} 1811218792Snp 1812218792Snp#define T4_ALLOC_IRQ(sc, irqid, rid, handler, arg, name) do { \ 1813218792Snp rc = t4_alloc_irq(sc, &sc->irq[irqid], rid, handler, arg, name); \ 1814218792Snp if (rc != 0) \ 1815218792Snp goto done; \ 1816218792Snp} while (0) 1817218792Snpstatic int 1818218792Snpfirst_port_up(struct adapter *sc) 1819218792Snp{ 1820218792Snp int rc, i; 1821218792Snp char name[8]; 1822218792Snp 1823218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 1824218792Snp 1825218792Snp /* 1826218792Snp * The firmware event queue and the optional forwarded interrupt queues. 1827218792Snp */ 1828218792Snp rc = t4_setup_adapter_iqs(sc); 1829218792Snp if (rc != 0) 1830218792Snp goto done; 1831218792Snp 1832218792Snp /* 1833218792Snp * Setup interrupts. 1834218792Snp */ 1835218792Snp if (sc->intr_count == 1) { 1836218792Snp KASSERT(sc->flags & INTR_FWD, 1837218792Snp ("%s: single interrupt but not forwarded?", __func__)); 1838218792Snp T4_ALLOC_IRQ(sc, 0, 0, t4_intr_all, sc, "all"); 1839218792Snp } else { 1840218792Snp /* Multiple interrupts. The first one is always error intr */ 1841218792Snp T4_ALLOC_IRQ(sc, 0, 1, t4_intr_err, sc, "err"); 1842218792Snp 1843218792Snp if (sc->flags & INTR_FWD) { 1844218792Snp /* The rest are shared by the fwq and all data intr */ 1845218792Snp for (i = 1; i < sc->intr_count; i++) { 1846218792Snp snprintf(name, sizeof(name), "mux%d", i - 1); 1847218792Snp T4_ALLOC_IRQ(sc, i, i + 1, t4_intr_fwd, 1848218792Snp &sc->sge.fiq[i - 1], name); 1849218792Snp } 1850218792Snp } else { 1851218792Snp struct port_info *pi; 1852218792Snp int p, q; 1853218792Snp 1854218792Snp T4_ALLOC_IRQ(sc, 1, 2, t4_intr_evt, &sc->sge.fwq, 1855218792Snp "evt"); 1856218792Snp 1857218792Snp p = q = 0; 1858218792Snp pi = sc->port[p]; 1859218792Snp for (i = 2; i < sc->intr_count; i++) { 1860218792Snp snprintf(name, sizeof(name), "p%dq%d", p, q); 1861218792Snp if (++q >= pi->nrxq) { 1862218792Snp p++; 1863218792Snp q = 0; 1864218792Snp pi = sc->port[p]; 1865218792Snp } 1866218792Snp T4_ALLOC_IRQ(sc, i, i + 1, t4_intr_data, 1867218792Snp &sc->sge.rxq[i - 2], name); 1868218792Snp } 1869218792Snp } 1870218792Snp } 1871218792Snp 1872218792Snp t4_intr_enable(sc); 1873218792Snp sc->flags |= FULL_INIT_DONE; 1874218792Snp 1875218792Snpdone: 1876218792Snp if (rc != 0) 1877218792Snp last_port_down(sc); 1878218792Snp 1879218792Snp return (rc); 1880218792Snp} 1881218792Snp#undef T4_ALLOC_IRQ 1882218792Snp 1883218792Snp/* 1884218792Snp * Idempotent. 1885218792Snp */ 1886218792Snpstatic int 1887218792Snplast_port_down(struct adapter *sc) 1888218792Snp{ 1889218792Snp int i; 1890218792Snp 1891218792Snp ADAPTER_LOCK_ASSERT_NOTOWNED(sc); 1892218792Snp 1893218792Snp t4_intr_disable(sc); 1894218792Snp 1895218792Snp t4_teardown_adapter_iqs(sc); 1896218792Snp 1897218792Snp for (i = 0; i < sc->intr_count; i++) 1898218792Snp t4_free_irq(sc, &sc->irq[i]); 1899218792Snp 1900218792Snp sc->flags &= ~FULL_INIT_DONE; 1901218792Snp 1902218792Snp return (0); 1903218792Snp} 1904218792Snp 1905218792Snpstatic int 1906218792Snpt4_alloc_irq(struct adapter *sc, struct irq *irq, int rid, 1907218792Snp iq_intr_handler_t *handler, void *arg, char *name) 1908218792Snp{ 1909218792Snp int rc; 1910218792Snp 1911218792Snp irq->rid = rid; 1912218792Snp irq->res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &irq->rid, 1913218792Snp RF_SHAREABLE | RF_ACTIVE); 1914218792Snp if (irq->res == NULL) { 1915218792Snp device_printf(sc->dev, 1916218792Snp "failed to allocate IRQ for rid %d, name %s.\n", rid, name); 1917218792Snp return (ENOMEM); 1918218792Snp } 1919218792Snp 1920218792Snp rc = bus_setup_intr(sc->dev, irq->res, INTR_MPSAFE | INTR_TYPE_NET, 1921218792Snp NULL, handler, arg, &irq->tag); 1922218792Snp if (rc != 0) { 1923218792Snp device_printf(sc->dev, 1924218792Snp "failed to setup interrupt for rid %d, name %s: %d\n", 1925218792Snp rid, name, rc); 1926218792Snp } else if (name) 1927218792Snp bus_describe_intr(sc->dev, irq->res, irq->tag, name); 1928218792Snp 1929218792Snp return (rc); 1930218792Snp} 1931218792Snp 1932218792Snpstatic int 1933218792Snpt4_free_irq(struct adapter *sc, struct irq *irq) 1934218792Snp{ 1935218792Snp if (irq->tag) 1936218792Snp bus_teardown_intr(sc->dev, irq->res, irq->tag); 1937218792Snp if (irq->res) 1938218792Snp bus_release_resource(sc->dev, SYS_RES_IRQ, irq->rid, irq->res); 1939218792Snp 1940218792Snp bzero(irq, sizeof(*irq)); 1941218792Snp 1942218792Snp return (0); 1943218792Snp} 1944218792Snp 1945218792Snpstatic void 1946218792Snpreg_block_dump(struct adapter *sc, uint8_t *buf, unsigned int start, 1947218792Snp unsigned int end) 1948218792Snp{ 1949218792Snp uint32_t *p = (uint32_t *)(buf + start); 1950218792Snp 1951218792Snp for ( ; start <= end; start += sizeof(uint32_t)) 1952218792Snp *p++ = t4_read_reg(sc, start); 1953218792Snp} 1954218792Snp 1955218792Snpstatic void 1956218792Snpt4_get_regs(struct adapter *sc, struct t4_regdump *regs, uint8_t *buf) 1957218792Snp{ 1958218792Snp int i; 1959218792Snp static const unsigned int reg_ranges[] = { 1960218792Snp 0x1008, 0x1108, 1961218792Snp 0x1180, 0x11b4, 1962218792Snp 0x11fc, 0x123c, 1963218792Snp 0x1300, 0x173c, 1964218792Snp 0x1800, 0x18fc, 1965218792Snp 0x3000, 0x30d8, 1966218792Snp 0x30e0, 0x5924, 1967218792Snp 0x5960, 0x59d4, 1968218792Snp 0x5a00, 0x5af8, 1969218792Snp 0x6000, 0x6098, 1970218792Snp 0x6100, 0x6150, 1971218792Snp 0x6200, 0x6208, 1972218792Snp 0x6240, 0x6248, 1973218792Snp 0x6280, 0x6338, 1974218792Snp 0x6370, 0x638c, 1975218792Snp 0x6400, 0x643c, 1976218792Snp 0x6500, 0x6524, 1977218792Snp 0x6a00, 0x6a38, 1978218792Snp 0x6a60, 0x6a78, 1979218792Snp 0x6b00, 0x6b84, 1980218792Snp 0x6bf0, 0x6c84, 1981218792Snp 0x6cf0, 0x6d84, 1982218792Snp 0x6df0, 0x6e84, 1983218792Snp 0x6ef0, 0x6f84, 1984218792Snp 0x6ff0, 0x7084, 1985218792Snp 0x70f0, 0x7184, 1986218792Snp 0x71f0, 0x7284, 1987218792Snp 0x72f0, 0x7384, 1988218792Snp 0x73f0, 0x7450, 1989218792Snp 0x7500, 0x7530, 1990218792Snp 0x7600, 0x761c, 1991218792Snp 0x7680, 0x76cc, 1992218792Snp 0x7700, 0x7798, 1993218792Snp 0x77c0, 0x77fc, 1994218792Snp 0x7900, 0x79fc, 1995218792Snp 0x7b00, 0x7c38, 1996218792Snp 0x7d00, 0x7efc, 1997218792Snp 0x8dc0, 0x8e1c, 1998218792Snp 0x8e30, 0x8e78, 1999218792Snp 0x8ea0, 0x8f6c, 2000218792Snp 0x8fc0, 0x9074, 2001218792Snp 0x90fc, 0x90fc, 2002218792Snp 0x9400, 0x9458, 2003218792Snp 0x9600, 0x96bc, 2004218792Snp 0x9800, 0x9808, 2005218792Snp 0x9820, 0x983c, 2006218792Snp 0x9850, 0x9864, 2007218792Snp 0x9c00, 0x9c6c, 2008218792Snp 0x9c80, 0x9cec, 2009218792Snp 0x9d00, 0x9d6c, 2010218792Snp 0x9d80, 0x9dec, 2011218792Snp 0x9e00, 0x9e6c, 2012218792Snp 0x9e80, 0x9eec, 2013218792Snp 0x9f00, 0x9f6c, 2014218792Snp 0x9f80, 0x9fec, 2015218792Snp 0xd004, 0xd03c, 2016218792Snp 0xdfc0, 0xdfe0, 2017218792Snp 0xe000, 0xea7c, 2018218792Snp 0xf000, 0x11190, 2019218792Snp 0x19040, 0x19124, 2020218792Snp 0x19150, 0x191b0, 2021218792Snp 0x191d0, 0x191e8, 2022218792Snp 0x19238, 0x1924c, 2023218792Snp 0x193f8, 0x19474, 2024218792Snp 0x19490, 0x194f8, 2025218792Snp 0x19800, 0x19f30, 2026218792Snp 0x1a000, 0x1a06c, 2027218792Snp 0x1a0b0, 0x1a120, 2028218792Snp 0x1a128, 0x1a138, 2029218792Snp 0x1a190, 0x1a1c4, 2030218792Snp 0x1a1fc, 0x1a1fc, 2031218792Snp 0x1e040, 0x1e04c, 2032218792Snp 0x1e240, 0x1e28c, 2033218792Snp 0x1e2c0, 0x1e2c0, 2034218792Snp 0x1e2e0, 0x1e2e0, 2035218792Snp 0x1e300, 0x1e384, 2036218792Snp 0x1e3c0, 0x1e3c8, 2037218792Snp 0x1e440, 0x1e44c, 2038218792Snp 0x1e640, 0x1e68c, 2039218792Snp 0x1e6c0, 0x1e6c0, 2040218792Snp 0x1e6e0, 0x1e6e0, 2041218792Snp 0x1e700, 0x1e784, 2042218792Snp 0x1e7c0, 0x1e7c8, 2043218792Snp 0x1e840, 0x1e84c, 2044218792Snp 0x1ea40, 0x1ea8c, 2045218792Snp 0x1eac0, 0x1eac0, 2046218792Snp 0x1eae0, 0x1eae0, 2047218792Snp 0x1eb00, 0x1eb84, 2048218792Snp 0x1ebc0, 0x1ebc8, 2049218792Snp 0x1ec40, 0x1ec4c, 2050218792Snp 0x1ee40, 0x1ee8c, 2051218792Snp 0x1eec0, 0x1eec0, 2052218792Snp 0x1eee0, 0x1eee0, 2053218792Snp 0x1ef00, 0x1ef84, 2054218792Snp 0x1efc0, 0x1efc8, 2055218792Snp 0x1f040, 0x1f04c, 2056218792Snp 0x1f240, 0x1f28c, 2057218792Snp 0x1f2c0, 0x1f2c0, 2058218792Snp 0x1f2e0, 0x1f2e0, 2059218792Snp 0x1f300, 0x1f384, 2060218792Snp 0x1f3c0, 0x1f3c8, 2061218792Snp 0x1f440, 0x1f44c, 2062218792Snp 0x1f640, 0x1f68c, 2063218792Snp 0x1f6c0, 0x1f6c0, 2064218792Snp 0x1f6e0, 0x1f6e0, 2065218792Snp 0x1f700, 0x1f784, 2066218792Snp 0x1f7c0, 0x1f7c8, 2067218792Snp 0x1f840, 0x1f84c, 2068218792Snp 0x1fa40, 0x1fa8c, 2069218792Snp 0x1fac0, 0x1fac0, 2070218792Snp 0x1fae0, 0x1fae0, 2071218792Snp 0x1fb00, 0x1fb84, 2072218792Snp 0x1fbc0, 0x1fbc8, 2073218792Snp 0x1fc40, 0x1fc4c, 2074218792Snp 0x1fe40, 0x1fe8c, 2075218792Snp 0x1fec0, 0x1fec0, 2076218792Snp 0x1fee0, 0x1fee0, 2077218792Snp 0x1ff00, 0x1ff84, 2078218792Snp 0x1ffc0, 0x1ffc8, 2079218792Snp 0x20000, 0x2002c, 2080218792Snp 0x20100, 0x2013c, 2081218792Snp 0x20190, 0x201c8, 2082218792Snp 0x20200, 0x20318, 2083218792Snp 0x20400, 0x20528, 2084218792Snp 0x20540, 0x20614, 2085218792Snp 0x21000, 0x21040, 2086218792Snp 0x2104c, 0x21060, 2087218792Snp 0x210c0, 0x210ec, 2088218792Snp 0x21200, 0x21268, 2089218792Snp 0x21270, 0x21284, 2090218792Snp 0x212fc, 0x21388, 2091218792Snp 0x21400, 0x21404, 2092218792Snp 0x21500, 0x21518, 2093218792Snp 0x2152c, 0x2153c, 2094218792Snp 0x21550, 0x21554, 2095218792Snp 0x21600, 0x21600, 2096218792Snp 0x21608, 0x21628, 2097218792Snp 0x21630, 0x2163c, 2098218792Snp 0x21700, 0x2171c, 2099218792Snp 0x21780, 0x2178c, 2100218792Snp 0x21800, 0x21c38, 2101218792Snp 0x21c80, 0x21d7c, 2102218792Snp 0x21e00, 0x21e04, 2103218792Snp 0x22000, 0x2202c, 2104218792Snp 0x22100, 0x2213c, 2105218792Snp 0x22190, 0x221c8, 2106218792Snp 0x22200, 0x22318, 2107218792Snp 0x22400, 0x22528, 2108218792Snp 0x22540, 0x22614, 2109218792Snp 0x23000, 0x23040, 2110218792Snp 0x2304c, 0x23060, 2111218792Snp 0x230c0, 0x230ec, 2112218792Snp 0x23200, 0x23268, 2113218792Snp 0x23270, 0x23284, 2114218792Snp 0x232fc, 0x23388, 2115218792Snp 0x23400, 0x23404, 2116218792Snp 0x23500, 0x23518, 2117218792Snp 0x2352c, 0x2353c, 2118218792Snp 0x23550, 0x23554, 2119218792Snp 0x23600, 0x23600, 2120218792Snp 0x23608, 0x23628, 2121218792Snp 0x23630, 0x2363c, 2122218792Snp 0x23700, 0x2371c, 2123218792Snp 0x23780, 0x2378c, 2124218792Snp 0x23800, 0x23c38, 2125218792Snp 0x23c80, 0x23d7c, 2126218792Snp 0x23e00, 0x23e04, 2127218792Snp 0x24000, 0x2402c, 2128218792Snp 0x24100, 0x2413c, 2129218792Snp 0x24190, 0x241c8, 2130218792Snp 0x24200, 0x24318, 2131218792Snp 0x24400, 0x24528, 2132218792Snp 0x24540, 0x24614, 2133218792Snp 0x25000, 0x25040, 2134218792Snp 0x2504c, 0x25060, 2135218792Snp 0x250c0, 0x250ec, 2136218792Snp 0x25200, 0x25268, 2137218792Snp 0x25270, 0x25284, 2138218792Snp 0x252fc, 0x25388, 2139218792Snp 0x25400, 0x25404, 2140218792Snp 0x25500, 0x25518, 2141218792Snp 0x2552c, 0x2553c, 2142218792Snp 0x25550, 0x25554, 2143218792Snp 0x25600, 0x25600, 2144218792Snp 0x25608, 0x25628, 2145218792Snp 0x25630, 0x2563c, 2146218792Snp 0x25700, 0x2571c, 2147218792Snp 0x25780, 0x2578c, 2148218792Snp 0x25800, 0x25c38, 2149218792Snp 0x25c80, 0x25d7c, 2150218792Snp 0x25e00, 0x25e04, 2151218792Snp 0x26000, 0x2602c, 2152218792Snp 0x26100, 0x2613c, 2153218792Snp 0x26190, 0x261c8, 2154218792Snp 0x26200, 0x26318, 2155218792Snp 0x26400, 0x26528, 2156218792Snp 0x26540, 0x26614, 2157218792Snp 0x27000, 0x27040, 2158218792Snp 0x2704c, 0x27060, 2159218792Snp 0x270c0, 0x270ec, 2160218792Snp 0x27200, 0x27268, 2161218792Snp 0x27270, 0x27284, 2162218792Snp 0x272fc, 0x27388, 2163218792Snp 0x27400, 0x27404, 2164218792Snp 0x27500, 0x27518, 2165218792Snp 0x2752c, 0x2753c, 2166218792Snp 0x27550, 0x27554, 2167218792Snp 0x27600, 0x27600, 2168218792Snp 0x27608, 0x27628, 2169218792Snp 0x27630, 0x2763c, 2170218792Snp 0x27700, 0x2771c, 2171218792Snp 0x27780, 0x2778c, 2172218792Snp 0x27800, 0x27c38, 2173218792Snp 0x27c80, 0x27d7c, 2174218792Snp 0x27e00, 0x27e04 2175218792Snp }; 2176218792Snp 2177218792Snp regs->version = 4 | (sc->params.rev << 10); 2178218792Snp for (i = 0; i < ARRAY_SIZE(reg_ranges); i += 2) 2179218792Snp reg_block_dump(sc, buf, reg_ranges[i], reg_ranges[i + 1]); 2180218792Snp} 2181218792Snp 2182218792Snpstatic void 2183218792Snpcxgbe_tick(void *arg) 2184218792Snp{ 2185218792Snp struct port_info *pi = arg; 2186218792Snp struct ifnet *ifp = pi->ifp; 2187218792Snp struct sge_txq *txq; 2188218792Snp int i, drops; 2189218792Snp struct port_stats *s = &pi->stats; 2190218792Snp 2191218792Snp PORT_LOCK(pi); 2192218792Snp if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2193218792Snp PORT_UNLOCK(pi); 2194218792Snp return; /* without scheduling another callout */ 2195218792Snp } 2196218792Snp 2197218792Snp t4_get_port_stats(pi->adapter, pi->tx_chan, s); 2198218792Snp 2199218792Snp ifp->if_opackets = s->tx_frames; 2200218792Snp ifp->if_ipackets = s->rx_frames; 2201218792Snp ifp->if_obytes = s->tx_octets; 2202218792Snp ifp->if_ibytes = s->rx_octets; 2203218792Snp ifp->if_omcasts = s->tx_mcast_frames; 2204218792Snp ifp->if_imcasts = s->rx_mcast_frames; 2205218792Snp ifp->if_iqdrops = s->rx_ovflow0 + s->rx_ovflow1 + s->rx_ovflow2 + 2206218792Snp s->rx_ovflow3; 2207218792Snp 2208218792Snp drops = s->tx_drop; 2209218792Snp for_each_txq(pi, i, txq) 2210218792Snp drops += txq->eq.br->br_drops; 2211218792Snp ifp->if_snd.ifq_drops = drops; 2212218792Snp 2213218792Snp ifp->if_oerrors = s->tx_error_frames; 2214218792Snp ifp->if_ierrors = s->rx_jabber + s->rx_runt + s->rx_too_long + 2215218792Snp s->rx_fcs_err + s->rx_len_err; 2216218792Snp 2217218792Snp callout_schedule(&pi->tick, hz); 2218218792Snp PORT_UNLOCK(pi); 2219218792Snp} 2220218792Snp 2221218792Snpstatic int 2222218792Snpt4_sysctls(struct adapter *sc) 2223218792Snp{ 2224218792Snp struct sysctl_ctx_list *ctx; 2225218792Snp struct sysctl_oid *oid; 2226218792Snp struct sysctl_oid_list *children; 2227218792Snp 2228218792Snp ctx = device_get_sysctl_ctx(sc->dev); 2229218792Snp oid = device_get_sysctl_tree(sc->dev); 2230218792Snp children = SYSCTL_CHILDREN(oid); 2231218792Snp 2232218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nports", CTLFLAG_RD, 2233218792Snp &sc->params.nports, 0, "# of ports"); 2234218792Snp 2235218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "hw_revision", CTLFLAG_RD, 2236218792Snp &sc->params.rev, 0, "chip hardware revision"); 2237218792Snp 2238218792Snp SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "firmware_version", 2239218792Snp CTLFLAG_RD, &sc->fw_version, 0, "firmware version"); 2240218792Snp 2241218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "TOE", CTLFLAG_RD, 2242218792Snp &sc->params.offload, 0, "hardware is capable of TCP offload"); 2243218792Snp 2244218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD, 2245218792Snp &sc->params.vpd.cclk, 0, "core clock frequency (in KHz)"); 2246218792Snp 2247218792Snp /* XXX: this doesn't seem to show up */ 2248218792Snp SYSCTL_ADD_OPAQUE(ctx, children, OID_AUTO, "holdoff_tmr", 2249218792Snp CTLFLAG_RD, &intr_timer, sizeof(intr_timer), "IU", 2250218792Snp "interrupt holdoff timer values (us)"); 2251218792Snp 2252218792Snp /* XXX: this doesn't seem to show up */ 2253218792Snp SYSCTL_ADD_OPAQUE(ctx, children, OID_AUTO, "holdoff_pktc", 2254218792Snp CTLFLAG_RD, &intr_pktcount, sizeof(intr_pktcount), "IU", 2255218792Snp "interrupt holdoff packet counter values"); 2256218792Snp 2257218792Snp return (0); 2258218792Snp} 2259218792Snp 2260218792Snpstatic int 2261218792Snpcxgbe_sysctls(struct port_info *pi) 2262218792Snp{ 2263218792Snp struct sysctl_ctx_list *ctx; 2264218792Snp struct sysctl_oid *oid; 2265218792Snp struct sysctl_oid_list *children; 2266218792Snp 2267218792Snp ctx = device_get_sysctl_ctx(pi->dev); 2268218792Snp 2269218792Snp /* 2270218792Snp * dev.cxgbe.X. 2271218792Snp */ 2272218792Snp oid = device_get_sysctl_tree(pi->dev); 2273218792Snp children = SYSCTL_CHILDREN(oid); 2274218792Snp 2275218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "nrxq", CTLFLAG_RD, 2276218792Snp &pi->nrxq, 0, "# of rx queues"); 2277218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "ntxq", CTLFLAG_RD, 2278218792Snp &pi->ntxq, 0, "# of tx queues"); 2279218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_rxq", CTLFLAG_RD, 2280218792Snp &pi->first_rxq, 0, "index of first rx queue"); 2281218792Snp SYSCTL_ADD_INT(ctx, children, OID_AUTO, "first_txq", CTLFLAG_RD, 2282218792Snp &pi->first_txq, 0, "index of first tx queue"); 2283218792Snp 2284218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_tmr_idx", 2285218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_tmr_idx, "I", 2286218792Snp "holdoff timer index"); 2287218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pktc_idx", 2288218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_holdoff_pktc_idx, "I", 2289218792Snp "holdoff packet counter index"); 2290218792Snp 2291218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_rxq", 2292218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_rxq, "I", 2293218792Snp "rx queue size"); 2294218792Snp SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "qsize_txq", 2295218792Snp CTLTYPE_INT | CTLFLAG_RW, pi, 0, sysctl_qsize_txq, "I", 2296218792Snp "tx queue size"); 2297218792Snp 2298218792Snp /* 2299218792Snp * dev.cxgbe.X.stats. 2300218792Snp */ 2301218792Snp oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD, 2302218792Snp NULL, "port statistics"); 2303218792Snp children = SYSCTL_CHILDREN(oid); 2304218792Snp 2305218792Snp#define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \ 2306218792Snp SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \ 2307218792Snp CTLTYPE_U64 | CTLFLAG_RD, pi->adapter, reg, \ 2308218792Snp sysctl_handle_t4_reg64, "QU", desc) 2309218792Snp 2310218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames", 2311218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BYTES_L)); 2312218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames", "total # of good frames", 2313218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_FRAMES_L)); 2314218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_bcast_frames", "# of broadcast frames", 2315218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_BCAST_L)); 2316218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_mcast_frames", "# of multicast frames", 2317218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_MCAST_L)); 2318218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ucast_frames", "# of unicast frames", 2319218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_UCAST_L)); 2320218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_error_frames", "# of error frames", 2321218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_ERROR_L)); 2322218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_64", 2323218792Snp "# of tx frames in this range", 2324218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_64B_L)); 2325218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_65_127", 2326218792Snp "# of tx frames in this range", 2327218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_65B_127B_L)); 2328218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_128_255", 2329218792Snp "# of tx frames in this range", 2330218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_128B_255B_L)); 2331218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_256_511", 2332218792Snp "# of tx frames in this range", 2333218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_256B_511B_L)); 2334218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_512_1023", 2335218792Snp "# of tx frames in this range", 2336218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_512B_1023B_L)); 2337218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1024_1518", 2338218792Snp "# of tx frames in this range", 2339218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1024B_1518B_L)); 2340218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_frames_1519_max", 2341218792Snp "# of tx frames in this range", 2342218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_1519B_MAX_L)); 2343218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_drop", "# of dropped tx frames", 2344218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_DROP_L)); 2345218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_pause", "# of pause frames transmitted", 2346218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PAUSE_L)); 2347218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp0", "# of PPP prio 0 frames transmitted", 2348218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP0_L)); 2349218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp1", "# of PPP prio 1 frames transmitted", 2350218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP1_L)); 2351218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp2", "# of PPP prio 2 frames transmitted", 2352218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP2_L)); 2353218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp3", "# of PPP prio 3 frames transmitted", 2354218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP3_L)); 2355218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp4", "# of PPP prio 4 frames transmitted", 2356218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP4_L)); 2357218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp5", "# of PPP prio 5 frames transmitted", 2358218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP5_L)); 2359218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp6", "# of PPP prio 6 frames transmitted", 2360218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP6_L)); 2361218792Snp SYSCTL_ADD_T4_REG64(pi, "tx_ppp7", "# of PPP prio 7 frames transmitted", 2362218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_TX_PORT_PPP7_L)); 2363218792Snp 2364218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_octets", "# of octets in good frames", 2365218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BYTES_L)); 2366218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames", "total # of good frames", 2367218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_FRAMES_L)); 2368218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_bcast_frames", "# of broadcast frames", 2369218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_BCAST_L)); 2370218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_mcast_frames", "# of multicast frames", 2371218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MCAST_L)); 2372218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ucast_frames", "# of unicast frames", 2373218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_UCAST_L)); 2374218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_too_long", "# of frames exceeding MTU", 2375218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_ERROR_L)); 2376218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_jabber", "# of jabber frames", 2377218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_MTU_CRC_ERROR_L)); 2378218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_fcs_err", 2379218792Snp "# of frames received with bad FCS", 2380218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_CRC_ERROR_L)); 2381218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_len_err", 2382218792Snp "# of frames received with length error", 2383218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LEN_ERROR_L)); 2384218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_symbol_err", "symbol errors", 2385218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_SYM_ERROR_L)); 2386218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_runt", "# of short frames received", 2387218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_LESS_64B_L)); 2388218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_64", 2389218792Snp "# of rx frames in this range", 2390218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_64B_L)); 2391218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_65_127", 2392218792Snp "# of rx frames in this range", 2393218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_65B_127B_L)); 2394218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_128_255", 2395218792Snp "# of rx frames in this range", 2396218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_128B_255B_L)); 2397218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_256_511", 2398218792Snp "# of rx frames in this range", 2399218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_256B_511B_L)); 2400218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_512_1023", 2401218792Snp "# of rx frames in this range", 2402218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_512B_1023B_L)); 2403218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1024_1518", 2404218792Snp "# of rx frames in this range", 2405218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1024B_1518B_L)); 2406218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_frames_1519_max", 2407218792Snp "# of rx frames in this range", 2408218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_1519B_MAX_L)); 2409218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_pause", "# of pause frames received", 2410218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PAUSE_L)); 2411218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp0", "# of PPP prio 0 frames received", 2412218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP0_L)); 2413218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp1", "# of PPP prio 1 frames received", 2414218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP1_L)); 2415218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp2", "# of PPP prio 2 frames received", 2416218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP2_L)); 2417218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp3", "# of PPP prio 3 frames received", 2418218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP3_L)); 2419218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp4", "# of PPP prio 4 frames received", 2420218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP4_L)); 2421218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp5", "# of PPP prio 5 frames received", 2422218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP5_L)); 2423218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp6", "# of PPP prio 6 frames received", 2424218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP6_L)); 2425218792Snp SYSCTL_ADD_T4_REG64(pi, "rx_ppp7", "# of PPP prio 7 frames received", 2426218792Snp PORT_REG(pi->tx_chan, A_MPS_PORT_STAT_RX_PORT_PPP7_L)); 2427218792Snp 2428218792Snp#undef SYSCTL_ADD_T4_REG64 2429218792Snp 2430218792Snp#define SYSCTL_ADD_T4_PORTSTAT(name, desc) \ 2431218792Snp SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \ 2432218792Snp &pi->stats.name, desc) 2433218792Snp 2434218792Snp /* We get these from port_stats and they may be stale by upto 1s */ 2435218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow0, 2436218792Snp "# drops due to buffer-group 0 overflows"); 2437218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow1, 2438218792Snp "# drops due to buffer-group 1 overflows"); 2439218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow2, 2440218792Snp "# drops due to buffer-group 2 overflows"); 2441218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_ovflow3, 2442218792Snp "# drops due to buffer-group 3 overflows"); 2443218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc0, 2444218792Snp "# of buffer-group 0 truncated packets"); 2445218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc1, 2446218792Snp "# of buffer-group 1 truncated packets"); 2447218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc2, 2448218792Snp "# of buffer-group 2 truncated packets"); 2449218792Snp SYSCTL_ADD_T4_PORTSTAT(rx_trunc3, 2450218792Snp "# of buffer-group 3 truncated packets"); 2451218792Snp 2452218792Snp#undef SYSCTL_ADD_T4_PORTSTAT 2453218792Snp 2454218792Snp return (0); 2455218792Snp} 2456218792Snp 2457218792Snpstatic int 2458218792Snpsysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS) 2459218792Snp{ 2460218792Snp struct port_info *pi = arg1; 2461218792Snp struct adapter *sc = pi->adapter; 2462218792Snp struct sge_rxq *rxq; 2463218792Snp int idx, rc, i; 2464218792Snp 2465218792Snp idx = pi->tmr_idx; 2466218792Snp 2467218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 2468218792Snp if (rc != 0 || req->newptr == NULL) 2469218792Snp return (rc); 2470218792Snp 2471218792Snp if (idx < 0 || idx >= SGE_NTIMERS) 2472218792Snp return (EINVAL); 2473218792Snp 2474218792Snp ADAPTER_LOCK(sc); 2475218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 2476218792Snp if (rc == 0) { 2477218792Snp for_each_rxq(pi, i, rxq) { 2478218792Snp rxq->iq.intr_params = V_QINTR_TIMER_IDX(idx) | 2479218792Snp V_QINTR_CNT_EN(pi->pktc_idx != -1); 2480218792Snp } 2481218792Snp pi->tmr_idx = idx; 2482218792Snp } 2483218792Snp 2484218792Snp ADAPTER_UNLOCK(sc); 2485218792Snp return (rc); 2486218792Snp} 2487218792Snp 2488218792Snpstatic int 2489218792Snpsysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS) 2490218792Snp{ 2491218792Snp struct port_info *pi = arg1; 2492218792Snp struct adapter *sc = pi->adapter; 2493218792Snp int idx, rc; 2494218792Snp 2495218792Snp idx = pi->pktc_idx; 2496218792Snp 2497218792Snp rc = sysctl_handle_int(oidp, &idx, 0, req); 2498218792Snp if (rc != 0 || req->newptr == NULL) 2499218792Snp return (rc); 2500218792Snp 2501218792Snp if (idx < -1 || idx >= SGE_NCOUNTERS) 2502218792Snp return (EINVAL); 2503218792Snp 2504218792Snp ADAPTER_LOCK(sc); 2505218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 2506218792Snp if (rc == 0 && pi->ifp->if_drv_flags & IFF_DRV_RUNNING) 2507218792Snp rc = EBUSY; /* can be changed only when port is down */ 2508218792Snp 2509218792Snp if (rc == 0) 2510218792Snp pi->pktc_idx = idx; 2511218792Snp 2512218792Snp ADAPTER_UNLOCK(sc); 2513218792Snp return (rc); 2514218792Snp} 2515218792Snp 2516218792Snpstatic int 2517218792Snpsysctl_qsize_rxq(SYSCTL_HANDLER_ARGS) 2518218792Snp{ 2519218792Snp struct port_info *pi = arg1; 2520218792Snp struct adapter *sc = pi->adapter; 2521218792Snp int qsize, rc; 2522218792Snp 2523218792Snp qsize = pi->qsize_rxq; 2524218792Snp 2525218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 2526218792Snp if (rc != 0 || req->newptr == NULL) 2527218792Snp return (rc); 2528218792Snp 2529218792Snp if (qsize < 128 || (qsize & 7)) 2530218792Snp return (EINVAL); 2531218792Snp 2532218792Snp ADAPTER_LOCK(sc); 2533218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 2534218792Snp if (rc == 0 && pi->ifp->if_drv_flags & IFF_DRV_RUNNING) 2535218792Snp rc = EBUSY; /* can be changed only when port is down */ 2536218792Snp 2537218792Snp if (rc == 0) 2538218792Snp pi->qsize_rxq = qsize; 2539218792Snp 2540218792Snp ADAPTER_UNLOCK(sc); 2541218792Snp return (rc); 2542218792Snp} 2543218792Snp 2544218792Snpstatic int 2545218792Snpsysctl_qsize_txq(SYSCTL_HANDLER_ARGS) 2546218792Snp{ 2547218792Snp struct port_info *pi = arg1; 2548218792Snp struct adapter *sc = pi->adapter; 2549218792Snp int qsize, rc; 2550218792Snp 2551218792Snp qsize = pi->qsize_txq; 2552218792Snp 2553218792Snp rc = sysctl_handle_int(oidp, &qsize, 0, req); 2554218792Snp if (rc != 0 || req->newptr == NULL) 2555218792Snp return (rc); 2556218792Snp 2557218792Snp if (qsize < 128) 2558218792Snp return (EINVAL); 2559218792Snp 2560218792Snp ADAPTER_LOCK(sc); 2561218792Snp rc = IS_DOOMED(pi) ? ENXIO : (IS_BUSY(sc) ? EBUSY : 0); 2562218792Snp if (rc == 0 && pi->ifp->if_drv_flags & IFF_DRV_RUNNING) 2563218792Snp rc = EBUSY; /* can be changed only when port is down */ 2564218792Snp 2565218792Snp if (rc == 0) 2566218792Snp pi->qsize_txq = qsize; 2567218792Snp 2568218792Snp ADAPTER_UNLOCK(sc); 2569218792Snp return (rc); 2570218792Snp} 2571218792Snp 2572218792Snpstatic int 2573218792Snpsysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS) 2574218792Snp{ 2575218792Snp struct adapter *sc = arg1; 2576218792Snp int reg = arg2; 2577218792Snp uint64_t val; 2578218792Snp 2579218792Snp val = t4_read_reg64(sc, reg); 2580218792Snp 2581218792Snp return (sysctl_handle_64(oidp, &val, 0, req)); 2582218792Snp} 2583218792Snp 2584218792Snpint 2585218792Snpt4_os_find_pci_capability(struct adapter *sc, int cap) 2586218792Snp{ 2587218792Snp device_t dev; 2588218792Snp struct pci_devinfo *dinfo; 2589218792Snp pcicfgregs *cfg; 2590218792Snp uint32_t status; 2591218792Snp uint8_t ptr; 2592218792Snp 2593218792Snp dev = sc->dev; 2594218792Snp dinfo = device_get_ivars(dev); 2595218792Snp cfg = &dinfo->cfg; 2596218792Snp 2597218792Snp status = pci_read_config(dev, PCIR_STATUS, 2); 2598218792Snp if (!(status & PCIM_STATUS_CAPPRESENT)) 2599218792Snp return (0); 2600218792Snp 2601218792Snp switch (cfg->hdrtype & PCIM_HDRTYPE) { 2602218792Snp case 0: 2603218792Snp case 1: 2604218792Snp ptr = PCIR_CAP_PTR; 2605218792Snp break; 2606218792Snp case 2: 2607218792Snp ptr = PCIR_CAP_PTR_2; 2608218792Snp break; 2609218792Snp default: 2610218792Snp return (0); 2611218792Snp break; 2612218792Snp } 2613218792Snp ptr = pci_read_config(dev, ptr, 1); 2614218792Snp 2615218792Snp while (ptr != 0) { 2616218792Snp if (pci_read_config(dev, ptr + PCICAP_ID, 1) == cap) 2617218792Snp return (ptr); 2618218792Snp ptr = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1); 2619218792Snp } 2620218792Snp 2621218792Snp return (0); 2622218792Snp} 2623218792Snp 2624218792Snpint 2625218792Snpt4_os_pci_save_state(struct adapter *sc) 2626218792Snp{ 2627218792Snp device_t dev; 2628218792Snp struct pci_devinfo *dinfo; 2629218792Snp 2630218792Snp dev = sc->dev; 2631218792Snp dinfo = device_get_ivars(dev); 2632218792Snp 2633218792Snp pci_cfg_save(dev, dinfo, 0); 2634218792Snp return (0); 2635218792Snp} 2636218792Snp 2637218792Snpint 2638218792Snpt4_os_pci_restore_state(struct adapter *sc) 2639218792Snp{ 2640218792Snp device_t dev; 2641218792Snp struct pci_devinfo *dinfo; 2642218792Snp 2643218792Snp dev = sc->dev; 2644218792Snp dinfo = device_get_ivars(dev); 2645218792Snp 2646218792Snp pci_cfg_restore(dev, dinfo); 2647218792Snp return (0); 2648218792Snp} 2649218792Snpvoid 2650218792Snpt4_os_portmod_changed(const struct adapter *sc, int idx) 2651218792Snp{ 2652218792Snp struct port_info *pi = sc->port[idx]; 2653218792Snp static const char *mod_str[] = { 2654218792Snp NULL, "LR", "SR", "ER", "TWINAX", "active TWINAX" 2655218792Snp }; 2656218792Snp 2657218792Snp if (pi->mod_type == FW_PORT_MOD_TYPE_NONE) 2658218792Snp if_printf(pi->ifp, "transceiver unplugged.\n"); 2659218792Snp else 2660218792Snp if_printf(pi->ifp, "%s transceiver inserted.\n", 2661218792Snp mod_str[pi->mod_type]); 2662218792Snp 2663218792Snp} 2664218792Snp 2665218792Snpvoid 2666218792Snpt4_os_link_changed(struct adapter *sc, int idx, int link_stat) 2667218792Snp{ 2668218792Snp struct port_info *pi = sc->port[idx]; 2669218792Snp struct ifnet *ifp = pi->ifp; 2670218792Snp 2671218792Snp if (link_stat) { 2672218792Snp ifp->if_baudrate = IF_Mbps(pi->link_cfg.speed); 2673218792Snp if_link_state_change(ifp, LINK_STATE_UP); 2674218792Snp } else 2675218792Snp if_link_state_change(ifp, LINK_STATE_DOWN); 2676218792Snp} 2677218792Snp 2678218792Snpstatic int 2679218792Snpt4_open(struct cdev *dev, int flags, int type, struct thread *td) 2680218792Snp{ 2681218792Snp return (0); 2682218792Snp} 2683218792Snp 2684218792Snpstatic int 2685218792Snpt4_close(struct cdev *dev, int flags, int type, struct thread *td) 2686218792Snp{ 2687218792Snp return (0); 2688218792Snp} 2689218792Snp 2690218792Snpstatic int 2691218792Snpt4_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, int fflag, 2692218792Snp struct thread *td) 2693218792Snp{ 2694218792Snp int rc; 2695218792Snp struct adapter *sc = dev->si_drv1; 2696218792Snp 2697218792Snp rc = priv_check(td, PRIV_DRIVER); 2698218792Snp if (rc != 0) 2699218792Snp return (rc); 2700218792Snp 2701218792Snp switch (cmd) { 2702218792Snp case CHELSIO_T4_GETREG32: { 2703218792Snp struct t4_reg32 *edata = (struct t4_reg32 *)data; 2704218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 2705218792Snp return (EFAULT); 2706218792Snp edata->val = t4_read_reg(sc, edata->addr); 2707218792Snp break; 2708218792Snp } 2709218792Snp case CHELSIO_T4_SETREG32: { 2710218792Snp struct t4_reg32 *edata = (struct t4_reg32 *)data; 2711218792Snp if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 2712218792Snp return (EFAULT); 2713218792Snp t4_write_reg(sc, edata->addr, edata->val); 2714218792Snp break; 2715218792Snp } 2716218792Snp case CHELSIO_T4_REGDUMP: { 2717218792Snp struct t4_regdump *regs = (struct t4_regdump *)data; 2718218792Snp int reglen = T4_REGDUMP_SIZE; 2719218792Snp uint8_t *buf; 2720218792Snp 2721218792Snp if (regs->len < reglen) { 2722218792Snp regs->len = reglen; /* hint to the caller */ 2723218792Snp return (ENOBUFS); 2724218792Snp } 2725218792Snp 2726218792Snp regs->len = reglen; 2727218792Snp buf = malloc(reglen, M_CXGBE, M_WAITOK | M_ZERO); 2728218792Snp t4_get_regs(sc, regs, buf); 2729218792Snp rc = copyout(buf, regs->data, reglen); 2730218792Snp free(buf, M_CXGBE); 2731218792Snp break; 2732218792Snp } 2733218792Snp default: 2734218792Snp rc = EINVAL; 2735218792Snp } 2736218792Snp 2737218792Snp return (rc); 2738218792Snp} 2739218792Snp 2740218792Snpstatic devclass_t t4_devclass; 2741218792Snpstatic devclass_t cxgbe_devclass; 2742218792Snp 2743218792SnpDRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, 0, 0); 2744218792SnpMODULE_VERSION(t4nex, 1); 2745218792Snp 2746218792SnpDRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0); 2747218792SnpMODULE_VERSION(cxgbe, 1); 2748