cxgb_main.c revision 192450
1167514Skmacy/************************************************************************** 2167514Skmacy 3189643SgnnCopyright (c) 2007-2009, Chelsio Inc. 4167514SkmacyAll rights reserved. 5167514Skmacy 6167514SkmacyRedistribution and use in source and binary forms, with or without 7167514Skmacymodification, are permitted provided that the following conditions are met: 8167514Skmacy 9167514Skmacy 1. Redistributions of source code must retain the above copyright notice, 10167514Skmacy this list of conditions and the following disclaimer. 11167514Skmacy 12178302Skmacy 2. Neither the name of the Chelsio Corporation nor the names of its 13167514Skmacy contributors may be used to endorse or promote products derived from 14167514Skmacy this software without specific prior written permission. 15167514Skmacy 16167514SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17167514SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18167514SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19167514SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20167514SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21167514SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22167514SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23167514SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24167514SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25167514SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26167514SkmacyPOSSIBILITY OF SUCH DAMAGE. 27167514Skmacy 28167514Skmacy***************************************************************************/ 29167514Skmacy 30167514Skmacy#include <sys/cdefs.h> 31167514Skmacy__FBSDID("$FreeBSD: head/sys/dev/cxgb/cxgb_main.c 192450 2009-05-20 17:29:21Z imp $"); 32167514Skmacy 33167514Skmacy#include <sys/param.h> 34167514Skmacy#include <sys/systm.h> 35167514Skmacy#include <sys/kernel.h> 36167514Skmacy#include <sys/bus.h> 37167514Skmacy#include <sys/module.h> 38167514Skmacy#include <sys/pciio.h> 39167514Skmacy#include <sys/conf.h> 40167514Skmacy#include <machine/bus.h> 41167514Skmacy#include <machine/resource.h> 42167514Skmacy#include <sys/bus_dma.h> 43176472Skmacy#include <sys/ktr.h> 44167514Skmacy#include <sys/rman.h> 45167514Skmacy#include <sys/ioccom.h> 46167514Skmacy#include <sys/mbuf.h> 47167514Skmacy#include <sys/linker.h> 48167514Skmacy#include <sys/firmware.h> 49167514Skmacy#include <sys/socket.h> 50167514Skmacy#include <sys/sockio.h> 51167514Skmacy#include <sys/smp.h> 52167514Skmacy#include <sys/sysctl.h> 53174708Skmacy#include <sys/syslog.h> 54167514Skmacy#include <sys/queue.h> 55167514Skmacy#include <sys/taskqueue.h> 56174708Skmacy#include <sys/proc.h> 57167514Skmacy 58167514Skmacy#include <net/bpf.h> 59167514Skmacy#include <net/ethernet.h> 60167514Skmacy#include <net/if.h> 61167514Skmacy#include <net/if_arp.h> 62167514Skmacy#include <net/if_dl.h> 63167514Skmacy#include <net/if_media.h> 64167514Skmacy#include <net/if_types.h> 65180583Skmacy#include <net/if_vlan_var.h> 66167514Skmacy 67167514Skmacy#include <netinet/in_systm.h> 68167514Skmacy#include <netinet/in.h> 69167514Skmacy#include <netinet/if_ether.h> 70167514Skmacy#include <netinet/ip.h> 71167514Skmacy#include <netinet/ip.h> 72167514Skmacy#include <netinet/tcp.h> 73167514Skmacy#include <netinet/udp.h> 74167514Skmacy 75167514Skmacy#include <dev/pci/pcireg.h> 76167514Skmacy#include <dev/pci/pcivar.h> 77167514Skmacy#include <dev/pci/pci_private.h> 78167514Skmacy 79170076Skmacy#include <cxgb_include.h> 80167514Skmacy 81167514Skmacy#ifdef PRIV_SUPPORTED 82167514Skmacy#include <sys/priv.h> 83167514Skmacy#endif 84167514Skmacy 85167514Skmacystatic int cxgb_setup_msix(adapter_t *, int); 86170654Skmacystatic void cxgb_teardown_msix(adapter_t *); 87167514Skmacystatic void cxgb_init(void *); 88167514Skmacystatic void cxgb_init_locked(struct port_info *); 89167734Skmacystatic void cxgb_stop_locked(struct port_info *); 90167514Skmacystatic void cxgb_set_rxmode(struct port_info *); 91167514Skmacystatic int cxgb_ioctl(struct ifnet *, unsigned long, caddr_t); 92167514Skmacystatic int cxgb_media_change(struct ifnet *); 93186282Sgnnstatic int cxgb_ifm_type(int); 94167514Skmacystatic void cxgb_media_status(struct ifnet *, struct ifmediareq *); 95167514Skmacystatic int setup_sge_qsets(adapter_t *); 96167514Skmacystatic void cxgb_async_intr(void *); 97167514Skmacystatic void cxgb_ext_intr_handler(void *, int); 98170869Skmacystatic void cxgb_tick_handler(void *, int); 99170869Skmacystatic void cxgb_down_locked(struct adapter *sc); 100167514Skmacystatic void cxgb_tick(void *); 101167514Skmacystatic void setup_rss(adapter_t *sc); 102167514Skmacy 103167514Skmacy/* Attachment glue for the PCI controller end of the device. Each port of 104167514Skmacy * the device is attached separately, as defined later. 105167514Skmacy */ 106167514Skmacystatic int cxgb_controller_probe(device_t); 107167514Skmacystatic int cxgb_controller_attach(device_t); 108167514Skmacystatic int cxgb_controller_detach(device_t); 109167514Skmacystatic void cxgb_free(struct adapter *); 110167514Skmacystatic __inline void reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start, 111167514Skmacy unsigned int end); 112182679Skmacystatic void cxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf); 113167514Skmacystatic int cxgb_get_regs_len(void); 114169978Skmacystatic int offload_open(struct port_info *pi); 115171978Skmacystatic void touch_bars(device_t dev); 116174626Skmacystatic int offload_close(struct t3cdev *tdev); 117176472Skmacystatic void cxgb_link_start(struct port_info *p); 118189643Sgnnstatic void cxgb_link_fault(void *arg, int ncount); 119167514Skmacy 120167514Skmacystatic device_method_t cxgb_controller_methods[] = { 121167514Skmacy DEVMETHOD(device_probe, cxgb_controller_probe), 122167514Skmacy DEVMETHOD(device_attach, cxgb_controller_attach), 123167514Skmacy DEVMETHOD(device_detach, cxgb_controller_detach), 124167514Skmacy 125167514Skmacy /* bus interface */ 126167514Skmacy DEVMETHOD(bus_print_child, bus_generic_print_child), 127167514Skmacy DEVMETHOD(bus_driver_added, bus_generic_driver_added), 128167514Skmacy 129167514Skmacy { 0, 0 } 130167514Skmacy}; 131167514Skmacy 132167514Skmacystatic driver_t cxgb_controller_driver = { 133167514Skmacy "cxgbc", 134167514Skmacy cxgb_controller_methods, 135167514Skmacy sizeof(struct adapter) 136167514Skmacy}; 137167514Skmacy 138167514Skmacystatic devclass_t cxgb_controller_devclass; 139167514SkmacyDRIVER_MODULE(cxgbc, pci, cxgb_controller_driver, cxgb_controller_devclass, 0, 0); 140167514Skmacy 141167514Skmacy/* 142167514Skmacy * Attachment glue for the ports. Attachment is done directly to the 143167514Skmacy * controller device. 144167514Skmacy */ 145167514Skmacystatic int cxgb_port_probe(device_t); 146167514Skmacystatic int cxgb_port_attach(device_t); 147167514Skmacystatic int cxgb_port_detach(device_t); 148167514Skmacy 149167514Skmacystatic device_method_t cxgb_port_methods[] = { 150167514Skmacy DEVMETHOD(device_probe, cxgb_port_probe), 151167514Skmacy DEVMETHOD(device_attach, cxgb_port_attach), 152167514Skmacy DEVMETHOD(device_detach, cxgb_port_detach), 153167514Skmacy { 0, 0 } 154167514Skmacy}; 155167514Skmacy 156167514Skmacystatic driver_t cxgb_port_driver = { 157167514Skmacy "cxgb", 158167514Skmacy cxgb_port_methods, 159167514Skmacy 0 160167514Skmacy}; 161167514Skmacy 162167514Skmacystatic d_ioctl_t cxgb_extension_ioctl; 163170654Skmacystatic d_open_t cxgb_extension_open; 164170654Skmacystatic d_close_t cxgb_extension_close; 165167514Skmacy 166170654Skmacystatic struct cdevsw cxgb_cdevsw = { 167170654Skmacy .d_version = D_VERSION, 168170654Skmacy .d_flags = 0, 169170654Skmacy .d_open = cxgb_extension_open, 170170654Skmacy .d_close = cxgb_extension_close, 171170654Skmacy .d_ioctl = cxgb_extension_ioctl, 172170654Skmacy .d_name = "cxgb", 173170654Skmacy}; 174170654Skmacy 175167514Skmacystatic devclass_t cxgb_port_devclass; 176167514SkmacyDRIVER_MODULE(cxgb, cxgbc, cxgb_port_driver, cxgb_port_devclass, 0, 0); 177167514Skmacy 178167514Skmacy#define SGE_MSIX_COUNT (SGE_QSETS + 1) 179167514Skmacy 180167514Skmacy/* 181167514Skmacy * The driver uses the best interrupt scheme available on a platform in the 182167514Skmacy * order MSI-X, MSI, legacy pin interrupts. This parameter determines which 183167514Skmacy * of these schemes the driver may consider as follows: 184167514Skmacy * 185167514Skmacy * msi = 2: choose from among all three options 186167514Skmacy * msi = 1 : only consider MSI and pin interrupts 187167514Skmacy * msi = 0: force pin interrupts 188167514Skmacy */ 189167760Skmacystatic int msi_allowed = 2; 190170083Skmacy 191167514SkmacyTUNABLE_INT("hw.cxgb.msi_allowed", &msi_allowed); 192167514SkmacySYSCTL_NODE(_hw, OID_AUTO, cxgb, CTLFLAG_RD, 0, "CXGB driver parameters"); 193167514SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, msi_allowed, CTLFLAG_RDTUN, &msi_allowed, 0, 194167514Skmacy "MSI-X, MSI, INTx selector"); 195169978Skmacy 196169053Skmacy/* 197169978Skmacy * The driver enables offload as a default. 198169978Skmacy * To disable it, use ofld_disable = 1. 199169053Skmacy */ 200169978Skmacystatic int ofld_disable = 0; 201169978SkmacyTUNABLE_INT("hw.cxgb.ofld_disable", &ofld_disable); 202169978SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, ofld_disable, CTLFLAG_RDTUN, &ofld_disable, 0, 203169978Skmacy "disable ULP offload"); 204169978Skmacy 205169978Skmacy/* 206169978Skmacy * The driver uses an auto-queue algorithm by default. 207185165Skmacy * To disable it and force a single queue-set per port, use multiq = 0 208169978Skmacy */ 209185165Skmacystatic int multiq = 1; 210185165SkmacyTUNABLE_INT("hw.cxgb.multiq", &multiq); 211185165SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, multiq, CTLFLAG_RDTUN, &multiq, 0, 212185165Skmacy "use min(ncpus/ports, 8) queue-sets per port"); 213167514Skmacy 214176572Skmacy/* 215185165Skmacy * By default the driver will not update the firmware unless 216185165Skmacy * it was compiled against a newer version 217185165Skmacy * 218176572Skmacy */ 219176572Skmacystatic int force_fw_update = 0; 220176572SkmacyTUNABLE_INT("hw.cxgb.force_fw_update", &force_fw_update); 221176572SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, force_fw_update, CTLFLAG_RDTUN, &force_fw_update, 0, 222176572Skmacy "update firmware even if up to date"); 223175200Skmacy 224183059Skmacyint cxgb_use_16k_clusters = 1; 225175200SkmacyTUNABLE_INT("hw.cxgb.use_16k_clusters", &cxgb_use_16k_clusters); 226175200SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, use_16k_clusters, CTLFLAG_RDTUN, 227175200Skmacy &cxgb_use_16k_clusters, 0, "use 16kB clusters for the jumbo queue "); 228175200Skmacy 229167514Skmacyenum { 230167514Skmacy MAX_TXQ_ENTRIES = 16384, 231167514Skmacy MAX_CTRL_TXQ_ENTRIES = 1024, 232167514Skmacy MAX_RSPQ_ENTRIES = 16384, 233167514Skmacy MAX_RX_BUFFERS = 16384, 234167514Skmacy MAX_RX_JUMBO_BUFFERS = 16384, 235167514Skmacy MIN_TXQ_ENTRIES = 4, 236167514Skmacy MIN_CTRL_TXQ_ENTRIES = 4, 237167514Skmacy MIN_RSPQ_ENTRIES = 32, 238172096Skmacy MIN_FL_ENTRIES = 32, 239172096Skmacy MIN_FL_JUMBO_ENTRIES = 32 240167514Skmacy}; 241167514Skmacy 242171471Skmacystruct filter_info { 243171471Skmacy u32 sip; 244171471Skmacy u32 sip_mask; 245171471Skmacy u32 dip; 246171471Skmacy u16 sport; 247171471Skmacy u16 dport; 248171471Skmacy u32 vlan:12; 249171471Skmacy u32 vlan_prio:3; 250171471Skmacy u32 mac_hit:1; 251171471Skmacy u32 mac_idx:4; 252171471Skmacy u32 mac_vld:1; 253171471Skmacy u32 pkt_type:2; 254171471Skmacy u32 report_filter_id:1; 255171471Skmacy u32 pass:1; 256171471Skmacy u32 rss:1; 257171471Skmacy u32 qset:3; 258171471Skmacy u32 locked:1; 259171471Skmacy u32 valid:1; 260171471Skmacy}; 261171471Skmacy 262171471Skmacyenum { FILTER_NO_VLAN_PRI = 7 }; 263171471Skmacy 264182679Skmacy#define EEPROM_MAGIC 0x38E2F10C 265182679Skmacy 266167514Skmacy#define PORT_MASK ((1 << MAX_NPORTS) - 1) 267167514Skmacy 268167514Skmacy/* Table for probing the cards. The desc field isn't actually used */ 269167514Skmacystruct cxgb_ident { 270167514Skmacy uint16_t vendor; 271167514Skmacy uint16_t device; 272167514Skmacy int index; 273167514Skmacy char *desc; 274167514Skmacy} cxgb_identifiers[] = { 275167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0020, 0, "PE9000"}, 276167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0021, 1, "T302E"}, 277167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0022, 2, "T310E"}, 278167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0023, 3, "T320X"}, 279167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0024, 1, "T302X"}, 280167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0025, 3, "T320E"}, 281167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0026, 2, "T310X"}, 282167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0030, 2, "T3B10"}, 283167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0031, 3, "T3B20"}, 284167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0032, 1, "T3B02"}, 285170654Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0033, 4, "T3B04"}, 286185662Sgnn {PCI_VENDOR_ID_CHELSIO, 0x0035, 6, "N310E"}, 287167514Skmacy {0, 0, 0, NULL} 288167514Skmacy}; 289167514Skmacy 290171471Skmacystatic int set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset); 291171471Skmacy 292176472Skmacy 293174708Skmacystatic __inline char 294171471Skmacyt3rev2char(struct adapter *adapter) 295171471Skmacy{ 296171471Skmacy char rev = 'z'; 297171471Skmacy 298171471Skmacy switch(adapter->params.rev) { 299171471Skmacy case T3_REV_A: 300171471Skmacy rev = 'a'; 301171471Skmacy break; 302171471Skmacy case T3_REV_B: 303171471Skmacy case T3_REV_B2: 304171471Skmacy rev = 'b'; 305171471Skmacy break; 306171471Skmacy case T3_REV_C: 307171471Skmacy rev = 'c'; 308171471Skmacy break; 309171471Skmacy } 310171471Skmacy return rev; 311171471Skmacy} 312171471Skmacy 313167514Skmacystatic struct cxgb_ident * 314167514Skmacycxgb_get_ident(device_t dev) 315167514Skmacy{ 316167514Skmacy struct cxgb_ident *id; 317167514Skmacy 318167514Skmacy for (id = cxgb_identifiers; id->desc != NULL; id++) { 319167514Skmacy if ((id->vendor == pci_get_vendor(dev)) && 320167514Skmacy (id->device == pci_get_device(dev))) { 321167514Skmacy return (id); 322167514Skmacy } 323167514Skmacy } 324167514Skmacy return (NULL); 325167514Skmacy} 326167514Skmacy 327167514Skmacystatic const struct adapter_info * 328167514Skmacycxgb_get_adapter_info(device_t dev) 329167514Skmacy{ 330167514Skmacy struct cxgb_ident *id; 331167514Skmacy const struct adapter_info *ai; 332183063Skmacy 333167514Skmacy id = cxgb_get_ident(dev); 334167514Skmacy if (id == NULL) 335167514Skmacy return (NULL); 336167514Skmacy 337167514Skmacy ai = t3_get_adapter_info(id->index); 338167514Skmacy 339167514Skmacy return (ai); 340167514Skmacy} 341167514Skmacy 342167514Skmacystatic int 343167514Skmacycxgb_controller_probe(device_t dev) 344167514Skmacy{ 345167514Skmacy const struct adapter_info *ai; 346167514Skmacy char *ports, buf[80]; 347170654Skmacy int nports; 348182695Skmacy struct adapter *sc = device_get_softc(dev); 349183063Skmacy 350167514Skmacy ai = cxgb_get_adapter_info(dev); 351167514Skmacy if (ai == NULL) 352167514Skmacy return (ENXIO); 353167514Skmacy 354170654Skmacy nports = ai->nports0 + ai->nports1; 355170654Skmacy if (nports == 1) 356167514Skmacy ports = "port"; 357167514Skmacy else 358167514Skmacy ports = "ports"; 359167514Skmacy 360182695Skmacy snprintf(buf, sizeof(buf), "%s %sNIC, rev: %d nports: %d %s", 361185165Skmacy ai->desc, is_offload(sc) ? "R" : "", 362185165Skmacy sc->params.rev, nports, ports); 363167514Skmacy device_set_desc_copy(dev, buf); 364167514Skmacy return (BUS_PROBE_DEFAULT); 365167514Skmacy} 366167514Skmacy 367176572Skmacy#define FW_FNAME "cxgb_t3fw" 368190330Sgnn#define TPEEPROM_NAME "cxgb_t3%c_tp_eeprom" 369190330Sgnn#define TPSRAM_NAME "cxgb_t3%c_protocol_sram" 370171471Skmacy 371167514Skmacystatic int 372169978Skmacyupgrade_fw(adapter_t *sc) 373167514Skmacy{ 374167514Skmacy#ifdef FIRMWARE_LATEST 375167514Skmacy const struct firmware *fw; 376167514Skmacy#else 377167514Skmacy struct firmware *fw; 378167514Skmacy#endif 379167514Skmacy int status; 380167514Skmacy 381176572Skmacy if ((fw = firmware_get(FW_FNAME)) == NULL) { 382176572Skmacy device_printf(sc->dev, "Could not find firmware image %s\n", FW_FNAME); 383169978Skmacy return (ENOENT); 384171471Skmacy } else 385176572Skmacy device_printf(sc->dev, "updating firmware on card\n"); 386167514Skmacy status = t3_load_fw(sc, (const uint8_t *)fw->data, fw->datasize); 387167514Skmacy 388171471Skmacy device_printf(sc->dev, "firmware update returned %s %d\n", (status == 0) ? "success" : "fail", status); 389171471Skmacy 390167514Skmacy firmware_put(fw, FIRMWARE_UNLOAD); 391167514Skmacy 392167514Skmacy return (status); 393167514Skmacy} 394167514Skmacy 395167514Skmacystatic int 396167514Skmacycxgb_controller_attach(device_t dev) 397167514Skmacy{ 398167514Skmacy device_t child; 399167514Skmacy const struct adapter_info *ai; 400167514Skmacy struct adapter *sc; 401172109Skmacy int i, error = 0; 402167514Skmacy uint32_t vers; 403167760Skmacy int port_qsets = 1; 404171868Skmacy#ifdef MSI_SUPPORTED 405172109Skmacy int msi_needed, reg; 406176472Skmacy#endif 407185655Sgnn char buf[80]; 408185655Sgnn 409167514Skmacy sc = device_get_softc(dev); 410167514Skmacy sc->dev = dev; 411169978Skmacy sc->msi_count = 0; 412172109Skmacy ai = cxgb_get_adapter_info(dev); 413172109Skmacy 414172109Skmacy /* 415172109Skmacy * XXX not really related but a recent addition 416172109Skmacy */ 417172109Skmacy#ifdef MSI_SUPPORTED 418167840Skmacy /* find the PCIe link width and set max read request to 4KB*/ 419167840Skmacy if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 420167840Skmacy uint16_t lnk, pectl; 421167840Skmacy lnk = pci_read_config(dev, reg + 0x12, 2); 422167840Skmacy sc->link_width = (lnk >> 4) & 0x3f; 423167840Skmacy 424167840Skmacy pectl = pci_read_config(dev, reg + 0x8, 2); 425167840Skmacy pectl = (pectl & ~0x7000) | (5 << 12); 426167840Skmacy pci_write_config(dev, reg + 0x8, pectl, 2); 427167840Skmacy } 428171471Skmacy 429171471Skmacy if (sc->link_width != 0 && sc->link_width <= 4 && 430171471Skmacy (ai->nports0 + ai->nports1) <= 2) { 431167840Skmacy device_printf(sc->dev, 432167862Skmacy "PCIe x%d Link, expect reduced performance\n", 433167840Skmacy sc->link_width); 434167840Skmacy } 435172109Skmacy#endif 436171978Skmacy touch_bars(dev); 437167514Skmacy pci_enable_busmaster(dev); 438167514Skmacy /* 439167514Skmacy * Allocate the registers and make them available to the driver. 440167514Skmacy * The registers that we care about for NIC mode are in BAR 0 441167514Skmacy */ 442167514Skmacy sc->regs_rid = PCIR_BAR(0); 443167514Skmacy if ((sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 444167514Skmacy &sc->regs_rid, RF_ACTIVE)) == NULL) { 445176472Skmacy device_printf(dev, "Cannot allocate BAR region 0\n"); 446167514Skmacy return (ENXIO); 447167514Skmacy } 448176472Skmacy sc->udbs_rid = PCIR_BAR(2); 449185662Sgnn sc->udbs_res = NULL; 450185662Sgnn if (is_offload(sc) && 451185662Sgnn ((sc->udbs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 452185662Sgnn &sc->udbs_rid, RF_ACTIVE)) == NULL)) { 453176472Skmacy device_printf(dev, "Cannot allocate BAR region 1\n"); 454176472Skmacy error = ENXIO; 455176472Skmacy goto out; 456185662Sgnn } 457167514Skmacy 458170869Skmacy snprintf(sc->lockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb controller lock %d", 459170869Skmacy device_get_unit(dev)); 460170869Skmacy ADAPTER_LOCK_INIT(sc, sc->lockbuf); 461170869Skmacy 462170869Skmacy snprintf(sc->reglockbuf, ADAPTER_LOCK_NAME_LEN, "SGE reg lock %d", 463170869Skmacy device_get_unit(dev)); 464170869Skmacy snprintf(sc->mdiolockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb mdio lock %d", 465170869Skmacy device_get_unit(dev)); 466170869Skmacy snprintf(sc->elmerlockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb elmer lock %d", 467170869Skmacy device_get_unit(dev)); 468167514Skmacy 469176472Skmacy MTX_INIT(&sc->sge.reg_lock, sc->reglockbuf, NULL, MTX_SPIN); 470170869Skmacy MTX_INIT(&sc->mdio_lock, sc->mdiolockbuf, NULL, MTX_DEF); 471170869Skmacy MTX_INIT(&sc->elmer_lock, sc->elmerlockbuf, NULL, MTX_DEF); 472170869Skmacy 473167514Skmacy sc->bt = rman_get_bustag(sc->regs_res); 474167514Skmacy sc->bh = rman_get_bushandle(sc->regs_res); 475167514Skmacy sc->mmio_len = rman_get_size(sc->regs_res); 476167769Skmacy 477167769Skmacy if (t3_prep_adapter(sc, ai, 1) < 0) { 478170654Skmacy printf("prep adapter failed\n"); 479167769Skmacy error = ENODEV; 480167769Skmacy goto out; 481167769Skmacy } 482177464Skmacy /* Allocate the BAR for doing MSI-X. If it succeeds, try to allocate 483167514Skmacy * enough messages for the queue sets. If that fails, try falling 484167514Skmacy * back to MSI. If that fails, then try falling back to the legacy 485167514Skmacy * interrupt pin model. 486167514Skmacy */ 487167514Skmacy#ifdef MSI_SUPPORTED 488167760Skmacy 489167514Skmacy sc->msix_regs_rid = 0x20; 490167514Skmacy if ((msi_allowed >= 2) && 491167514Skmacy (sc->msix_regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 492167514Skmacy &sc->msix_regs_rid, RF_ACTIVE)) != NULL) { 493167514Skmacy 494169978Skmacy msi_needed = sc->msi_count = SGE_MSIX_COUNT; 495167760Skmacy 496169978Skmacy if (((error = pci_alloc_msix(dev, &sc->msi_count)) != 0) || 497169978Skmacy (sc->msi_count != msi_needed)) { 498169978Skmacy device_printf(dev, "msix allocation failed - msi_count = %d" 499169978Skmacy " msi_needed=%d will try msi err=%d\n", sc->msi_count, 500169978Skmacy msi_needed, error); 501169978Skmacy sc->msi_count = 0; 502167514Skmacy pci_release_msi(dev); 503167514Skmacy bus_release_resource(dev, SYS_RES_MEMORY, 504167514Skmacy sc->msix_regs_rid, sc->msix_regs_res); 505167514Skmacy sc->msix_regs_res = NULL; 506167514Skmacy } else { 507167514Skmacy sc->flags |= USING_MSIX; 508170081Skmacy sc->cxgb_intr = t3_intr_msix; 509167514Skmacy } 510167514Skmacy } 511167514Skmacy 512169978Skmacy if ((msi_allowed >= 1) && (sc->msi_count == 0)) { 513169978Skmacy sc->msi_count = 1; 514169978Skmacy if (pci_alloc_msi(dev, &sc->msi_count)) { 515167760Skmacy device_printf(dev, "alloc msi failed - will try INTx\n"); 516169978Skmacy sc->msi_count = 0; 517167514Skmacy pci_release_msi(dev); 518167514Skmacy } else { 519167514Skmacy sc->flags |= USING_MSI; 520167514Skmacy sc->irq_rid = 1; 521170081Skmacy sc->cxgb_intr = t3_intr_msi; 522167514Skmacy } 523167514Skmacy } 524167514Skmacy#endif 525169978Skmacy if (sc->msi_count == 0) { 526167760Skmacy device_printf(dev, "using line interrupts\n"); 527167514Skmacy sc->irq_rid = 0; 528170081Skmacy sc->cxgb_intr = t3b_intr; 529167514Skmacy } 530167514Skmacy 531185165Skmacy if ((sc->flags & USING_MSIX) && multiq) 532177464Skmacy port_qsets = min((SGE_QSETS/(sc)->params.nports), mp_ncpus); 533177464Skmacy 534167514Skmacy /* Create a private taskqueue thread for handling driver events */ 535167514Skmacy#ifdef TASKQUEUE_CURRENT 536167514Skmacy sc->tq = taskqueue_create("cxgb_taskq", M_NOWAIT, 537167514Skmacy taskqueue_thread_enqueue, &sc->tq); 538167514Skmacy#else 539167514Skmacy sc->tq = taskqueue_create_fast("cxgb_taskq", M_NOWAIT, 540167514Skmacy taskqueue_thread_enqueue, &sc->tq); 541167514Skmacy#endif 542167514Skmacy if (sc->tq == NULL) { 543167514Skmacy device_printf(dev, "failed to allocate controller task queue\n"); 544167514Skmacy goto out; 545167514Skmacy } 546171804Skmacy 547167514Skmacy taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq", 548167514Skmacy device_get_nameunit(dev)); 549167514Skmacy TASK_INIT(&sc->ext_intr_task, 0, cxgb_ext_intr_handler, sc); 550170869Skmacy TASK_INIT(&sc->tick_task, 0, cxgb_tick_handler, sc); 551167514Skmacy 552167514Skmacy 553167514Skmacy /* Create a periodic callout for checking adapter status */ 554170869Skmacy callout_init(&sc->cxgb_tick_ch, TRUE); 555167514Skmacy 556189643Sgnn if (t3_check_fw_version(sc) < 0 || force_fw_update) { 557167514Skmacy /* 558167514Skmacy * Warn user that a firmware update will be attempted in init. 559167514Skmacy */ 560169978Skmacy device_printf(dev, "firmware needs to be updated to version %d.%d.%d\n", 561169978Skmacy FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO); 562167514Skmacy sc->flags &= ~FW_UPTODATE; 563167514Skmacy } else { 564167514Skmacy sc->flags |= FW_UPTODATE; 565167514Skmacy } 566171471Skmacy 567189643Sgnn if (t3_check_tpsram_version(sc) < 0) { 568171471Skmacy /* 569171471Skmacy * Warn user that a firmware update will be attempted in init. 570171471Skmacy */ 571171471Skmacy device_printf(dev, "SRAM needs to be updated to version %c-%d.%d.%d\n", 572171471Skmacy t3rev2char(sc), TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); 573171471Skmacy sc->flags &= ~TPS_UPTODATE; 574171471Skmacy } else { 575171471Skmacy sc->flags |= TPS_UPTODATE; 576171471Skmacy } 577167514Skmacy 578167514Skmacy /* 579167514Skmacy * Create a child device for each MAC. The ethernet attachment 580167514Skmacy * will be done in these children. 581167760Skmacy */ 582167760Skmacy for (i = 0; i < (sc)->params.nports; i++) { 583171978Skmacy struct port_info *pi; 584171978Skmacy 585167514Skmacy if ((child = device_add_child(dev, "cxgb", -1)) == NULL) { 586167514Skmacy device_printf(dev, "failed to add child port\n"); 587167514Skmacy error = EINVAL; 588167514Skmacy goto out; 589167514Skmacy } 590171978Skmacy pi = &sc->port[i]; 591171978Skmacy pi->adapter = sc; 592171978Skmacy pi->nqsets = port_qsets; 593171978Skmacy pi->first_qset = i*port_qsets; 594171978Skmacy pi->port_id = i; 595171978Skmacy pi->tx_chan = i >= ai->nports0; 596171978Skmacy pi->txpkt_intf = pi->tx_chan ? 2 * (i - ai->nports0) + 1 : 2 * i; 597171978Skmacy sc->rxpkt_map[pi->txpkt_intf] = i; 598174708Skmacy sc->port[i].tx_chan = i >= ai->nports0; 599171471Skmacy sc->portdev[i] = child; 600171978Skmacy device_set_softc(child, pi); 601167514Skmacy } 602167514Skmacy if ((error = bus_generic_attach(dev)) != 0) 603167514Skmacy goto out; 604167514Skmacy 605167514Skmacy /* initialize sge private state */ 606170654Skmacy t3_sge_init_adapter(sc); 607167514Skmacy 608167514Skmacy t3_led_ready(sc); 609169978Skmacy 610169978Skmacy cxgb_offload_init(); 611169978Skmacy if (is_offload(sc)) { 612169978Skmacy setbit(&sc->registered_device_map, OFFLOAD_DEVMAP_BIT); 613169978Skmacy cxgb_adapter_ofld(sc); 614169978Skmacy } 615167514Skmacy error = t3_get_fw_version(sc, &vers); 616167514Skmacy if (error) 617167514Skmacy goto out; 618167514Skmacy 619169978Skmacy snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d.%d", 620169978Skmacy G_FW_VERSION_MAJOR(vers), G_FW_VERSION_MINOR(vers), 621169978Skmacy G_FW_VERSION_MICRO(vers)); 622169978Skmacy 623185655Sgnn snprintf(buf, sizeof(buf), "%s\t E/C: %s S/N: %s", 624185655Sgnn ai->desc, 625185655Sgnn sc->params.vpd.ec, sc->params.vpd.sn); 626185655Sgnn device_set_desc_copy(dev, buf); 627185655Sgnn 628176472Skmacy device_printf(sc->dev, "Firmware Version %s\n", &sc->fw_version[0]); 629181652Skmacy callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc); 630174708Skmacy t3_add_attach_sysctls(sc); 631167514Skmacyout: 632167514Skmacy if (error) 633167514Skmacy cxgb_free(sc); 634167514Skmacy 635167514Skmacy return (error); 636167514Skmacy} 637167514Skmacy 638167514Skmacystatic int 639167514Skmacycxgb_controller_detach(device_t dev) 640167514Skmacy{ 641167514Skmacy struct adapter *sc; 642167514Skmacy 643167514Skmacy sc = device_get_softc(dev); 644167514Skmacy 645167514Skmacy cxgb_free(sc); 646167514Skmacy 647167514Skmacy return (0); 648167514Skmacy} 649167514Skmacy 650167514Skmacystatic void 651167514Skmacycxgb_free(struct adapter *sc) 652167514Skmacy{ 653167514Skmacy int i; 654167514Skmacy 655176472Skmacy ADAPTER_LOCK(sc); 656176472Skmacy sc->flags |= CXGB_SHUTDOWN; 657176472Skmacy ADAPTER_UNLOCK(sc); 658174708Skmacy cxgb_pcpu_shutdown_threads(sc); 659170869Skmacy ADAPTER_LOCK(sc); 660176472Skmacy 661174708Skmacy/* 662174708Skmacy * drops the lock 663174708Skmacy */ 664170869Skmacy cxgb_down_locked(sc); 665169978Skmacy 666169978Skmacy#ifdef MSI_SUPPORTED 667169978Skmacy if (sc->flags & (USING_MSI | USING_MSIX)) { 668169978Skmacy device_printf(sc->dev, "releasing msi message(s)\n"); 669169978Skmacy pci_release_msi(sc->dev); 670169978Skmacy } else { 671169978Skmacy device_printf(sc->dev, "no msi message to release\n"); 672169978Skmacy } 673169978Skmacy#endif 674169978Skmacy if (sc->msix_regs_res != NULL) { 675169978Skmacy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid, 676169978Skmacy sc->msix_regs_res); 677169978Skmacy } 678176472Skmacy 679171978Skmacy t3_sge_deinit_sw(sc); 680171978Skmacy /* 681171978Skmacy * Wait for last callout 682171978Skmacy */ 683171978Skmacy 684174708Skmacy DELAY(hz*100); 685170869Skmacy 686167760Skmacy for (i = 0; i < (sc)->params.nports; ++i) { 687167760Skmacy if (sc->portdev[i] != NULL) 688167760Skmacy device_delete_child(sc->dev, sc->portdev[i]); 689167760Skmacy } 690167760Skmacy 691167514Skmacy bus_generic_detach(sc->dev); 692176472Skmacy if (sc->tq != NULL) { 693171978Skmacy taskqueue_free(sc->tq); 694176472Skmacy sc->tq = NULL; 695176472Skmacy } 696176472Skmacy 697169978Skmacy if (is_offload(sc)) { 698169978Skmacy cxgb_adapter_unofld(sc); 699169978Skmacy if (isset(&sc->open_device_map, OFFLOAD_DEVMAP_BIT)) 700169978Skmacy offload_close(&sc->tdev); 701174708Skmacy else 702174708Skmacy printf("cxgb_free: DEVMAP_BIT not set\n"); 703174708Skmacy } else 704174708Skmacy printf("not offloading set\n"); 705183059Skmacy#ifdef notyet 706176472Skmacy if (sc->flags & CXGB_OFLD_INIT) 707176472Skmacy cxgb_offload_deactivate(sc); 708178302Skmacy#endif 709171471Skmacy free(sc->filters, M_DEVBUF); 710167514Skmacy t3_sge_free(sc); 711170869Skmacy 712170869Skmacy cxgb_offload_exit(); 713176472Skmacy 714176472Skmacy if (sc->udbs_res != NULL) 715176472Skmacy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->udbs_rid, 716176472Skmacy sc->udbs_res); 717176472Skmacy 718167514Skmacy if (sc->regs_res != NULL) 719167514Skmacy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->regs_rid, 720167514Skmacy sc->regs_res); 721167514Skmacy 722170869Skmacy MTX_DESTROY(&sc->mdio_lock); 723170869Skmacy MTX_DESTROY(&sc->sge.reg_lock); 724170869Skmacy MTX_DESTROY(&sc->elmer_lock); 725170869Skmacy ADAPTER_LOCK_DEINIT(sc); 726167514Skmacy} 727167514Skmacy 728167514Skmacy/** 729167514Skmacy * setup_sge_qsets - configure SGE Tx/Rx/response queues 730167514Skmacy * @sc: the controller softc 731167514Skmacy * 732167514Skmacy * Determines how many sets of SGE queues to use and initializes them. 733167514Skmacy * We support multiple queue sets per port if we have MSI-X, otherwise 734167514Skmacy * just one queue set per port. 735167514Skmacy */ 736167514Skmacystatic int 737167514Skmacysetup_sge_qsets(adapter_t *sc) 738167514Skmacy{ 739172096Skmacy int i, j, err, irq_idx = 0, qset_idx = 0; 740169978Skmacy u_int ntxq = SGE_TXQ_PER_SET; 741167514Skmacy 742167514Skmacy if ((err = t3_sge_alloc(sc)) != 0) { 743167760Skmacy device_printf(sc->dev, "t3_sge_alloc returned %d\n", err); 744167514Skmacy return (err); 745167514Skmacy } 746167514Skmacy 747167514Skmacy if (sc->params.rev > 0 && !(sc->flags & USING_MSI)) 748167514Skmacy irq_idx = -1; 749167514Skmacy 750172096Skmacy for (i = 0; i < (sc)->params.nports; i++) { 751167514Skmacy struct port_info *pi = &sc->port[i]; 752167514Skmacy 753171978Skmacy for (j = 0; j < pi->nqsets; j++, qset_idx++) { 754167760Skmacy err = t3_sge_alloc_qset(sc, qset_idx, (sc)->params.nports, 755167514Skmacy (sc->flags & USING_MSIX) ? qset_idx + 1 : irq_idx, 756167514Skmacy &sc->params.sge.qset[qset_idx], ntxq, pi); 757167514Skmacy if (err) { 758167514Skmacy t3_free_sge_resources(sc); 759171978Skmacy device_printf(sc->dev, "t3_sge_alloc_qset failed with %d\n", 760171978Skmacy err); 761167514Skmacy return (err); 762167514Skmacy } 763167514Skmacy } 764167514Skmacy } 765167514Skmacy 766167514Skmacy return (0); 767167514Skmacy} 768167514Skmacy 769170654Skmacystatic void 770170654Skmacycxgb_teardown_msix(adapter_t *sc) 771170654Skmacy{ 772170654Skmacy int i, nqsets; 773170654Skmacy 774170654Skmacy for (nqsets = i = 0; i < (sc)->params.nports; i++) 775170654Skmacy nqsets += sc->port[i].nqsets; 776170654Skmacy 777170654Skmacy for (i = 0; i < nqsets; i++) { 778170654Skmacy if (sc->msix_intr_tag[i] != NULL) { 779170654Skmacy bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 780170654Skmacy sc->msix_intr_tag[i]); 781170654Skmacy sc->msix_intr_tag[i] = NULL; 782170654Skmacy } 783170654Skmacy if (sc->msix_irq_res[i] != NULL) { 784170654Skmacy bus_release_resource(sc->dev, SYS_RES_IRQ, 785170654Skmacy sc->msix_irq_rid[i], sc->msix_irq_res[i]); 786170654Skmacy sc->msix_irq_res[i] = NULL; 787170654Skmacy } 788170654Skmacy } 789170654Skmacy} 790170654Skmacy 791167514Skmacystatic int 792167514Skmacycxgb_setup_msix(adapter_t *sc, int msix_count) 793167514Skmacy{ 794167514Skmacy int i, j, k, nqsets, rid; 795167514Skmacy 796167514Skmacy /* The first message indicates link changes and error conditions */ 797167514Skmacy sc->irq_rid = 1; 798167514Skmacy if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 799167514Skmacy &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 800167514Skmacy device_printf(sc->dev, "Cannot allocate msix interrupt\n"); 801167514Skmacy return (EINVAL); 802167514Skmacy } 803167760Skmacy 804167514Skmacy if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET, 805167514Skmacy#ifdef INTR_FILTERS 806171978Skmacy NULL, 807167514Skmacy#endif 808167514Skmacy cxgb_async_intr, sc, &sc->intr_tag)) { 809167514Skmacy device_printf(sc->dev, "Cannot set up interrupt\n"); 810167514Skmacy return (EINVAL); 811167514Skmacy } 812170654Skmacy for (i = k = 0; i < (sc)->params.nports; i++) { 813167514Skmacy nqsets = sc->port[i].nqsets; 814170654Skmacy for (j = 0; j < nqsets; j++, k++) { 815167514Skmacy struct sge_qset *qs = &sc->sge.qs[k]; 816171804Skmacy 817167514Skmacy rid = k + 2; 818167514Skmacy if (cxgb_debug) 819167514Skmacy printf("rid=%d ", rid); 820167514Skmacy if ((sc->msix_irq_res[k] = bus_alloc_resource_any( 821167514Skmacy sc->dev, SYS_RES_IRQ, &rid, 822167514Skmacy RF_SHAREABLE | RF_ACTIVE)) == NULL) { 823167514Skmacy device_printf(sc->dev, "Cannot allocate " 824167514Skmacy "interrupt for message %d\n", rid); 825167514Skmacy return (EINVAL); 826167514Skmacy } 827167514Skmacy sc->msix_irq_rid[k] = rid; 828170654Skmacy if (bus_setup_intr(sc->dev, sc->msix_irq_res[k], 829174708Skmacy INTR_MPSAFE|INTR_TYPE_NET, 830167514Skmacy#ifdef INTR_FILTERS 831171978Skmacy NULL, 832167514Skmacy#endif 833167514Skmacy t3_intr_msix, qs, &sc->msix_intr_tag[k])) { 834167514Skmacy device_printf(sc->dev, "Cannot set up " 835167514Skmacy "interrupt for message %d\n", rid); 836167514Skmacy return (EINVAL); 837185165Skmacy 838167514Skmacy } 839185165Skmacy#if 0 840174708Skmacy#ifdef IFNET_MULTIQUEUE 841185165Skmacy if (multiq) { 842174708Skmacy int vector = rman_get_start(sc->msix_irq_res[k]); 843174708Skmacy if (bootverbose) 844174708Skmacy device_printf(sc->dev, "binding vector=%d to cpu=%d\n", vector, k % mp_ncpus); 845174708Skmacy intr_bind(vector, k % mp_ncpus); 846174708Skmacy } 847185165Skmacy#endif 848185165Skmacy#endif 849167514Skmacy } 850167514Skmacy } 851167760Skmacy 852167514Skmacy return (0); 853167514Skmacy} 854167514Skmacy 855167514Skmacystatic int 856167514Skmacycxgb_port_probe(device_t dev) 857167514Skmacy{ 858167514Skmacy struct port_info *p; 859167514Skmacy char buf[80]; 860176472Skmacy const char *desc; 861176472Skmacy 862167514Skmacy p = device_get_softc(dev); 863176472Skmacy desc = p->phy.desc; 864176472Skmacy snprintf(buf, sizeof(buf), "Port %d %s", p->port_id, desc); 865167514Skmacy device_set_desc_copy(dev, buf); 866167514Skmacy return (0); 867167514Skmacy} 868167514Skmacy 869167514Skmacy 870167514Skmacystatic int 871167514Skmacycxgb_makedev(struct port_info *pi) 872167514Skmacy{ 873167514Skmacy 874170654Skmacy pi->port_cdev = make_dev(&cxgb_cdevsw, pi->ifp->if_dunit, 875170654Skmacy UID_ROOT, GID_WHEEL, 0600, if_name(pi->ifp)); 876167514Skmacy 877167514Skmacy if (pi->port_cdev == NULL) 878167514Skmacy return (ENOMEM); 879167514Skmacy 880167514Skmacy pi->port_cdev->si_drv1 = (void *)pi; 881167514Skmacy 882167514Skmacy return (0); 883167514Skmacy} 884167514Skmacy 885183289Skmacy#ifndef LRO_SUPPORTED 886183289Skmacy#ifdef IFCAP_LRO 887183289Skmacy#undef IFCAP_LRO 888183289Skmacy#endif 889183289Skmacy#define IFCAP_LRO 0x0 890183289Skmacy#endif 891167514Skmacy 892167514Skmacy#ifdef TSO_SUPPORTED 893181616Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO) 894167514Skmacy/* Don't enable TSO6 yet */ 895181616Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO4 | IFCAP_JUMBO_MTU | IFCAP_LRO) 896167514Skmacy#else 897167514Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU) 898167514Skmacy/* Don't enable TSO6 yet */ 899167514Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU) 900167514Skmacy#define IFCAP_TSO4 0x0 901171868Skmacy#define IFCAP_TSO6 0x0 902167514Skmacy#define CSUM_TSO 0x0 903167514Skmacy#endif 904167514Skmacy 905167514Skmacy 906167514Skmacystatic int 907167514Skmacycxgb_port_attach(device_t dev) 908167514Skmacy{ 909167514Skmacy struct port_info *p; 910167514Skmacy struct ifnet *ifp; 911170654Skmacy int err, media_flags; 912176472Skmacy struct adapter *sc; 913167514Skmacy 914176472Skmacy 915167514Skmacy p = device_get_softc(dev); 916176472Skmacy sc = p->adapter; 917170869Skmacy snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d", 918171803Skmacy device_get_unit(device_get_parent(dev)), p->port_id); 919170869Skmacy PORT_LOCK_INIT(p, p->lockbuf); 920167514Skmacy 921167514Skmacy /* Allocate an ifnet object and set it up */ 922167514Skmacy ifp = p->ifp = if_alloc(IFT_ETHER); 923167514Skmacy if (ifp == NULL) { 924167514Skmacy device_printf(dev, "Cannot allocate ifnet\n"); 925167514Skmacy return (ENOMEM); 926167514Skmacy } 927167514Skmacy 928167514Skmacy /* 929167514Skmacy * Note that there is currently no watchdog timer. 930167514Skmacy */ 931167514Skmacy if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 932167514Skmacy ifp->if_init = cxgb_init; 933167514Skmacy ifp->if_softc = p; 934167514Skmacy ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 935167514Skmacy ifp->if_ioctl = cxgb_ioctl; 936167514Skmacy ifp->if_start = cxgb_start; 937174708Skmacy 938185165Skmacy 939167514Skmacy ifp->if_timer = 0; /* Disable ifnet watchdog */ 940167514Skmacy ifp->if_watchdog = NULL; 941167514Skmacy 942185165Skmacy ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 943167514Skmacy IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 944167514Skmacy IFQ_SET_READY(&ifp->if_snd); 945167514Skmacy 946167514Skmacy ifp->if_hwassist = ifp->if_capabilities = ifp->if_capenable = 0; 947167514Skmacy ifp->if_capabilities |= CXGB_CAP; 948167514Skmacy ifp->if_capenable |= CXGB_CAP_ENABLE; 949167514Skmacy ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO); 950171471Skmacy /* 951171471Skmacy * disable TSO on 4-port - it isn't supported by the firmware yet 952171471Skmacy */ 953171471Skmacy if (p->adapter->params.nports > 2) { 954171471Skmacy ifp->if_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6); 955171471Skmacy ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TSO6); 956171471Skmacy ifp->if_hwassist &= ~CSUM_TSO; 957171471Skmacy } 958171471Skmacy 959167514Skmacy ether_ifattach(ifp, p->hw_addr); 960185199Skmacy#ifdef IFNET_MULTIQUEUE 961185165Skmacy ifp->if_transmit = cxgb_pcpu_transmit; 962185199Skmacy#endif 963171471Skmacy /* 964171471Skmacy * Only default to jumbo frames on 10GigE 965171471Skmacy */ 966171471Skmacy if (p->adapter->params.nports <= 2) 967180583Skmacy ifp->if_mtu = ETHERMTU_JUMBO; 968167514Skmacy if ((err = cxgb_makedev(p)) != 0) { 969167514Skmacy printf("makedev failed %d\n", err); 970167514Skmacy return (err); 971167514Skmacy } 972167514Skmacy ifmedia_init(&p->media, IFM_IMASK, cxgb_media_change, 973167514Skmacy cxgb_media_status); 974176472Skmacy 975176472Skmacy if (!strcmp(p->phy.desc, "10GBASE-CX4")) { 976170654Skmacy media_flags = IFM_ETHER | IFM_10G_CX4 | IFM_FDX; 977176472Skmacy } else if (!strcmp(p->phy.desc, "10GBASE-SR")) { 978170654Skmacy media_flags = IFM_ETHER | IFM_10G_SR | IFM_FDX; 979177340Skmacy } else if (!strcmp(p->phy.desc, "10GBASE-R")) { 980186282Sgnn media_flags = cxgb_ifm_type(p->phy.modtype); 981176472Skmacy } else if (!strcmp(p->phy.desc, "10/100/1000BASE-T")) { 982170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_10_T, 0, NULL); 983170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_10_T | IFM_FDX, 984170654Skmacy 0, NULL); 985170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX, 986170654Skmacy 0, NULL); 987170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX | IFM_FDX, 988170654Skmacy 0, NULL); 989170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_1000_T | IFM_FDX, 990170654Skmacy 0, NULL); 991170654Skmacy media_flags = 0; 992183506Skmacy } else if (!strcmp(p->phy.desc, "1000BASE-X")) { 993183506Skmacy /* 994183506Skmacy * XXX: This is not very accurate. Fix when common code 995183506Skmacy * returns more specific value - eg 1000BASE-SX, LX, etc. 996186282Sgnn * 997186282Sgnn * XXX: In the meantime, don't lie. Consider setting IFM_AUTO 998186282Sgnn * instead of SX. 999183506Skmacy */ 1000183506Skmacy media_flags = IFM_ETHER | IFM_1000_SX | IFM_FDX; 1001170654Skmacy } else { 1002176472Skmacy printf("unsupported media type %s\n", p->phy.desc); 1003167514Skmacy return (ENXIO); 1004167514Skmacy } 1005170654Skmacy if (media_flags) { 1006186282Sgnn /* 1007186282Sgnn * Note the modtype on which we based our flags. If modtype 1008186282Sgnn * changes, we'll redo the ifmedia for this ifp. modtype may 1009186282Sgnn * change when transceivers are plugged in/out, and in other 1010186282Sgnn * situations. 1011186282Sgnn */ 1012186282Sgnn ifmedia_add(&p->media, media_flags, p->phy.modtype, NULL); 1013170654Skmacy ifmedia_set(&p->media, media_flags); 1014170654Skmacy } else { 1015170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL); 1016170654Skmacy ifmedia_set(&p->media, IFM_ETHER | IFM_AUTO); 1017170654Skmacy } 1018167514Skmacy 1019177340Skmacy /* Get the latest mac address, User can use a LAA */ 1020177340Skmacy bcopy(IF_LLADDR(p->ifp), p->hw_addr, ETHER_ADDR_LEN); 1021170654Skmacy t3_sge_init_port(p); 1022189643Sgnn 1023189643Sgnn TASK_INIT(&p->link_fault_task, 0, cxgb_link_fault, p); 1024189643Sgnn 1025177415Skmacy#if defined(LINK_ATTACH) 1026176472Skmacy cxgb_link_start(p); 1027176472Skmacy t3_link_changed(sc, p->port_id); 1028177415Skmacy#endif 1029167514Skmacy return (0); 1030167514Skmacy} 1031167514Skmacy 1032167514Skmacystatic int 1033167514Skmacycxgb_port_detach(device_t dev) 1034167514Skmacy{ 1035167514Skmacy struct port_info *p; 1036167514Skmacy 1037167514Skmacy p = device_get_softc(dev); 1038169978Skmacy 1039169978Skmacy PORT_LOCK(p); 1040170654Skmacy if (p->ifp->if_drv_flags & IFF_DRV_RUNNING) 1041170654Skmacy cxgb_stop_locked(p); 1042169978Skmacy PORT_UNLOCK(p); 1043169978Skmacy 1044171978Skmacy ether_ifdetach(p->ifp); 1045174708Skmacy printf("waiting for callout to stop ..."); 1046174708Skmacy DELAY(1000000); 1047174708Skmacy printf("done\n"); 1048171978Skmacy /* 1049171978Skmacy * the lock may be acquired in ifdetach 1050171978Skmacy */ 1051170869Skmacy PORT_LOCK_DEINIT(p); 1052167514Skmacy if_free(p->ifp); 1053167514Skmacy 1054170654Skmacy if (p->port_cdev != NULL) 1055170654Skmacy destroy_dev(p->port_cdev); 1056170654Skmacy 1057167514Skmacy return (0); 1058167514Skmacy} 1059167514Skmacy 1060167514Skmacyvoid 1061167514Skmacyt3_fatal_err(struct adapter *sc) 1062167514Skmacy{ 1063167514Skmacy u_int fw_status[4]; 1064183062Skmacy 1065172096Skmacy if (sc->flags & FULL_INIT_DONE) { 1066172096Skmacy t3_sge_stop(sc); 1067172096Skmacy t3_write_reg(sc, A_XGM_TX_CTRL, 0); 1068172096Skmacy t3_write_reg(sc, A_XGM_RX_CTRL, 0); 1069172096Skmacy t3_write_reg(sc, XGM_REG(A_XGM_TX_CTRL, 1), 0); 1070172096Skmacy t3_write_reg(sc, XGM_REG(A_XGM_RX_CTRL, 1), 0); 1071172096Skmacy t3_intr_disable(sc); 1072172096Skmacy } 1073167514Skmacy device_printf(sc->dev,"encountered fatal error, operation suspended\n"); 1074167514Skmacy if (!t3_cim_ctl_blk_read(sc, 0xa0, 4, fw_status)) 1075167514Skmacy device_printf(sc->dev, "FW_ status: 0x%x, 0x%x, 0x%x, 0x%x\n", 1076167514Skmacy fw_status[0], fw_status[1], fw_status[2], fw_status[3]); 1077167514Skmacy} 1078167514Skmacy 1079167514Skmacyint 1080167514Skmacyt3_os_find_pci_capability(adapter_t *sc, int cap) 1081167514Skmacy{ 1082167514Skmacy device_t dev; 1083167514Skmacy struct pci_devinfo *dinfo; 1084167514Skmacy pcicfgregs *cfg; 1085167514Skmacy uint32_t status; 1086167514Skmacy uint8_t ptr; 1087167514Skmacy 1088167514Skmacy dev = sc->dev; 1089167514Skmacy dinfo = device_get_ivars(dev); 1090167514Skmacy cfg = &dinfo->cfg; 1091167514Skmacy 1092167514Skmacy status = pci_read_config(dev, PCIR_STATUS, 2); 1093167514Skmacy if (!(status & PCIM_STATUS_CAPPRESENT)) 1094167514Skmacy return (0); 1095167514Skmacy 1096167514Skmacy switch (cfg->hdrtype & PCIM_HDRTYPE) { 1097167514Skmacy case 0: 1098167514Skmacy case 1: 1099167514Skmacy ptr = PCIR_CAP_PTR; 1100167514Skmacy break; 1101167514Skmacy case 2: 1102167514Skmacy ptr = PCIR_CAP_PTR_2; 1103167514Skmacy break; 1104167514Skmacy default: 1105167514Skmacy return (0); 1106167514Skmacy break; 1107167514Skmacy } 1108167514Skmacy ptr = pci_read_config(dev, ptr, 1); 1109167514Skmacy 1110167514Skmacy while (ptr != 0) { 1111167514Skmacy if (pci_read_config(dev, ptr + PCICAP_ID, 1) == cap) 1112167514Skmacy return (ptr); 1113167514Skmacy ptr = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1); 1114167514Skmacy } 1115167514Skmacy 1116167514Skmacy return (0); 1117167514Skmacy} 1118167514Skmacy 1119167514Skmacyint 1120167514Skmacyt3_os_pci_save_state(struct adapter *sc) 1121167514Skmacy{ 1122167514Skmacy device_t dev; 1123167514Skmacy struct pci_devinfo *dinfo; 1124167514Skmacy 1125167514Skmacy dev = sc->dev; 1126167514Skmacy dinfo = device_get_ivars(dev); 1127167514Skmacy 1128167514Skmacy pci_cfg_save(dev, dinfo, 0); 1129167514Skmacy return (0); 1130167514Skmacy} 1131167514Skmacy 1132167514Skmacyint 1133167514Skmacyt3_os_pci_restore_state(struct adapter *sc) 1134167514Skmacy{ 1135167514Skmacy device_t dev; 1136167514Skmacy struct pci_devinfo *dinfo; 1137167514Skmacy 1138167514Skmacy dev = sc->dev; 1139167514Skmacy dinfo = device_get_ivars(dev); 1140167514Skmacy 1141167514Skmacy pci_cfg_restore(dev, dinfo); 1142167514Skmacy return (0); 1143167514Skmacy} 1144167514Skmacy 1145189643Sgnnvoid t3_os_link_fault(struct adapter *adap, int port_id, int state) 1146189643Sgnn{ 1147189643Sgnn struct port_info *pi = &adap->port[port_id]; 1148189643Sgnn 1149189643Sgnn if (!state) { 1150189643Sgnn if_link_state_change(pi->ifp, LINK_STATE_DOWN); 1151189643Sgnn return; 1152189643Sgnn } 1153189643Sgnn 1154189643Sgnn if (adap->params.nports <= 2) { 1155189643Sgnn struct cmac *mac = &pi->mac; 1156189643Sgnn 1157189643Sgnn /* Clear local faults */ 1158189643Sgnn t3_xgm_intr_disable(adap, port_id); 1159189643Sgnn t3_read_reg(adap, A_XGM_INT_STATUS + pi->mac.offset); 1160189643Sgnn t3_write_reg(adap, A_XGM_INT_CAUSE + pi->mac.offset, F_XGM_INT); 1161189643Sgnn 1162189643Sgnn t3_set_reg_field(adap, A_XGM_INT_ENABLE + pi->mac.offset, 1163189643Sgnn F_XGM_INT, F_XGM_INT); 1164189643Sgnn t3_xgm_intr_enable(adap, pi->port_id); 1165189643Sgnn t3_mac_enable(mac, MAC_DIRECTION_TX); 1166189643Sgnn } 1167189643Sgnn 1168189643Sgnn if_link_state_change(pi->ifp, LINK_STATE_UP); 1169189643Sgnn} 1170189643Sgnn 1171167514Skmacy/** 1172167514Skmacy * t3_os_link_changed - handle link status changes 1173167514Skmacy * @adapter: the adapter associated with the link change 1174167514Skmacy * @port_id: the port index whose limk status has changed 1175177340Skmacy * @link_status: the new status of the link 1176167514Skmacy * @speed: the new speed setting 1177167514Skmacy * @duplex: the new duplex setting 1178167514Skmacy * @fc: the new flow-control setting 1179167514Skmacy * 1180167514Skmacy * This is the OS-dependent handler for link status changes. The OS 1181167514Skmacy * neutral handler takes care of most of the processing for these events, 1182167514Skmacy * then calls this handler for any OS-specific processing. 1183167514Skmacy */ 1184167514Skmacyvoid 1185167514Skmacyt3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed, 1186167514Skmacy int duplex, int fc) 1187167514Skmacy{ 1188167514Skmacy struct port_info *pi = &adapter->port[port_id]; 1189169978Skmacy struct cmac *mac = &adapter->port[port_id].mac; 1190167514Skmacy 1191169978Skmacy if (link_status) { 1192177340Skmacy DELAY(10); 1193177340Skmacy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 1194189643Sgnn /* Clear errors created by MAC enable */ 1195189643Sgnn t3_set_reg_field(adapter, A_XGM_STAT_CTRL + pi->mac.offset, 1196189643Sgnn F_CLRSTATS, 1); 1197189643Sgnn 1198189643Sgnn if (adapter->params.nports <= 2) { 1199189643Sgnn /* Clear local faults */ 1200189643Sgnn t3_xgm_intr_disable(adapter, pi->port_id); 1201189643Sgnn t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); 1202189643Sgnn t3_write_reg(adapter, A_XGM_INT_CAUSE + pi->mac.offset, 1203189643Sgnn F_XGM_INT); 1204189643Sgnn 1205177340Skmacy t3_set_reg_field(adapter, 1206189643Sgnn A_XGM_INT_ENABLE + pi->mac.offset, 1207189643Sgnn F_XGM_INT, F_XGM_INT); 1208189643Sgnn t3_xgm_intr_enable(adapter, pi->port_id); 1209189643Sgnn } 1210189643Sgnn 1211167514Skmacy if_link_state_change(pi->ifp, LINK_STATE_UP); 1212189643Sgnn } else { 1213189643Sgnn t3_xgm_intr_disable(adapter, pi->port_id); 1214189643Sgnn t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); 1215189643Sgnn if (adapter->params.nports <= 2) { 1216189643Sgnn t3_set_reg_field(adapter, 1217189643Sgnn A_XGM_INT_ENABLE + pi->mac.offset, 1218189643Sgnn F_XGM_INT, 0); 1219189643Sgnn } 1220177340Skmacy 1221189643Sgnn /* PR 5666. We shouldn't power down 1G phys */ 1222189643Sgnn if (is_10G(adapter)) 1223189643Sgnn pi->phy.ops->power_down(&pi->phy, 1); 1224189643Sgnn 1225189643Sgnn t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); 1226169978Skmacy t3_mac_disable(mac, MAC_DIRECTION_RX); 1227169978Skmacy t3_link_start(&pi->phy, mac, &pi->link_config); 1228189643Sgnn 1229176472Skmacy if_link_state_change(pi->ifp, LINK_STATE_DOWN); 1230169978Skmacy } 1231167514Skmacy} 1232167514Skmacy 1233181614Skmacy/** 1234181614Skmacy * t3_os_phymod_changed - handle PHY module changes 1235181614Skmacy * @phy: the PHY reporting the module change 1236181614Skmacy * @mod_type: new module type 1237181614Skmacy * 1238181614Skmacy * This is the OS-dependent handler for PHY module changes. It is 1239181614Skmacy * invoked when a PHY module is removed or inserted for any OS-specific 1240181614Skmacy * processing. 1241181614Skmacy */ 1242181614Skmacyvoid t3_os_phymod_changed(struct adapter *adap, int port_id) 1243181614Skmacy{ 1244181614Skmacy static const char *mod_str[] = { 1245181614Skmacy NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown" 1246181614Skmacy }; 1247181614Skmacy 1248181614Skmacy struct port_info *pi = &adap->port[port_id]; 1249181614Skmacy 1250181614Skmacy if (pi->phy.modtype == phy_modtype_none) 1251181614Skmacy device_printf(adap->dev, "PHY module unplugged\n"); 1252181614Skmacy else { 1253181614Skmacy KASSERT(pi->phy.modtype < ARRAY_SIZE(mod_str), 1254181614Skmacy ("invalid PHY module type %d", pi->phy.modtype)); 1255181614Skmacy device_printf(adap->dev, "%s PHY module inserted\n", 1256181614Skmacy mod_str[pi->phy.modtype]); 1257181614Skmacy } 1258181614Skmacy} 1259181614Skmacy 1260167514Skmacy/* 1261167514Skmacy * Interrupt-context handler for external (PHY) interrupts. 1262167514Skmacy */ 1263167514Skmacyvoid 1264167514Skmacyt3_os_ext_intr_handler(adapter_t *sc) 1265167514Skmacy{ 1266167514Skmacy if (cxgb_debug) 1267167514Skmacy printf("t3_os_ext_intr_handler\n"); 1268167514Skmacy /* 1269167514Skmacy * Schedule a task to handle external interrupts as they may be slow 1270167514Skmacy * and we use a mutex to protect MDIO registers. We disable PHY 1271167514Skmacy * interrupts in the meantime and let the task reenable them when 1272167514Skmacy * it's done. 1273167514Skmacy */ 1274169978Skmacy ADAPTER_LOCK(sc); 1275167514Skmacy if (sc->slow_intr_mask) { 1276167514Skmacy sc->slow_intr_mask &= ~F_T3DBG; 1277167514Skmacy t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask); 1278167514Skmacy taskqueue_enqueue(sc->tq, &sc->ext_intr_task); 1279167514Skmacy } 1280169978Skmacy ADAPTER_UNLOCK(sc); 1281167514Skmacy} 1282167514Skmacy 1283189643Sgnnstatic void 1284189643Sgnncxgb_link_fault(void *arg, int ncount) 1285189643Sgnn{ 1286189643Sgnn struct port_info *pi = arg; 1287189643Sgnn 1288189643Sgnn t3_link_fault(pi->adapter, pi->port_id); 1289189643Sgnn} 1290189643Sgnn 1291189643Sgnnvoid t3_os_link_fault_handler(struct adapter *sc, int port_id) 1292189643Sgnn{ 1293189643Sgnn struct port_info *pi = &sc->port[port_id]; 1294189643Sgnn 1295189643Sgnn pi->link_fault = 1; 1296189643Sgnn taskqueue_enqueue(sc->tq, &pi->link_fault_task); 1297189643Sgnn} 1298189643Sgnn 1299167514Skmacyvoid 1300167514Skmacyt3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[]) 1301167514Skmacy{ 1302167514Skmacy 1303167514Skmacy /* 1304167514Skmacy * The ifnet might not be allocated before this gets called, 1305167514Skmacy * as this is called early on in attach by t3_prep_adapter 1306167514Skmacy * save the address off in the port structure 1307167514Skmacy */ 1308167514Skmacy if (cxgb_debug) 1309167514Skmacy printf("set_hw_addr on idx %d addr %6D\n", port_idx, hw_addr, ":"); 1310167514Skmacy bcopy(hw_addr, adapter->port[port_idx].hw_addr, ETHER_ADDR_LEN); 1311167514Skmacy} 1312167514Skmacy 1313167514Skmacy/** 1314167514Skmacy * link_start - enable a port 1315167514Skmacy * @p: the port to enable 1316167514Skmacy * 1317167514Skmacy * Performs the MAC and PHY actions needed to enable a port. 1318167514Skmacy */ 1319167514Skmacystatic void 1320167514Skmacycxgb_link_start(struct port_info *p) 1321167514Skmacy{ 1322167514Skmacy struct ifnet *ifp; 1323167514Skmacy struct t3_rx_mode rm; 1324167514Skmacy struct cmac *mac = &p->mac; 1325180583Skmacy int mtu, hwtagging; 1326167514Skmacy 1327167514Skmacy ifp = p->ifp; 1328167514Skmacy 1329180583Skmacy bcopy(IF_LLADDR(ifp), p->hw_addr, ETHER_ADDR_LEN); 1330180583Skmacy 1331180583Skmacy mtu = ifp->if_mtu; 1332180583Skmacy if (ifp->if_capenable & IFCAP_VLAN_MTU) 1333180583Skmacy mtu += ETHER_VLAN_ENCAP_LEN; 1334180583Skmacy 1335180583Skmacy hwtagging = (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0; 1336180583Skmacy 1337167514Skmacy t3_init_rx_mode(&rm, p); 1338172096Skmacy if (!mac->multiport) 1339171978Skmacy t3_mac_reset(mac); 1340180583Skmacy t3_mac_set_mtu(mac, mtu); 1341180583Skmacy t3_set_vlan_accel(p->adapter, 1 << p->tx_chan, hwtagging); 1342167514Skmacy t3_mac_set_address(mac, 0, p->hw_addr); 1343167514Skmacy t3_mac_set_rx_mode(mac, &rm); 1344167514Skmacy t3_link_start(&p->phy, mac, &p->link_config); 1345167514Skmacy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 1346167514Skmacy} 1347167514Skmacy 1348176472Skmacy 1349176472Skmacystatic int 1350176472Skmacyawait_mgmt_replies(struct adapter *adap, unsigned long init_cnt, 1351176472Skmacy unsigned long n) 1352176472Skmacy{ 1353176472Skmacy int attempts = 5; 1354176472Skmacy 1355176472Skmacy while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) { 1356176472Skmacy if (!--attempts) 1357176472Skmacy return (ETIMEDOUT); 1358176472Skmacy t3_os_sleep(10); 1359176472Skmacy } 1360176472Skmacy return 0; 1361176472Skmacy} 1362176472Skmacy 1363176472Skmacystatic int 1364176472Skmacyinit_tp_parity(struct adapter *adap) 1365176472Skmacy{ 1366176472Skmacy int i; 1367176472Skmacy struct mbuf *m; 1368176472Skmacy struct cpl_set_tcb_field *greq; 1369176472Skmacy unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts; 1370176472Skmacy 1371176472Skmacy t3_tp_set_offload_mode(adap, 1); 1372176472Skmacy 1373176472Skmacy for (i = 0; i < 16; i++) { 1374176472Skmacy struct cpl_smt_write_req *req; 1375176472Skmacy 1376176472Skmacy m = m_gethdr(M_WAITOK, MT_DATA); 1377176472Skmacy req = mtod(m, struct cpl_smt_write_req *); 1378176472Skmacy m->m_len = m->m_pkthdr.len = sizeof(*req); 1379176472Skmacy memset(req, 0, sizeof(*req)); 1380176472Skmacy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1381176472Skmacy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); 1382176472Skmacy req->iff = i; 1383176472Skmacy t3_mgmt_tx(adap, m); 1384176472Skmacy } 1385176472Skmacy 1386176472Skmacy for (i = 0; i < 2048; i++) { 1387176472Skmacy struct cpl_l2t_write_req *req; 1388176472Skmacy 1389176472Skmacy m = m_gethdr(M_WAITOK, MT_DATA); 1390176472Skmacy req = mtod(m, struct cpl_l2t_write_req *); 1391176472Skmacy m->m_len = m->m_pkthdr.len = sizeof(*req); 1392176472Skmacy memset(req, 0, sizeof(*req)); 1393176472Skmacy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1394176472Skmacy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i)); 1395176472Skmacy req->params = htonl(V_L2T_W_IDX(i)); 1396176472Skmacy t3_mgmt_tx(adap, m); 1397176472Skmacy } 1398176472Skmacy 1399176472Skmacy for (i = 0; i < 2048; i++) { 1400176472Skmacy struct cpl_rte_write_req *req; 1401176472Skmacy 1402176472Skmacy m = m_gethdr(M_WAITOK, MT_DATA); 1403176472Skmacy req = mtod(m, struct cpl_rte_write_req *); 1404176472Skmacy m->m_len = m->m_pkthdr.len = sizeof(*req); 1405176472Skmacy memset(req, 0, sizeof(*req)); 1406176472Skmacy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1407176472Skmacy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i)); 1408176472Skmacy req->l2t_idx = htonl(V_L2T_W_IDX(i)); 1409176472Skmacy t3_mgmt_tx(adap, m); 1410176472Skmacy } 1411176472Skmacy 1412176472Skmacy m = m_gethdr(M_WAITOK, MT_DATA); 1413176472Skmacy greq = mtod(m, struct cpl_set_tcb_field *); 1414176472Skmacy m->m_len = m->m_pkthdr.len = sizeof(*greq); 1415176472Skmacy memset(greq, 0, sizeof(*greq)); 1416176472Skmacy greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1417176472Skmacy OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0)); 1418176472Skmacy greq->mask = htobe64(1); 1419176472Skmacy t3_mgmt_tx(adap, m); 1420176472Skmacy 1421176472Skmacy i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); 1422176472Skmacy t3_tp_set_offload_mode(adap, 0); 1423176472Skmacy return (i); 1424176472Skmacy} 1425176472Skmacy 1426167514Skmacy/** 1427167514Skmacy * setup_rss - configure Receive Side Steering (per-queue connection demux) 1428167514Skmacy * @adap: the adapter 1429167514Skmacy * 1430167514Skmacy * Sets up RSS to distribute packets to multiple receive queues. We 1431167514Skmacy * configure the RSS CPU lookup table to distribute to the number of HW 1432167514Skmacy * receive queues, and the response queue lookup table to narrow that 1433167514Skmacy * down to the response queues actually configured for each port. 1434167514Skmacy * We always configure the RSS mapping for two ports since the mapping 1435167514Skmacy * table has plenty of entries. 1436167514Skmacy */ 1437167514Skmacystatic void 1438167514Skmacysetup_rss(adapter_t *adap) 1439167514Skmacy{ 1440167514Skmacy int i; 1441171471Skmacy u_int nq[2]; 1442167514Skmacy uint8_t cpus[SGE_QSETS + 1]; 1443167514Skmacy uint16_t rspq_map[RSS_TABLE_SIZE]; 1444171471Skmacy 1445167514Skmacy for (i = 0; i < SGE_QSETS; ++i) 1446167514Skmacy cpus[i] = i; 1447167514Skmacy cpus[SGE_QSETS] = 0xff; 1448167514Skmacy 1449171978Skmacy nq[0] = nq[1] = 0; 1450171978Skmacy for_each_port(adap, i) { 1451171978Skmacy const struct port_info *pi = adap2pinfo(adap, i); 1452171978Skmacy 1453171978Skmacy nq[pi->tx_chan] += pi->nqsets; 1454171978Skmacy } 1455167514Skmacy for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) { 1456176472Skmacy rspq_map[i] = nq[0] ? i % nq[0] : 0; 1457176472Skmacy rspq_map[i + RSS_TABLE_SIZE / 2] = nq[1] ? i % nq[1] + nq[0] : 0; 1458167514Skmacy } 1459171471Skmacy /* Calculate the reverse RSS map table */ 1460171471Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) 1461171471Skmacy if (adap->rrss_map[rspq_map[i]] == 0xff) 1462171471Skmacy adap->rrss_map[rspq_map[i]] = i; 1463167514Skmacy 1464167514Skmacy t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN | 1465171471Skmacy F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | F_OFDMAPEN | 1466176472Skmacy F_RRCPLMAPEN | V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, 1467176472Skmacy cpus, rspq_map); 1468171471Skmacy 1469167514Skmacy} 1470167514Skmacy 1471169978Skmacy/* 1472169978Skmacy * Sends an mbuf to an offload queue driver 1473169978Skmacy * after dealing with any active network taps. 1474169978Skmacy */ 1475169978Skmacystatic inline int 1476174626Skmacyoffload_tx(struct t3cdev *tdev, struct mbuf *m) 1477169978Skmacy{ 1478169978Skmacy int ret; 1479169978Skmacy 1480169978Skmacy ret = t3_offload_tx(tdev, m); 1481170654Skmacy return (ret); 1482169978Skmacy} 1483169978Skmacy 1484169978Skmacystatic int 1485169978Skmacywrite_smt_entry(struct adapter *adapter, int idx) 1486169978Skmacy{ 1487169978Skmacy struct port_info *pi = &adapter->port[idx]; 1488169978Skmacy struct cpl_smt_write_req *req; 1489169978Skmacy struct mbuf *m; 1490169978Skmacy 1491169978Skmacy if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL) 1492169978Skmacy return (ENOMEM); 1493169978Skmacy 1494169978Skmacy req = mtod(m, struct cpl_smt_write_req *); 1495174708Skmacy m->m_pkthdr.len = m->m_len = sizeof(struct cpl_smt_write_req); 1496174708Skmacy 1497169978Skmacy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1498169978Skmacy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx)); 1499169978Skmacy req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */ 1500169978Skmacy req->iff = idx; 1501169978Skmacy memset(req->src_mac1, 0, sizeof(req->src_mac1)); 1502169978Skmacy memcpy(req->src_mac0, pi->hw_addr, ETHER_ADDR_LEN); 1503169978Skmacy 1504169978Skmacy m_set_priority(m, 1); 1505169978Skmacy 1506169978Skmacy offload_tx(&adapter->tdev, m); 1507169978Skmacy 1508169978Skmacy return (0); 1509169978Skmacy} 1510169978Skmacy 1511169978Skmacystatic int 1512169978Skmacyinit_smt(struct adapter *adapter) 1513169978Skmacy{ 1514169978Skmacy int i; 1515169978Skmacy 1516169978Skmacy for_each_port(adapter, i) 1517169978Skmacy write_smt_entry(adapter, i); 1518169978Skmacy return 0; 1519169978Skmacy} 1520169978Skmacy 1521167514Skmacystatic void 1522169978Skmacyinit_port_mtus(adapter_t *adapter) 1523169978Skmacy{ 1524169978Skmacy unsigned int mtus = adapter->port[0].ifp->if_mtu; 1525169978Skmacy 1526169978Skmacy if (adapter->port[1].ifp) 1527169978Skmacy mtus |= adapter->port[1].ifp->if_mtu << 16; 1528169978Skmacy t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus); 1529169978Skmacy} 1530169978Skmacy 1531169978Skmacystatic void 1532167514Skmacysend_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, 1533167514Skmacy int hi, int port) 1534167514Skmacy{ 1535167514Skmacy struct mbuf *m; 1536167514Skmacy struct mngt_pktsched_wr *req; 1537167514Skmacy 1538171471Skmacy m = m_gethdr(M_DONTWAIT, MT_DATA); 1539167848Skmacy if (m) { 1540169978Skmacy req = mtod(m, struct mngt_pktsched_wr *); 1541167848Skmacy req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); 1542167848Skmacy req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET; 1543167848Skmacy req->sched = sched; 1544167848Skmacy req->idx = qidx; 1545167848Skmacy req->min = lo; 1546167848Skmacy req->max = hi; 1547167848Skmacy req->binding = port; 1548167848Skmacy m->m_len = m->m_pkthdr.len = sizeof(*req); 1549167848Skmacy t3_mgmt_tx(adap, m); 1550167848Skmacy } 1551167514Skmacy} 1552167514Skmacy 1553167514Skmacystatic void 1554167514Skmacybind_qsets(adapter_t *sc) 1555167514Skmacy{ 1556167514Skmacy int i, j; 1557167514Skmacy 1558174708Skmacy cxgb_pcpu_startup_threads(sc); 1559167514Skmacy for (i = 0; i < (sc)->params.nports; ++i) { 1560167514Skmacy const struct port_info *pi = adap2pinfo(sc, i); 1561167514Skmacy 1562172096Skmacy for (j = 0; j < pi->nqsets; ++j) { 1563167514Skmacy send_pktsched_cmd(sc, 1, pi->first_qset + j, -1, 1564172096Skmacy -1, pi->tx_chan); 1565172096Skmacy 1566172096Skmacy } 1567167514Skmacy } 1568167514Skmacy} 1569167514Skmacy 1570171471Skmacystatic void 1571171471Skmacyupdate_tpeeprom(struct adapter *adap) 1572171471Skmacy{ 1573172109Skmacy#ifdef FIRMWARE_LATEST 1574171471Skmacy const struct firmware *tpeeprom; 1575172109Skmacy#else 1576172109Skmacy struct firmware *tpeeprom; 1577172109Skmacy#endif 1578172109Skmacy 1579171471Skmacy uint32_t version; 1580171471Skmacy unsigned int major, minor; 1581171471Skmacy int ret, len; 1582189643Sgnn char rev, name[32]; 1583171471Skmacy 1584171471Skmacy t3_seeprom_read(adap, TP_SRAM_OFFSET, &version); 1585171471Skmacy 1586171471Skmacy major = G_TP_VERSION_MAJOR(version); 1587171471Skmacy minor = G_TP_VERSION_MINOR(version); 1588171471Skmacy if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) 1589171471Skmacy return; 1590171471Skmacy 1591171471Skmacy rev = t3rev2char(adap); 1592189643Sgnn snprintf(name, sizeof(name), TPEEPROM_NAME, rev); 1593171471Skmacy 1594189643Sgnn tpeeprom = firmware_get(name); 1595171471Skmacy if (tpeeprom == NULL) { 1596190330Sgnn device_printf(adap->dev, 1597190330Sgnn "could not load TP EEPROM: unable to load %s\n", 1598190330Sgnn name); 1599171471Skmacy return; 1600171471Skmacy } 1601171471Skmacy 1602171471Skmacy len = tpeeprom->datasize - 4; 1603171471Skmacy 1604171471Skmacy ret = t3_check_tpsram(adap, tpeeprom->data, tpeeprom->datasize); 1605171471Skmacy if (ret) 1606171471Skmacy goto release_tpeeprom; 1607171471Skmacy 1608171471Skmacy if (len != TP_SRAM_LEN) { 1609190330Sgnn device_printf(adap->dev, 1610190330Sgnn "%s length is wrong len=%d expected=%d\n", name, 1611190330Sgnn len, TP_SRAM_LEN); 1612171471Skmacy return; 1613171471Skmacy } 1614171471Skmacy 1615171471Skmacy ret = set_eeprom(&adap->port[0], tpeeprom->data, tpeeprom->datasize, 1616171471Skmacy TP_SRAM_OFFSET); 1617171471Skmacy 1618171471Skmacy if (!ret) { 1619171471Skmacy device_printf(adap->dev, 1620171471Skmacy "Protocol SRAM image updated in EEPROM to %d.%d.%d\n", 1621171471Skmacy TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); 1622171471Skmacy } else 1623190330Sgnn device_printf(adap->dev, 1624190330Sgnn "Protocol SRAM image update in EEPROM failed\n"); 1625171471Skmacy 1626171471Skmacyrelease_tpeeprom: 1627171471Skmacy firmware_put(tpeeprom, FIRMWARE_UNLOAD); 1628171471Skmacy 1629171471Skmacy return; 1630171471Skmacy} 1631171471Skmacy 1632171471Skmacystatic int 1633171471Skmacyupdate_tpsram(struct adapter *adap) 1634171471Skmacy{ 1635172109Skmacy#ifdef FIRMWARE_LATEST 1636171471Skmacy const struct firmware *tpsram; 1637172109Skmacy#else 1638172109Skmacy struct firmware *tpsram; 1639172109Skmacy#endif 1640171471Skmacy int ret; 1641189643Sgnn char rev, name[32]; 1642171471Skmacy 1643171471Skmacy rev = t3rev2char(adap); 1644189643Sgnn snprintf(name, sizeof(name), TPSRAM_NAME, rev); 1645171471Skmacy 1646171471Skmacy update_tpeeprom(adap); 1647171471Skmacy 1648189643Sgnn tpsram = firmware_get(name); 1649171471Skmacy if (tpsram == NULL){ 1650176613Skmacy device_printf(adap->dev, "could not load TP SRAM\n"); 1651171471Skmacy return (EINVAL); 1652171471Skmacy } else 1653176613Skmacy device_printf(adap->dev, "updating TP SRAM\n"); 1654171471Skmacy 1655171471Skmacy ret = t3_check_tpsram(adap, tpsram->data, tpsram->datasize); 1656171471Skmacy if (ret) 1657171471Skmacy goto release_tpsram; 1658171471Skmacy 1659171471Skmacy ret = t3_set_proto_sram(adap, tpsram->data); 1660171471Skmacy if (ret) 1661171471Skmacy device_printf(adap->dev, "loading protocol SRAM failed\n"); 1662171471Skmacy 1663171471Skmacyrelease_tpsram: 1664171471Skmacy firmware_put(tpsram, FIRMWARE_UNLOAD); 1665171471Skmacy 1666171471Skmacy return ret; 1667171471Skmacy} 1668171471Skmacy 1669169978Skmacy/** 1670169978Skmacy * cxgb_up - enable the adapter 1671169978Skmacy * @adap: adapter being enabled 1672169978Skmacy * 1673169978Skmacy * Called when the first port is enabled, this function performs the 1674169978Skmacy * actions necessary to make an adapter operational, such as completing 1675169978Skmacy * the initialization of HW modules, and enabling interrupts. 1676169978Skmacy */ 1677169978Skmacystatic int 1678169978Skmacycxgb_up(struct adapter *sc) 1679169978Skmacy{ 1680169978Skmacy int err = 0; 1681169978Skmacy 1682169978Skmacy if ((sc->flags & FULL_INIT_DONE) == 0) { 1683169978Skmacy 1684169978Skmacy if ((sc->flags & FW_UPTODATE) == 0) 1685171471Skmacy if ((err = upgrade_fw(sc))) 1686171471Skmacy goto out; 1687171471Skmacy if ((sc->flags & TPS_UPTODATE) == 0) 1688171471Skmacy if ((err = update_tpsram(sc))) 1689171471Skmacy goto out; 1690169978Skmacy err = t3_init_hw(sc, 0); 1691169978Skmacy if (err) 1692169978Skmacy goto out; 1693169978Skmacy 1694176472Skmacy t3_set_reg_field(sc, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT); 1695169978Skmacy t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12)); 1696169978Skmacy 1697169978Skmacy err = setup_sge_qsets(sc); 1698169978Skmacy if (err) 1699169978Skmacy goto out; 1700169978Skmacy 1701169978Skmacy setup_rss(sc); 1702174708Skmacy t3_add_configured_sysctls(sc); 1703169978Skmacy sc->flags |= FULL_INIT_DONE; 1704169978Skmacy } 1705169978Skmacy 1706169978Skmacy t3_intr_clear(sc); 1707169978Skmacy 1708169978Skmacy /* If it's MSI or INTx, allocate a single interrupt for everything */ 1709169978Skmacy if ((sc->flags & USING_MSIX) == 0) { 1710169978Skmacy if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 1711169978Skmacy &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 1712171978Skmacy device_printf(sc->dev, "Cannot allocate interrupt rid=%d\n", 1713171978Skmacy sc->irq_rid); 1714169978Skmacy err = EINVAL; 1715169978Skmacy goto out; 1716169978Skmacy } 1717169978Skmacy device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res); 1718169978Skmacy 1719169978Skmacy if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET, 1720169978Skmacy#ifdef INTR_FILTERS 1721169978Skmacy NULL, 1722169978Skmacy#endif 1723169978Skmacy sc->cxgb_intr, sc, &sc->intr_tag)) { 1724169978Skmacy device_printf(sc->dev, "Cannot set up interrupt\n"); 1725169978Skmacy err = EINVAL; 1726169978Skmacy goto irq_err; 1727169978Skmacy } 1728169978Skmacy } else { 1729169978Skmacy cxgb_setup_msix(sc, sc->msi_count); 1730169978Skmacy } 1731169978Skmacy 1732169978Skmacy t3_sge_start(sc); 1733169978Skmacy t3_intr_enable(sc); 1734169978Skmacy 1735176472Skmacy if (sc->params.rev >= T3_REV_C && !(sc->flags & TP_PARITY_INIT) && 1736176472Skmacy is_offload(sc) && init_tp_parity(sc) == 0) 1737176472Skmacy sc->flags |= TP_PARITY_INIT; 1738176472Skmacy 1739176472Skmacy if (sc->flags & TP_PARITY_INIT) { 1740176472Skmacy t3_write_reg(sc, A_TP_INT_CAUSE, 1741176472Skmacy F_CMCACHEPERR | F_ARPLUTPERR); 1742176472Skmacy t3_write_reg(sc, A_TP_INT_ENABLE, 0x7fbfffff); 1743176472Skmacy } 1744176472Skmacy 1745176472Skmacy 1746172096Skmacy if (!(sc->flags & QUEUES_BOUND)) { 1747169978Skmacy bind_qsets(sc); 1748171471Skmacy sc->flags |= QUEUES_BOUND; 1749171471Skmacy } 1750169978Skmacyout: 1751169978Skmacy return (err); 1752169978Skmacyirq_err: 1753169978Skmacy CH_ERR(sc, "request_irq failed, err %d\n", err); 1754169978Skmacy goto out; 1755169978Skmacy} 1756169978Skmacy 1757169978Skmacy 1758169978Skmacy/* 1759169978Skmacy * Release resources when all the ports and offloading have been stopped. 1760169978Skmacy */ 1761167514Skmacystatic void 1762170869Skmacycxgb_down_locked(struct adapter *sc) 1763169978Skmacy{ 1764170654Skmacy 1765169978Skmacy t3_sge_stop(sc); 1766169978Skmacy t3_intr_disable(sc); 1767189643Sgnn 1768169978Skmacy if (sc->intr_tag != NULL) { 1769169978Skmacy bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag); 1770169978Skmacy sc->intr_tag = NULL; 1771169978Skmacy } 1772169978Skmacy if (sc->irq_res != NULL) { 1773169978Skmacy device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n", 1774169978Skmacy sc->irq_rid, sc->irq_res); 1775169978Skmacy bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid, 1776169978Skmacy sc->irq_res); 1777169978Skmacy sc->irq_res = NULL; 1778169978Skmacy } 1779170654Skmacy 1780176472Skmacy if (sc->flags & USING_MSIX) 1781170654Skmacy cxgb_teardown_msix(sc); 1782176472Skmacy 1783174708Skmacy callout_stop(&sc->cxgb_tick_ch); 1784174708Skmacy callout_stop(&sc->sge_timer_ch); 1785170869Skmacy callout_drain(&sc->cxgb_tick_ch); 1786169978Skmacy callout_drain(&sc->sge_timer_ch); 1787170869Skmacy 1788171978Skmacy if (sc->tq != NULL) { 1789176472Skmacy printf("draining slow intr\n"); 1790176472Skmacy 1791170654Skmacy taskqueue_drain(sc->tq, &sc->slow_intr_task); 1792176472Skmacy printf("draining ext intr\n"); 1793176472Skmacy taskqueue_drain(sc->tq, &sc->ext_intr_task); 1794176472Skmacy printf("draining tick task\n"); 1795176472Skmacy taskqueue_drain(sc->tq, &sc->tick_task); 1796171978Skmacy } 1797176472Skmacy ADAPTER_UNLOCK(sc); 1798169978Skmacy} 1799169978Skmacy 1800169978Skmacystatic int 1801169978Skmacyoffload_open(struct port_info *pi) 1802169978Skmacy{ 1803169978Skmacy struct adapter *adapter = pi->adapter; 1804174708Skmacy struct t3cdev *tdev = &adapter->tdev; 1805183059Skmacy 1806169978Skmacy int adap_up = adapter->open_device_map & PORT_MASK; 1807169978Skmacy int err = 0; 1808169978Skmacy 1809169978Skmacy if (atomic_cmpset_int(&adapter->open_device_map, 1810174708Skmacy (adapter->open_device_map & ~(1<<OFFLOAD_DEVMAP_BIT)), 1811174708Skmacy (adapter->open_device_map | (1<<OFFLOAD_DEVMAP_BIT))) == 0) 1812169978Skmacy return (0); 1813169978Skmacy 1814174708Skmacy if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT)) 1815183059Skmacy printf("offload_open: DEVMAP_BIT did not get set 0x%x\n", 1816183059Skmacy adapter->open_device_map); 1817169978Skmacy ADAPTER_LOCK(pi->adapter); 1818169978Skmacy if (!adap_up) 1819169978Skmacy err = cxgb_up(adapter); 1820169978Skmacy ADAPTER_UNLOCK(pi->adapter); 1821171471Skmacy if (err) 1822169978Skmacy return (err); 1823169978Skmacy 1824169978Skmacy t3_tp_set_offload_mode(adapter, 1); 1825174708Skmacy tdev->lldev = pi->ifp; 1826169978Skmacy 1827169978Skmacy init_port_mtus(adapter); 1828169978Skmacy t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd, 1829169978Skmacy adapter->params.b_wnd, 1830169978Skmacy adapter->params.rev == 0 ? 1831169978Skmacy adapter->port[0].ifp->if_mtu : 0xffff); 1832169978Skmacy init_smt(adapter); 1833178767Skmacy /* Call back all registered clients */ 1834178767Skmacy cxgb_add_clients(tdev); 1835178767Skmacy 1836169978Skmacy /* restore them in case the offload module has changed them */ 1837169978Skmacy if (err) { 1838169978Skmacy t3_tp_set_offload_mode(adapter, 0); 1839169978Skmacy clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT); 1840169978Skmacy cxgb_set_dummy_ops(tdev); 1841169978Skmacy } 1842169978Skmacy return (err); 1843169978Skmacy} 1844174708Skmacy 1845169978Skmacystatic int 1846174708Skmacyoffload_close(struct t3cdev *tdev) 1847169978Skmacy{ 1848169978Skmacy struct adapter *adapter = tdev2adap(tdev); 1849169978Skmacy 1850176472Skmacy if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT)) 1851170654Skmacy return (0); 1852178767Skmacy 1853178767Skmacy /* Call back all registered clients */ 1854178767Skmacy cxgb_remove_clients(tdev); 1855178767Skmacy 1856169978Skmacy tdev->lldev = NULL; 1857169978Skmacy cxgb_set_dummy_ops(tdev); 1858169978Skmacy t3_tp_set_offload_mode(adapter, 0); 1859169978Skmacy clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT); 1860169978Skmacy 1861174708Skmacy ADAPTER_LOCK(adapter); 1862169978Skmacy if (!adapter->open_device_map) 1863174708Skmacy cxgb_down_locked(adapter); 1864174708Skmacy else 1865174708Skmacy ADAPTER_UNLOCK(adapter); 1866170654Skmacy return (0); 1867169978Skmacy} 1868169978Skmacy 1869174708Skmacy 1870169978Skmacystatic void 1871167514Skmacycxgb_init(void *arg) 1872167514Skmacy{ 1873167514Skmacy struct port_info *p = arg; 1874167514Skmacy 1875167514Skmacy PORT_LOCK(p); 1876167514Skmacy cxgb_init_locked(p); 1877167514Skmacy PORT_UNLOCK(p); 1878167514Skmacy} 1879167514Skmacy 1880167514Skmacystatic void 1881167514Skmacycxgb_init_locked(struct port_info *p) 1882167514Skmacy{ 1883167514Skmacy struct ifnet *ifp; 1884167514Skmacy adapter_t *sc = p->adapter; 1885169978Skmacy int err; 1886167514Skmacy 1887170869Skmacy PORT_LOCK_ASSERT_OWNED(p); 1888167514Skmacy ifp = p->ifp; 1889167514Skmacy 1890167514Skmacy ADAPTER_LOCK(p->adapter); 1891171471Skmacy if ((sc->open_device_map == 0) && (err = cxgb_up(sc))) { 1892169978Skmacy ADAPTER_UNLOCK(p->adapter); 1893169978Skmacy cxgb_stop_locked(p); 1894169978Skmacy return; 1895169978Skmacy } 1896170869Skmacy if (p->adapter->open_device_map == 0) { 1897167514Skmacy t3_intr_clear(sc); 1898170869Skmacy } 1899171803Skmacy setbit(&p->adapter->open_device_map, p->port_id); 1900170654Skmacy ADAPTER_UNLOCK(p->adapter); 1901169978Skmacy 1902169978Skmacy if (is_offload(sc) && !ofld_disable) { 1903169978Skmacy err = offload_open(p); 1904169978Skmacy if (err) 1905169978Skmacy log(LOG_WARNING, 1906169978Skmacy "Could not initialize offload capabilities\n"); 1907169978Skmacy } 1908177415Skmacy#if !defined(LINK_ATTACH) 1909177415Skmacy cxgb_link_start(p); 1910177415Skmacy t3_link_changed(sc, p->port_id); 1911177415Skmacy#endif 1912186282Sgnn ifp->if_baudrate = IF_Mbps(p->link_config.speed); 1913171978Skmacy 1914172096Skmacy device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id); 1915171803Skmacy t3_port_intr_enable(sc, p->port_id); 1916167760Skmacy 1917190206Sgnn callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc); 1918175224Skmacy t3_sge_reset_adapter(sc); 1919170869Skmacy 1920167514Skmacy ifp->if_drv_flags |= IFF_DRV_RUNNING; 1921167514Skmacy ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1922167514Skmacy} 1923167514Skmacy 1924167514Skmacystatic void 1925167514Skmacycxgb_set_rxmode(struct port_info *p) 1926167514Skmacy{ 1927167514Skmacy struct t3_rx_mode rm; 1928167514Skmacy struct cmac *mac = &p->mac; 1929167760Skmacy 1930167514Skmacy t3_init_rx_mode(&rm, p); 1931176472Skmacy mtx_lock(&p->adapter->mdio_lock); 1932167514Skmacy t3_mac_set_rx_mode(mac, &rm); 1933176472Skmacy mtx_unlock(&p->adapter->mdio_lock); 1934167514Skmacy} 1935167514Skmacy 1936167514Skmacystatic void 1937177340Skmacycxgb_stop_locked(struct port_info *pi) 1938167514Skmacy{ 1939167514Skmacy struct ifnet *ifp; 1940167514Skmacy 1941177340Skmacy PORT_LOCK_ASSERT_OWNED(pi); 1942177340Skmacy ADAPTER_LOCK_ASSERT_NOTOWNED(pi->adapter); 1943170654Skmacy 1944177340Skmacy ifp = pi->ifp; 1945177340Skmacy t3_port_intr_disable(pi->adapter, pi->port_id); 1946169978Skmacy ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1947169978Skmacy 1948177340Skmacy /* disable pause frames */ 1949177340Skmacy t3_set_reg_field(pi->adapter, A_XGM_TX_CFG + pi->mac.offset, 1950177340Skmacy F_TXPAUSEEN, 0); 1951170869Skmacy 1952177340Skmacy /* Reset RX FIFO HWM */ 1953177340Skmacy t3_set_reg_field(pi->adapter, A_XGM_RXFIFO_CFG + pi->mac.offset, 1954177340Skmacy V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM), 0); 1955177340Skmacy 1956177340Skmacy 1957177340Skmacy ADAPTER_LOCK(pi->adapter); 1958177340Skmacy clrbit(&pi->adapter->open_device_map, pi->port_id); 1959177340Skmacy 1960177340Skmacy if (pi->adapter->open_device_map == 0) { 1961177340Skmacy cxgb_down_locked(pi->adapter); 1962170869Skmacy } else 1963177340Skmacy ADAPTER_UNLOCK(pi->adapter); 1964170869Skmacy 1965177415Skmacy#if !defined(LINK_ATTACH) 1966177340Skmacy DELAY(100); 1967177340Skmacy 1968177340Skmacy /* Wait for TXFIFO empty */ 1969177340Skmacy t3_wait_op_done(pi->adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 1970177340Skmacy F_TXFIFO_EMPTY, 1, 20, 5); 1971177340Skmacy 1972177340Skmacy DELAY(100); 1973177340Skmacy t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); 1974177340Skmacy 1975177340Skmacy pi->phy.ops->power_down(&pi->phy, 1); 1976177415Skmacy#endif 1977177340Skmacy 1978167514Skmacy} 1979167514Skmacy 1980167514Skmacystatic int 1981170654Skmacycxgb_set_mtu(struct port_info *p, int mtu) 1982170654Skmacy{ 1983170654Skmacy struct ifnet *ifp = p->ifp; 1984170654Skmacy int error = 0; 1985170654Skmacy 1986180583Skmacy if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) 1987170654Skmacy error = EINVAL; 1988170654Skmacy else if (ifp->if_mtu != mtu) { 1989170654Skmacy PORT_LOCK(p); 1990170654Skmacy ifp->if_mtu = mtu; 1991170654Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1992170654Skmacy cxgb_stop_locked(p); 1993170654Skmacy cxgb_init_locked(p); 1994170654Skmacy } 1995170654Skmacy PORT_UNLOCK(p); 1996170654Skmacy } 1997170654Skmacy return (error); 1998170654Skmacy} 1999170654Skmacy 2000183289Skmacy#ifdef LRO_SUPPORTED 2001181616Skmacy/* 2002181616Skmacy * Mark lro enabled or disabled in all qsets for this port 2003181616Skmacy */ 2004170654Skmacystatic int 2005181616Skmacycxgb_set_lro(struct port_info *p, int enabled) 2006181616Skmacy{ 2007181616Skmacy int i; 2008181616Skmacy struct adapter *adp = p->adapter; 2009181616Skmacy struct sge_qset *q; 2010181616Skmacy 2011181616Skmacy PORT_LOCK_ASSERT_OWNED(p); 2012181616Skmacy for (i = 0; i < p->nqsets; i++) { 2013181616Skmacy q = &adp->sge.qs[p->first_qset + i]; 2014181616Skmacy q->lro.enabled = (enabled != 0); 2015181616Skmacy } 2016181616Skmacy return (0); 2017181616Skmacy} 2018183289Skmacy#endif 2019181616Skmacy 2020181616Skmacystatic int 2021167514Skmacycxgb_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data) 2022167514Skmacy{ 2023167514Skmacy struct port_info *p = ifp->if_softc; 2024184714Sbz#ifdef INET 2025167514Skmacy struct ifaddr *ifa = (struct ifaddr *)data; 2026184714Sbz#endif 2027167514Skmacy struct ifreq *ifr = (struct ifreq *)data; 2028180583Skmacy int flags, error = 0, reinit = 0; 2029167514Skmacy uint32_t mask; 2030167514Skmacy 2031168737Skmacy /* 2032168737Skmacy * XXX need to check that we aren't in the middle of an unload 2033168737Skmacy */ 2034167514Skmacy switch (command) { 2035167514Skmacy case SIOCSIFMTU: 2036170654Skmacy error = cxgb_set_mtu(p, ifr->ifr_mtu); 2037167514Skmacy break; 2038167514Skmacy case SIOCSIFADDR: 2039184714Sbz#ifdef INET 2040167514Skmacy if (ifa->ifa_addr->sa_family == AF_INET) { 2041167514Skmacy ifp->if_flags |= IFF_UP; 2042176472Skmacy if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2043176472Skmacy PORT_LOCK(p); 2044170654Skmacy cxgb_init_locked(p); 2045176472Skmacy PORT_UNLOCK(p); 2046176472Skmacy } 2047167514Skmacy arp_ifinit(ifp, ifa); 2048167514Skmacy } else 2049184714Sbz#endif 2050167514Skmacy error = ether_ioctl(ifp, command, data); 2051167514Skmacy break; 2052167514Skmacy case SIOCSIFFLAGS: 2053170869Skmacy PORT_LOCK(p); 2054167514Skmacy if (ifp->if_flags & IFF_UP) { 2055167514Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2056167514Skmacy flags = p->if_flags; 2057167514Skmacy if (((ifp->if_flags ^ flags) & IFF_PROMISC) || 2058167514Skmacy ((ifp->if_flags ^ flags) & IFF_ALLMULTI)) 2059167514Skmacy cxgb_set_rxmode(p); 2060167514Skmacy } else 2061167514Skmacy cxgb_init_locked(p); 2062167760Skmacy p->if_flags = ifp->if_flags; 2063170869Skmacy } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2064170869Skmacy cxgb_stop_locked(p); 2065170869Skmacy 2066176472Skmacy PORT_UNLOCK(p); 2067176472Skmacy break; 2068176472Skmacy case SIOCADDMULTI: 2069176472Skmacy case SIOCDELMULTI: 2070170869Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2071176472Skmacy cxgb_set_rxmode(p); 2072167514Skmacy } 2073167514Skmacy break; 2074167514Skmacy case SIOCSIFMEDIA: 2075167514Skmacy case SIOCGIFMEDIA: 2076186282Sgnn PORT_LOCK(p); 2077167514Skmacy error = ifmedia_ioctl(ifp, ifr, &p->media, command); 2078186282Sgnn PORT_UNLOCK(p); 2079167514Skmacy break; 2080167514Skmacy case SIOCSIFCAP: 2081167514Skmacy PORT_LOCK(p); 2082167514Skmacy mask = ifr->ifr_reqcap ^ ifp->if_capenable; 2083167514Skmacy if (mask & IFCAP_TXCSUM) { 2084167514Skmacy if (IFCAP_TXCSUM & ifp->if_capenable) { 2085167514Skmacy ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 2086167514Skmacy ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 2087180583Skmacy | CSUM_IP | CSUM_TSO); 2088167514Skmacy } else { 2089167514Skmacy ifp->if_capenable |= IFCAP_TXCSUM; 2090180583Skmacy ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP 2091180583Skmacy | CSUM_IP); 2092167514Skmacy } 2093167514Skmacy } 2094180583Skmacy if (mask & IFCAP_RXCSUM) { 2095180583Skmacy ifp->if_capenable ^= IFCAP_RXCSUM; 2096180583Skmacy } 2097167514Skmacy if (mask & IFCAP_TSO4) { 2098167514Skmacy if (IFCAP_TSO4 & ifp->if_capenable) { 2099167514Skmacy ifp->if_capenable &= ~IFCAP_TSO4; 2100167514Skmacy ifp->if_hwassist &= ~CSUM_TSO; 2101167514Skmacy } else if (IFCAP_TXCSUM & ifp->if_capenable) { 2102167514Skmacy ifp->if_capenable |= IFCAP_TSO4; 2103167514Skmacy ifp->if_hwassist |= CSUM_TSO; 2104167514Skmacy } else { 2105167514Skmacy if (cxgb_debug) 2106167514Skmacy printf("cxgb requires tx checksum offload" 2107167514Skmacy " be enabled to use TSO\n"); 2108167514Skmacy error = EINVAL; 2109167514Skmacy } 2110167514Skmacy } 2111183289Skmacy#ifdef LRO_SUPPORTED 2112181616Skmacy if (mask & IFCAP_LRO) { 2113181616Skmacy ifp->if_capenable ^= IFCAP_LRO; 2114181616Skmacy 2115181616Skmacy /* Safe to do this even if cxgb_up not called yet */ 2116181616Skmacy cxgb_set_lro(p, ifp->if_capenable & IFCAP_LRO); 2117181616Skmacy } 2118183289Skmacy#endif 2119180583Skmacy if (mask & IFCAP_VLAN_HWTAGGING) { 2120180583Skmacy ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 2121180583Skmacy reinit = ifp->if_drv_flags & IFF_DRV_RUNNING; 2122180583Skmacy } 2123180583Skmacy if (mask & IFCAP_VLAN_MTU) { 2124180583Skmacy ifp->if_capenable ^= IFCAP_VLAN_MTU; 2125180583Skmacy reinit = ifp->if_drv_flags & IFF_DRV_RUNNING; 2126180583Skmacy } 2127180583Skmacy if (mask & IFCAP_VLAN_HWCSUM) { 2128180583Skmacy ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 2129180583Skmacy } 2130180583Skmacy if (reinit) { 2131180583Skmacy cxgb_stop_locked(p); 2132180583Skmacy cxgb_init_locked(p); 2133180583Skmacy } 2134167514Skmacy PORT_UNLOCK(p); 2135180583Skmacy 2136180583Skmacy#ifdef VLAN_CAPABILITIES 2137180583Skmacy VLAN_CAPABILITIES(ifp); 2138180583Skmacy#endif 2139167514Skmacy break; 2140167514Skmacy default: 2141167514Skmacy error = ether_ioctl(ifp, command, data); 2142167514Skmacy break; 2143167514Skmacy } 2144167514Skmacy return (error); 2145167514Skmacy} 2146167514Skmacy 2147174708Skmacystatic int 2148167514Skmacycxgb_media_change(struct ifnet *ifp) 2149167514Skmacy{ 2150167514Skmacy if_printf(ifp, "media change not supported\n"); 2151167514Skmacy return (ENXIO); 2152167514Skmacy} 2153167514Skmacy 2154186282Sgnn/* 2155186282Sgnn * Translates from phy->modtype to IFM_TYPE. 2156186282Sgnn */ 2157186282Sgnnstatic int 2158186282Sgnncxgb_ifm_type(int phymod) 2159186282Sgnn{ 2160186282Sgnn int rc = IFM_ETHER | IFM_FDX; 2161186282Sgnn 2162186282Sgnn switch (phymod) { 2163186282Sgnn case phy_modtype_sr: 2164186282Sgnn rc |= IFM_10G_SR; 2165186282Sgnn break; 2166186282Sgnn case phy_modtype_lr: 2167186282Sgnn rc |= IFM_10G_LR; 2168186282Sgnn break; 2169186282Sgnn case phy_modtype_lrm: 2170186282Sgnn#ifdef IFM_10G_LRM 2171186282Sgnn rc |= IFM_10G_LRM; 2172186282Sgnn#endif 2173186282Sgnn break; 2174186282Sgnn case phy_modtype_twinax: 2175186282Sgnn#ifdef IFM_10G_TWINAX 2176186282Sgnn rc |= IFM_10G_TWINAX; 2177186282Sgnn#endif 2178186282Sgnn break; 2179186282Sgnn case phy_modtype_twinax_long: 2180186282Sgnn#ifdef IFM_10G_TWINAX_LONG 2181186282Sgnn rc |= IFM_10G_TWINAX_LONG; 2182186282Sgnn#endif 2183186282Sgnn break; 2184186282Sgnn case phy_modtype_none: 2185186282Sgnn rc = IFM_ETHER | IFM_NONE; 2186186282Sgnn break; 2187186282Sgnn case phy_modtype_unknown: 2188186282Sgnn break; 2189186282Sgnn } 2190186282Sgnn 2191186282Sgnn return (rc); 2192186282Sgnn} 2193186282Sgnn 2194167514Skmacystatic void 2195167514Skmacycxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 2196167514Skmacy{ 2197167514Skmacy struct port_info *p = ifp->if_softc; 2198186282Sgnn struct ifmedia_entry *cur = p->media.ifm_cur; 2199186282Sgnn int m; 2200167514Skmacy 2201186282Sgnn if (cur->ifm_data != p->phy.modtype) { 2202186282Sgnn /* p->media about to be rebuilt, must hold lock */ 2203186282Sgnn PORT_LOCK_ASSERT_OWNED(p); 2204186282Sgnn 2205186282Sgnn m = cxgb_ifm_type(p->phy.modtype); 2206186282Sgnn ifmedia_removeall(&p->media); 2207186282Sgnn ifmedia_add(&p->media, m, p->phy.modtype, NULL); 2208186282Sgnn ifmedia_set(&p->media, m); 2209186282Sgnn cur = p->media.ifm_cur; /* ifmedia_set modified ifm_cur */ 2210186282Sgnn ifmr->ifm_current = m; 2211186282Sgnn } 2212186282Sgnn 2213167514Skmacy ifmr->ifm_status = IFM_AVALID; 2214167514Skmacy ifmr->ifm_active = IFM_ETHER; 2215167514Skmacy 2216167514Skmacy if (!p->link_config.link_ok) 2217167514Skmacy return; 2218167514Skmacy 2219167514Skmacy ifmr->ifm_status |= IFM_ACTIVE; 2220167514Skmacy 2221170654Skmacy switch (p->link_config.speed) { 2222170654Skmacy case 10: 2223170654Skmacy ifmr->ifm_active |= IFM_10_T; 2224170654Skmacy break; 2225170654Skmacy case 100: 2226170654Skmacy ifmr->ifm_active |= IFM_100_TX; 2227170654Skmacy break; 2228170654Skmacy case 1000: 2229170654Skmacy ifmr->ifm_active |= IFM_1000_T; 2230170654Skmacy break; 2231186282Sgnn case 10000: 2232186282Sgnn ifmr->ifm_active |= IFM_SUBTYPE(cur->ifm_media); 2233186282Sgnn break; 2234170654Skmacy } 2235170654Skmacy 2236167514Skmacy if (p->link_config.duplex) 2237167514Skmacy ifmr->ifm_active |= IFM_FDX; 2238167514Skmacy else 2239167514Skmacy ifmr->ifm_active |= IFM_HDX; 2240167514Skmacy} 2241167514Skmacy 2242167514Skmacystatic void 2243167514Skmacycxgb_async_intr(void *data) 2244167514Skmacy{ 2245167760Skmacy adapter_t *sc = data; 2246167760Skmacy 2247167514Skmacy if (cxgb_debug) 2248167760Skmacy device_printf(sc->dev, "cxgb_async_intr\n"); 2249170869Skmacy /* 2250170869Skmacy * May need to sleep - defer to taskqueue 2251170869Skmacy */ 2252170869Skmacy taskqueue_enqueue(sc->tq, &sc->slow_intr_task); 2253167514Skmacy} 2254167514Skmacy 2255167514Skmacystatic void 2256167514Skmacycxgb_ext_intr_handler(void *arg, int count) 2257167514Skmacy{ 2258167514Skmacy adapter_t *sc = (adapter_t *)arg; 2259167514Skmacy 2260167514Skmacy if (cxgb_debug) 2261167514Skmacy printf("cxgb_ext_intr_handler\n"); 2262167514Skmacy 2263167514Skmacy t3_phy_intr_handler(sc); 2264167514Skmacy 2265167514Skmacy /* Now reenable external interrupts */ 2266169978Skmacy ADAPTER_LOCK(sc); 2267167514Skmacy if (sc->slow_intr_mask) { 2268167514Skmacy sc->slow_intr_mask |= F_T3DBG; 2269167514Skmacy t3_write_reg(sc, A_PL_INT_CAUSE0, F_T3DBG); 2270167514Skmacy t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask); 2271167514Skmacy } 2272169978Skmacy ADAPTER_UNLOCK(sc); 2273167514Skmacy} 2274167514Skmacy 2275167514Skmacystatic void 2276167746Skmacycheck_link_status(adapter_t *sc) 2277167514Skmacy{ 2278167746Skmacy int i; 2279167514Skmacy 2280167746Skmacy for (i = 0; i < (sc)->params.nports; ++i) { 2281167746Skmacy struct port_info *p = &sc->port[i]; 2282167514Skmacy 2283176472Skmacy if (!(p->phy.caps & SUPPORTED_IRQ)) 2284167746Skmacy t3_link_changed(sc, i); 2285186282Sgnn p->ifp->if_baudrate = IF_Mbps(p->link_config.speed); 2286167746Skmacy } 2287167514Skmacy} 2288167514Skmacy 2289167514Skmacystatic void 2290167746Skmacycheck_t3b2_mac(struct adapter *adapter) 2291167514Skmacy{ 2292167514Skmacy int i; 2293167514Skmacy 2294176472Skmacy if(adapter->flags & CXGB_SHUTDOWN) 2295176472Skmacy return; 2296176472Skmacy 2297167746Skmacy for_each_port(adapter, i) { 2298167746Skmacy struct port_info *p = &adapter->port[i]; 2299167746Skmacy struct ifnet *ifp = p->ifp; 2300167746Skmacy int status; 2301176472Skmacy 2302176472Skmacy if(adapter->flags & CXGB_SHUTDOWN) 2303176472Skmacy return; 2304176472Skmacy 2305167746Skmacy if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 2306167746Skmacy continue; 2307167746Skmacy 2308167746Skmacy status = 0; 2309167746Skmacy PORT_LOCK(p); 2310167746Skmacy if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) 2311167746Skmacy status = t3b2_mac_watchdog_task(&p->mac); 2312167746Skmacy if (status == 1) 2313167746Skmacy p->mac.stats.num_toggled++; 2314167746Skmacy else if (status == 2) { 2315167746Skmacy struct cmac *mac = &p->mac; 2316180583Skmacy int mtu = ifp->if_mtu; 2317167746Skmacy 2318180583Skmacy if (ifp->if_capenable & IFCAP_VLAN_MTU) 2319180583Skmacy mtu += ETHER_VLAN_ENCAP_LEN; 2320180583Skmacy t3_mac_set_mtu(mac, mtu); 2321167746Skmacy t3_mac_set_address(mac, 0, p->hw_addr); 2322167746Skmacy cxgb_set_rxmode(p); 2323167746Skmacy t3_link_start(&p->phy, mac, &p->link_config); 2324167746Skmacy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 2325171803Skmacy t3_port_intr_enable(adapter, p->port_id); 2326167746Skmacy p->mac.stats.num_resets++; 2327167746Skmacy } 2328167746Skmacy PORT_UNLOCK(p); 2329167514Skmacy } 2330167514Skmacy} 2331167514Skmacy 2332167746Skmacystatic void 2333167746Skmacycxgb_tick(void *arg) 2334167746Skmacy{ 2335167746Skmacy adapter_t *sc = (adapter_t *)arg; 2336170869Skmacy 2337176472Skmacy if(sc->flags & CXGB_SHUTDOWN) 2338176472Skmacy return; 2339174708Skmacy 2340185508Skmacy taskqueue_enqueue(sc->tq, &sc->tick_task); 2341181652Skmacy callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc); 2342170869Skmacy} 2343170869Skmacy 2344170869Skmacystatic void 2345170869Skmacycxgb_tick_handler(void *arg, int count) 2346170869Skmacy{ 2347170869Skmacy adapter_t *sc = (adapter_t *)arg; 2348167746Skmacy const struct adapter_params *p = &sc->params; 2349181652Skmacy int i; 2350189643Sgnn uint32_t cause, reset; 2351167746Skmacy 2352176472Skmacy if(sc->flags & CXGB_SHUTDOWN) 2353176472Skmacy return; 2354176472Skmacy 2355170869Skmacy ADAPTER_LOCK(sc); 2356167746Skmacy if (p->linkpoll_period) 2357167746Skmacy check_link_status(sc); 2358167746Skmacy 2359185508Skmacy sc->check_task_cnt++; 2360185508Skmacy 2361185508Skmacy /* 2362185508Skmacy * adapter lock can currently only be acquired after the 2363185508Skmacy * port lock 2364185508Skmacy */ 2365185508Skmacy ADAPTER_UNLOCK(sc); 2366185508Skmacy 2367185508Skmacy if (p->rev == T3_REV_B2 && p->nports < 4 && sc->open_device_map) 2368185508Skmacy check_t3b2_mac(sc); 2369185508Skmacy 2370189643Sgnn cause = t3_read_reg(sc, A_SG_INT_CAUSE); 2371189643Sgnn reset = 0; 2372189643Sgnn if (cause & F_FLEMPTY) { 2373189643Sgnn struct sge_qset *qs = &sc->sge.qs[0]; 2374189643Sgnn 2375189643Sgnn i = 0; 2376189643Sgnn reset |= F_FLEMPTY; 2377189643Sgnn 2378189643Sgnn cause = (t3_read_reg(sc, A_SG_RSPQ_FL_STATUS) >> 2379189643Sgnn S_FL0EMPTY) & 0xffff; 2380189643Sgnn while (cause) { 2381189643Sgnn qs->fl[i].empty += (cause & 1); 2382189643Sgnn if (i) 2383189643Sgnn qs++; 2384189643Sgnn i ^= 1; 2385189643Sgnn cause >>= 1; 2386189643Sgnn } 2387189643Sgnn } 2388189643Sgnn t3_write_reg(sc, A_SG_INT_CAUSE, reset); 2389189643Sgnn 2390185506Skmacy for (i = 0; i < sc->params.nports; i++) { 2391185506Skmacy struct port_info *pi = &sc->port[i]; 2392185506Skmacy struct ifnet *ifp = pi->ifp; 2393189643Sgnn struct cmac *mac = &pi->mac; 2394189643Sgnn struct mac_stats *mstats = &mac->stats; 2395185508Skmacy PORT_LOCK(pi); 2396189643Sgnn t3_mac_update_stats(mac); 2397185508Skmacy PORT_UNLOCK(pi); 2398185508Skmacy 2399189643Sgnn if (pi->link_fault) 2400189643Sgnn taskqueue_enqueue(sc->tq, &pi->link_fault_task); 2401189643Sgnn 2402185506Skmacy ifp->if_opackets = 2403185506Skmacy mstats->tx_frames_64 + 2404185506Skmacy mstats->tx_frames_65_127 + 2405185506Skmacy mstats->tx_frames_128_255 + 2406185506Skmacy mstats->tx_frames_256_511 + 2407185506Skmacy mstats->tx_frames_512_1023 + 2408185506Skmacy mstats->tx_frames_1024_1518 + 2409185506Skmacy mstats->tx_frames_1519_max; 2410185506Skmacy 2411185506Skmacy ifp->if_ipackets = 2412185506Skmacy mstats->rx_frames_64 + 2413185506Skmacy mstats->rx_frames_65_127 + 2414185506Skmacy mstats->rx_frames_128_255 + 2415185506Skmacy mstats->rx_frames_256_511 + 2416185506Skmacy mstats->rx_frames_512_1023 + 2417185506Skmacy mstats->rx_frames_1024_1518 + 2418185506Skmacy mstats->rx_frames_1519_max; 2419185506Skmacy 2420185506Skmacy ifp->if_obytes = mstats->tx_octets; 2421185506Skmacy ifp->if_ibytes = mstats->rx_octets; 2422185506Skmacy ifp->if_omcasts = mstats->tx_mcast_frames; 2423185506Skmacy ifp->if_imcasts = mstats->rx_mcast_frames; 2424185506Skmacy 2425185506Skmacy ifp->if_collisions = 2426185506Skmacy mstats->tx_total_collisions; 2427185506Skmacy 2428185506Skmacy ifp->if_iqdrops = mstats->rx_cong_drops; 2429185506Skmacy 2430185506Skmacy ifp->if_oerrors = 2431185506Skmacy mstats->tx_excess_collisions + 2432185506Skmacy mstats->tx_underrun + 2433185506Skmacy mstats->tx_len_errs + 2434185506Skmacy mstats->tx_mac_internal_errs + 2435185506Skmacy mstats->tx_excess_deferral + 2436185506Skmacy mstats->tx_fcs_errs; 2437185506Skmacy ifp->if_ierrors = 2438185506Skmacy mstats->rx_jabber + 2439185506Skmacy mstats->rx_data_errs + 2440185506Skmacy mstats->rx_sequence_errs + 2441185506Skmacy mstats->rx_runt + 2442185506Skmacy mstats->rx_too_long + 2443185506Skmacy mstats->rx_mac_internal_errs + 2444185506Skmacy mstats->rx_short + 2445185506Skmacy mstats->rx_fcs_errs; 2446189643Sgnn 2447189643Sgnn if (mac->multiport) 2448189643Sgnn continue; 2449189643Sgnn 2450189643Sgnn /* Count rx fifo overflows, once per second */ 2451189643Sgnn cause = t3_read_reg(sc, A_XGM_INT_CAUSE + mac->offset); 2452189643Sgnn reset = 0; 2453189643Sgnn if (cause & F_RXFIFO_OVERFLOW) { 2454189643Sgnn mac->stats.rx_fifo_ovfl++; 2455189643Sgnn reset |= F_RXFIFO_OVERFLOW; 2456189643Sgnn } 2457189643Sgnn t3_write_reg(sc, A_XGM_INT_CAUSE + mac->offset, reset); 2458185506Skmacy } 2459167746Skmacy} 2460167746Skmacy 2461171978Skmacystatic void 2462171978Skmacytouch_bars(device_t dev) 2463171978Skmacy{ 2464171978Skmacy /* 2465171978Skmacy * Don't enable yet 2466171978Skmacy */ 2467171978Skmacy#if !defined(__LP64__) && 0 2468171978Skmacy u32 v; 2469171978Skmacy 2470171978Skmacy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &v); 2471171978Skmacy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, v); 2472171978Skmacy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3, &v); 2473171978Skmacy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_3, v); 2474171978Skmacy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &v); 2475171978Skmacy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_5, v); 2476171978Skmacy#endif 2477171978Skmacy} 2478171978Skmacy 2479167514Skmacystatic int 2480171471Skmacyset_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset) 2481171471Skmacy{ 2482171471Skmacy uint8_t *buf; 2483171471Skmacy int err = 0; 2484171471Skmacy u32 aligned_offset, aligned_len, *p; 2485171471Skmacy struct adapter *adapter = pi->adapter; 2486171471Skmacy 2487171471Skmacy 2488171471Skmacy aligned_offset = offset & ~3; 2489171471Skmacy aligned_len = (len + (offset & 3) + 3) & ~3; 2490171471Skmacy 2491171471Skmacy if (aligned_offset != offset || aligned_len != len) { 2492171471Skmacy buf = malloc(aligned_len, M_DEVBUF, M_WAITOK|M_ZERO); 2493171471Skmacy if (!buf) 2494171471Skmacy return (ENOMEM); 2495171471Skmacy err = t3_seeprom_read(adapter, aligned_offset, (u32 *)buf); 2496171471Skmacy if (!err && aligned_len > 4) 2497171471Skmacy err = t3_seeprom_read(adapter, 2498171471Skmacy aligned_offset + aligned_len - 4, 2499171471Skmacy (u32 *)&buf[aligned_len - 4]); 2500171471Skmacy if (err) 2501171471Skmacy goto out; 2502171471Skmacy memcpy(buf + (offset & 3), data, len); 2503171471Skmacy } else 2504171471Skmacy buf = (uint8_t *)(uintptr_t)data; 2505171471Skmacy 2506171471Skmacy err = t3_seeprom_wp(adapter, 0); 2507171471Skmacy if (err) 2508171471Skmacy goto out; 2509171471Skmacy 2510171471Skmacy for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { 2511171471Skmacy err = t3_seeprom_write(adapter, aligned_offset, *p); 2512171471Skmacy aligned_offset += 4; 2513171471Skmacy } 2514171471Skmacy 2515171471Skmacy if (!err) 2516171471Skmacy err = t3_seeprom_wp(adapter, 1); 2517171471Skmacyout: 2518171471Skmacy if (buf != data) 2519171471Skmacy free(buf, M_DEVBUF); 2520171471Skmacy return err; 2521171471Skmacy} 2522171471Skmacy 2523171471Skmacy 2524171471Skmacystatic int 2525167514Skmacyin_range(int val, int lo, int hi) 2526167514Skmacy{ 2527167514Skmacy return val < 0 || (val <= hi && val >= lo); 2528167514Skmacy} 2529167514Skmacy 2530167514Skmacystatic int 2531192450Simpcxgb_extension_open(struct cdev *dev, int flags, int fmp, struct thread *td) 2532170654Skmacy{ 2533170654Skmacy return (0); 2534170654Skmacy} 2535170654Skmacy 2536170654Skmacystatic int 2537192450Simpcxgb_extension_close(struct cdev *dev, int flags, int fmt, struct thread *td) 2538170654Skmacy{ 2539170654Skmacy return (0); 2540170654Skmacy} 2541170654Skmacy 2542170654Skmacystatic int 2543167514Skmacycxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, 2544167514Skmacy int fflag, struct thread *td) 2545167514Skmacy{ 2546167514Skmacy int mmd, error = 0; 2547167514Skmacy struct port_info *pi = dev->si_drv1; 2548167514Skmacy adapter_t *sc = pi->adapter; 2549167514Skmacy 2550167514Skmacy#ifdef PRIV_SUPPORTED 2551167514Skmacy if (priv_check(td, PRIV_DRIVER)) { 2552167514Skmacy if (cxgb_debug) 2553167514Skmacy printf("user does not have access to privileged ioctls\n"); 2554167514Skmacy return (EPERM); 2555167514Skmacy } 2556167514Skmacy#else 2557167514Skmacy if (suser(td)) { 2558167514Skmacy if (cxgb_debug) 2559167514Skmacy printf("user does not have access to privileged ioctls\n"); 2560167514Skmacy return (EPERM); 2561167514Skmacy } 2562167514Skmacy#endif 2563167514Skmacy 2564167514Skmacy switch (cmd) { 2565182679Skmacy case CHELSIO_GET_MIIREG: { 2566167514Skmacy uint32_t val; 2567167514Skmacy struct cphy *phy = &pi->phy; 2568182679Skmacy struct ch_mii_data *mid = (struct ch_mii_data *)data; 2569167514Skmacy 2570167514Skmacy if (!phy->mdio_read) 2571167514Skmacy return (EOPNOTSUPP); 2572167514Skmacy if (is_10G(sc)) { 2573167514Skmacy mmd = mid->phy_id >> 8; 2574167514Skmacy if (!mmd) 2575167514Skmacy mmd = MDIO_DEV_PCS; 2576190330Sgnn else if (mmd > MDIO_DEV_VEND2) 2577171471Skmacy return (EINVAL); 2578167514Skmacy 2579167514Skmacy error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd, 2580167514Skmacy mid->reg_num, &val); 2581167514Skmacy } else 2582167514Skmacy error = phy->mdio_read(sc, mid->phy_id & 0x1f, 0, 2583167514Skmacy mid->reg_num & 0x1f, &val); 2584167514Skmacy if (error == 0) 2585167514Skmacy mid->val_out = val; 2586167514Skmacy break; 2587167514Skmacy } 2588182679Skmacy case CHELSIO_SET_MIIREG: { 2589167514Skmacy struct cphy *phy = &pi->phy; 2590182679Skmacy struct ch_mii_data *mid = (struct ch_mii_data *)data; 2591167514Skmacy 2592167514Skmacy if (!phy->mdio_write) 2593167514Skmacy return (EOPNOTSUPP); 2594167514Skmacy if (is_10G(sc)) { 2595167514Skmacy mmd = mid->phy_id >> 8; 2596167514Skmacy if (!mmd) 2597167514Skmacy mmd = MDIO_DEV_PCS; 2598190330Sgnn else if (mmd > MDIO_DEV_VEND2) 2599167514Skmacy return (EINVAL); 2600167514Skmacy 2601167514Skmacy error = phy->mdio_write(sc, mid->phy_id & 0x1f, 2602167514Skmacy mmd, mid->reg_num, mid->val_in); 2603167514Skmacy } else 2604167514Skmacy error = phy->mdio_write(sc, mid->phy_id & 0x1f, 0, 2605167514Skmacy mid->reg_num & 0x1f, 2606167514Skmacy mid->val_in); 2607167514Skmacy break; 2608167514Skmacy } 2609167514Skmacy case CHELSIO_SETREG: { 2610167514Skmacy struct ch_reg *edata = (struct ch_reg *)data; 2611167514Skmacy if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 2612167514Skmacy return (EFAULT); 2613167514Skmacy t3_write_reg(sc, edata->addr, edata->val); 2614167514Skmacy break; 2615167514Skmacy } 2616167514Skmacy case CHELSIO_GETREG: { 2617167514Skmacy struct ch_reg *edata = (struct ch_reg *)data; 2618167514Skmacy if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 2619167514Skmacy return (EFAULT); 2620167514Skmacy edata->val = t3_read_reg(sc, edata->addr); 2621167514Skmacy break; 2622167514Skmacy } 2623167514Skmacy case CHELSIO_GET_SGE_CONTEXT: { 2624167514Skmacy struct ch_cntxt *ecntxt = (struct ch_cntxt *)data; 2625176472Skmacy mtx_lock_spin(&sc->sge.reg_lock); 2626167514Skmacy switch (ecntxt->cntxt_type) { 2627167514Skmacy case CNTXT_TYPE_EGRESS: 2628182679Skmacy error = -t3_sge_read_ecntxt(sc, ecntxt->cntxt_id, 2629167514Skmacy ecntxt->data); 2630167514Skmacy break; 2631167514Skmacy case CNTXT_TYPE_FL: 2632182679Skmacy error = -t3_sge_read_fl(sc, ecntxt->cntxt_id, 2633167514Skmacy ecntxt->data); 2634167514Skmacy break; 2635167514Skmacy case CNTXT_TYPE_RSP: 2636182679Skmacy error = -t3_sge_read_rspq(sc, ecntxt->cntxt_id, 2637167514Skmacy ecntxt->data); 2638167514Skmacy break; 2639167514Skmacy case CNTXT_TYPE_CQ: 2640182679Skmacy error = -t3_sge_read_cq(sc, ecntxt->cntxt_id, 2641167514Skmacy ecntxt->data); 2642167514Skmacy break; 2643167514Skmacy default: 2644167514Skmacy error = EINVAL; 2645167514Skmacy break; 2646167514Skmacy } 2647176472Skmacy mtx_unlock_spin(&sc->sge.reg_lock); 2648167514Skmacy break; 2649167514Skmacy } 2650167514Skmacy case CHELSIO_GET_SGE_DESC: { 2651167514Skmacy struct ch_desc *edesc = (struct ch_desc *)data; 2652167514Skmacy int ret; 2653167514Skmacy if (edesc->queue_num >= SGE_QSETS * 6) 2654167514Skmacy return (EINVAL); 2655167514Skmacy ret = t3_get_desc(&sc->sge.qs[edesc->queue_num / 6], 2656167514Skmacy edesc->queue_num % 6, edesc->idx, edesc->data); 2657167514Skmacy if (ret < 0) 2658167514Skmacy return (EINVAL); 2659167514Skmacy edesc->size = ret; 2660167514Skmacy break; 2661167514Skmacy } 2662182679Skmacy case CHELSIO_GET_QSET_PARAMS: { 2663167514Skmacy struct qset_params *q; 2664167514Skmacy struct ch_qset_params *t = (struct ch_qset_params *)data; 2665182679Skmacy int q1 = pi->first_qset; 2666182679Skmacy int nqsets = pi->nqsets; 2667176472Skmacy int i; 2668176472Skmacy 2669182679Skmacy if (t->qset_idx >= nqsets) 2670182679Skmacy return EINVAL; 2671167514Skmacy 2672182679Skmacy i = q1 + t->qset_idx; 2673182679Skmacy q = &sc->params.sge.qset[i]; 2674167514Skmacy t->rspq_size = q->rspq_size; 2675167514Skmacy t->txq_size[0] = q->txq_size[0]; 2676167514Skmacy t->txq_size[1] = q->txq_size[1]; 2677167514Skmacy t->txq_size[2] = q->txq_size[2]; 2678167514Skmacy t->fl_size[0] = q->fl_size; 2679167514Skmacy t->fl_size[1] = q->jumbo_size; 2680167514Skmacy t->polling = q->polling; 2681182679Skmacy t->lro = q->lro; 2682180583Skmacy t->intr_lat = q->coalesce_usecs; 2683167514Skmacy t->cong_thres = q->cong_thres; 2684182679Skmacy t->qnum = i; 2685182679Skmacy 2686182679Skmacy if (sc->flags & USING_MSIX) 2687182679Skmacy t->vector = rman_get_start(sc->msix_irq_res[i]); 2688182679Skmacy else 2689182679Skmacy t->vector = rman_get_start(sc->irq_res); 2690182679Skmacy 2691167514Skmacy break; 2692167514Skmacy } 2693182679Skmacy case CHELSIO_GET_QSET_NUM: { 2694167514Skmacy struct ch_reg *edata = (struct ch_reg *)data; 2695182679Skmacy edata->val = pi->nqsets; 2696182679Skmacy break; 2697182679Skmacy } 2698182679Skmacy case CHELSIO_LOAD_FW: { 2699182679Skmacy uint8_t *fw_data; 2700182679Skmacy uint32_t vers; 2701182679Skmacy struct ch_mem_range *t = (struct ch_mem_range *)data; 2702182679Skmacy 2703167514Skmacy /* 2704182679Skmacy * You're allowed to load a firmware only before FULL_INIT_DONE 2705182679Skmacy * 2706182679Skmacy * FW_UPTODATE is also set so the rest of the initialization 2707182679Skmacy * will not overwrite what was loaded here. This gives you the 2708182679Skmacy * flexibility to load any firmware (and maybe shoot yourself in 2709182679Skmacy * the foot). 2710167514Skmacy */ 2711182679Skmacy 2712182679Skmacy ADAPTER_LOCK(sc); 2713182679Skmacy if (sc->open_device_map || sc->flags & FULL_INIT_DONE) { 2714182679Skmacy ADAPTER_UNLOCK(sc); 2715182679Skmacy return (EBUSY); 2716182679Skmacy } 2717182679Skmacy 2718182679Skmacy fw_data = malloc(t->len, M_DEVBUF, M_NOWAIT); 2719182679Skmacy if (!fw_data) 2720182679Skmacy error = ENOMEM; 2721182679Skmacy else 2722182679Skmacy error = copyin(t->buf, fw_data, t->len); 2723182679Skmacy 2724182679Skmacy if (!error) 2725182679Skmacy error = -t3_load_fw(sc, fw_data, t->len); 2726182679Skmacy 2727182679Skmacy if (t3_get_fw_version(sc, &vers) == 0) { 2728182679Skmacy snprintf(&sc->fw_version[0], sizeof(sc->fw_version), 2729182679Skmacy "%d.%d.%d", G_FW_VERSION_MAJOR(vers), 2730182679Skmacy G_FW_VERSION_MINOR(vers), G_FW_VERSION_MICRO(vers)); 2731182679Skmacy } 2732182679Skmacy 2733182679Skmacy if (!error) 2734182679Skmacy sc->flags |= FW_UPTODATE; 2735182679Skmacy 2736182679Skmacy free(fw_data, M_DEVBUF); 2737182679Skmacy ADAPTER_UNLOCK(sc); 2738167514Skmacy break; 2739167514Skmacy } 2740182679Skmacy case CHELSIO_LOAD_BOOT: { 2741182679Skmacy uint8_t *boot_data; 2742182679Skmacy struct ch_mem_range *t = (struct ch_mem_range *)data; 2743182679Skmacy 2744182679Skmacy boot_data = malloc(t->len, M_DEVBUF, M_NOWAIT); 2745182679Skmacy if (!boot_data) 2746182679Skmacy return ENOMEM; 2747182679Skmacy 2748182679Skmacy error = copyin(t->buf, boot_data, t->len); 2749182679Skmacy if (!error) 2750182679Skmacy error = -t3_load_boot(sc, boot_data, t->len); 2751182679Skmacy 2752182679Skmacy free(boot_data, M_DEVBUF); 2753167514Skmacy break; 2754167514Skmacy } 2755182679Skmacy case CHELSIO_GET_PM: { 2756182679Skmacy struct ch_pm *m = (struct ch_pm *)data; 2757182679Skmacy struct tp_params *p = &sc->params.tp; 2758182679Skmacy 2759182679Skmacy if (!is_offload(sc)) 2760182679Skmacy return (EOPNOTSUPP); 2761182679Skmacy 2762182679Skmacy m->tx_pg_sz = p->tx_pg_size; 2763182679Skmacy m->tx_num_pg = p->tx_num_pgs; 2764182679Skmacy m->rx_pg_sz = p->rx_pg_size; 2765182679Skmacy m->rx_num_pg = p->rx_num_pgs; 2766182679Skmacy m->pm_total = p->pmtx_size + p->chan_rx_size * p->nchan; 2767182679Skmacy 2768167514Skmacy break; 2769182679Skmacy } 2770182679Skmacy case CHELSIO_SET_PM: { 2771182679Skmacy struct ch_pm *m = (struct ch_pm *)data; 2772182679Skmacy struct tp_params *p = &sc->params.tp; 2773182679Skmacy 2774182679Skmacy if (!is_offload(sc)) 2775182679Skmacy return (EOPNOTSUPP); 2776182679Skmacy if (sc->flags & FULL_INIT_DONE) 2777182679Skmacy return (EBUSY); 2778182679Skmacy 2779182679Skmacy if (!m->rx_pg_sz || (m->rx_pg_sz & (m->rx_pg_sz - 1)) || 2780182679Skmacy !m->tx_pg_sz || (m->tx_pg_sz & (m->tx_pg_sz - 1))) 2781182679Skmacy return (EINVAL); /* not power of 2 */ 2782182679Skmacy if (!(m->rx_pg_sz & 0x14000)) 2783182679Skmacy return (EINVAL); /* not 16KB or 64KB */ 2784182679Skmacy if (!(m->tx_pg_sz & 0x1554000)) 2785182679Skmacy return (EINVAL); 2786182679Skmacy if (m->tx_num_pg == -1) 2787182679Skmacy m->tx_num_pg = p->tx_num_pgs; 2788182679Skmacy if (m->rx_num_pg == -1) 2789182679Skmacy m->rx_num_pg = p->rx_num_pgs; 2790182679Skmacy if (m->tx_num_pg % 24 || m->rx_num_pg % 24) 2791182679Skmacy return (EINVAL); 2792182679Skmacy if (m->rx_num_pg * m->rx_pg_sz > p->chan_rx_size || 2793182679Skmacy m->tx_num_pg * m->tx_pg_sz > p->chan_tx_size) 2794182679Skmacy return (EINVAL); 2795182679Skmacy 2796182679Skmacy p->rx_pg_size = m->rx_pg_sz; 2797182679Skmacy p->tx_pg_size = m->tx_pg_sz; 2798182679Skmacy p->rx_num_pgs = m->rx_num_pg; 2799182679Skmacy p->tx_num_pgs = m->tx_num_pg; 2800182679Skmacy break; 2801182679Skmacy } 2802169978Skmacy case CHELSIO_SETMTUTAB: { 2803169978Skmacy struct ch_mtus *m = (struct ch_mtus *)data; 2804169978Skmacy int i; 2805169978Skmacy 2806169978Skmacy if (!is_offload(sc)) 2807169978Skmacy return (EOPNOTSUPP); 2808169978Skmacy if (offload_running(sc)) 2809169978Skmacy return (EBUSY); 2810169978Skmacy if (m->nmtus != NMTUS) 2811169978Skmacy return (EINVAL); 2812169978Skmacy if (m->mtus[0] < 81) /* accommodate SACK */ 2813169978Skmacy return (EINVAL); 2814169978Skmacy 2815169978Skmacy /* 2816169978Skmacy * MTUs must be in ascending order 2817169978Skmacy */ 2818169978Skmacy for (i = 1; i < NMTUS; ++i) 2819169978Skmacy if (m->mtus[i] < m->mtus[i - 1]) 2820169978Skmacy return (EINVAL); 2821169978Skmacy 2822182679Skmacy memcpy(sc->params.mtus, m->mtus, sizeof(sc->params.mtus)); 2823169978Skmacy break; 2824169978Skmacy } 2825169978Skmacy case CHELSIO_GETMTUTAB: { 2826169978Skmacy struct ch_mtus *m = (struct ch_mtus *)data; 2827169978Skmacy 2828169978Skmacy if (!is_offload(sc)) 2829169978Skmacy return (EOPNOTSUPP); 2830169978Skmacy 2831169978Skmacy memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus)); 2832169978Skmacy m->nmtus = NMTUS; 2833169978Skmacy break; 2834171471Skmacy } 2835167514Skmacy case CHELSIO_GET_MEM: { 2836167514Skmacy struct ch_mem_range *t = (struct ch_mem_range *)data; 2837167514Skmacy struct mc7 *mem; 2838167514Skmacy uint8_t *useraddr; 2839167514Skmacy u64 buf[32]; 2840182679Skmacy 2841182679Skmacy /* 2842182679Skmacy * Use these to avoid modifying len/addr in the the return 2843182679Skmacy * struct 2844182679Skmacy */ 2845182679Skmacy uint32_t len = t->len, addr = t->addr; 2846182679Skmacy 2847167514Skmacy if (!is_offload(sc)) 2848167514Skmacy return (EOPNOTSUPP); 2849167514Skmacy if (!(sc->flags & FULL_INIT_DONE)) 2850167514Skmacy return (EIO); /* need the memory controllers */ 2851182679Skmacy if ((addr & 0x7) || (len & 0x7)) 2852167514Skmacy return (EINVAL); 2853167514Skmacy if (t->mem_id == MEM_CM) 2854167514Skmacy mem = &sc->cm; 2855167514Skmacy else if (t->mem_id == MEM_PMRX) 2856167514Skmacy mem = &sc->pmrx; 2857167514Skmacy else if (t->mem_id == MEM_PMTX) 2858167514Skmacy mem = &sc->pmtx; 2859167514Skmacy else 2860167514Skmacy return (EINVAL); 2861167514Skmacy 2862167514Skmacy /* 2863167514Skmacy * Version scheme: 2864167514Skmacy * bits 0..9: chip version 2865167514Skmacy * bits 10..15: chip revision 2866167514Skmacy */ 2867167514Skmacy t->version = 3 | (sc->params.rev << 10); 2868167514Skmacy 2869167514Skmacy /* 2870167514Skmacy * Read 256 bytes at a time as len can be large and we don't 2871167514Skmacy * want to use huge intermediate buffers. 2872167514Skmacy */ 2873174708Skmacy useraddr = (uint8_t *)t->buf; 2874182679Skmacy while (len) { 2875182679Skmacy unsigned int chunk = min(len, sizeof(buf)); 2876167514Skmacy 2877182679Skmacy error = t3_mc7_bd_read(mem, addr / 8, chunk / 8, buf); 2878167514Skmacy if (error) 2879167514Skmacy return (-error); 2880167514Skmacy if (copyout(buf, useraddr, chunk)) 2881167514Skmacy return (EFAULT); 2882167514Skmacy useraddr += chunk; 2883182679Skmacy addr += chunk; 2884182679Skmacy len -= chunk; 2885167514Skmacy } 2886167514Skmacy break; 2887167514Skmacy } 2888169978Skmacy case CHELSIO_READ_TCAM_WORD: { 2889169978Skmacy struct ch_tcam_word *t = (struct ch_tcam_word *)data; 2890169978Skmacy 2891169978Skmacy if (!is_offload(sc)) 2892169978Skmacy return (EOPNOTSUPP); 2893171471Skmacy if (!(sc->flags & FULL_INIT_DONE)) 2894171471Skmacy return (EIO); /* need MC5 */ 2895169978Skmacy return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf); 2896169978Skmacy break; 2897169978Skmacy } 2898167514Skmacy case CHELSIO_SET_TRACE_FILTER: { 2899167514Skmacy struct ch_trace *t = (struct ch_trace *)data; 2900167514Skmacy const struct trace_params *tp; 2901167514Skmacy 2902167514Skmacy tp = (const struct trace_params *)&t->sip; 2903167514Skmacy if (t->config_tx) 2904167514Skmacy t3_config_trace_filter(sc, tp, 0, t->invert_match, 2905167514Skmacy t->trace_tx); 2906167514Skmacy if (t->config_rx) 2907167514Skmacy t3_config_trace_filter(sc, tp, 1, t->invert_match, 2908167514Skmacy t->trace_rx); 2909167514Skmacy break; 2910167514Skmacy } 2911167514Skmacy case CHELSIO_SET_PKTSCHED: { 2912167514Skmacy struct ch_pktsched_params *p = (struct ch_pktsched_params *)data; 2913167514Skmacy if (sc->open_device_map == 0) 2914167514Skmacy return (EAGAIN); 2915167514Skmacy send_pktsched_cmd(sc, p->sched, p->idx, p->min, p->max, 2916167514Skmacy p->binding); 2917167514Skmacy break; 2918167514Skmacy } 2919167514Skmacy case CHELSIO_IFCONF_GETREGS: { 2920182679Skmacy struct ch_ifconf_regs *regs = (struct ch_ifconf_regs *)data; 2921167514Skmacy int reglen = cxgb_get_regs_len(); 2922182679Skmacy uint8_t *buf = malloc(reglen, M_DEVBUF, M_NOWAIT); 2923167514Skmacy if (buf == NULL) { 2924167514Skmacy return (ENOMEM); 2925182679Skmacy } 2926182679Skmacy if (regs->len > reglen) 2927167514Skmacy regs->len = reglen; 2928182679Skmacy else if (regs->len < reglen) 2929189643Sgnn error = ENOBUFS; 2930182679Skmacy 2931182679Skmacy if (!error) { 2932182679Skmacy cxgb_get_regs(sc, regs, buf); 2933182679Skmacy error = copyout(buf, regs->data, reglen); 2934167514Skmacy } 2935167514Skmacy free(buf, M_DEVBUF); 2936167514Skmacy 2937167514Skmacy break; 2938167514Skmacy } 2939169978Skmacy case CHELSIO_SET_HW_SCHED: { 2940169978Skmacy struct ch_hw_sched *t = (struct ch_hw_sched *)data; 2941169978Skmacy unsigned int ticks_per_usec = core_ticks_per_usec(sc); 2942169978Skmacy 2943169978Skmacy if ((sc->flags & FULL_INIT_DONE) == 0) 2944169978Skmacy return (EAGAIN); /* need TP to be initialized */ 2945169978Skmacy if (t->sched >= NTX_SCHED || !in_range(t->mode, 0, 1) || 2946169978Skmacy !in_range(t->channel, 0, 1) || 2947169978Skmacy !in_range(t->kbps, 0, 10000000) || 2948169978Skmacy !in_range(t->class_ipg, 0, 10000 * 65535 / ticks_per_usec) || 2949169978Skmacy !in_range(t->flow_ipg, 0, 2950169978Skmacy dack_ticks_to_usec(sc, 0x7ff))) 2951169978Skmacy return (EINVAL); 2952169978Skmacy 2953169978Skmacy if (t->kbps >= 0) { 2954169978Skmacy error = t3_config_sched(sc, t->kbps, t->sched); 2955169978Skmacy if (error < 0) 2956169978Skmacy return (-error); 2957169978Skmacy } 2958169978Skmacy if (t->class_ipg >= 0) 2959169978Skmacy t3_set_sched_ipg(sc, t->sched, t->class_ipg); 2960169978Skmacy if (t->flow_ipg >= 0) { 2961169978Skmacy t->flow_ipg *= 1000; /* us -> ns */ 2962169978Skmacy t3_set_pace_tbl(sc, &t->flow_ipg, t->sched, 1); 2963169978Skmacy } 2964169978Skmacy if (t->mode >= 0) { 2965169978Skmacy int bit = 1 << (S_TX_MOD_TIMER_MODE + t->sched); 2966169978Skmacy 2967169978Skmacy t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP, 2968169978Skmacy bit, t->mode ? bit : 0); 2969169978Skmacy } 2970169978Skmacy if (t->channel >= 0) 2971169978Skmacy t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP, 2972169978Skmacy 1 << t->sched, t->channel << t->sched); 2973169978Skmacy break; 2974182679Skmacy } 2975182679Skmacy case CHELSIO_GET_EEPROM: { 2976182679Skmacy int i; 2977182679Skmacy struct ch_eeprom *e = (struct ch_eeprom *)data; 2978182679Skmacy uint8_t *buf = malloc(EEPROMSIZE, M_DEVBUF, M_NOWAIT); 2979182679Skmacy 2980182679Skmacy if (buf == NULL) { 2981182679Skmacy return (ENOMEM); 2982182679Skmacy } 2983182679Skmacy e->magic = EEPROM_MAGIC; 2984182679Skmacy for (i = e->offset & ~3; !error && i < e->offset + e->len; i += 4) 2985182679Skmacy error = -t3_seeprom_read(sc, i, (uint32_t *)&buf[i]); 2986182679Skmacy 2987182679Skmacy if (!error) 2988182679Skmacy error = copyout(buf + e->offset, e->data, e->len); 2989182679Skmacy 2990182679Skmacy free(buf, M_DEVBUF); 2991182679Skmacy break; 2992182679Skmacy } 2993182679Skmacy case CHELSIO_CLEAR_STATS: { 2994182679Skmacy if (!(sc->flags & FULL_INIT_DONE)) 2995182679Skmacy return EAGAIN; 2996182679Skmacy 2997182679Skmacy PORT_LOCK(pi); 2998182679Skmacy t3_mac_update_stats(&pi->mac); 2999182679Skmacy memset(&pi->mac.stats, 0, sizeof(pi->mac.stats)); 3000182679Skmacy PORT_UNLOCK(pi); 3001182679Skmacy break; 3002182679Skmacy } 3003189643Sgnn case CHELSIO_GET_UP_LA: { 3004189643Sgnn struct ch_up_la *la = (struct ch_up_la *)data; 3005189643Sgnn uint8_t *buf = malloc(LA_BUFSIZE, M_DEVBUF, M_NOWAIT); 3006189643Sgnn if (buf == NULL) { 3007189643Sgnn return (ENOMEM); 3008189643Sgnn } 3009189643Sgnn if (la->bufsize < LA_BUFSIZE) 3010189643Sgnn error = ENOBUFS; 3011189643Sgnn 3012189643Sgnn if (!error) 3013189643Sgnn error = -t3_get_up_la(sc, &la->stopped, &la->idx, 3014189643Sgnn &la->bufsize, buf); 3015189643Sgnn if (!error) 3016189643Sgnn error = copyout(buf, la->data, la->bufsize); 3017189643Sgnn 3018189643Sgnn free(buf, M_DEVBUF); 3019189643Sgnn break; 3020189643Sgnn } 3021189643Sgnn case CHELSIO_GET_UP_IOQS: { 3022189643Sgnn struct ch_up_ioqs *ioqs = (struct ch_up_ioqs *)data; 3023189643Sgnn uint8_t *buf = malloc(IOQS_BUFSIZE, M_DEVBUF, M_NOWAIT); 3024189643Sgnn uint32_t *v; 3025189643Sgnn 3026189643Sgnn if (buf == NULL) { 3027189643Sgnn return (ENOMEM); 3028189643Sgnn } 3029189643Sgnn if (ioqs->bufsize < IOQS_BUFSIZE) 3030189643Sgnn error = ENOBUFS; 3031189643Sgnn 3032189643Sgnn if (!error) 3033189643Sgnn error = -t3_get_up_ioqs(sc, &ioqs->bufsize, buf); 3034189643Sgnn 3035189643Sgnn if (!error) { 3036189643Sgnn v = (uint32_t *)buf; 3037189643Sgnn 3038189643Sgnn ioqs->bufsize -= 4 * sizeof(uint32_t); 3039189643Sgnn ioqs->ioq_rx_enable = *v++; 3040189643Sgnn ioqs->ioq_tx_enable = *v++; 3041189643Sgnn ioqs->ioq_rx_status = *v++; 3042189643Sgnn ioqs->ioq_tx_status = *v++; 3043189643Sgnn 3044189643Sgnn error = copyout(v, ioqs->data, ioqs->bufsize); 3045189643Sgnn } 3046189643Sgnn 3047189643Sgnn free(buf, M_DEVBUF); 3048189643Sgnn break; 3049189643Sgnn } 3050167514Skmacy default: 3051167514Skmacy return (EOPNOTSUPP); 3052167514Skmacy break; 3053167514Skmacy } 3054167514Skmacy 3055167514Skmacy return (error); 3056167514Skmacy} 3057167514Skmacy 3058167514Skmacystatic __inline void 3059167514Skmacyreg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start, 3060167514Skmacy unsigned int end) 3061167514Skmacy{ 3062182679Skmacy uint32_t *p = (uint32_t *)(buf + start); 3063167514Skmacy 3064167514Skmacy for ( ; start <= end; start += sizeof(uint32_t)) 3065167514Skmacy *p++ = t3_read_reg(ap, start); 3066167514Skmacy} 3067167514Skmacy 3068167514Skmacy#define T3_REGMAP_SIZE (3 * 1024) 3069167514Skmacystatic int 3070167514Skmacycxgb_get_regs_len(void) 3071167514Skmacy{ 3072167514Skmacy return T3_REGMAP_SIZE; 3073167514Skmacy} 3074167514Skmacy 3075167514Skmacystatic void 3076182679Skmacycxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf) 3077167514Skmacy{ 3078167514Skmacy 3079167514Skmacy /* 3080167514Skmacy * Version scheme: 3081167514Skmacy * bits 0..9: chip version 3082167514Skmacy * bits 10..15: chip revision 3083167514Skmacy * bit 31: set for PCIe cards 3084167514Skmacy */ 3085167514Skmacy regs->version = 3 | (sc->params.rev << 10) | (is_pcie(sc) << 31); 3086167514Skmacy 3087167514Skmacy /* 3088167514Skmacy * We skip the MAC statistics registers because they are clear-on-read. 3089167514Skmacy * Also reading multi-register stats would need to synchronize with the 3090167514Skmacy * periodic mac stats accumulation. Hard to justify the complexity. 3091167514Skmacy */ 3092182679Skmacy memset(buf, 0, cxgb_get_regs_len()); 3093167514Skmacy reg_block_dump(sc, buf, 0, A_SG_RSPQ_CREDIT_RETURN); 3094167514Skmacy reg_block_dump(sc, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT); 3095167514Skmacy reg_block_dump(sc, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE); 3096167514Skmacy reg_block_dump(sc, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA); 3097167514Skmacy reg_block_dump(sc, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3); 3098167514Skmacy reg_block_dump(sc, buf, A_XGM_SERDES_STATUS0, 3099167514Skmacy XGM_REG(A_XGM_SERDES_STAT3, 1)); 3100167514Skmacy reg_block_dump(sc, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1), 3101167514Skmacy XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1)); 3102167514Skmacy} 3103176572Skmacy 3104176572Skmacy 3105176572SkmacyMODULE_DEPEND(if_cxgb, cxgb_t3fw, 1, 1, 1); 3106