cxgb_main.c revision 174626
1167514Skmacy/************************************************************************** 2167514Skmacy 3167514SkmacyCopyright (c) 2007, 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 12169978Skmacy2. 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 174626 2007-12-15 21:54:59Z kmacy $"); 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> 43167514Skmacy#include <sys/rman.h> 44167514Skmacy#include <sys/ioccom.h> 45167514Skmacy#include <sys/mbuf.h> 46167514Skmacy#include <sys/linker.h> 47174626Skmacy#include <sys/syslog.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> 53167514Skmacy#include <sys/queue.h> 54167514Skmacy#include <sys/taskqueue.h> 55167514Skmacy 56167514Skmacy#include <net/bpf.h> 57167514Skmacy#include <net/ethernet.h> 58167514Skmacy#include <net/if.h> 59167514Skmacy#include <net/if_arp.h> 60167514Skmacy#include <net/if_dl.h> 61167514Skmacy#include <net/if_media.h> 62167514Skmacy#include <net/if_types.h> 63167514Skmacy 64167514Skmacy#include <netinet/in_systm.h> 65167514Skmacy#include <netinet/in.h> 66167514Skmacy#include <netinet/if_ether.h> 67167514Skmacy#include <netinet/ip.h> 68167514Skmacy#include <netinet/ip.h> 69167514Skmacy#include <netinet/tcp.h> 70167514Skmacy#include <netinet/udp.h> 71167514Skmacy 72167514Skmacy#include <dev/pci/pcireg.h> 73167514Skmacy#include <dev/pci/pcivar.h> 74167514Skmacy#include <dev/pci/pci_private.h> 75167514Skmacy 76170076Skmacy#ifdef CONFIG_DEFINED 77170076Skmacy#include <cxgb_include.h> 78170076Skmacy#else 79170076Skmacy#include <dev/cxgb/cxgb_include.h> 80170076Skmacy#endif 81167514Skmacy 82167514Skmacy#ifdef PRIV_SUPPORTED 83167514Skmacy#include <sys/priv.h> 84167514Skmacy#endif 85167514Skmacy 86167514Skmacystatic int cxgb_setup_msix(adapter_t *, int); 87170654Skmacystatic void cxgb_teardown_msix(adapter_t *); 88167514Skmacystatic void cxgb_init(void *); 89167514Skmacystatic void cxgb_init_locked(struct port_info *); 90167734Skmacystatic void cxgb_stop_locked(struct port_info *); 91167514Skmacystatic void cxgb_set_rxmode(struct port_info *); 92167514Skmacystatic int cxgb_ioctl(struct ifnet *, unsigned long, caddr_t); 93167514Skmacystatic void cxgb_start(struct ifnet *); 94167514Skmacystatic void cxgb_start_proc(void *, int ncount); 95167514Skmacystatic int cxgb_media_change(struct ifnet *); 96167514Skmacystatic void cxgb_media_status(struct ifnet *, struct ifmediareq *); 97167514Skmacystatic int setup_sge_qsets(adapter_t *); 98167514Skmacystatic void cxgb_async_intr(void *); 99167514Skmacystatic void cxgb_ext_intr_handler(void *, int); 100170869Skmacystatic void cxgb_tick_handler(void *, int); 101170869Skmacystatic void cxgb_down_locked(struct adapter *sc); 102167514Skmacystatic void cxgb_tick(void *); 103167514Skmacystatic void setup_rss(adapter_t *sc); 104167514Skmacy 105167514Skmacy/* Attachment glue for the PCI controller end of the device. Each port of 106167514Skmacy * the device is attached separately, as defined later. 107167514Skmacy */ 108167514Skmacystatic int cxgb_controller_probe(device_t); 109167514Skmacystatic int cxgb_controller_attach(device_t); 110167514Skmacystatic int cxgb_controller_detach(device_t); 111167514Skmacystatic void cxgb_free(struct adapter *); 112167514Skmacystatic __inline void reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start, 113167514Skmacy unsigned int end); 114167514Skmacystatic void cxgb_get_regs(adapter_t *sc, struct ifconf_regs *regs, uint8_t *buf); 115167514Skmacystatic int cxgb_get_regs_len(void); 116169978Skmacystatic int offload_open(struct port_info *pi); 117171978Skmacystatic void touch_bars(device_t dev); 118171978Skmacy 119170789Skmacy#ifdef notyet 120174626Skmacystatic int offload_close(struct t3cdev *tdev); 121170789Skmacy#endif 122167514Skmacy 123169978Skmacy 124167514Skmacystatic device_method_t cxgb_controller_methods[] = { 125167514Skmacy DEVMETHOD(device_probe, cxgb_controller_probe), 126167514Skmacy DEVMETHOD(device_attach, cxgb_controller_attach), 127167514Skmacy DEVMETHOD(device_detach, cxgb_controller_detach), 128167514Skmacy 129167514Skmacy /* bus interface */ 130167514Skmacy DEVMETHOD(bus_print_child, bus_generic_print_child), 131167514Skmacy DEVMETHOD(bus_driver_added, bus_generic_driver_added), 132167514Skmacy 133167514Skmacy { 0, 0 } 134167514Skmacy}; 135167514Skmacy 136167514Skmacystatic driver_t cxgb_controller_driver = { 137167514Skmacy "cxgbc", 138167514Skmacy cxgb_controller_methods, 139167514Skmacy sizeof(struct adapter) 140167514Skmacy}; 141167514Skmacy 142167514Skmacystatic devclass_t cxgb_controller_devclass; 143167514SkmacyDRIVER_MODULE(cxgbc, pci, cxgb_controller_driver, cxgb_controller_devclass, 0, 0); 144167514Skmacy 145167514Skmacy/* 146167514Skmacy * Attachment glue for the ports. Attachment is done directly to the 147167514Skmacy * controller device. 148167514Skmacy */ 149167514Skmacystatic int cxgb_port_probe(device_t); 150167514Skmacystatic int cxgb_port_attach(device_t); 151167514Skmacystatic int cxgb_port_detach(device_t); 152167514Skmacy 153167514Skmacystatic device_method_t cxgb_port_methods[] = { 154167514Skmacy DEVMETHOD(device_probe, cxgb_port_probe), 155167514Skmacy DEVMETHOD(device_attach, cxgb_port_attach), 156167514Skmacy DEVMETHOD(device_detach, cxgb_port_detach), 157167514Skmacy { 0, 0 } 158167514Skmacy}; 159167514Skmacy 160167514Skmacystatic driver_t cxgb_port_driver = { 161167514Skmacy "cxgb", 162167514Skmacy cxgb_port_methods, 163167514Skmacy 0 164167514Skmacy}; 165167514Skmacy 166167514Skmacystatic d_ioctl_t cxgb_extension_ioctl; 167170654Skmacystatic d_open_t cxgb_extension_open; 168170654Skmacystatic d_close_t cxgb_extension_close; 169167514Skmacy 170170654Skmacystatic struct cdevsw cxgb_cdevsw = { 171170654Skmacy .d_version = D_VERSION, 172170654Skmacy .d_flags = 0, 173170654Skmacy .d_open = cxgb_extension_open, 174170654Skmacy .d_close = cxgb_extension_close, 175170654Skmacy .d_ioctl = cxgb_extension_ioctl, 176170654Skmacy .d_name = "cxgb", 177170654Skmacy}; 178170654Skmacy 179167514Skmacystatic devclass_t cxgb_port_devclass; 180167514SkmacyDRIVER_MODULE(cxgb, cxgbc, cxgb_port_driver, cxgb_port_devclass, 0, 0); 181167514Skmacy 182167514Skmacy#define SGE_MSIX_COUNT (SGE_QSETS + 1) 183167514Skmacy 184168749Skmacyextern int collapse_mbufs; 185167514Skmacy/* 186167514Skmacy * The driver uses the best interrupt scheme available on a platform in the 187167514Skmacy * order MSI-X, MSI, legacy pin interrupts. This parameter determines which 188167514Skmacy * of these schemes the driver may consider as follows: 189167514Skmacy * 190167514Skmacy * msi = 2: choose from among all three options 191167514Skmacy * msi = 1 : only consider MSI and pin interrupts 192167514Skmacy * msi = 0: force pin interrupts 193167514Skmacy */ 194167760Skmacystatic int msi_allowed = 2; 195170083Skmacy 196167514SkmacyTUNABLE_INT("hw.cxgb.msi_allowed", &msi_allowed); 197167514SkmacySYSCTL_NODE(_hw, OID_AUTO, cxgb, CTLFLAG_RD, 0, "CXGB driver parameters"); 198167514SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, msi_allowed, CTLFLAG_RDTUN, &msi_allowed, 0, 199167514Skmacy "MSI-X, MSI, INTx selector"); 200169978Skmacy 201169053Skmacy/* 202169978Skmacy * The driver enables offload as a default. 203169978Skmacy * To disable it, use ofld_disable = 1. 204169053Skmacy */ 205169978Skmacystatic int ofld_disable = 0; 206169978SkmacyTUNABLE_INT("hw.cxgb.ofld_disable", &ofld_disable); 207169978SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, ofld_disable, CTLFLAG_RDTUN, &ofld_disable, 0, 208169978Skmacy "disable ULP offload"); 209169978Skmacy 210169978Skmacy/* 211169978Skmacy * The driver uses an auto-queue algorithm by default. 212169978Skmacy * To disable it and force a single queue-set per port, use singleq = 1. 213169978Skmacy */ 214169053Skmacystatic int singleq = 1; 215169978SkmacyTUNABLE_INT("hw.cxgb.singleq", &singleq); 216169978SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, singleq, CTLFLAG_RDTUN, &singleq, 0, 217169978Skmacy "use a single queue-set per port"); 218167514Skmacy 219167514Skmacyenum { 220167514Skmacy MAX_TXQ_ENTRIES = 16384, 221167514Skmacy MAX_CTRL_TXQ_ENTRIES = 1024, 222167514Skmacy MAX_RSPQ_ENTRIES = 16384, 223167514Skmacy MAX_RX_BUFFERS = 16384, 224167514Skmacy MAX_RX_JUMBO_BUFFERS = 16384, 225167514Skmacy MIN_TXQ_ENTRIES = 4, 226167514Skmacy MIN_CTRL_TXQ_ENTRIES = 4, 227167514Skmacy MIN_RSPQ_ENTRIES = 32, 228172096Skmacy MIN_FL_ENTRIES = 32, 229172096Skmacy MIN_FL_JUMBO_ENTRIES = 32 230167514Skmacy}; 231167514Skmacy 232171471Skmacystruct filter_info { 233171471Skmacy u32 sip; 234171471Skmacy u32 sip_mask; 235171471Skmacy u32 dip; 236171471Skmacy u16 sport; 237171471Skmacy u16 dport; 238171471Skmacy u32 vlan:12; 239171471Skmacy u32 vlan_prio:3; 240171471Skmacy u32 mac_hit:1; 241171471Skmacy u32 mac_idx:4; 242171471Skmacy u32 mac_vld:1; 243171471Skmacy u32 pkt_type:2; 244171471Skmacy u32 report_filter_id:1; 245171471Skmacy u32 pass:1; 246171471Skmacy u32 rss:1; 247171471Skmacy u32 qset:3; 248171471Skmacy u32 locked:1; 249171471Skmacy u32 valid:1; 250171471Skmacy}; 251171471Skmacy 252171471Skmacyenum { FILTER_NO_VLAN_PRI = 7 }; 253171471Skmacy 254167514Skmacy#define PORT_MASK ((1 << MAX_NPORTS) - 1) 255167514Skmacy 256167514Skmacy/* Table for probing the cards. The desc field isn't actually used */ 257167514Skmacystruct cxgb_ident { 258167514Skmacy uint16_t vendor; 259167514Skmacy uint16_t device; 260167514Skmacy int index; 261167514Skmacy char *desc; 262167514Skmacy} cxgb_identifiers[] = { 263167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0020, 0, "PE9000"}, 264167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0021, 1, "T302E"}, 265167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0022, 2, "T310E"}, 266167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0023, 3, "T320X"}, 267167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0024, 1, "T302X"}, 268167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0025, 3, "T320E"}, 269167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0026, 2, "T310X"}, 270167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0030, 2, "T3B10"}, 271167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0031, 3, "T3B20"}, 272167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0032, 1, "T3B02"}, 273170654Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0033, 4, "T3B04"}, 274167514Skmacy {0, 0, 0, NULL} 275167514Skmacy}; 276167514Skmacy 277171471Skmacy 278171471Skmacystatic int set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset); 279171471Skmacy 280171471Skmacystatic inline char 281171471Skmacyt3rev2char(struct adapter *adapter) 282171471Skmacy{ 283171471Skmacy char rev = 'z'; 284171471Skmacy 285171471Skmacy switch(adapter->params.rev) { 286171471Skmacy case T3_REV_A: 287171471Skmacy rev = 'a'; 288171471Skmacy break; 289171471Skmacy case T3_REV_B: 290171471Skmacy case T3_REV_B2: 291171471Skmacy rev = 'b'; 292171471Skmacy break; 293171471Skmacy case T3_REV_C: 294171471Skmacy rev = 'c'; 295171471Skmacy break; 296171471Skmacy } 297171471Skmacy return rev; 298171471Skmacy} 299171471Skmacy 300167514Skmacystatic struct cxgb_ident * 301167514Skmacycxgb_get_ident(device_t dev) 302167514Skmacy{ 303167514Skmacy struct cxgb_ident *id; 304167514Skmacy 305167514Skmacy for (id = cxgb_identifiers; id->desc != NULL; id++) { 306167514Skmacy if ((id->vendor == pci_get_vendor(dev)) && 307167514Skmacy (id->device == pci_get_device(dev))) { 308167514Skmacy return (id); 309167514Skmacy } 310167514Skmacy } 311167514Skmacy return (NULL); 312167514Skmacy} 313167514Skmacy 314167514Skmacystatic const struct adapter_info * 315167514Skmacycxgb_get_adapter_info(device_t dev) 316167514Skmacy{ 317167514Skmacy struct cxgb_ident *id; 318167514Skmacy const struct adapter_info *ai; 319167514Skmacy 320167514Skmacy id = cxgb_get_ident(dev); 321167514Skmacy if (id == NULL) 322167514Skmacy return (NULL); 323167514Skmacy 324167514Skmacy ai = t3_get_adapter_info(id->index); 325167514Skmacy 326167514Skmacy return (ai); 327167514Skmacy} 328167514Skmacy 329167514Skmacystatic int 330167514Skmacycxgb_controller_probe(device_t dev) 331167514Skmacy{ 332167514Skmacy const struct adapter_info *ai; 333167514Skmacy char *ports, buf[80]; 334170654Skmacy int nports; 335170654Skmacy 336167514Skmacy ai = cxgb_get_adapter_info(dev); 337167514Skmacy if (ai == NULL) 338167514Skmacy return (ENXIO); 339167514Skmacy 340170654Skmacy nports = ai->nports0 + ai->nports1; 341170654Skmacy if (nports == 1) 342167514Skmacy ports = "port"; 343167514Skmacy else 344167514Skmacy ports = "ports"; 345167514Skmacy 346170654Skmacy snprintf(buf, sizeof(buf), "%s RNIC, %d %s", ai->desc, nports, ports); 347167514Skmacy device_set_desc_copy(dev, buf); 348167514Skmacy return (BUS_PROBE_DEFAULT); 349167514Skmacy} 350167514Skmacy 351171471Skmacy#define FW_FNAME "t3fw%d%d%d" 352171471Skmacy#define TPEEPROM_NAME "t3%ctpe%d%d%d" 353171471Skmacy#define TPSRAM_NAME "t3%cps%d%d%d" 354171471Skmacy 355167514Skmacystatic int 356169978Skmacyupgrade_fw(adapter_t *sc) 357167514Skmacy{ 358167514Skmacy char buf[32]; 359167514Skmacy#ifdef FIRMWARE_LATEST 360167514Skmacy const struct firmware *fw; 361167514Skmacy#else 362167514Skmacy struct firmware *fw; 363167514Skmacy#endif 364167514Skmacy int status; 365167514Skmacy 366171471Skmacy snprintf(&buf[0], sizeof(buf), FW_FNAME, FW_VERSION_MAJOR, 367169978Skmacy FW_VERSION_MINOR, FW_VERSION_MICRO); 368167514Skmacy 369167514Skmacy fw = firmware_get(buf); 370167514Skmacy 371167514Skmacy if (fw == NULL) { 372169978Skmacy device_printf(sc->dev, "Could not find firmware image %s\n", buf); 373169978Skmacy return (ENOENT); 374171471Skmacy } else 375171471Skmacy device_printf(sc->dev, "updating firmware on card with %s\n", buf); 376167514Skmacy status = t3_load_fw(sc, (const uint8_t *)fw->data, fw->datasize); 377167514Skmacy 378171471Skmacy device_printf(sc->dev, "firmware update returned %s %d\n", (status == 0) ? "success" : "fail", status); 379171471Skmacy 380167514Skmacy firmware_put(fw, FIRMWARE_UNLOAD); 381167514Skmacy 382167514Skmacy return (status); 383167514Skmacy} 384167514Skmacy 385167514Skmacystatic int 386167514Skmacycxgb_controller_attach(device_t dev) 387167514Skmacy{ 388167514Skmacy device_t child; 389167514Skmacy const struct adapter_info *ai; 390167514Skmacy struct adapter *sc; 391172109Skmacy int i, error = 0; 392167514Skmacy uint32_t vers; 393167760Skmacy int port_qsets = 1; 394171868Skmacy#ifdef MSI_SUPPORTED 395172109Skmacy int msi_needed, reg; 396171868Skmacy#endif 397167514Skmacy sc = device_get_softc(dev); 398167514Skmacy sc->dev = dev; 399169978Skmacy sc->msi_count = 0; 400172109Skmacy ai = cxgb_get_adapter_info(dev); 401172109Skmacy 402172109Skmacy /* 403172109Skmacy * XXX not really related but a recent addition 404172109Skmacy */ 405172109Skmacy#ifdef MSI_SUPPORTED 406167840Skmacy /* find the PCIe link width and set max read request to 4KB*/ 407167840Skmacy if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 408167840Skmacy uint16_t lnk, pectl; 409167840Skmacy lnk = pci_read_config(dev, reg + 0x12, 2); 410167840Skmacy sc->link_width = (lnk >> 4) & 0x3f; 411167840Skmacy 412167840Skmacy pectl = pci_read_config(dev, reg + 0x8, 2); 413167840Skmacy pectl = (pectl & ~0x7000) | (5 << 12); 414167840Skmacy pci_write_config(dev, reg + 0x8, pectl, 2); 415167840Skmacy } 416171471Skmacy 417171471Skmacy if (sc->link_width != 0 && sc->link_width <= 4 && 418171471Skmacy (ai->nports0 + ai->nports1) <= 2) { 419167840Skmacy device_printf(sc->dev, 420167862Skmacy "PCIe x%d Link, expect reduced performance\n", 421167840Skmacy sc->link_width); 422167840Skmacy } 423172109Skmacy#endif 424171978Skmacy touch_bars(dev); 425167514Skmacy pci_enable_busmaster(dev); 426167514Skmacy /* 427167514Skmacy * Allocate the registers and make them available to the driver. 428167514Skmacy * The registers that we care about for NIC mode are in BAR 0 429167514Skmacy */ 430167514Skmacy sc->regs_rid = PCIR_BAR(0); 431167514Skmacy if ((sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 432167514Skmacy &sc->regs_rid, RF_ACTIVE)) == NULL) { 433167514Skmacy device_printf(dev, "Cannot allocate BAR\n"); 434167514Skmacy return (ENXIO); 435167514Skmacy } 436167514Skmacy 437170869Skmacy snprintf(sc->lockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb controller lock %d", 438170869Skmacy device_get_unit(dev)); 439170869Skmacy ADAPTER_LOCK_INIT(sc, sc->lockbuf); 440170869Skmacy 441170869Skmacy snprintf(sc->reglockbuf, ADAPTER_LOCK_NAME_LEN, "SGE reg lock %d", 442170869Skmacy device_get_unit(dev)); 443170869Skmacy snprintf(sc->mdiolockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb mdio lock %d", 444170869Skmacy device_get_unit(dev)); 445170869Skmacy snprintf(sc->elmerlockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb elmer lock %d", 446170869Skmacy device_get_unit(dev)); 447167514Skmacy 448170869Skmacy MTX_INIT(&sc->sge.reg_lock, sc->reglockbuf, NULL, MTX_DEF); 449170869Skmacy MTX_INIT(&sc->mdio_lock, sc->mdiolockbuf, NULL, MTX_DEF); 450170869Skmacy MTX_INIT(&sc->elmer_lock, sc->elmerlockbuf, NULL, MTX_DEF); 451170869Skmacy 452167514Skmacy sc->bt = rman_get_bustag(sc->regs_res); 453167514Skmacy sc->bh = rman_get_bushandle(sc->regs_res); 454167514Skmacy sc->mmio_len = rman_get_size(sc->regs_res); 455167769Skmacy 456167769Skmacy if (t3_prep_adapter(sc, ai, 1) < 0) { 457170654Skmacy printf("prep adapter failed\n"); 458167769Skmacy error = ENODEV; 459167769Skmacy goto out; 460167769Skmacy } 461167514Skmacy /* Allocate the BAR for doing MSI-X. If it succeeds, try to allocate 462167514Skmacy * enough messages for the queue sets. If that fails, try falling 463167514Skmacy * back to MSI. If that fails, then try falling back to the legacy 464167514Skmacy * interrupt pin model. 465167514Skmacy */ 466167514Skmacy#ifdef MSI_SUPPORTED 467167760Skmacy 468167514Skmacy sc->msix_regs_rid = 0x20; 469167514Skmacy if ((msi_allowed >= 2) && 470167514Skmacy (sc->msix_regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 471167514Skmacy &sc->msix_regs_rid, RF_ACTIVE)) != NULL) { 472167514Skmacy 473169978Skmacy msi_needed = sc->msi_count = SGE_MSIX_COUNT; 474167760Skmacy 475169978Skmacy if (((error = pci_alloc_msix(dev, &sc->msi_count)) != 0) || 476169978Skmacy (sc->msi_count != msi_needed)) { 477169978Skmacy device_printf(dev, "msix allocation failed - msi_count = %d" 478169978Skmacy " msi_needed=%d will try msi err=%d\n", sc->msi_count, 479169978Skmacy msi_needed, error); 480169978Skmacy sc->msi_count = 0; 481167514Skmacy pci_release_msi(dev); 482167514Skmacy bus_release_resource(dev, SYS_RES_MEMORY, 483167514Skmacy sc->msix_regs_rid, sc->msix_regs_res); 484167514Skmacy sc->msix_regs_res = NULL; 485167514Skmacy } else { 486167514Skmacy sc->flags |= USING_MSIX; 487170081Skmacy sc->cxgb_intr = t3_intr_msix; 488167514Skmacy } 489167514Skmacy } 490167514Skmacy 491169978Skmacy if ((msi_allowed >= 1) && (sc->msi_count == 0)) { 492169978Skmacy sc->msi_count = 1; 493169978Skmacy if (pci_alloc_msi(dev, &sc->msi_count)) { 494167760Skmacy device_printf(dev, "alloc msi failed - will try INTx\n"); 495169978Skmacy sc->msi_count = 0; 496167514Skmacy pci_release_msi(dev); 497167514Skmacy } else { 498167514Skmacy sc->flags |= USING_MSI; 499167514Skmacy sc->irq_rid = 1; 500170081Skmacy sc->cxgb_intr = t3_intr_msi; 501167514Skmacy } 502167514Skmacy } 503167514Skmacy#endif 504169978Skmacy if (sc->msi_count == 0) { 505167760Skmacy device_printf(dev, "using line interrupts\n"); 506167514Skmacy sc->irq_rid = 0; 507170081Skmacy sc->cxgb_intr = t3b_intr; 508167514Skmacy } 509167514Skmacy 510167514Skmacy 511167514Skmacy /* Create a private taskqueue thread for handling driver events */ 512167514Skmacy#ifdef TASKQUEUE_CURRENT 513167514Skmacy sc->tq = taskqueue_create("cxgb_taskq", M_NOWAIT, 514167514Skmacy taskqueue_thread_enqueue, &sc->tq); 515167514Skmacy#else 516167514Skmacy sc->tq = taskqueue_create_fast("cxgb_taskq", M_NOWAIT, 517167514Skmacy taskqueue_thread_enqueue, &sc->tq); 518167514Skmacy#endif 519167514Skmacy if (sc->tq == NULL) { 520167514Skmacy device_printf(dev, "failed to allocate controller task queue\n"); 521167514Skmacy goto out; 522167514Skmacy } 523171804Skmacy 524167514Skmacy taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq", 525167514Skmacy device_get_nameunit(dev)); 526167514Skmacy TASK_INIT(&sc->ext_intr_task, 0, cxgb_ext_intr_handler, sc); 527170869Skmacy TASK_INIT(&sc->tick_task, 0, cxgb_tick_handler, sc); 528167514Skmacy 529167514Skmacy 530167514Skmacy /* Create a periodic callout for checking adapter status */ 531170869Skmacy callout_init(&sc->cxgb_tick_ch, TRUE); 532167514Skmacy 533167514Skmacy if (t3_check_fw_version(sc) != 0) { 534167514Skmacy /* 535167514Skmacy * Warn user that a firmware update will be attempted in init. 536167514Skmacy */ 537169978Skmacy device_printf(dev, "firmware needs to be updated to version %d.%d.%d\n", 538169978Skmacy FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO); 539167514Skmacy sc->flags &= ~FW_UPTODATE; 540167514Skmacy } else { 541167514Skmacy sc->flags |= FW_UPTODATE; 542167514Skmacy } 543171471Skmacy 544171471Skmacy if (t3_check_tpsram_version(sc) != 0) { 545171471Skmacy /* 546171471Skmacy * Warn user that a firmware update will be attempted in init. 547171471Skmacy */ 548171471Skmacy device_printf(dev, "SRAM needs to be updated to version %c-%d.%d.%d\n", 549171471Skmacy t3rev2char(sc), TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); 550171471Skmacy sc->flags &= ~TPS_UPTODATE; 551171471Skmacy } else { 552171471Skmacy sc->flags |= TPS_UPTODATE; 553171471Skmacy } 554167514Skmacy 555169978Skmacy if ((sc->flags & USING_MSIX) && !singleq) 556167760Skmacy port_qsets = min((SGE_QSETS/(sc)->params.nports), mp_ncpus); 557167760Skmacy 558167514Skmacy /* 559167514Skmacy * Create a child device for each MAC. The ethernet attachment 560167514Skmacy * will be done in these children. 561167760Skmacy */ 562167760Skmacy for (i = 0; i < (sc)->params.nports; i++) { 563171978Skmacy struct port_info *pi; 564171978Skmacy 565167514Skmacy if ((child = device_add_child(dev, "cxgb", -1)) == NULL) { 566167514Skmacy device_printf(dev, "failed to add child port\n"); 567167514Skmacy error = EINVAL; 568167514Skmacy goto out; 569167514Skmacy } 570171978Skmacy pi = &sc->port[i]; 571171978Skmacy pi->adapter = sc; 572171978Skmacy pi->nqsets = port_qsets; 573171978Skmacy pi->first_qset = i*port_qsets; 574171978Skmacy pi->port_id = i; 575171978Skmacy pi->tx_chan = i >= ai->nports0; 576171978Skmacy pi->txpkt_intf = pi->tx_chan ? 2 * (i - ai->nports0) + 1 : 2 * i; 577171978Skmacy sc->rxpkt_map[pi->txpkt_intf] = i; 578171471Skmacy sc->portdev[i] = child; 579171978Skmacy device_set_softc(child, pi); 580167514Skmacy } 581167514Skmacy if ((error = bus_generic_attach(dev)) != 0) 582167514Skmacy goto out; 583167514Skmacy 584169978Skmacy /* 585169978Skmacy * XXX need to poll for link status 586169978Skmacy */ 587167514Skmacy sc->params.stats_update_period = 1; 588167514Skmacy 589167514Skmacy /* initialize sge private state */ 590170654Skmacy t3_sge_init_adapter(sc); 591167514Skmacy 592167514Skmacy t3_led_ready(sc); 593169978Skmacy 594169978Skmacy cxgb_offload_init(); 595169978Skmacy if (is_offload(sc)) { 596169978Skmacy setbit(&sc->registered_device_map, OFFLOAD_DEVMAP_BIT); 597169978Skmacy cxgb_adapter_ofld(sc); 598169978Skmacy } 599167514Skmacy error = t3_get_fw_version(sc, &vers); 600167514Skmacy if (error) 601167514Skmacy goto out; 602167514Skmacy 603169978Skmacy snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d.%d", 604169978Skmacy G_FW_VERSION_MAJOR(vers), G_FW_VERSION_MINOR(vers), 605169978Skmacy G_FW_VERSION_MICRO(vers)); 606169978Skmacy 607167514Skmacy t3_add_sysctls(sc); 608167514Skmacyout: 609167514Skmacy if (error) 610167514Skmacy cxgb_free(sc); 611167514Skmacy 612167514Skmacy return (error); 613167514Skmacy} 614167514Skmacy 615167514Skmacystatic int 616167514Skmacycxgb_controller_detach(device_t dev) 617167514Skmacy{ 618167514Skmacy struct adapter *sc; 619167514Skmacy 620167514Skmacy sc = device_get_softc(dev); 621167514Skmacy 622167514Skmacy cxgb_free(sc); 623167514Skmacy 624167514Skmacy return (0); 625167514Skmacy} 626167514Skmacy 627167514Skmacystatic void 628167514Skmacycxgb_free(struct adapter *sc) 629167514Skmacy{ 630167514Skmacy int i; 631167514Skmacy 632170869Skmacy ADAPTER_LOCK(sc); 633170869Skmacy /* 634170869Skmacy * drops the lock 635170869Skmacy */ 636170869Skmacy cxgb_down_locked(sc); 637169978Skmacy 638169978Skmacy#ifdef MSI_SUPPORTED 639169978Skmacy if (sc->flags & (USING_MSI | USING_MSIX)) { 640169978Skmacy device_printf(sc->dev, "releasing msi message(s)\n"); 641169978Skmacy pci_release_msi(sc->dev); 642169978Skmacy } else { 643169978Skmacy device_printf(sc->dev, "no msi message to release\n"); 644169978Skmacy } 645169978Skmacy#endif 646169978Skmacy if (sc->msix_regs_res != NULL) { 647169978Skmacy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid, 648169978Skmacy sc->msix_regs_res); 649169978Skmacy } 650169978Skmacy 651167514Skmacy if (sc->tq != NULL) { 652167514Skmacy taskqueue_drain(sc->tq, &sc->ext_intr_task); 653170869Skmacy taskqueue_drain(sc->tq, &sc->tick_task); 654171978Skmacy } 655171978Skmacy t3_sge_deinit_sw(sc); 656171978Skmacy /* 657171978Skmacy * Wait for last callout 658171978Skmacy */ 659171978Skmacy 660171978Skmacy tsleep(&sc, 0, "cxgb unload", 3*hz); 661170869Skmacy 662167760Skmacy for (i = 0; i < (sc)->params.nports; ++i) { 663167760Skmacy if (sc->portdev[i] != NULL) 664167760Skmacy device_delete_child(sc->dev, sc->portdev[i]); 665167760Skmacy } 666167760Skmacy 667167514Skmacy bus_generic_detach(sc->dev); 668171978Skmacy if (sc->tq != NULL) 669171978Skmacy taskqueue_free(sc->tq); 670170654Skmacy#ifdef notyet 671169978Skmacy if (is_offload(sc)) { 672169978Skmacy cxgb_adapter_unofld(sc); 673169978Skmacy if (isset(&sc->open_device_map, OFFLOAD_DEVMAP_BIT)) 674169978Skmacy offload_close(&sc->tdev); 675169978Skmacy } 676171804Skmacy#endif 677171804Skmacy 678167514Skmacy t3_free_sge_resources(sc); 679171471Skmacy free(sc->filters, M_DEVBUF); 680167514Skmacy t3_sge_free(sc); 681170869Skmacy 682170869Skmacy cxgb_offload_exit(); 683170869Skmacy 684167514Skmacy if (sc->regs_res != NULL) 685167514Skmacy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->regs_rid, 686167514Skmacy sc->regs_res); 687167514Skmacy 688170869Skmacy MTX_DESTROY(&sc->mdio_lock); 689170869Skmacy MTX_DESTROY(&sc->sge.reg_lock); 690170869Skmacy MTX_DESTROY(&sc->elmer_lock); 691170869Skmacy ADAPTER_LOCK_DEINIT(sc); 692167514Skmacy 693167514Skmacy return; 694167514Skmacy} 695167514Skmacy 696167514Skmacy/** 697167514Skmacy * setup_sge_qsets - configure SGE Tx/Rx/response queues 698167514Skmacy * @sc: the controller softc 699167514Skmacy * 700167514Skmacy * Determines how many sets of SGE queues to use and initializes them. 701167514Skmacy * We support multiple queue sets per port if we have MSI-X, otherwise 702167514Skmacy * just one queue set per port. 703167514Skmacy */ 704167514Skmacystatic int 705167514Skmacysetup_sge_qsets(adapter_t *sc) 706167514Skmacy{ 707172096Skmacy int i, j, err, irq_idx = 0, qset_idx = 0; 708169978Skmacy u_int ntxq = SGE_TXQ_PER_SET; 709167514Skmacy 710167514Skmacy if ((err = t3_sge_alloc(sc)) != 0) { 711167760Skmacy device_printf(sc->dev, "t3_sge_alloc returned %d\n", err); 712167514Skmacy return (err); 713167514Skmacy } 714167514Skmacy 715167514Skmacy if (sc->params.rev > 0 && !(sc->flags & USING_MSI)) 716167514Skmacy irq_idx = -1; 717167514Skmacy 718172096Skmacy for (i = 0; i < (sc)->params.nports; i++) { 719167514Skmacy struct port_info *pi = &sc->port[i]; 720167514Skmacy 721171978Skmacy for (j = 0; j < pi->nqsets; j++, qset_idx++) { 722167760Skmacy err = t3_sge_alloc_qset(sc, qset_idx, (sc)->params.nports, 723167514Skmacy (sc->flags & USING_MSIX) ? qset_idx + 1 : irq_idx, 724167514Skmacy &sc->params.sge.qset[qset_idx], ntxq, pi); 725167514Skmacy if (err) { 726167514Skmacy t3_free_sge_resources(sc); 727171978Skmacy device_printf(sc->dev, "t3_sge_alloc_qset failed with %d\n", 728171978Skmacy err); 729167514Skmacy return (err); 730167514Skmacy } 731167514Skmacy } 732167514Skmacy } 733167514Skmacy 734167514Skmacy return (0); 735167514Skmacy} 736167514Skmacy 737170654Skmacystatic void 738170654Skmacycxgb_teardown_msix(adapter_t *sc) 739170654Skmacy{ 740170654Skmacy int i, nqsets; 741170654Skmacy 742170654Skmacy for (nqsets = i = 0; i < (sc)->params.nports; i++) 743170654Skmacy nqsets += sc->port[i].nqsets; 744170654Skmacy 745170654Skmacy for (i = 0; i < nqsets; i++) { 746170654Skmacy if (sc->msix_intr_tag[i] != NULL) { 747170654Skmacy bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 748170654Skmacy sc->msix_intr_tag[i]); 749170654Skmacy sc->msix_intr_tag[i] = NULL; 750170654Skmacy } 751170654Skmacy if (sc->msix_irq_res[i] != NULL) { 752170654Skmacy bus_release_resource(sc->dev, SYS_RES_IRQ, 753170654Skmacy sc->msix_irq_rid[i], sc->msix_irq_res[i]); 754170654Skmacy sc->msix_irq_res[i] = NULL; 755170654Skmacy } 756170654Skmacy } 757170654Skmacy} 758170654Skmacy 759167514Skmacystatic int 760167514Skmacycxgb_setup_msix(adapter_t *sc, int msix_count) 761167514Skmacy{ 762167514Skmacy int i, j, k, nqsets, rid; 763167514Skmacy 764167514Skmacy /* The first message indicates link changes and error conditions */ 765167514Skmacy sc->irq_rid = 1; 766167514Skmacy if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 767167514Skmacy &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 768167514Skmacy device_printf(sc->dev, "Cannot allocate msix interrupt\n"); 769167514Skmacy return (EINVAL); 770167514Skmacy } 771167760Skmacy 772167514Skmacy if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET, 773167514Skmacy#ifdef INTR_FILTERS 774171978Skmacy NULL, 775167514Skmacy#endif 776167514Skmacy cxgb_async_intr, sc, &sc->intr_tag)) { 777167514Skmacy device_printf(sc->dev, "Cannot set up interrupt\n"); 778167514Skmacy return (EINVAL); 779167514Skmacy } 780170654Skmacy for (i = k = 0; i < (sc)->params.nports; i++) { 781167514Skmacy nqsets = sc->port[i].nqsets; 782170654Skmacy for (j = 0; j < nqsets; j++, k++) { 783167514Skmacy struct sge_qset *qs = &sc->sge.qs[k]; 784171804Skmacy 785167514Skmacy rid = k + 2; 786167514Skmacy if (cxgb_debug) 787167514Skmacy printf("rid=%d ", rid); 788167514Skmacy if ((sc->msix_irq_res[k] = bus_alloc_resource_any( 789167514Skmacy sc->dev, SYS_RES_IRQ, &rid, 790167514Skmacy RF_SHAREABLE | RF_ACTIVE)) == NULL) { 791167514Skmacy device_printf(sc->dev, "Cannot allocate " 792167514Skmacy "interrupt for message %d\n", rid); 793167514Skmacy return (EINVAL); 794167514Skmacy } 795167514Skmacy sc->msix_irq_rid[k] = rid; 796171978Skmacy printf("setting up interrupt for port=%d\n", 797171978Skmacy qs->port->port_id); 798170654Skmacy if (bus_setup_intr(sc->dev, sc->msix_irq_res[k], 799167514Skmacy INTR_MPSAFE|INTR_TYPE_NET, 800167514Skmacy#ifdef INTR_FILTERS 801171978Skmacy NULL, 802167514Skmacy#endif 803167514Skmacy t3_intr_msix, qs, &sc->msix_intr_tag[k])) { 804167514Skmacy device_printf(sc->dev, "Cannot set up " 805167514Skmacy "interrupt for message %d\n", rid); 806167514Skmacy return (EINVAL); 807167514Skmacy } 808167514Skmacy } 809167514Skmacy } 810167760Skmacy 811167760Skmacy 812167514Skmacy return (0); 813167514Skmacy} 814167514Skmacy 815167514Skmacystatic int 816167514Skmacycxgb_port_probe(device_t dev) 817167514Skmacy{ 818167514Skmacy struct port_info *p; 819167514Skmacy char buf[80]; 820167514Skmacy 821167514Skmacy p = device_get_softc(dev); 822167514Skmacy 823171803Skmacy snprintf(buf, sizeof(buf), "Port %d %s", p->port_id, p->port_type->desc); 824167514Skmacy device_set_desc_copy(dev, buf); 825167514Skmacy return (0); 826167514Skmacy} 827167514Skmacy 828167514Skmacy 829167514Skmacystatic int 830167514Skmacycxgb_makedev(struct port_info *pi) 831167514Skmacy{ 832167514Skmacy 833170654Skmacy pi->port_cdev = make_dev(&cxgb_cdevsw, pi->ifp->if_dunit, 834170654Skmacy UID_ROOT, GID_WHEEL, 0600, if_name(pi->ifp)); 835167514Skmacy 836167514Skmacy if (pi->port_cdev == NULL) 837167514Skmacy return (ENOMEM); 838167514Skmacy 839167514Skmacy pi->port_cdev->si_drv1 = (void *)pi; 840167514Skmacy 841167514Skmacy return (0); 842167514Skmacy} 843167514Skmacy 844167514Skmacy 845167514Skmacy#ifdef TSO_SUPPORTED 846167514Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU) 847167514Skmacy/* Don't enable TSO6 yet */ 848167514Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO4 | IFCAP_JUMBO_MTU) 849167514Skmacy#else 850167514Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU) 851167514Skmacy/* Don't enable TSO6 yet */ 852167514Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU) 853167514Skmacy#define IFCAP_TSO4 0x0 854171868Skmacy#define IFCAP_TSO6 0x0 855167514Skmacy#define CSUM_TSO 0x0 856167514Skmacy#endif 857167514Skmacy 858167514Skmacy 859167514Skmacystatic int 860167514Skmacycxgb_port_attach(device_t dev) 861167514Skmacy{ 862167514Skmacy struct port_info *p; 863167514Skmacy struct ifnet *ifp; 864170654Skmacy int err, media_flags; 865167514Skmacy 866167514Skmacy p = device_get_softc(dev); 867167514Skmacy 868170869Skmacy snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d", 869171803Skmacy device_get_unit(device_get_parent(dev)), p->port_id); 870170869Skmacy PORT_LOCK_INIT(p, p->lockbuf); 871167514Skmacy 872167514Skmacy /* Allocate an ifnet object and set it up */ 873167514Skmacy ifp = p->ifp = if_alloc(IFT_ETHER); 874167514Skmacy if (ifp == NULL) { 875167514Skmacy device_printf(dev, "Cannot allocate ifnet\n"); 876167514Skmacy return (ENOMEM); 877167514Skmacy } 878167514Skmacy 879167514Skmacy /* 880167514Skmacy * Note that there is currently no watchdog timer. 881167514Skmacy */ 882167514Skmacy if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 883167514Skmacy ifp->if_init = cxgb_init; 884167514Skmacy ifp->if_softc = p; 885167514Skmacy ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 886167514Skmacy ifp->if_ioctl = cxgb_ioctl; 887167514Skmacy ifp->if_start = cxgb_start; 888167514Skmacy ifp->if_timer = 0; /* Disable ifnet watchdog */ 889167514Skmacy ifp->if_watchdog = NULL; 890167514Skmacy 891167514Skmacy ifp->if_snd.ifq_drv_maxlen = TX_ETH_Q_SIZE; 892167514Skmacy IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 893167514Skmacy IFQ_SET_READY(&ifp->if_snd); 894167514Skmacy 895167514Skmacy ifp->if_hwassist = ifp->if_capabilities = ifp->if_capenable = 0; 896167514Skmacy ifp->if_capabilities |= CXGB_CAP; 897167514Skmacy ifp->if_capenable |= CXGB_CAP_ENABLE; 898167514Skmacy ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO); 899171471Skmacy /* 900171471Skmacy * disable TSO on 4-port - it isn't supported by the firmware yet 901171471Skmacy */ 902171471Skmacy if (p->adapter->params.nports > 2) { 903171471Skmacy ifp->if_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6); 904171471Skmacy ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TSO6); 905171471Skmacy ifp->if_hwassist &= ~CSUM_TSO; 906171471Skmacy } 907171471Skmacy 908167514Skmacy ether_ifattach(ifp, p->hw_addr); 909171471Skmacy /* 910171471Skmacy * Only default to jumbo frames on 10GigE 911171471Skmacy */ 912171471Skmacy if (p->adapter->params.nports <= 2) 913171471Skmacy ifp->if_mtu = 9000; 914167514Skmacy if ((err = cxgb_makedev(p)) != 0) { 915167514Skmacy printf("makedev failed %d\n", err); 916167514Skmacy return (err); 917167514Skmacy } 918167514Skmacy ifmedia_init(&p->media, IFM_IMASK, cxgb_media_change, 919167514Skmacy cxgb_media_status); 920170654Skmacy 921170654Skmacy if (!strcmp(p->port_type->desc, "10GBASE-CX4")) { 922170654Skmacy media_flags = IFM_ETHER | IFM_10G_CX4 | IFM_FDX; 923170654Skmacy } else if (!strcmp(p->port_type->desc, "10GBASE-SR")) { 924170654Skmacy media_flags = IFM_ETHER | IFM_10G_SR | IFM_FDX; 925170654Skmacy } else if (!strcmp(p->port_type->desc, "10GBASE-XR")) { 926170654Skmacy media_flags = IFM_ETHER | IFM_10G_LR | IFM_FDX; 927170654Skmacy } else if (!strcmp(p->port_type->desc, "10/100/1000BASE-T")) { 928170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_10_T, 0, NULL); 929170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_10_T | IFM_FDX, 930170654Skmacy 0, NULL); 931170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX, 932170654Skmacy 0, NULL); 933170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX | IFM_FDX, 934170654Skmacy 0, NULL); 935170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_1000_T | IFM_FDX, 936170654Skmacy 0, NULL); 937170654Skmacy media_flags = 0; 938170654Skmacy } else { 939167514Skmacy printf("unsupported media type %s\n", p->port_type->desc); 940167514Skmacy return (ENXIO); 941167514Skmacy } 942170654Skmacy if (media_flags) { 943170654Skmacy ifmedia_add(&p->media, media_flags, 0, NULL); 944170654Skmacy ifmedia_set(&p->media, media_flags); 945170654Skmacy } else { 946170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL); 947170654Skmacy ifmedia_set(&p->media, IFM_ETHER | IFM_AUTO); 948170654Skmacy } 949167514Skmacy 950170654Skmacy 951171803Skmacy snprintf(p->taskqbuf, TASKQ_NAME_LEN, "cxgb_port_taskq%d", p->port_id); 952167514Skmacy#ifdef TASKQUEUE_CURRENT 953167514Skmacy /* Create a port for handling TX without starvation */ 954170869Skmacy p->tq = taskqueue_create(p->taskqbuf, M_NOWAIT, 955167514Skmacy taskqueue_thread_enqueue, &p->tq); 956167514Skmacy#else 957167514Skmacy /* Create a port for handling TX without starvation */ 958171868Skmacy p->tq = taskqueue_create_fast(p->taskqbuf, M_NOWAIT, 959167514Skmacy taskqueue_thread_enqueue, &p->tq); 960167514Skmacy#endif 961170654Skmacy 962167514Skmacy if (p->tq == NULL) { 963167514Skmacy device_printf(dev, "failed to allocate port task queue\n"); 964167514Skmacy return (ENOMEM); 965167514Skmacy } 966167514Skmacy taskqueue_start_threads(&p->tq, 1, PI_NET, "%s taskq", 967167514Skmacy device_get_nameunit(dev)); 968171804Skmacy 969167514Skmacy TASK_INIT(&p->start_task, 0, cxgb_start_proc, ifp); 970167514Skmacy 971170654Skmacy t3_sge_init_port(p); 972170654Skmacy 973167514Skmacy return (0); 974167514Skmacy} 975167514Skmacy 976167514Skmacystatic int 977167514Skmacycxgb_port_detach(device_t dev) 978167514Skmacy{ 979167514Skmacy struct port_info *p; 980167514Skmacy 981167514Skmacy p = device_get_softc(dev); 982169978Skmacy 983169978Skmacy PORT_LOCK(p); 984170654Skmacy if (p->ifp->if_drv_flags & IFF_DRV_RUNNING) 985170654Skmacy cxgb_stop_locked(p); 986169978Skmacy PORT_UNLOCK(p); 987169978Skmacy 988167514Skmacy if (p->tq != NULL) { 989167514Skmacy taskqueue_drain(p->tq, &p->start_task); 990167514Skmacy taskqueue_free(p->tq); 991167514Skmacy p->tq = NULL; 992167514Skmacy } 993170869Skmacy 994171978Skmacy ether_ifdetach(p->ifp); 995171978Skmacy /* 996171978Skmacy * the lock may be acquired in ifdetach 997171978Skmacy */ 998170869Skmacy PORT_LOCK_DEINIT(p); 999167514Skmacy if_free(p->ifp); 1000167514Skmacy 1001170654Skmacy if (p->port_cdev != NULL) 1002170654Skmacy destroy_dev(p->port_cdev); 1003170654Skmacy 1004167514Skmacy return (0); 1005167514Skmacy} 1006167514Skmacy 1007167514Skmacyvoid 1008167514Skmacyt3_fatal_err(struct adapter *sc) 1009167514Skmacy{ 1010167514Skmacy u_int fw_status[4]; 1011172096Skmacy 1012172096Skmacy if (sc->flags & FULL_INIT_DONE) { 1013172096Skmacy t3_sge_stop(sc); 1014172096Skmacy t3_write_reg(sc, A_XGM_TX_CTRL, 0); 1015172096Skmacy t3_write_reg(sc, A_XGM_RX_CTRL, 0); 1016172096Skmacy t3_write_reg(sc, XGM_REG(A_XGM_TX_CTRL, 1), 0); 1017172096Skmacy t3_write_reg(sc, XGM_REG(A_XGM_RX_CTRL, 1), 0); 1018172096Skmacy t3_intr_disable(sc); 1019172096Skmacy } 1020167514Skmacy device_printf(sc->dev,"encountered fatal error, operation suspended\n"); 1021167514Skmacy if (!t3_cim_ctl_blk_read(sc, 0xa0, 4, fw_status)) 1022167514Skmacy device_printf(sc->dev, "FW_ status: 0x%x, 0x%x, 0x%x, 0x%x\n", 1023167514Skmacy fw_status[0], fw_status[1], fw_status[2], fw_status[3]); 1024167514Skmacy} 1025167514Skmacy 1026167514Skmacyint 1027167514Skmacyt3_os_find_pci_capability(adapter_t *sc, int cap) 1028167514Skmacy{ 1029167514Skmacy device_t dev; 1030167514Skmacy struct pci_devinfo *dinfo; 1031167514Skmacy pcicfgregs *cfg; 1032167514Skmacy uint32_t status; 1033167514Skmacy uint8_t ptr; 1034167514Skmacy 1035167514Skmacy dev = sc->dev; 1036167514Skmacy dinfo = device_get_ivars(dev); 1037167514Skmacy cfg = &dinfo->cfg; 1038167514Skmacy 1039167514Skmacy status = pci_read_config(dev, PCIR_STATUS, 2); 1040167514Skmacy if (!(status & PCIM_STATUS_CAPPRESENT)) 1041167514Skmacy return (0); 1042167514Skmacy 1043167514Skmacy switch (cfg->hdrtype & PCIM_HDRTYPE) { 1044167514Skmacy case 0: 1045167514Skmacy case 1: 1046167514Skmacy ptr = PCIR_CAP_PTR; 1047167514Skmacy break; 1048167514Skmacy case 2: 1049167514Skmacy ptr = PCIR_CAP_PTR_2; 1050167514Skmacy break; 1051167514Skmacy default: 1052167514Skmacy return (0); 1053167514Skmacy break; 1054167514Skmacy } 1055167514Skmacy ptr = pci_read_config(dev, ptr, 1); 1056167514Skmacy 1057167514Skmacy while (ptr != 0) { 1058167514Skmacy if (pci_read_config(dev, ptr + PCICAP_ID, 1) == cap) 1059167514Skmacy return (ptr); 1060167514Skmacy ptr = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1); 1061167514Skmacy } 1062167514Skmacy 1063167514Skmacy return (0); 1064167514Skmacy} 1065167514Skmacy 1066167514Skmacyint 1067167514Skmacyt3_os_pci_save_state(struct adapter *sc) 1068167514Skmacy{ 1069167514Skmacy device_t dev; 1070167514Skmacy struct pci_devinfo *dinfo; 1071167514Skmacy 1072167514Skmacy dev = sc->dev; 1073167514Skmacy dinfo = device_get_ivars(dev); 1074167514Skmacy 1075167514Skmacy pci_cfg_save(dev, dinfo, 0); 1076167514Skmacy return (0); 1077167514Skmacy} 1078167514Skmacy 1079167514Skmacyint 1080167514Skmacyt3_os_pci_restore_state(struct adapter *sc) 1081167514Skmacy{ 1082167514Skmacy device_t dev; 1083167514Skmacy struct pci_devinfo *dinfo; 1084167514Skmacy 1085167514Skmacy dev = sc->dev; 1086167514Skmacy dinfo = device_get_ivars(dev); 1087167514Skmacy 1088167514Skmacy pci_cfg_restore(dev, dinfo); 1089167514Skmacy return (0); 1090167514Skmacy} 1091167514Skmacy 1092167514Skmacy/** 1093167514Skmacy * t3_os_link_changed - handle link status changes 1094167514Skmacy * @adapter: the adapter associated with the link change 1095167514Skmacy * @port_id: the port index whose limk status has changed 1096167514Skmacy * @link_stat: the new status of the link 1097167514Skmacy * @speed: the new speed setting 1098167514Skmacy * @duplex: the new duplex setting 1099167514Skmacy * @fc: the new flow-control setting 1100167514Skmacy * 1101167514Skmacy * This is the OS-dependent handler for link status changes. The OS 1102167514Skmacy * neutral handler takes care of most of the processing for these events, 1103167514Skmacy * then calls this handler for any OS-specific processing. 1104167514Skmacy */ 1105167514Skmacyvoid 1106167514Skmacyt3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed, 1107167514Skmacy int duplex, int fc) 1108167514Skmacy{ 1109167514Skmacy struct port_info *pi = &adapter->port[port_id]; 1110169978Skmacy struct cmac *mac = &adapter->port[port_id].mac; 1111167514Skmacy 1112167514Skmacy if ((pi->ifp->if_flags & IFF_UP) == 0) 1113167514Skmacy return; 1114169978Skmacy 1115169978Skmacy if (link_status) { 1116169978Skmacy t3_mac_enable(mac, MAC_DIRECTION_RX); 1117167514Skmacy if_link_state_change(pi->ifp, LINK_STATE_UP); 1118169978Skmacy } else { 1119167514Skmacy if_link_state_change(pi->ifp, LINK_STATE_DOWN); 1120169978Skmacy pi->phy.ops->power_down(&pi->phy, 1); 1121169978Skmacy t3_mac_disable(mac, MAC_DIRECTION_RX); 1122169978Skmacy t3_link_start(&pi->phy, mac, &pi->link_config); 1123169978Skmacy } 1124167514Skmacy} 1125167514Skmacy 1126167514Skmacy/* 1127167514Skmacy * Interrupt-context handler for external (PHY) interrupts. 1128167514Skmacy */ 1129167514Skmacyvoid 1130167514Skmacyt3_os_ext_intr_handler(adapter_t *sc) 1131167514Skmacy{ 1132167514Skmacy if (cxgb_debug) 1133167514Skmacy printf("t3_os_ext_intr_handler\n"); 1134167514Skmacy /* 1135167514Skmacy * Schedule a task to handle external interrupts as they may be slow 1136167514Skmacy * and we use a mutex to protect MDIO registers. We disable PHY 1137167514Skmacy * interrupts in the meantime and let the task reenable them when 1138167514Skmacy * it's done. 1139167514Skmacy */ 1140169978Skmacy ADAPTER_LOCK(sc); 1141167514Skmacy if (sc->slow_intr_mask) { 1142167514Skmacy sc->slow_intr_mask &= ~F_T3DBG; 1143167514Skmacy t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask); 1144167514Skmacy taskqueue_enqueue(sc->tq, &sc->ext_intr_task); 1145167514Skmacy } 1146169978Skmacy ADAPTER_UNLOCK(sc); 1147167514Skmacy} 1148167514Skmacy 1149167514Skmacyvoid 1150167514Skmacyt3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[]) 1151167514Skmacy{ 1152167514Skmacy 1153167514Skmacy /* 1154167514Skmacy * The ifnet might not be allocated before this gets called, 1155167514Skmacy * as this is called early on in attach by t3_prep_adapter 1156167514Skmacy * save the address off in the port structure 1157167514Skmacy */ 1158167514Skmacy if (cxgb_debug) 1159167514Skmacy printf("set_hw_addr on idx %d addr %6D\n", port_idx, hw_addr, ":"); 1160167514Skmacy bcopy(hw_addr, adapter->port[port_idx].hw_addr, ETHER_ADDR_LEN); 1161167514Skmacy} 1162167514Skmacy 1163167514Skmacy/** 1164167514Skmacy * link_start - enable a port 1165167514Skmacy * @p: the port to enable 1166167514Skmacy * 1167167514Skmacy * Performs the MAC and PHY actions needed to enable a port. 1168167514Skmacy */ 1169167514Skmacystatic void 1170167514Skmacycxgb_link_start(struct port_info *p) 1171167514Skmacy{ 1172167514Skmacy struct ifnet *ifp; 1173167514Skmacy struct t3_rx_mode rm; 1174167514Skmacy struct cmac *mac = &p->mac; 1175167514Skmacy 1176167514Skmacy ifp = p->ifp; 1177167514Skmacy 1178167514Skmacy t3_init_rx_mode(&rm, p); 1179172096Skmacy if (!mac->multiport) 1180171978Skmacy t3_mac_reset(mac); 1181170654Skmacy t3_mac_set_mtu(mac, ifp->if_mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN); 1182167514Skmacy t3_mac_set_address(mac, 0, p->hw_addr); 1183167514Skmacy t3_mac_set_rx_mode(mac, &rm); 1184167514Skmacy t3_link_start(&p->phy, mac, &p->link_config); 1185167514Skmacy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 1186167514Skmacy} 1187167514Skmacy 1188167514Skmacy/** 1189167514Skmacy * setup_rss - configure Receive Side Steering (per-queue connection demux) 1190167514Skmacy * @adap: the adapter 1191167514Skmacy * 1192167514Skmacy * Sets up RSS to distribute packets to multiple receive queues. We 1193167514Skmacy * configure the RSS CPU lookup table to distribute to the number of HW 1194167514Skmacy * receive queues, and the response queue lookup table to narrow that 1195167514Skmacy * down to the response queues actually configured for each port. 1196167514Skmacy * We always configure the RSS mapping for two ports since the mapping 1197167514Skmacy * table has plenty of entries. 1198167514Skmacy */ 1199167514Skmacystatic void 1200167514Skmacysetup_rss(adapter_t *adap) 1201167514Skmacy{ 1202167514Skmacy int i; 1203171471Skmacy u_int nq[2]; 1204167514Skmacy uint8_t cpus[SGE_QSETS + 1]; 1205167514Skmacy uint16_t rspq_map[RSS_TABLE_SIZE]; 1206171471Skmacy 1207167514Skmacy for (i = 0; i < SGE_QSETS; ++i) 1208167514Skmacy cpus[i] = i; 1209167514Skmacy cpus[SGE_QSETS] = 0xff; 1210167514Skmacy 1211171978Skmacy nq[0] = nq[1] = 0; 1212171978Skmacy for_each_port(adap, i) { 1213171978Skmacy const struct port_info *pi = adap2pinfo(adap, i); 1214171978Skmacy 1215171978Skmacy nq[pi->tx_chan] += pi->nqsets; 1216171978Skmacy } 1217172096Skmacy nq[0] = max(nq[0], 1U); 1218172096Skmacy nq[1] = max(nq[1], 1U); 1219167514Skmacy for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) { 1220172096Skmacy rspq_map[i] = i % nq[0]; 1221172096Skmacy rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq[1]) + nq[0]; 1222167514Skmacy } 1223171471Skmacy /* Calculate the reverse RSS map table */ 1224171471Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) 1225171471Skmacy if (adap->rrss_map[rspq_map[i]] == 0xff) 1226171471Skmacy adap->rrss_map[rspq_map[i]] = i; 1227167514Skmacy 1228167514Skmacy t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN | 1229171471Skmacy F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | F_OFDMAPEN | 1230172096Skmacy V_RRCPLCPUSIZE(6), cpus, rspq_map); 1231171471Skmacy 1232167514Skmacy} 1233167514Skmacy 1234169978Skmacy/* 1235169978Skmacy * Sends an mbuf to an offload queue driver 1236169978Skmacy * after dealing with any active network taps. 1237169978Skmacy */ 1238169978Skmacystatic inline int 1239174626Skmacyoffload_tx(struct t3cdev *tdev, struct mbuf *m) 1240169978Skmacy{ 1241169978Skmacy int ret; 1242169978Skmacy 1243169978Skmacy critical_enter(); 1244169978Skmacy ret = t3_offload_tx(tdev, m); 1245169978Skmacy critical_exit(); 1246170654Skmacy return (ret); 1247169978Skmacy} 1248169978Skmacy 1249169978Skmacystatic int 1250169978Skmacywrite_smt_entry(struct adapter *adapter, int idx) 1251169978Skmacy{ 1252169978Skmacy struct port_info *pi = &adapter->port[idx]; 1253169978Skmacy struct cpl_smt_write_req *req; 1254169978Skmacy struct mbuf *m; 1255169978Skmacy 1256169978Skmacy if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL) 1257169978Skmacy return (ENOMEM); 1258169978Skmacy 1259169978Skmacy req = mtod(m, struct cpl_smt_write_req *); 1260169978Skmacy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1261169978Skmacy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx)); 1262169978Skmacy req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */ 1263169978Skmacy req->iff = idx; 1264169978Skmacy memset(req->src_mac1, 0, sizeof(req->src_mac1)); 1265169978Skmacy memcpy(req->src_mac0, pi->hw_addr, ETHER_ADDR_LEN); 1266169978Skmacy 1267169978Skmacy m_set_priority(m, 1); 1268169978Skmacy 1269169978Skmacy offload_tx(&adapter->tdev, m); 1270169978Skmacy 1271169978Skmacy return (0); 1272169978Skmacy} 1273169978Skmacy 1274169978Skmacystatic int 1275169978Skmacyinit_smt(struct adapter *adapter) 1276169978Skmacy{ 1277169978Skmacy int i; 1278169978Skmacy 1279169978Skmacy for_each_port(adapter, i) 1280169978Skmacy write_smt_entry(adapter, i); 1281169978Skmacy return 0; 1282169978Skmacy} 1283169978Skmacy 1284167514Skmacystatic void 1285169978Skmacyinit_port_mtus(adapter_t *adapter) 1286169978Skmacy{ 1287169978Skmacy unsigned int mtus = adapter->port[0].ifp->if_mtu; 1288169978Skmacy 1289169978Skmacy if (adapter->port[1].ifp) 1290169978Skmacy mtus |= adapter->port[1].ifp->if_mtu << 16; 1291169978Skmacy t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus); 1292169978Skmacy} 1293169978Skmacy 1294169978Skmacystatic void 1295167514Skmacysend_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, 1296167514Skmacy int hi, int port) 1297167514Skmacy{ 1298167514Skmacy struct mbuf *m; 1299167514Skmacy struct mngt_pktsched_wr *req; 1300167514Skmacy 1301171471Skmacy m = m_gethdr(M_DONTWAIT, MT_DATA); 1302167848Skmacy if (m) { 1303169978Skmacy req = mtod(m, struct mngt_pktsched_wr *); 1304167848Skmacy req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); 1305167848Skmacy req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET; 1306167848Skmacy req->sched = sched; 1307167848Skmacy req->idx = qidx; 1308167848Skmacy req->min = lo; 1309167848Skmacy req->max = hi; 1310167848Skmacy req->binding = port; 1311167848Skmacy m->m_len = m->m_pkthdr.len = sizeof(*req); 1312167848Skmacy t3_mgmt_tx(adap, m); 1313167848Skmacy } 1314167514Skmacy} 1315167514Skmacy 1316167514Skmacystatic void 1317167514Skmacybind_qsets(adapter_t *sc) 1318167514Skmacy{ 1319167514Skmacy int i, j; 1320167514Skmacy 1321167514Skmacy for (i = 0; i < (sc)->params.nports; ++i) { 1322167514Skmacy const struct port_info *pi = adap2pinfo(sc, i); 1323167514Skmacy 1324172096Skmacy for (j = 0; j < pi->nqsets; ++j) { 1325167514Skmacy send_pktsched_cmd(sc, 1, pi->first_qset + j, -1, 1326172096Skmacy -1, pi->tx_chan); 1327172096Skmacy 1328172096Skmacy } 1329167514Skmacy } 1330167514Skmacy} 1331167514Skmacy 1332171471Skmacystatic void 1333171471Skmacyupdate_tpeeprom(struct adapter *adap) 1334171471Skmacy{ 1335172109Skmacy#ifdef FIRMWARE_LATEST 1336171471Skmacy const struct firmware *tpeeprom; 1337172109Skmacy#else 1338172109Skmacy struct firmware *tpeeprom; 1339172109Skmacy#endif 1340172109Skmacy 1341171471Skmacy char buf[64]; 1342171471Skmacy uint32_t version; 1343171471Skmacy unsigned int major, minor; 1344171471Skmacy int ret, len; 1345171471Skmacy char rev; 1346171471Skmacy 1347171471Skmacy t3_seeprom_read(adap, TP_SRAM_OFFSET, &version); 1348171471Skmacy 1349171471Skmacy major = G_TP_VERSION_MAJOR(version); 1350171471Skmacy minor = G_TP_VERSION_MINOR(version); 1351171471Skmacy if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) 1352171471Skmacy return; 1353171471Skmacy 1354171471Skmacy rev = t3rev2char(adap); 1355171471Skmacy 1356171471Skmacy snprintf(buf, sizeof(buf), TPEEPROM_NAME, rev, 1357171471Skmacy TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); 1358171471Skmacy 1359171471Skmacy tpeeprom = firmware_get(buf); 1360171471Skmacy if (tpeeprom == NULL) { 1361171471Skmacy device_printf(adap->dev, "could not load TP EEPROM: unable to load %s\n", 1362171471Skmacy buf); 1363171471Skmacy return; 1364171471Skmacy } 1365171471Skmacy 1366171471Skmacy len = tpeeprom->datasize - 4; 1367171471Skmacy 1368171471Skmacy ret = t3_check_tpsram(adap, tpeeprom->data, tpeeprom->datasize); 1369171471Skmacy if (ret) 1370171471Skmacy goto release_tpeeprom; 1371171471Skmacy 1372171471Skmacy if (len != TP_SRAM_LEN) { 1373171471Skmacy device_printf(adap->dev, "%s length is wrong len=%d expected=%d\n", buf, len, TP_SRAM_LEN); 1374171471Skmacy return; 1375171471Skmacy } 1376171471Skmacy 1377171471Skmacy ret = set_eeprom(&adap->port[0], tpeeprom->data, tpeeprom->datasize, 1378171471Skmacy TP_SRAM_OFFSET); 1379171471Skmacy 1380171471Skmacy if (!ret) { 1381171471Skmacy device_printf(adap->dev, 1382171471Skmacy "Protocol SRAM image updated in EEPROM to %d.%d.%d\n", 1383171471Skmacy TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); 1384171471Skmacy } else 1385171471Skmacy device_printf(adap->dev, "Protocol SRAM image update in EEPROM failed\n"); 1386171471Skmacy 1387171471Skmacyrelease_tpeeprom: 1388171471Skmacy firmware_put(tpeeprom, FIRMWARE_UNLOAD); 1389171471Skmacy 1390171471Skmacy return; 1391171471Skmacy} 1392171471Skmacy 1393171471Skmacystatic int 1394171471Skmacyupdate_tpsram(struct adapter *adap) 1395171471Skmacy{ 1396172109Skmacy#ifdef FIRMWARE_LATEST 1397171471Skmacy const struct firmware *tpsram; 1398172109Skmacy#else 1399172109Skmacy struct firmware *tpsram; 1400172109Skmacy#endif 1401171471Skmacy char buf[64]; 1402171471Skmacy int ret; 1403171471Skmacy char rev; 1404171471Skmacy 1405171471Skmacy rev = t3rev2char(adap); 1406171471Skmacy if (!rev) 1407171471Skmacy return 0; 1408171471Skmacy 1409171471Skmacy update_tpeeprom(adap); 1410171471Skmacy 1411171471Skmacy snprintf(buf, sizeof(buf), TPSRAM_NAME, rev, 1412171471Skmacy TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); 1413171471Skmacy 1414171471Skmacy tpsram = firmware_get(buf); 1415171471Skmacy if (tpsram == NULL){ 1416171471Skmacy device_printf(adap->dev, "could not load TP SRAM: unable to load %s\n", 1417171471Skmacy buf); 1418171471Skmacy return (EINVAL); 1419171471Skmacy } else 1420171471Skmacy device_printf(adap->dev, "updating TP SRAM with %s\n", buf); 1421171471Skmacy 1422171471Skmacy ret = t3_check_tpsram(adap, tpsram->data, tpsram->datasize); 1423171471Skmacy if (ret) 1424171471Skmacy goto release_tpsram; 1425171471Skmacy 1426171471Skmacy ret = t3_set_proto_sram(adap, tpsram->data); 1427171471Skmacy if (ret) 1428171471Skmacy device_printf(adap->dev, "loading protocol SRAM failed\n"); 1429171471Skmacy 1430171471Skmacyrelease_tpsram: 1431171471Skmacy firmware_put(tpsram, FIRMWARE_UNLOAD); 1432171471Skmacy 1433171471Skmacy return ret; 1434171471Skmacy} 1435171471Skmacy 1436169978Skmacy/** 1437169978Skmacy * cxgb_up - enable the adapter 1438169978Skmacy * @adap: adapter being enabled 1439169978Skmacy * 1440169978Skmacy * Called when the first port is enabled, this function performs the 1441169978Skmacy * actions necessary to make an adapter operational, such as completing 1442169978Skmacy * the initialization of HW modules, and enabling interrupts. 1443169978Skmacy * 1444169978Skmacy */ 1445169978Skmacystatic int 1446169978Skmacycxgb_up(struct adapter *sc) 1447169978Skmacy{ 1448169978Skmacy int err = 0; 1449169978Skmacy 1450169978Skmacy if ((sc->flags & FULL_INIT_DONE) == 0) { 1451169978Skmacy 1452169978Skmacy if ((sc->flags & FW_UPTODATE) == 0) 1453171471Skmacy if ((err = upgrade_fw(sc))) 1454171471Skmacy goto out; 1455171471Skmacy if ((sc->flags & TPS_UPTODATE) == 0) 1456171471Skmacy if ((err = update_tpsram(sc))) 1457171471Skmacy goto out; 1458169978Skmacy err = t3_init_hw(sc, 0); 1459169978Skmacy if (err) 1460169978Skmacy goto out; 1461169978Skmacy 1462169978Skmacy t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12)); 1463169978Skmacy 1464169978Skmacy err = setup_sge_qsets(sc); 1465169978Skmacy if (err) 1466169978Skmacy goto out; 1467169978Skmacy 1468169978Skmacy setup_rss(sc); 1469169978Skmacy sc->flags |= FULL_INIT_DONE; 1470169978Skmacy } 1471169978Skmacy 1472169978Skmacy t3_intr_clear(sc); 1473169978Skmacy 1474169978Skmacy /* If it's MSI or INTx, allocate a single interrupt for everything */ 1475169978Skmacy if ((sc->flags & USING_MSIX) == 0) { 1476169978Skmacy if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 1477169978Skmacy &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 1478171978Skmacy device_printf(sc->dev, "Cannot allocate interrupt rid=%d\n", 1479171978Skmacy sc->irq_rid); 1480169978Skmacy err = EINVAL; 1481169978Skmacy goto out; 1482169978Skmacy } 1483169978Skmacy device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res); 1484169978Skmacy 1485169978Skmacy if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET, 1486169978Skmacy#ifdef INTR_FILTERS 1487169978Skmacy NULL, 1488169978Skmacy#endif 1489169978Skmacy sc->cxgb_intr, sc, &sc->intr_tag)) { 1490169978Skmacy device_printf(sc->dev, "Cannot set up interrupt\n"); 1491169978Skmacy err = EINVAL; 1492169978Skmacy goto irq_err; 1493169978Skmacy } 1494169978Skmacy } else { 1495169978Skmacy cxgb_setup_msix(sc, sc->msi_count); 1496169978Skmacy } 1497169978Skmacy 1498169978Skmacy t3_sge_start(sc); 1499169978Skmacy t3_intr_enable(sc); 1500169978Skmacy 1501172096Skmacy if (!(sc->flags & QUEUES_BOUND)) { 1502172096Skmacy printf("bind qsets\n"); 1503169978Skmacy bind_qsets(sc); 1504171471Skmacy sc->flags |= QUEUES_BOUND; 1505171471Skmacy } 1506169978Skmacyout: 1507169978Skmacy return (err); 1508169978Skmacyirq_err: 1509169978Skmacy CH_ERR(sc, "request_irq failed, err %d\n", err); 1510169978Skmacy goto out; 1511169978Skmacy} 1512169978Skmacy 1513169978Skmacy 1514169978Skmacy/* 1515169978Skmacy * Release resources when all the ports and offloading have been stopped. 1516169978Skmacy */ 1517167514Skmacystatic void 1518170869Skmacycxgb_down_locked(struct adapter *sc) 1519169978Skmacy{ 1520169978Skmacy int i; 1521170654Skmacy 1522169978Skmacy t3_sge_stop(sc); 1523169978Skmacy t3_intr_disable(sc); 1524170654Skmacy 1525169978Skmacy if (sc->intr_tag != NULL) { 1526169978Skmacy bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag); 1527169978Skmacy sc->intr_tag = NULL; 1528169978Skmacy } 1529169978Skmacy if (sc->irq_res != NULL) { 1530169978Skmacy device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n", 1531169978Skmacy sc->irq_rid, sc->irq_res); 1532169978Skmacy bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid, 1533169978Skmacy sc->irq_res); 1534169978Skmacy sc->irq_res = NULL; 1535169978Skmacy } 1536170654Skmacy 1537170654Skmacy if (sc->flags & USING_MSIX) 1538170654Skmacy cxgb_teardown_msix(sc); 1539170869Skmacy ADAPTER_UNLOCK(sc); 1540169978Skmacy 1541170869Skmacy callout_drain(&sc->cxgb_tick_ch); 1542169978Skmacy callout_drain(&sc->sge_timer_ch); 1543170869Skmacy 1544171978Skmacy if (sc->tq != NULL) { 1545170654Skmacy taskqueue_drain(sc->tq, &sc->slow_intr_task); 1546171978Skmacy for (i = 0; i < sc->params.nports; i++) 1547171978Skmacy taskqueue_drain(sc->tq, &sc->port[i].timer_reclaim_task); 1548171978Skmacy } 1549171978Skmacy#ifdef notyet 1550171978Skmacy 1551170654Skmacy if (sc->port[i].tq != NULL) 1552171978Skmacy#endif 1553170654Skmacy 1554169978Skmacy} 1555169978Skmacy 1556169978Skmacystatic int 1557169978Skmacyoffload_open(struct port_info *pi) 1558169978Skmacy{ 1559169978Skmacy struct adapter *adapter = pi->adapter; 1560174626Skmacy struct t3cdev *tdev = TOEDEV(pi->ifp); 1561169978Skmacy int adap_up = adapter->open_device_map & PORT_MASK; 1562169978Skmacy int err = 0; 1563169978Skmacy 1564169978Skmacy if (atomic_cmpset_int(&adapter->open_device_map, 1565169978Skmacy (adapter->open_device_map & ~OFFLOAD_DEVMAP_BIT), 1566169978Skmacy (adapter->open_device_map | OFFLOAD_DEVMAP_BIT)) == 0) 1567169978Skmacy return (0); 1568169978Skmacy 1569169978Skmacy ADAPTER_LOCK(pi->adapter); 1570169978Skmacy if (!adap_up) 1571169978Skmacy err = cxgb_up(adapter); 1572169978Skmacy ADAPTER_UNLOCK(pi->adapter); 1573171471Skmacy if (err) 1574169978Skmacy return (err); 1575169978Skmacy 1576169978Skmacy t3_tp_set_offload_mode(adapter, 1); 1577169978Skmacy tdev->lldev = adapter->port[0].ifp; 1578169978Skmacy err = cxgb_offload_activate(adapter); 1579169978Skmacy if (err) 1580169978Skmacy goto out; 1581169978Skmacy 1582169978Skmacy init_port_mtus(adapter); 1583169978Skmacy t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd, 1584169978Skmacy adapter->params.b_wnd, 1585169978Skmacy adapter->params.rev == 0 ? 1586169978Skmacy adapter->port[0].ifp->if_mtu : 0xffff); 1587169978Skmacy init_smt(adapter); 1588169978Skmacy 1589169978Skmacy /* Call back all registered clients */ 1590169978Skmacy cxgb_add_clients(tdev); 1591169978Skmacy 1592169978Skmacyout: 1593169978Skmacy /* restore them in case the offload module has changed them */ 1594169978Skmacy if (err) { 1595169978Skmacy t3_tp_set_offload_mode(adapter, 0); 1596169978Skmacy clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT); 1597169978Skmacy cxgb_set_dummy_ops(tdev); 1598169978Skmacy } 1599169978Skmacy return (err); 1600169978Skmacy} 1601170789Skmacy#ifdef notyet 1602169978Skmacystatic int 1603174626Skmacyoffload_close(struct t3cev *tdev) 1604169978Skmacy{ 1605169978Skmacy struct adapter *adapter = tdev2adap(tdev); 1606169978Skmacy 1607169978Skmacy if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT)) 1608170654Skmacy return (0); 1609169978Skmacy 1610169978Skmacy /* Call back all registered clients */ 1611169978Skmacy cxgb_remove_clients(tdev); 1612169978Skmacy tdev->lldev = NULL; 1613169978Skmacy cxgb_set_dummy_ops(tdev); 1614169978Skmacy t3_tp_set_offload_mode(adapter, 0); 1615169978Skmacy clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT); 1616169978Skmacy 1617169978Skmacy if (!adapter->open_device_map) 1618169978Skmacy cxgb_down(adapter); 1619169978Skmacy 1620169978Skmacy cxgb_offload_deactivate(adapter); 1621170654Skmacy return (0); 1622169978Skmacy} 1623170789Skmacy#endif 1624169978Skmacy 1625169978Skmacystatic void 1626167514Skmacycxgb_init(void *arg) 1627167514Skmacy{ 1628167514Skmacy struct port_info *p = arg; 1629167514Skmacy 1630167514Skmacy PORT_LOCK(p); 1631167514Skmacy cxgb_init_locked(p); 1632167514Skmacy PORT_UNLOCK(p); 1633167514Skmacy} 1634167514Skmacy 1635167514Skmacystatic void 1636167514Skmacycxgb_init_locked(struct port_info *p) 1637167514Skmacy{ 1638167514Skmacy struct ifnet *ifp; 1639167514Skmacy adapter_t *sc = p->adapter; 1640169978Skmacy int err; 1641167514Skmacy 1642170869Skmacy PORT_LOCK_ASSERT_OWNED(p); 1643167514Skmacy ifp = p->ifp; 1644167514Skmacy 1645167514Skmacy ADAPTER_LOCK(p->adapter); 1646171471Skmacy if ((sc->open_device_map == 0) && (err = cxgb_up(sc))) { 1647169978Skmacy ADAPTER_UNLOCK(p->adapter); 1648169978Skmacy cxgb_stop_locked(p); 1649169978Skmacy return; 1650169978Skmacy } 1651170869Skmacy if (p->adapter->open_device_map == 0) { 1652167514Skmacy t3_intr_clear(sc); 1653170869Skmacy t3_sge_init_adapter(sc); 1654170869Skmacy } 1655171803Skmacy setbit(&p->adapter->open_device_map, p->port_id); 1656170654Skmacy ADAPTER_UNLOCK(p->adapter); 1657169978Skmacy 1658169978Skmacy if (is_offload(sc) && !ofld_disable) { 1659169978Skmacy err = offload_open(p); 1660169978Skmacy if (err) 1661169978Skmacy log(LOG_WARNING, 1662169978Skmacy "Could not initialize offload capabilities\n"); 1663169978Skmacy } 1664169978Skmacy cxgb_link_start(p); 1665171803Skmacy t3_link_changed(sc, p->port_id); 1666170654Skmacy ifp->if_baudrate = p->link_config.speed * 1000000; 1667171978Skmacy 1668172096Skmacy device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id); 1669171803Skmacy t3_port_intr_enable(sc, p->port_id); 1670167760Skmacy 1671167514Skmacy callout_reset(&sc->cxgb_tick_ch, sc->params.stats_update_period * hz, 1672167514Skmacy cxgb_tick, sc); 1673170869Skmacy 1674167514Skmacy ifp->if_drv_flags |= IFF_DRV_RUNNING; 1675167514Skmacy ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1676167514Skmacy} 1677167514Skmacy 1678167514Skmacystatic void 1679167514Skmacycxgb_set_rxmode(struct port_info *p) 1680167514Skmacy{ 1681167514Skmacy struct t3_rx_mode rm; 1682167514Skmacy struct cmac *mac = &p->mac; 1683167760Skmacy 1684170869Skmacy PORT_LOCK_ASSERT_OWNED(p); 1685170654Skmacy 1686167514Skmacy t3_init_rx_mode(&rm, p); 1687167514Skmacy t3_mac_set_rx_mode(mac, &rm); 1688167514Skmacy} 1689167514Skmacy 1690167514Skmacystatic void 1691167734Skmacycxgb_stop_locked(struct port_info *p) 1692167514Skmacy{ 1693167514Skmacy struct ifnet *ifp; 1694167514Skmacy 1695170869Skmacy PORT_LOCK_ASSERT_OWNED(p); 1696170869Skmacy ADAPTER_LOCK_ASSERT_NOTOWNED(p->adapter); 1697170654Skmacy 1698167514Skmacy ifp = p->ifp; 1699167514Skmacy 1700171803Skmacy t3_port_intr_disable(p->adapter, p->port_id); 1701169978Skmacy ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1702169978Skmacy p->phy.ops->power_down(&p->phy, 1); 1703169978Skmacy t3_mac_disable(&p->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); 1704169978Skmacy 1705167514Skmacy ADAPTER_LOCK(p->adapter); 1706171803Skmacy clrbit(&p->adapter->open_device_map, p->port_id); 1707170869Skmacy 1708170869Skmacy 1709170869Skmacy if (p->adapter->open_device_map == 0) { 1710170869Skmacy cxgb_down_locked(p->adapter); 1711170869Skmacy } else 1712170869Skmacy ADAPTER_UNLOCK(p->adapter); 1713170869Skmacy 1714167514Skmacy} 1715167514Skmacy 1716167514Skmacystatic int 1717170654Skmacycxgb_set_mtu(struct port_info *p, int mtu) 1718170654Skmacy{ 1719170654Skmacy struct ifnet *ifp = p->ifp; 1720170654Skmacy int error = 0; 1721170654Skmacy 1722170654Skmacy if ((mtu < ETHERMIN) || (mtu > ETHER_MAX_LEN_JUMBO)) 1723170654Skmacy error = EINVAL; 1724170654Skmacy else if (ifp->if_mtu != mtu) { 1725170654Skmacy PORT_LOCK(p); 1726170654Skmacy ifp->if_mtu = mtu; 1727170654Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1728170654Skmacy callout_stop(&p->adapter->cxgb_tick_ch); 1729170654Skmacy cxgb_stop_locked(p); 1730170654Skmacy cxgb_init_locked(p); 1731170654Skmacy } 1732170654Skmacy PORT_UNLOCK(p); 1733170654Skmacy } 1734170654Skmacy return (error); 1735170654Skmacy} 1736170654Skmacy 1737170654Skmacystatic int 1738167514Skmacycxgb_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data) 1739167514Skmacy{ 1740167514Skmacy struct port_info *p = ifp->if_softc; 1741167514Skmacy struct ifaddr *ifa = (struct ifaddr *)data; 1742167514Skmacy struct ifreq *ifr = (struct ifreq *)data; 1743167514Skmacy int flags, error = 0; 1744167514Skmacy uint32_t mask; 1745167514Skmacy 1746168737Skmacy /* 1747168737Skmacy * XXX need to check that we aren't in the middle of an unload 1748168737Skmacy */ 1749167514Skmacy switch (command) { 1750167514Skmacy case SIOCSIFMTU: 1751170654Skmacy error = cxgb_set_mtu(p, ifr->ifr_mtu); 1752167514Skmacy break; 1753167514Skmacy case SIOCSIFADDR: 1754167514Skmacy case SIOCGIFADDR: 1755170654Skmacy PORT_LOCK(p); 1756167514Skmacy if (ifa->ifa_addr->sa_family == AF_INET) { 1757167514Skmacy ifp->if_flags |= IFF_UP; 1758170654Skmacy if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1759170654Skmacy cxgb_init_locked(p); 1760167514Skmacy arp_ifinit(ifp, ifa); 1761167514Skmacy } else 1762167514Skmacy error = ether_ioctl(ifp, command, data); 1763170654Skmacy PORT_UNLOCK(p); 1764167514Skmacy break; 1765167514Skmacy case SIOCSIFFLAGS: 1766170869Skmacy callout_drain(&p->adapter->cxgb_tick_ch); 1767170869Skmacy PORT_LOCK(p); 1768167514Skmacy if (ifp->if_flags & IFF_UP) { 1769167514Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1770167514Skmacy flags = p->if_flags; 1771167514Skmacy if (((ifp->if_flags ^ flags) & IFF_PROMISC) || 1772167514Skmacy ((ifp->if_flags ^ flags) & IFF_ALLMULTI)) 1773167514Skmacy cxgb_set_rxmode(p); 1774167514Skmacy } else 1775167514Skmacy cxgb_init_locked(p); 1776167760Skmacy p->if_flags = ifp->if_flags; 1777170869Skmacy } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1778170869Skmacy cxgb_stop_locked(p); 1779170869Skmacy 1780170869Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1781170869Skmacy adapter_t *sc = p->adapter; 1782170869Skmacy callout_reset(&sc->cxgb_tick_ch, 1783170869Skmacy sc->params.stats_update_period * hz, 1784170869Skmacy cxgb_tick, sc); 1785167514Skmacy } 1786170654Skmacy PORT_UNLOCK(p); 1787167514Skmacy break; 1788167514Skmacy case SIOCSIFMEDIA: 1789167514Skmacy case SIOCGIFMEDIA: 1790167514Skmacy error = ifmedia_ioctl(ifp, ifr, &p->media, command); 1791167514Skmacy break; 1792167514Skmacy case SIOCSIFCAP: 1793167514Skmacy PORT_LOCK(p); 1794167514Skmacy mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1795167514Skmacy if (mask & IFCAP_TXCSUM) { 1796167514Skmacy if (IFCAP_TXCSUM & ifp->if_capenable) { 1797167514Skmacy ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 1798167514Skmacy ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 1799167514Skmacy | CSUM_TSO); 1800167514Skmacy } else { 1801167514Skmacy ifp->if_capenable |= IFCAP_TXCSUM; 1802167514Skmacy ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP); 1803167514Skmacy } 1804167514Skmacy } else if (mask & IFCAP_RXCSUM) { 1805167514Skmacy if (IFCAP_RXCSUM & ifp->if_capenable) { 1806167514Skmacy ifp->if_capenable &= ~IFCAP_RXCSUM; 1807167514Skmacy } else { 1808167514Skmacy ifp->if_capenable |= IFCAP_RXCSUM; 1809167514Skmacy } 1810167514Skmacy } 1811167514Skmacy if (mask & IFCAP_TSO4) { 1812167514Skmacy if (IFCAP_TSO4 & ifp->if_capenable) { 1813167514Skmacy ifp->if_capenable &= ~IFCAP_TSO4; 1814167514Skmacy ifp->if_hwassist &= ~CSUM_TSO; 1815167514Skmacy } else if (IFCAP_TXCSUM & ifp->if_capenable) { 1816167514Skmacy ifp->if_capenable |= IFCAP_TSO4; 1817167514Skmacy ifp->if_hwassist |= CSUM_TSO; 1818167514Skmacy } else { 1819167514Skmacy if (cxgb_debug) 1820167514Skmacy printf("cxgb requires tx checksum offload" 1821167514Skmacy " be enabled to use TSO\n"); 1822167514Skmacy error = EINVAL; 1823167514Skmacy } 1824167514Skmacy } 1825167514Skmacy PORT_UNLOCK(p); 1826167514Skmacy break; 1827167514Skmacy default: 1828167514Skmacy error = ether_ioctl(ifp, command, data); 1829167514Skmacy break; 1830167514Skmacy } 1831167514Skmacy return (error); 1832167514Skmacy} 1833167514Skmacy 1834167514Skmacystatic int 1835167514Skmacycxgb_start_tx(struct ifnet *ifp, uint32_t txmax) 1836167514Skmacy{ 1837167514Skmacy struct sge_qset *qs; 1838167514Skmacy struct sge_txq *txq; 1839167514Skmacy struct port_info *p = ifp->if_softc; 1840172109Skmacy struct mbuf *m = NULL; 1841172096Skmacy int err, in_use_init, free; 1842170654Skmacy 1843167514Skmacy if (!p->link_config.link_ok) 1844167514Skmacy return (ENXIO); 1845167514Skmacy 1846167514Skmacy if (IFQ_DRV_IS_EMPTY(&ifp->if_snd)) 1847167514Skmacy return (ENOBUFS); 1848167514Skmacy 1849172096Skmacy qs = &p->adapter->sge.qs[p->first_qset]; 1850167514Skmacy txq = &qs->txq[TXQ_ETH]; 1851167514Skmacy err = 0; 1852167514Skmacy 1853171335Skmacy if (txq->flags & TXQ_TRANSMITTING) 1854171335Skmacy return (EINPROGRESS); 1855171335Skmacy 1856167514Skmacy mtx_lock(&txq->lock); 1857171335Skmacy txq->flags |= TXQ_TRANSMITTING; 1858167514Skmacy in_use_init = txq->in_use; 1859167514Skmacy while ((txq->in_use - in_use_init < txmax) && 1860167514Skmacy (txq->size > txq->in_use + TX_MAX_DESC)) { 1861172096Skmacy free = 0; 1862167514Skmacy IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 1863167514Skmacy if (m == NULL) 1864167514Skmacy break; 1865168737Skmacy /* 1866168737Skmacy * Convert chain to M_IOVEC 1867168737Skmacy */ 1868168737Skmacy KASSERT((m->m_flags & M_IOVEC) == 0, ("IOVEC set too early")); 1869172109Skmacy#ifdef notyet 1870168737Skmacy m0 = m; 1871168749Skmacy if (collapse_mbufs && m->m_pkthdr.len > MCLBYTES && 1872168737Skmacy m_collapse(m, TX_MAX_SEGS, &m0) == EFBIG) { 1873168737Skmacy if ((m0 = m_defrag(m, M_NOWAIT)) != NULL) { 1874168737Skmacy m = m0; 1875168737Skmacy m_collapse(m, TX_MAX_SEGS, &m0); 1876168737Skmacy } else 1877171804Skmacy break; 1878168737Skmacy } 1879168737Skmacy m = m0; 1880172109Skmacy#endif 1881172096Skmacy if ((err = t3_encap(p, &m, &free)) != 0) 1882167514Skmacy break; 1883169978Skmacy BPF_MTAP(ifp, m); 1884172096Skmacy if (free) 1885172096Skmacy m_freem(m); 1886167514Skmacy } 1887171335Skmacy txq->flags &= ~TXQ_TRANSMITTING; 1888167514Skmacy mtx_unlock(&txq->lock); 1889167514Skmacy 1890167514Skmacy if (__predict_false(err)) { 1891167514Skmacy if (err == ENOMEM) { 1892170083Skmacy ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1893167514Skmacy IFQ_LOCK(&ifp->if_snd); 1894167514Skmacy IFQ_DRV_PREPEND(&ifp->if_snd, m); 1895167514Skmacy IFQ_UNLOCK(&ifp->if_snd); 1896167514Skmacy } 1897167514Skmacy } 1898170654Skmacy if (err == 0 && m == NULL) 1899170654Skmacy err = ENOBUFS; 1900170654Skmacy else if ((err == 0) && (txq->size <= txq->in_use + TX_MAX_DESC) && 1901170007Skmacy (ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { 1902170007Skmacy ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1903170654Skmacy err = ENOSPC; 1904170007Skmacy } 1905167514Skmacy return (err); 1906167514Skmacy} 1907167514Skmacy 1908167514Skmacystatic void 1909167514Skmacycxgb_start_proc(void *arg, int ncount) 1910167514Skmacy{ 1911167514Skmacy struct ifnet *ifp = arg; 1912167514Skmacy struct port_info *pi = ifp->if_softc; 1913167514Skmacy struct sge_qset *qs; 1914167514Skmacy struct sge_txq *txq; 1915170654Skmacy int error; 1916167514Skmacy 1917167514Skmacy qs = &pi->adapter->sge.qs[pi->first_qset]; 1918167514Skmacy txq = &qs->txq[TXQ_ETH]; 1919167514Skmacy 1920170654Skmacy do { 1921171469Skmacy if (desc_reclaimable(txq) > TX_CLEAN_MAX_DESC >> 2) 1922171469Skmacy taskqueue_enqueue(pi->tq, &txq->qreclaim_task); 1923167525Skmacy 1924167538Skmacy error = cxgb_start_tx(ifp, TX_START_MAX_DESC); 1925170654Skmacy } while (error == 0); 1926167514Skmacy} 1927167514Skmacy 1928167514Skmacystatic void 1929167514Skmacycxgb_start(struct ifnet *ifp) 1930167514Skmacy{ 1931167514Skmacy struct port_info *pi = ifp->if_softc; 1932167514Skmacy struct sge_qset *qs; 1933167514Skmacy struct sge_txq *txq; 1934167514Skmacy int err; 1935167514Skmacy 1936167514Skmacy qs = &pi->adapter->sge.qs[pi->first_qset]; 1937167514Skmacy txq = &qs->txq[TXQ_ETH]; 1938167514Skmacy 1939171469Skmacy if (desc_reclaimable(txq) > TX_CLEAN_MAX_DESC >> 2) 1940171469Skmacy taskqueue_enqueue(pi->tq, 1941171469Skmacy &txq->qreclaim_task); 1942167538Skmacy 1943167514Skmacy err = cxgb_start_tx(ifp, TX_START_MAX_DESC); 1944167514Skmacy 1945167514Skmacy if (err == 0) 1946167514Skmacy taskqueue_enqueue(pi->tq, &pi->start_task); 1947167514Skmacy} 1948167514Skmacy 1949167514Skmacy 1950167514Skmacystatic int 1951167514Skmacycxgb_media_change(struct ifnet *ifp) 1952167514Skmacy{ 1953167514Skmacy if_printf(ifp, "media change not supported\n"); 1954167514Skmacy return (ENXIO); 1955167514Skmacy} 1956167514Skmacy 1957167514Skmacystatic void 1958167514Skmacycxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1959167514Skmacy{ 1960167514Skmacy struct port_info *p = ifp->if_softc; 1961167514Skmacy 1962167514Skmacy ifmr->ifm_status = IFM_AVALID; 1963167514Skmacy ifmr->ifm_active = IFM_ETHER; 1964167514Skmacy 1965167514Skmacy if (!p->link_config.link_ok) 1966167514Skmacy return; 1967167514Skmacy 1968167514Skmacy ifmr->ifm_status |= IFM_ACTIVE; 1969167514Skmacy 1970170654Skmacy switch (p->link_config.speed) { 1971170654Skmacy case 10: 1972170654Skmacy ifmr->ifm_active |= IFM_10_T; 1973170654Skmacy break; 1974170654Skmacy case 100: 1975170654Skmacy ifmr->ifm_active |= IFM_100_TX; 1976170654Skmacy break; 1977170654Skmacy case 1000: 1978170654Skmacy ifmr->ifm_active |= IFM_1000_T; 1979170654Skmacy break; 1980170654Skmacy } 1981170654Skmacy 1982167514Skmacy if (p->link_config.duplex) 1983167514Skmacy ifmr->ifm_active |= IFM_FDX; 1984167514Skmacy else 1985167514Skmacy ifmr->ifm_active |= IFM_HDX; 1986167514Skmacy} 1987167514Skmacy 1988167514Skmacystatic void 1989167514Skmacycxgb_async_intr(void *data) 1990167514Skmacy{ 1991167760Skmacy adapter_t *sc = data; 1992167760Skmacy 1993167514Skmacy if (cxgb_debug) 1994167760Skmacy device_printf(sc->dev, "cxgb_async_intr\n"); 1995170869Skmacy /* 1996170869Skmacy * May need to sleep - defer to taskqueue 1997170869Skmacy */ 1998170869Skmacy taskqueue_enqueue(sc->tq, &sc->slow_intr_task); 1999167514Skmacy} 2000167514Skmacy 2001167514Skmacystatic void 2002167514Skmacycxgb_ext_intr_handler(void *arg, int count) 2003167514Skmacy{ 2004167514Skmacy adapter_t *sc = (adapter_t *)arg; 2005167514Skmacy 2006167514Skmacy if (cxgb_debug) 2007167514Skmacy printf("cxgb_ext_intr_handler\n"); 2008167514Skmacy 2009167514Skmacy t3_phy_intr_handler(sc); 2010167514Skmacy 2011167514Skmacy /* Now reenable external interrupts */ 2012169978Skmacy ADAPTER_LOCK(sc); 2013167514Skmacy if (sc->slow_intr_mask) { 2014167514Skmacy sc->slow_intr_mask |= F_T3DBG; 2015167514Skmacy t3_write_reg(sc, A_PL_INT_CAUSE0, F_T3DBG); 2016167514Skmacy t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask); 2017167514Skmacy } 2018169978Skmacy ADAPTER_UNLOCK(sc); 2019167514Skmacy} 2020167514Skmacy 2021167514Skmacystatic void 2022167746Skmacycheck_link_status(adapter_t *sc) 2023167514Skmacy{ 2024167746Skmacy int i; 2025167514Skmacy 2026167746Skmacy for (i = 0; i < (sc)->params.nports; ++i) { 2027167746Skmacy struct port_info *p = &sc->port[i]; 2028167514Skmacy 2029170654Skmacy if (!(p->port_type->caps & SUPPORTED_IRQ)) 2030167746Skmacy t3_link_changed(sc, i); 2031170654Skmacy p->ifp->if_baudrate = p->link_config.speed * 1000000; 2032167746Skmacy } 2033167514Skmacy} 2034167514Skmacy 2035167514Skmacystatic void 2036167746Skmacycheck_t3b2_mac(struct adapter *adapter) 2037167514Skmacy{ 2038167514Skmacy int i; 2039167514Skmacy 2040167746Skmacy for_each_port(adapter, i) { 2041167746Skmacy struct port_info *p = &adapter->port[i]; 2042167746Skmacy struct ifnet *ifp = p->ifp; 2043167746Skmacy int status; 2044167514Skmacy 2045167746Skmacy if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 2046167746Skmacy continue; 2047167746Skmacy 2048167746Skmacy status = 0; 2049167746Skmacy PORT_LOCK(p); 2050167746Skmacy if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) 2051167746Skmacy status = t3b2_mac_watchdog_task(&p->mac); 2052167746Skmacy if (status == 1) 2053167746Skmacy p->mac.stats.num_toggled++; 2054167746Skmacy else if (status == 2) { 2055167746Skmacy struct cmac *mac = &p->mac; 2056167746Skmacy 2057170654Skmacy t3_mac_set_mtu(mac, ifp->if_mtu + ETHER_HDR_LEN 2058170654Skmacy + ETHER_VLAN_ENCAP_LEN); 2059167746Skmacy t3_mac_set_address(mac, 0, p->hw_addr); 2060167746Skmacy cxgb_set_rxmode(p); 2061167746Skmacy t3_link_start(&p->phy, mac, &p->link_config); 2062167746Skmacy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 2063171803Skmacy t3_port_intr_enable(adapter, p->port_id); 2064167746Skmacy p->mac.stats.num_resets++; 2065167746Skmacy } 2066167746Skmacy PORT_UNLOCK(p); 2067167514Skmacy } 2068167514Skmacy} 2069167514Skmacy 2070167746Skmacystatic void 2071167746Skmacycxgb_tick(void *arg) 2072167746Skmacy{ 2073167746Skmacy adapter_t *sc = (adapter_t *)arg; 2074170869Skmacy 2075170869Skmacy taskqueue_enqueue(sc->tq, &sc->tick_task); 2076170869Skmacy 2077170869Skmacy if (sc->open_device_map != 0) 2078170869Skmacy callout_reset(&sc->cxgb_tick_ch, sc->params.stats_update_period * hz, 2079170869Skmacy cxgb_tick, sc); 2080170869Skmacy} 2081170869Skmacy 2082170869Skmacystatic void 2083170869Skmacycxgb_tick_handler(void *arg, int count) 2084170869Skmacy{ 2085170869Skmacy adapter_t *sc = (adapter_t *)arg; 2086167746Skmacy const struct adapter_params *p = &sc->params; 2087167746Skmacy 2088170869Skmacy ADAPTER_LOCK(sc); 2089167746Skmacy if (p->linkpoll_period) 2090167746Skmacy check_link_status(sc); 2091167746Skmacy 2092167746Skmacy /* 2093167746Skmacy * adapter lock can currently only be acquire after the 2094167746Skmacy * port lock 2095167746Skmacy */ 2096167746Skmacy ADAPTER_UNLOCK(sc); 2097170654Skmacy 2098171471Skmacy if (p->rev == T3_REV_B2 && p->nports < 4) 2099167746Skmacy check_t3b2_mac(sc); 2100167746Skmacy} 2101167746Skmacy 2102171978Skmacystatic void 2103171978Skmacytouch_bars(device_t dev) 2104171978Skmacy{ 2105171978Skmacy /* 2106171978Skmacy * Don't enable yet 2107171978Skmacy */ 2108171978Skmacy#if !defined(__LP64__) && 0 2109171978Skmacy u32 v; 2110171978Skmacy 2111171978Skmacy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &v); 2112171978Skmacy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, v); 2113171978Skmacy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3, &v); 2114171978Skmacy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_3, v); 2115171978Skmacy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &v); 2116171978Skmacy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_5, v); 2117171978Skmacy#endif 2118171978Skmacy} 2119171978Skmacy 2120167514Skmacystatic int 2121171471Skmacyset_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset) 2122171471Skmacy{ 2123171471Skmacy uint8_t *buf; 2124171471Skmacy int err = 0; 2125171471Skmacy u32 aligned_offset, aligned_len, *p; 2126171471Skmacy struct adapter *adapter = pi->adapter; 2127171471Skmacy 2128171471Skmacy 2129171471Skmacy aligned_offset = offset & ~3; 2130171471Skmacy aligned_len = (len + (offset & 3) + 3) & ~3; 2131171471Skmacy 2132171471Skmacy if (aligned_offset != offset || aligned_len != len) { 2133171471Skmacy buf = malloc(aligned_len, M_DEVBUF, M_WAITOK|M_ZERO); 2134171471Skmacy if (!buf) 2135171471Skmacy return (ENOMEM); 2136171471Skmacy err = t3_seeprom_read(adapter, aligned_offset, (u32 *)buf); 2137171471Skmacy if (!err && aligned_len > 4) 2138171471Skmacy err = t3_seeprom_read(adapter, 2139171471Skmacy aligned_offset + aligned_len - 4, 2140171471Skmacy (u32 *)&buf[aligned_len - 4]); 2141171471Skmacy if (err) 2142171471Skmacy goto out; 2143171471Skmacy memcpy(buf + (offset & 3), data, len); 2144171471Skmacy } else 2145171471Skmacy buf = (uint8_t *)(uintptr_t)data; 2146171471Skmacy 2147171471Skmacy err = t3_seeprom_wp(adapter, 0); 2148171471Skmacy if (err) 2149171471Skmacy goto out; 2150171471Skmacy 2151171471Skmacy for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { 2152171471Skmacy err = t3_seeprom_write(adapter, aligned_offset, *p); 2153171471Skmacy aligned_offset += 4; 2154171471Skmacy } 2155171471Skmacy 2156171471Skmacy if (!err) 2157171471Skmacy err = t3_seeprom_wp(adapter, 1); 2158171471Skmacyout: 2159171471Skmacy if (buf != data) 2160171471Skmacy free(buf, M_DEVBUF); 2161171471Skmacy return err; 2162171471Skmacy} 2163171471Skmacy 2164171471Skmacy 2165171471Skmacystatic int 2166167514Skmacyin_range(int val, int lo, int hi) 2167167514Skmacy{ 2168167514Skmacy return val < 0 || (val <= hi && val >= lo); 2169167514Skmacy} 2170167514Skmacy 2171167514Skmacystatic int 2172170654Skmacycxgb_extension_open(struct cdev *dev, int flags, int fmp, d_thread_t *td) 2173170654Skmacy{ 2174170654Skmacy return (0); 2175170654Skmacy} 2176170654Skmacy 2177170654Skmacystatic int 2178170654Skmacycxgb_extension_close(struct cdev *dev, int flags, int fmt, d_thread_t *td) 2179170654Skmacy{ 2180170654Skmacy return (0); 2181170654Skmacy} 2182170654Skmacy 2183170654Skmacystatic int 2184167514Skmacycxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, 2185167514Skmacy int fflag, struct thread *td) 2186167514Skmacy{ 2187167514Skmacy int mmd, error = 0; 2188167514Skmacy struct port_info *pi = dev->si_drv1; 2189167514Skmacy adapter_t *sc = pi->adapter; 2190167514Skmacy 2191167514Skmacy#ifdef PRIV_SUPPORTED 2192167514Skmacy if (priv_check(td, PRIV_DRIVER)) { 2193167514Skmacy if (cxgb_debug) 2194167514Skmacy printf("user does not have access to privileged ioctls\n"); 2195167514Skmacy return (EPERM); 2196167514Skmacy } 2197167514Skmacy#else 2198167514Skmacy if (suser(td)) { 2199167514Skmacy if (cxgb_debug) 2200167514Skmacy printf("user does not have access to privileged ioctls\n"); 2201167514Skmacy return (EPERM); 2202167514Skmacy } 2203167514Skmacy#endif 2204167514Skmacy 2205167514Skmacy switch (cmd) { 2206167514Skmacy case SIOCGMIIREG: { 2207167514Skmacy uint32_t val; 2208167514Skmacy struct cphy *phy = &pi->phy; 2209167514Skmacy struct mii_data *mid = (struct mii_data *)data; 2210167514Skmacy 2211167514Skmacy if (!phy->mdio_read) 2212167514Skmacy return (EOPNOTSUPP); 2213167514Skmacy if (is_10G(sc)) { 2214167514Skmacy mmd = mid->phy_id >> 8; 2215167514Skmacy if (!mmd) 2216167514Skmacy mmd = MDIO_DEV_PCS; 2217167514Skmacy else if (mmd > MDIO_DEV_XGXS) 2218171471Skmacy return (EINVAL); 2219167514Skmacy 2220167514Skmacy error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd, 2221167514Skmacy mid->reg_num, &val); 2222167514Skmacy } else 2223167514Skmacy error = phy->mdio_read(sc, mid->phy_id & 0x1f, 0, 2224167514Skmacy mid->reg_num & 0x1f, &val); 2225167514Skmacy if (error == 0) 2226167514Skmacy mid->val_out = val; 2227167514Skmacy break; 2228167514Skmacy } 2229167514Skmacy case SIOCSMIIREG: { 2230167514Skmacy struct cphy *phy = &pi->phy; 2231167514Skmacy struct mii_data *mid = (struct mii_data *)data; 2232167514Skmacy 2233167514Skmacy if (!phy->mdio_write) 2234167514Skmacy return (EOPNOTSUPP); 2235167514Skmacy if (is_10G(sc)) { 2236167514Skmacy mmd = mid->phy_id >> 8; 2237167514Skmacy if (!mmd) 2238167514Skmacy mmd = MDIO_DEV_PCS; 2239167514Skmacy else if (mmd > MDIO_DEV_XGXS) 2240167514Skmacy return (EINVAL); 2241167514Skmacy 2242167514Skmacy error = phy->mdio_write(sc, mid->phy_id & 0x1f, 2243167514Skmacy mmd, mid->reg_num, mid->val_in); 2244167514Skmacy } else 2245167514Skmacy error = phy->mdio_write(sc, mid->phy_id & 0x1f, 0, 2246167514Skmacy mid->reg_num & 0x1f, 2247167514Skmacy mid->val_in); 2248167514Skmacy break; 2249167514Skmacy } 2250167514Skmacy case CHELSIO_SETREG: { 2251167514Skmacy struct ch_reg *edata = (struct ch_reg *)data; 2252167514Skmacy if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 2253167514Skmacy return (EFAULT); 2254167514Skmacy t3_write_reg(sc, edata->addr, edata->val); 2255167514Skmacy break; 2256167514Skmacy } 2257167514Skmacy case CHELSIO_GETREG: { 2258167514Skmacy struct ch_reg *edata = (struct ch_reg *)data; 2259167514Skmacy if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 2260167514Skmacy return (EFAULT); 2261167514Skmacy edata->val = t3_read_reg(sc, edata->addr); 2262167514Skmacy break; 2263167514Skmacy } 2264167514Skmacy case CHELSIO_GET_SGE_CONTEXT: { 2265167514Skmacy struct ch_cntxt *ecntxt = (struct ch_cntxt *)data; 2266167514Skmacy mtx_lock(&sc->sge.reg_lock); 2267167514Skmacy switch (ecntxt->cntxt_type) { 2268167514Skmacy case CNTXT_TYPE_EGRESS: 2269167514Skmacy error = t3_sge_read_ecntxt(sc, ecntxt->cntxt_id, 2270167514Skmacy ecntxt->data); 2271167514Skmacy break; 2272167514Skmacy case CNTXT_TYPE_FL: 2273167514Skmacy error = t3_sge_read_fl(sc, ecntxt->cntxt_id, 2274167514Skmacy ecntxt->data); 2275167514Skmacy break; 2276167514Skmacy case CNTXT_TYPE_RSP: 2277167514Skmacy error = t3_sge_read_rspq(sc, ecntxt->cntxt_id, 2278167514Skmacy ecntxt->data); 2279167514Skmacy break; 2280167514Skmacy case CNTXT_TYPE_CQ: 2281167514Skmacy error = t3_sge_read_cq(sc, ecntxt->cntxt_id, 2282167514Skmacy ecntxt->data); 2283167514Skmacy break; 2284167514Skmacy default: 2285167514Skmacy error = EINVAL; 2286167514Skmacy break; 2287167514Skmacy } 2288167514Skmacy mtx_unlock(&sc->sge.reg_lock); 2289167514Skmacy break; 2290167514Skmacy } 2291167514Skmacy case CHELSIO_GET_SGE_DESC: { 2292167514Skmacy struct ch_desc *edesc = (struct ch_desc *)data; 2293167514Skmacy int ret; 2294167514Skmacy if (edesc->queue_num >= SGE_QSETS * 6) 2295167514Skmacy return (EINVAL); 2296167514Skmacy ret = t3_get_desc(&sc->sge.qs[edesc->queue_num / 6], 2297167514Skmacy edesc->queue_num % 6, edesc->idx, edesc->data); 2298167514Skmacy if (ret < 0) 2299167514Skmacy return (EINVAL); 2300167514Skmacy edesc->size = ret; 2301167514Skmacy break; 2302167514Skmacy } 2303167514Skmacy case CHELSIO_SET_QSET_PARAMS: { 2304167514Skmacy struct qset_params *q; 2305167514Skmacy struct ch_qset_params *t = (struct ch_qset_params *)data; 2306167514Skmacy 2307167514Skmacy if (t->qset_idx >= SGE_QSETS) 2308171471Skmacy return (EINVAL); 2309167514Skmacy if (!in_range(t->intr_lat, 0, M_NEWTIMER) || 2310167514Skmacy !in_range(t->cong_thres, 0, 255) || 2311167514Skmacy !in_range(t->txq_size[0], MIN_TXQ_ENTRIES, 2312167514Skmacy MAX_TXQ_ENTRIES) || 2313167514Skmacy !in_range(t->txq_size[1], MIN_TXQ_ENTRIES, 2314167514Skmacy MAX_TXQ_ENTRIES) || 2315167514Skmacy !in_range(t->txq_size[2], MIN_CTRL_TXQ_ENTRIES, 2316167514Skmacy MAX_CTRL_TXQ_ENTRIES) || 2317167514Skmacy !in_range(t->fl_size[0], MIN_FL_ENTRIES, MAX_RX_BUFFERS) || 2318167514Skmacy !in_range(t->fl_size[1], MIN_FL_ENTRIES, 2319167514Skmacy MAX_RX_JUMBO_BUFFERS) || 2320167514Skmacy !in_range(t->rspq_size, MIN_RSPQ_ENTRIES, MAX_RSPQ_ENTRIES)) 2321171471Skmacy return (EINVAL); 2322167514Skmacy if ((sc->flags & FULL_INIT_DONE) && 2323167514Skmacy (t->rspq_size >= 0 || t->fl_size[0] >= 0 || 2324167514Skmacy t->fl_size[1] >= 0 || t->txq_size[0] >= 0 || 2325167514Skmacy t->txq_size[1] >= 0 || t->txq_size[2] >= 0 || 2326167514Skmacy t->polling >= 0 || t->cong_thres >= 0)) 2327171471Skmacy return (EBUSY); 2328167514Skmacy 2329167514Skmacy q = &sc->params.sge.qset[t->qset_idx]; 2330167514Skmacy 2331167514Skmacy if (t->rspq_size >= 0) 2332167514Skmacy q->rspq_size = t->rspq_size; 2333167514Skmacy if (t->fl_size[0] >= 0) 2334167514Skmacy q->fl_size = t->fl_size[0]; 2335167514Skmacy if (t->fl_size[1] >= 0) 2336167514Skmacy q->jumbo_size = t->fl_size[1]; 2337167514Skmacy if (t->txq_size[0] >= 0) 2338167514Skmacy q->txq_size[0] = t->txq_size[0]; 2339167514Skmacy if (t->txq_size[1] >= 0) 2340167514Skmacy q->txq_size[1] = t->txq_size[1]; 2341167514Skmacy if (t->txq_size[2] >= 0) 2342167514Skmacy q->txq_size[2] = t->txq_size[2]; 2343167514Skmacy if (t->cong_thres >= 0) 2344167514Skmacy q->cong_thres = t->cong_thres; 2345167514Skmacy if (t->intr_lat >= 0) { 2346167514Skmacy struct sge_qset *qs = &sc->sge.qs[t->qset_idx]; 2347167514Skmacy 2348167514Skmacy q->coalesce_nsecs = t->intr_lat*1000; 2349167514Skmacy t3_update_qset_coalesce(qs, q); 2350167514Skmacy } 2351167514Skmacy break; 2352167514Skmacy } 2353167514Skmacy case CHELSIO_GET_QSET_PARAMS: { 2354167514Skmacy struct qset_params *q; 2355167514Skmacy struct ch_qset_params *t = (struct ch_qset_params *)data; 2356167514Skmacy 2357167514Skmacy if (t->qset_idx >= SGE_QSETS) 2358167514Skmacy return (EINVAL); 2359167514Skmacy 2360167514Skmacy q = &(sc)->params.sge.qset[t->qset_idx]; 2361167514Skmacy t->rspq_size = q->rspq_size; 2362167514Skmacy t->txq_size[0] = q->txq_size[0]; 2363167514Skmacy t->txq_size[1] = q->txq_size[1]; 2364167514Skmacy t->txq_size[2] = q->txq_size[2]; 2365167514Skmacy t->fl_size[0] = q->fl_size; 2366167514Skmacy t->fl_size[1] = q->jumbo_size; 2367167514Skmacy t->polling = q->polling; 2368167514Skmacy t->intr_lat = q->coalesce_nsecs / 1000; 2369167514Skmacy t->cong_thres = q->cong_thres; 2370167514Skmacy break; 2371167514Skmacy } 2372167514Skmacy case CHELSIO_SET_QSET_NUM: { 2373167514Skmacy struct ch_reg *edata = (struct ch_reg *)data; 2374171803Skmacy unsigned int port_idx = pi->port_id; 2375167514Skmacy 2376167514Skmacy if (sc->flags & FULL_INIT_DONE) 2377167514Skmacy return (EBUSY); 2378167514Skmacy if (edata->val < 1 || 2379167514Skmacy (edata->val > 1 && !(sc->flags & USING_MSIX))) 2380167514Skmacy return (EINVAL); 2381167514Skmacy if (edata->val + sc->port[!port_idx].nqsets > SGE_QSETS) 2382167514Skmacy return (EINVAL); 2383167514Skmacy sc->port[port_idx].nqsets = edata->val; 2384169978Skmacy sc->port[0].first_qset = 0; 2385167514Skmacy /* 2386169978Skmacy * XXX hardcode ourselves to 2 ports just like LEEENUX 2387167514Skmacy */ 2388167514Skmacy sc->port[1].first_qset = sc->port[0].nqsets; 2389167514Skmacy break; 2390167514Skmacy } 2391167514Skmacy case CHELSIO_GET_QSET_NUM: { 2392167514Skmacy struct ch_reg *edata = (struct ch_reg *)data; 2393167514Skmacy edata->val = pi->nqsets; 2394167514Skmacy break; 2395167514Skmacy } 2396169978Skmacy#ifdef notyet 2397167514Skmacy case CHELSIO_LOAD_FW: 2398167514Skmacy case CHELSIO_GET_PM: 2399167514Skmacy case CHELSIO_SET_PM: 2400167514Skmacy return (EOPNOTSUPP); 2401167514Skmacy break; 2402167514Skmacy#endif 2403169978Skmacy case CHELSIO_SETMTUTAB: { 2404169978Skmacy struct ch_mtus *m = (struct ch_mtus *)data; 2405169978Skmacy int i; 2406169978Skmacy 2407169978Skmacy if (!is_offload(sc)) 2408169978Skmacy return (EOPNOTSUPP); 2409169978Skmacy if (offload_running(sc)) 2410169978Skmacy return (EBUSY); 2411169978Skmacy if (m->nmtus != NMTUS) 2412169978Skmacy return (EINVAL); 2413169978Skmacy if (m->mtus[0] < 81) /* accommodate SACK */ 2414169978Skmacy return (EINVAL); 2415169978Skmacy 2416169978Skmacy /* 2417169978Skmacy * MTUs must be in ascending order 2418169978Skmacy */ 2419169978Skmacy for (i = 1; i < NMTUS; ++i) 2420169978Skmacy if (m->mtus[i] < m->mtus[i - 1]) 2421169978Skmacy return (EINVAL); 2422169978Skmacy 2423169978Skmacy memcpy(sc->params.mtus, m->mtus, 2424169978Skmacy sizeof(sc->params.mtus)); 2425169978Skmacy break; 2426169978Skmacy } 2427169978Skmacy case CHELSIO_GETMTUTAB: { 2428169978Skmacy struct ch_mtus *m = (struct ch_mtus *)data; 2429169978Skmacy 2430169978Skmacy if (!is_offload(sc)) 2431169978Skmacy return (EOPNOTSUPP); 2432169978Skmacy 2433169978Skmacy memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus)); 2434169978Skmacy m->nmtus = NMTUS; 2435169978Skmacy break; 2436171471Skmacy } 2437169978Skmacy case CHELSIO_DEVUP: 2438169978Skmacy if (!is_offload(sc)) 2439169978Skmacy return (EOPNOTSUPP); 2440169978Skmacy return offload_open(pi); 2441169978Skmacy break; 2442167514Skmacy case CHELSIO_GET_MEM: { 2443167514Skmacy struct ch_mem_range *t = (struct ch_mem_range *)data; 2444167514Skmacy struct mc7 *mem; 2445167514Skmacy uint8_t *useraddr; 2446167514Skmacy u64 buf[32]; 2447167514Skmacy 2448167514Skmacy if (!is_offload(sc)) 2449167514Skmacy return (EOPNOTSUPP); 2450167514Skmacy if (!(sc->flags & FULL_INIT_DONE)) 2451167514Skmacy return (EIO); /* need the memory controllers */ 2452167514Skmacy if ((t->addr & 0x7) || (t->len & 0x7)) 2453167514Skmacy return (EINVAL); 2454167514Skmacy if (t->mem_id == MEM_CM) 2455167514Skmacy mem = &sc->cm; 2456167514Skmacy else if (t->mem_id == MEM_PMRX) 2457167514Skmacy mem = &sc->pmrx; 2458167514Skmacy else if (t->mem_id == MEM_PMTX) 2459167514Skmacy mem = &sc->pmtx; 2460167514Skmacy else 2461167514Skmacy return (EINVAL); 2462167514Skmacy 2463167514Skmacy /* 2464167514Skmacy * Version scheme: 2465167514Skmacy * bits 0..9: chip version 2466167514Skmacy * bits 10..15: chip revision 2467167514Skmacy */ 2468167514Skmacy t->version = 3 | (sc->params.rev << 10); 2469167514Skmacy 2470167514Skmacy /* 2471167514Skmacy * Read 256 bytes at a time as len can be large and we don't 2472167514Skmacy * want to use huge intermediate buffers. 2473167514Skmacy */ 2474167514Skmacy useraddr = (uint8_t *)(t + 1); /* advance to start of buffer */ 2475167514Skmacy while (t->len) { 2476167514Skmacy unsigned int chunk = min(t->len, sizeof(buf)); 2477167514Skmacy 2478167514Skmacy error = t3_mc7_bd_read(mem, t->addr / 8, chunk / 8, buf); 2479167514Skmacy if (error) 2480167514Skmacy return (-error); 2481167514Skmacy if (copyout(buf, useraddr, chunk)) 2482167514Skmacy return (EFAULT); 2483167514Skmacy useraddr += chunk; 2484167514Skmacy t->addr += chunk; 2485167514Skmacy t->len -= chunk; 2486167514Skmacy } 2487167514Skmacy break; 2488167514Skmacy } 2489169978Skmacy case CHELSIO_READ_TCAM_WORD: { 2490169978Skmacy struct ch_tcam_word *t = (struct ch_tcam_word *)data; 2491169978Skmacy 2492169978Skmacy if (!is_offload(sc)) 2493169978Skmacy return (EOPNOTSUPP); 2494171471Skmacy if (!(sc->flags & FULL_INIT_DONE)) 2495171471Skmacy return (EIO); /* need MC5 */ 2496169978Skmacy return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf); 2497169978Skmacy break; 2498169978Skmacy } 2499167514Skmacy case CHELSIO_SET_TRACE_FILTER: { 2500167514Skmacy struct ch_trace *t = (struct ch_trace *)data; 2501167514Skmacy const struct trace_params *tp; 2502167514Skmacy 2503167514Skmacy tp = (const struct trace_params *)&t->sip; 2504167514Skmacy if (t->config_tx) 2505167514Skmacy t3_config_trace_filter(sc, tp, 0, t->invert_match, 2506167514Skmacy t->trace_tx); 2507167514Skmacy if (t->config_rx) 2508167514Skmacy t3_config_trace_filter(sc, tp, 1, t->invert_match, 2509167514Skmacy t->trace_rx); 2510167514Skmacy break; 2511167514Skmacy } 2512167514Skmacy case CHELSIO_SET_PKTSCHED: { 2513167514Skmacy struct ch_pktsched_params *p = (struct ch_pktsched_params *)data; 2514167514Skmacy if (sc->open_device_map == 0) 2515167514Skmacy return (EAGAIN); 2516167514Skmacy send_pktsched_cmd(sc, p->sched, p->idx, p->min, p->max, 2517167514Skmacy p->binding); 2518167514Skmacy break; 2519167514Skmacy } 2520167514Skmacy case CHELSIO_IFCONF_GETREGS: { 2521167514Skmacy struct ifconf_regs *regs = (struct ifconf_regs *)data; 2522167514Skmacy int reglen = cxgb_get_regs_len(); 2523167514Skmacy uint8_t *buf = malloc(REGDUMP_SIZE, M_DEVBUF, M_NOWAIT); 2524167514Skmacy if (buf == NULL) { 2525167514Skmacy return (ENOMEM); 2526167514Skmacy } if (regs->len > reglen) 2527167514Skmacy regs->len = reglen; 2528167514Skmacy else if (regs->len < reglen) { 2529167514Skmacy error = E2BIG; 2530167514Skmacy goto done; 2531167514Skmacy } 2532167514Skmacy cxgb_get_regs(sc, regs, buf); 2533167514Skmacy error = copyout(buf, regs->data, reglen); 2534167514Skmacy 2535167514Skmacy done: 2536167514Skmacy free(buf, M_DEVBUF); 2537167514Skmacy 2538167514Skmacy break; 2539167514Skmacy } 2540169978Skmacy case CHELSIO_SET_HW_SCHED: { 2541169978Skmacy struct ch_hw_sched *t = (struct ch_hw_sched *)data; 2542169978Skmacy unsigned int ticks_per_usec = core_ticks_per_usec(sc); 2543169978Skmacy 2544169978Skmacy if ((sc->flags & FULL_INIT_DONE) == 0) 2545169978Skmacy return (EAGAIN); /* need TP to be initialized */ 2546169978Skmacy if (t->sched >= NTX_SCHED || !in_range(t->mode, 0, 1) || 2547169978Skmacy !in_range(t->channel, 0, 1) || 2548169978Skmacy !in_range(t->kbps, 0, 10000000) || 2549169978Skmacy !in_range(t->class_ipg, 0, 10000 * 65535 / ticks_per_usec) || 2550169978Skmacy !in_range(t->flow_ipg, 0, 2551169978Skmacy dack_ticks_to_usec(sc, 0x7ff))) 2552169978Skmacy return (EINVAL); 2553169978Skmacy 2554169978Skmacy if (t->kbps >= 0) { 2555169978Skmacy error = t3_config_sched(sc, t->kbps, t->sched); 2556169978Skmacy if (error < 0) 2557169978Skmacy return (-error); 2558169978Skmacy } 2559169978Skmacy if (t->class_ipg >= 0) 2560169978Skmacy t3_set_sched_ipg(sc, t->sched, t->class_ipg); 2561169978Skmacy if (t->flow_ipg >= 0) { 2562169978Skmacy t->flow_ipg *= 1000; /* us -> ns */ 2563169978Skmacy t3_set_pace_tbl(sc, &t->flow_ipg, t->sched, 1); 2564169978Skmacy } 2565169978Skmacy if (t->mode >= 0) { 2566169978Skmacy int bit = 1 << (S_TX_MOD_TIMER_MODE + t->sched); 2567169978Skmacy 2568169978Skmacy t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP, 2569169978Skmacy bit, t->mode ? bit : 0); 2570169978Skmacy } 2571169978Skmacy if (t->channel >= 0) 2572169978Skmacy t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP, 2573169978Skmacy 1 << t->sched, t->channel << t->sched); 2574169978Skmacy break; 2575169978Skmacy } 2576167514Skmacy default: 2577167514Skmacy return (EOPNOTSUPP); 2578167514Skmacy break; 2579167514Skmacy } 2580167514Skmacy 2581167514Skmacy return (error); 2582167514Skmacy} 2583167514Skmacy 2584167514Skmacystatic __inline void 2585167514Skmacyreg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start, 2586167514Skmacy unsigned int end) 2587167514Skmacy{ 2588167514Skmacy uint32_t *p = (uint32_t *)buf + start; 2589167514Skmacy 2590167514Skmacy for ( ; start <= end; start += sizeof(uint32_t)) 2591167514Skmacy *p++ = t3_read_reg(ap, start); 2592167514Skmacy} 2593167514Skmacy 2594167514Skmacy#define T3_REGMAP_SIZE (3 * 1024) 2595167514Skmacystatic int 2596167514Skmacycxgb_get_regs_len(void) 2597167514Skmacy{ 2598167514Skmacy return T3_REGMAP_SIZE; 2599167514Skmacy} 2600167514Skmacy#undef T3_REGMAP_SIZE 2601167514Skmacy 2602167514Skmacystatic void 2603167514Skmacycxgb_get_regs(adapter_t *sc, struct ifconf_regs *regs, uint8_t *buf) 2604167514Skmacy{ 2605167514Skmacy 2606167514Skmacy /* 2607167514Skmacy * Version scheme: 2608167514Skmacy * bits 0..9: chip version 2609167514Skmacy * bits 10..15: chip revision 2610167514Skmacy * bit 31: set for PCIe cards 2611167514Skmacy */ 2612167514Skmacy regs->version = 3 | (sc->params.rev << 10) | (is_pcie(sc) << 31); 2613167514Skmacy 2614167514Skmacy /* 2615167514Skmacy * We skip the MAC statistics registers because they are clear-on-read. 2616167514Skmacy * Also reading multi-register stats would need to synchronize with the 2617167514Skmacy * periodic mac stats accumulation. Hard to justify the complexity. 2618167514Skmacy */ 2619167514Skmacy memset(buf, 0, REGDUMP_SIZE); 2620167514Skmacy reg_block_dump(sc, buf, 0, A_SG_RSPQ_CREDIT_RETURN); 2621167514Skmacy reg_block_dump(sc, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT); 2622167514Skmacy reg_block_dump(sc, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE); 2623167514Skmacy reg_block_dump(sc, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA); 2624167514Skmacy reg_block_dump(sc, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3); 2625167514Skmacy reg_block_dump(sc, buf, A_XGM_SERDES_STATUS0, 2626167514Skmacy XGM_REG(A_XGM_SERDES_STAT3, 1)); 2627167514Skmacy reg_block_dump(sc, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1), 2628167514Skmacy XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1)); 2629167514Skmacy} 2630