cxgb_main.c revision 183062
1167514Skmacy/************************************************************************** 2167514Skmacy 3178302SkmacyCopyright (c) 2007-2008, Chelsio Inc. 4167514SkmacyAll rights reserved. 5167514Skmacy 6167514SkmacyRedistribution and use in source and binary forms, with or without 7167514Skmacymodification, are permitted provided that the following conditions are met: 8167514Skmacy 9167514Skmacy 1. Redistributions of source code must retain the above copyright notice, 10167514Skmacy this list of conditions and the following disclaimer. 11167514Skmacy 12178302Skmacy 2. Neither the name of the Chelsio Corporation nor the names of its 13167514Skmacy contributors may be used to endorse or promote products derived from 14167514Skmacy this software without specific prior written permission. 15167514Skmacy 16167514SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17167514SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18167514SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19167514SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20167514SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21167514SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22167514SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23167514SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24167514SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25167514SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26167514SkmacyPOSSIBILITY OF SUCH DAMAGE. 27167514Skmacy 28167514Skmacy***************************************************************************/ 29167514Skmacy 30167514Skmacy#include <sys/cdefs.h> 31167514Skmacy__FBSDID("$FreeBSD: head/sys/dev/cxgb/cxgb_main.c 183062 2008-09-16 02:03:28Z 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> 43176472Skmacy#include <sys/ktr.h> 44167514Skmacy#include <sys/rman.h> 45167514Skmacy#include <sys/ioccom.h> 46167514Skmacy#include <sys/mbuf.h> 47167514Skmacy#include <sys/linker.h> 48167514Skmacy#include <sys/firmware.h> 49167514Skmacy#include <sys/socket.h> 50167514Skmacy#include <sys/sockio.h> 51167514Skmacy#include <sys/smp.h> 52167514Skmacy#include <sys/sysctl.h> 53174708Skmacy#include <sys/syslog.h> 54167514Skmacy#include <sys/queue.h> 55167514Skmacy#include <sys/taskqueue.h> 56174708Skmacy#include <sys/proc.h> 57167514Skmacy 58167514Skmacy#include <net/bpf.h> 59167514Skmacy#include <net/ethernet.h> 60167514Skmacy#include <net/if.h> 61167514Skmacy#include <net/if_arp.h> 62167514Skmacy#include <net/if_dl.h> 63167514Skmacy#include <net/if_media.h> 64167514Skmacy#include <net/if_types.h> 65180583Skmacy#include <net/if_vlan_var.h> 66167514Skmacy 67167514Skmacy#include <netinet/in_systm.h> 68167514Skmacy#include <netinet/in.h> 69167514Skmacy#include <netinet/if_ether.h> 70167514Skmacy#include <netinet/ip.h> 71167514Skmacy#include <netinet/ip.h> 72167514Skmacy#include <netinet/tcp.h> 73167514Skmacy#include <netinet/udp.h> 74167514Skmacy 75167514Skmacy#include <dev/pci/pcireg.h> 76167514Skmacy#include <dev/pci/pcivar.h> 77167514Skmacy#include <dev/pci/pci_private.h> 78167514Skmacy 79170076Skmacy#ifdef CONFIG_DEFINED 80170076Skmacy#include <cxgb_include.h> 81170076Skmacy#else 82170076Skmacy#include <dev/cxgb/cxgb_include.h> 83170076Skmacy#endif 84167514Skmacy 85167514Skmacy#ifdef PRIV_SUPPORTED 86167514Skmacy#include <sys/priv.h> 87167514Skmacy#endif 88167514Skmacy 89174726Skmacy#ifdef IFNET_MULTIQUEUE 90174708Skmacy#include <machine/intr_machdep.h> 91174726Skmacy#endif 92174708Skmacy 93167514Skmacystatic int cxgb_setup_msix(adapter_t *, int); 94170654Skmacystatic void cxgb_teardown_msix(adapter_t *); 95167514Skmacystatic void cxgb_init(void *); 96167514Skmacystatic void cxgb_init_locked(struct port_info *); 97167734Skmacystatic void cxgb_stop_locked(struct port_info *); 98167514Skmacystatic void cxgb_set_rxmode(struct port_info *); 99167514Skmacystatic int cxgb_ioctl(struct ifnet *, unsigned long, caddr_t); 100167514Skmacystatic int cxgb_media_change(struct ifnet *); 101167514Skmacystatic void cxgb_media_status(struct ifnet *, struct ifmediareq *); 102167514Skmacystatic int setup_sge_qsets(adapter_t *); 103167514Skmacystatic void cxgb_async_intr(void *); 104167514Skmacystatic void cxgb_ext_intr_handler(void *, int); 105170869Skmacystatic void cxgb_tick_handler(void *, int); 106170869Skmacystatic void cxgb_down_locked(struct adapter *sc); 107167514Skmacystatic void cxgb_tick(void *); 108167514Skmacystatic void setup_rss(adapter_t *sc); 109167514Skmacy 110167514Skmacy/* Attachment glue for the PCI controller end of the device. Each port of 111167514Skmacy * the device is attached separately, as defined later. 112167514Skmacy */ 113167514Skmacystatic int cxgb_controller_probe(device_t); 114167514Skmacystatic int cxgb_controller_attach(device_t); 115167514Skmacystatic int cxgb_controller_detach(device_t); 116167514Skmacystatic void cxgb_free(struct adapter *); 117167514Skmacystatic __inline void reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start, 118167514Skmacy unsigned int end); 119182679Skmacystatic void cxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf); 120167514Skmacystatic int cxgb_get_regs_len(void); 121169978Skmacystatic int offload_open(struct port_info *pi); 122171978Skmacystatic void touch_bars(device_t dev); 123174626Skmacystatic int offload_close(struct t3cdev *tdev); 124176472Skmacystatic void cxgb_link_start(struct port_info *p); 125167514Skmacy 126167514Skmacystatic device_method_t cxgb_controller_methods[] = { 127167514Skmacy DEVMETHOD(device_probe, cxgb_controller_probe), 128167514Skmacy DEVMETHOD(device_attach, cxgb_controller_attach), 129167514Skmacy DEVMETHOD(device_detach, cxgb_controller_detach), 130167514Skmacy 131167514Skmacy /* bus interface */ 132167514Skmacy DEVMETHOD(bus_print_child, bus_generic_print_child), 133167514Skmacy DEVMETHOD(bus_driver_added, bus_generic_driver_added), 134167514Skmacy 135167514Skmacy { 0, 0 } 136167514Skmacy}; 137167514Skmacy 138167514Skmacystatic driver_t cxgb_controller_driver = { 139167514Skmacy "cxgbc", 140167514Skmacy cxgb_controller_methods, 141167514Skmacy sizeof(struct adapter) 142167514Skmacy}; 143167514Skmacy 144167514Skmacystatic devclass_t cxgb_controller_devclass; 145167514SkmacyDRIVER_MODULE(cxgbc, pci, cxgb_controller_driver, cxgb_controller_devclass, 0, 0); 146167514Skmacy 147167514Skmacy/* 148167514Skmacy * Attachment glue for the ports. Attachment is done directly to the 149167514Skmacy * controller device. 150167514Skmacy */ 151167514Skmacystatic int cxgb_port_probe(device_t); 152167514Skmacystatic int cxgb_port_attach(device_t); 153167514Skmacystatic int cxgb_port_detach(device_t); 154167514Skmacy 155167514Skmacystatic device_method_t cxgb_port_methods[] = { 156167514Skmacy DEVMETHOD(device_probe, cxgb_port_probe), 157167514Skmacy DEVMETHOD(device_attach, cxgb_port_attach), 158167514Skmacy DEVMETHOD(device_detach, cxgb_port_detach), 159167514Skmacy { 0, 0 } 160167514Skmacy}; 161167514Skmacy 162167514Skmacystatic driver_t cxgb_port_driver = { 163167514Skmacy "cxgb", 164167514Skmacy cxgb_port_methods, 165167514Skmacy 0 166167514Skmacy}; 167167514Skmacy 168167514Skmacystatic d_ioctl_t cxgb_extension_ioctl; 169170654Skmacystatic d_open_t cxgb_extension_open; 170170654Skmacystatic d_close_t cxgb_extension_close; 171167514Skmacy 172170654Skmacystatic struct cdevsw cxgb_cdevsw = { 173170654Skmacy .d_version = D_VERSION, 174170654Skmacy .d_flags = 0, 175170654Skmacy .d_open = cxgb_extension_open, 176170654Skmacy .d_close = cxgb_extension_close, 177170654Skmacy .d_ioctl = cxgb_extension_ioctl, 178170654Skmacy .d_name = "cxgb", 179170654Skmacy}; 180170654Skmacy 181167514Skmacystatic devclass_t cxgb_port_devclass; 182167514SkmacyDRIVER_MODULE(cxgb, cxgbc, cxgb_port_driver, cxgb_port_devclass, 0, 0); 183167514Skmacy 184167514Skmacy#define SGE_MSIX_COUNT (SGE_QSETS + 1) 185167514Skmacy 186167514Skmacy/* 187167514Skmacy * The driver uses the best interrupt scheme available on a platform in the 188167514Skmacy * order MSI-X, MSI, legacy pin interrupts. This parameter determines which 189167514Skmacy * of these schemes the driver may consider as follows: 190167514Skmacy * 191167514Skmacy * msi = 2: choose from among all three options 192167514Skmacy * msi = 1 : only consider MSI and pin interrupts 193167514Skmacy * msi = 0: force pin interrupts 194167514Skmacy */ 195167760Skmacystatic int msi_allowed = 2; 196170083Skmacy 197167514SkmacyTUNABLE_INT("hw.cxgb.msi_allowed", &msi_allowed); 198167514SkmacySYSCTL_NODE(_hw, OID_AUTO, cxgb, CTLFLAG_RD, 0, "CXGB driver parameters"); 199167514SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, msi_allowed, CTLFLAG_RDTUN, &msi_allowed, 0, 200167514Skmacy "MSI-X, MSI, INTx selector"); 201169978Skmacy 202169053Skmacy/* 203169978Skmacy * The driver enables offload as a default. 204169978Skmacy * To disable it, use ofld_disable = 1. 205169053Skmacy */ 206169978Skmacystatic int ofld_disable = 0; 207169978SkmacyTUNABLE_INT("hw.cxgb.ofld_disable", &ofld_disable); 208169978SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, ofld_disable, CTLFLAG_RDTUN, &ofld_disable, 0, 209169978Skmacy "disable ULP offload"); 210169978Skmacy 211169978Skmacy/* 212169978Skmacy * The driver uses an auto-queue algorithm by default. 213169978Skmacy * To disable it and force a single queue-set per port, use singleq = 1. 214169978Skmacy */ 215174708Skmacystatic int singleq = 0; 216169978SkmacyTUNABLE_INT("hw.cxgb.singleq", &singleq); 217169978SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, singleq, CTLFLAG_RDTUN, &singleq, 0, 218169978Skmacy "use a single queue-set per port"); 219167514Skmacy 220175200Skmacy 221176572Skmacy/* 222176572Skmacy * The driver uses an auto-queue algorithm by default. 223176572Skmacy * To disable it and force a single queue-set per port, use singleq = 1. 224176572Skmacy */ 225176572Skmacystatic int force_fw_update = 0; 226176572SkmacyTUNABLE_INT("hw.cxgb.force_fw_update", &force_fw_update); 227176572SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, force_fw_update, CTLFLAG_RDTUN, &force_fw_update, 0, 228176572Skmacy "update firmware even if up to date"); 229175200Skmacy 230183059Skmacyint cxgb_use_16k_clusters = 1; 231175200SkmacyTUNABLE_INT("hw.cxgb.use_16k_clusters", &cxgb_use_16k_clusters); 232175200SkmacySYSCTL_UINT(_hw_cxgb, OID_AUTO, use_16k_clusters, CTLFLAG_RDTUN, 233175200Skmacy &cxgb_use_16k_clusters, 0, "use 16kB clusters for the jumbo queue "); 234175200Skmacy 235167514Skmacyenum { 236167514Skmacy MAX_TXQ_ENTRIES = 16384, 237167514Skmacy MAX_CTRL_TXQ_ENTRIES = 1024, 238167514Skmacy MAX_RSPQ_ENTRIES = 16384, 239167514Skmacy MAX_RX_BUFFERS = 16384, 240167514Skmacy MAX_RX_JUMBO_BUFFERS = 16384, 241167514Skmacy MIN_TXQ_ENTRIES = 4, 242167514Skmacy MIN_CTRL_TXQ_ENTRIES = 4, 243167514Skmacy MIN_RSPQ_ENTRIES = 32, 244172096Skmacy MIN_FL_ENTRIES = 32, 245172096Skmacy MIN_FL_JUMBO_ENTRIES = 32 246167514Skmacy}; 247167514Skmacy 248171471Skmacystruct filter_info { 249171471Skmacy u32 sip; 250171471Skmacy u32 sip_mask; 251171471Skmacy u32 dip; 252171471Skmacy u16 sport; 253171471Skmacy u16 dport; 254171471Skmacy u32 vlan:12; 255171471Skmacy u32 vlan_prio:3; 256171471Skmacy u32 mac_hit:1; 257171471Skmacy u32 mac_idx:4; 258171471Skmacy u32 mac_vld:1; 259171471Skmacy u32 pkt_type:2; 260171471Skmacy u32 report_filter_id:1; 261171471Skmacy u32 pass:1; 262171471Skmacy u32 rss:1; 263171471Skmacy u32 qset:3; 264171471Skmacy u32 locked:1; 265171471Skmacy u32 valid:1; 266171471Skmacy}; 267171471Skmacy 268171471Skmacyenum { FILTER_NO_VLAN_PRI = 7 }; 269171471Skmacy 270182679Skmacy#define EEPROM_MAGIC 0x38E2F10C 271182679Skmacy 272167514Skmacy#define PORT_MASK ((1 << MAX_NPORTS) - 1) 273167514Skmacy 274167514Skmacy/* Table for probing the cards. The desc field isn't actually used */ 275167514Skmacystruct cxgb_ident { 276167514Skmacy uint16_t vendor; 277167514Skmacy uint16_t device; 278167514Skmacy int index; 279167514Skmacy char *desc; 280167514Skmacy} cxgb_identifiers[] = { 281167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0020, 0, "PE9000"}, 282167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0021, 1, "T302E"}, 283167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0022, 2, "T310E"}, 284167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0023, 3, "T320X"}, 285167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0024, 1, "T302X"}, 286167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0025, 3, "T320E"}, 287167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0026, 2, "T310X"}, 288167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0030, 2, "T3B10"}, 289167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0031, 3, "T3B20"}, 290167514Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0032, 1, "T3B02"}, 291170654Skmacy {PCI_VENDOR_ID_CHELSIO, 0x0033, 4, "T3B04"}, 292167514Skmacy {0, 0, 0, NULL} 293167514Skmacy}; 294167514Skmacy 295171471Skmacystatic int set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset); 296171471Skmacy 297176472Skmacy 298174708Skmacystatic __inline char 299171471Skmacyt3rev2char(struct adapter *adapter) 300171471Skmacy{ 301171471Skmacy char rev = 'z'; 302171471Skmacy 303171471Skmacy switch(adapter->params.rev) { 304171471Skmacy case T3_REV_A: 305171471Skmacy rev = 'a'; 306171471Skmacy break; 307171471Skmacy case T3_REV_B: 308171471Skmacy case T3_REV_B2: 309171471Skmacy rev = 'b'; 310171471Skmacy break; 311171471Skmacy case T3_REV_C: 312171471Skmacy rev = 'c'; 313171471Skmacy break; 314171471Skmacy } 315171471Skmacy return rev; 316171471Skmacy} 317171471Skmacy 318167514Skmacystatic struct cxgb_ident * 319167514Skmacycxgb_get_ident(device_t dev) 320167514Skmacy{ 321167514Skmacy struct cxgb_ident *id; 322167514Skmacy 323167514Skmacy for (id = cxgb_identifiers; id->desc != NULL; id++) { 324167514Skmacy if ((id->vendor == pci_get_vendor(dev)) && 325167514Skmacy (id->device == pci_get_device(dev))) { 326167514Skmacy return (id); 327167514Skmacy } 328167514Skmacy } 329167514Skmacy return (NULL); 330167514Skmacy} 331167514Skmacy 332167514Skmacystatic const struct adapter_info * 333167514Skmacycxgb_get_adapter_info(device_t dev) 334167514Skmacy{ 335167514Skmacy struct cxgb_ident *id; 336167514Skmacy const struct adapter_info *ai; 337167514Skmacy 338167514Skmacy id = cxgb_get_ident(dev); 339167514Skmacy if (id == NULL) 340167514Skmacy return (NULL); 341167514Skmacy 342167514Skmacy ai = t3_get_adapter_info(id->index); 343167514Skmacy 344167514Skmacy return (ai); 345167514Skmacy} 346167514Skmacy 347167514Skmacystatic int 348167514Skmacycxgb_controller_probe(device_t dev) 349167514Skmacy{ 350167514Skmacy const struct adapter_info *ai; 351167514Skmacy char *ports, buf[80]; 352170654Skmacy int nports; 353182695Skmacy struct adapter *sc = device_get_softc(dev); 354170654Skmacy 355167514Skmacy ai = cxgb_get_adapter_info(dev); 356167514Skmacy if (ai == NULL) 357167514Skmacy return (ENXIO); 358167514Skmacy 359170654Skmacy nports = ai->nports0 + ai->nports1; 360170654Skmacy if (nports == 1) 361167514Skmacy ports = "port"; 362167514Skmacy else 363167514Skmacy ports = "ports"; 364167514Skmacy 365182695Skmacy snprintf(buf, sizeof(buf), "%s %sNIC, rev: %d nports: %d %s", 366182695Skmacy ai->desc, is_offload(sc) ? "R" : "", 367182695Skmacy sc->params.rev, nports, ports); 368167514Skmacy device_set_desc_copy(dev, buf); 369167514Skmacy return (BUS_PROBE_DEFAULT); 370167514Skmacy} 371167514Skmacy 372176572Skmacy#define FW_FNAME "cxgb_t3fw" 373176613Skmacy#define TPEEPROM_NAME "t3b_tp_eeprom" 374176613Skmacy#define TPSRAM_NAME "t3b_protocol_sram" 375171471Skmacy 376167514Skmacystatic int 377169978Skmacyupgrade_fw(adapter_t *sc) 378167514Skmacy{ 379167514Skmacy#ifdef FIRMWARE_LATEST 380167514Skmacy const struct firmware *fw; 381167514Skmacy#else 382167514Skmacy struct firmware *fw; 383167514Skmacy#endif 384167514Skmacy int status; 385167514Skmacy 386176572Skmacy if ((fw = firmware_get(FW_FNAME)) == NULL) { 387176572Skmacy device_printf(sc->dev, "Could not find firmware image %s\n", FW_FNAME); 388169978Skmacy return (ENOENT); 389171471Skmacy } else 390176572Skmacy device_printf(sc->dev, "updating firmware on card\n"); 391167514Skmacy status = t3_load_fw(sc, (const uint8_t *)fw->data, fw->datasize); 392167514Skmacy 393171471Skmacy device_printf(sc->dev, "firmware update returned %s %d\n", (status == 0) ? "success" : "fail", status); 394171471Skmacy 395167514Skmacy firmware_put(fw, FIRMWARE_UNLOAD); 396167514Skmacy 397167514Skmacy return (status); 398167514Skmacy} 399167514Skmacy 400167514Skmacystatic int 401167514Skmacycxgb_controller_attach(device_t dev) 402167514Skmacy{ 403167514Skmacy device_t child; 404167514Skmacy const struct adapter_info *ai; 405167514Skmacy struct adapter *sc; 406172109Skmacy int i, error = 0; 407167514Skmacy uint32_t vers; 408167760Skmacy int port_qsets = 1; 409171868Skmacy#ifdef MSI_SUPPORTED 410172109Skmacy int msi_needed, reg; 411176472Skmacy#endif 412176472Skmacy int must_load = 0; 413167514Skmacy sc = device_get_softc(dev); 414167514Skmacy sc->dev = dev; 415169978Skmacy sc->msi_count = 0; 416172109Skmacy ai = cxgb_get_adapter_info(dev); 417172109Skmacy 418172109Skmacy /* 419172109Skmacy * XXX not really related but a recent addition 420172109Skmacy */ 421172109Skmacy#ifdef MSI_SUPPORTED 422167840Skmacy /* find the PCIe link width and set max read request to 4KB*/ 423167840Skmacy if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 424167840Skmacy uint16_t lnk, pectl; 425167840Skmacy lnk = pci_read_config(dev, reg + 0x12, 2); 426167840Skmacy sc->link_width = (lnk >> 4) & 0x3f; 427167840Skmacy 428167840Skmacy pectl = pci_read_config(dev, reg + 0x8, 2); 429167840Skmacy pectl = (pectl & ~0x7000) | (5 << 12); 430167840Skmacy pci_write_config(dev, reg + 0x8, pectl, 2); 431167840Skmacy } 432171471Skmacy 433171471Skmacy if (sc->link_width != 0 && sc->link_width <= 4 && 434171471Skmacy (ai->nports0 + ai->nports1) <= 2) { 435167840Skmacy device_printf(sc->dev, 436167862Skmacy "PCIe x%d Link, expect reduced performance\n", 437167840Skmacy sc->link_width); 438167840Skmacy } 439172109Skmacy#endif 440171978Skmacy touch_bars(dev); 441167514Skmacy pci_enable_busmaster(dev); 442167514Skmacy /* 443167514Skmacy * Allocate the registers and make them available to the driver. 444167514Skmacy * The registers that we care about for NIC mode are in BAR 0 445167514Skmacy */ 446167514Skmacy sc->regs_rid = PCIR_BAR(0); 447167514Skmacy if ((sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 448167514Skmacy &sc->regs_rid, RF_ACTIVE)) == NULL) { 449176472Skmacy device_printf(dev, "Cannot allocate BAR region 0\n"); 450167514Skmacy return (ENXIO); 451167514Skmacy } 452176472Skmacy sc->udbs_rid = PCIR_BAR(2); 453176472Skmacy if ((sc->udbs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 454176472Skmacy &sc->udbs_rid, RF_ACTIVE)) == NULL) { 455176472Skmacy device_printf(dev, "Cannot allocate BAR region 1\n"); 456176472Skmacy error = ENXIO; 457176472Skmacy goto out; 458176472Skmacy } 459167514Skmacy 460170869Skmacy snprintf(sc->lockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb controller lock %d", 461170869Skmacy device_get_unit(dev)); 462170869Skmacy ADAPTER_LOCK_INIT(sc, sc->lockbuf); 463170869Skmacy 464170869Skmacy snprintf(sc->reglockbuf, ADAPTER_LOCK_NAME_LEN, "SGE reg lock %d", 465170869Skmacy device_get_unit(dev)); 466170869Skmacy snprintf(sc->mdiolockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb mdio lock %d", 467170869Skmacy device_get_unit(dev)); 468170869Skmacy snprintf(sc->elmerlockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb elmer lock %d", 469170869Skmacy device_get_unit(dev)); 470167514Skmacy 471176472Skmacy MTX_INIT(&sc->sge.reg_lock, sc->reglockbuf, NULL, MTX_SPIN); 472170869Skmacy MTX_INIT(&sc->mdio_lock, sc->mdiolockbuf, NULL, MTX_DEF); 473170869Skmacy MTX_INIT(&sc->elmer_lock, sc->elmerlockbuf, NULL, MTX_DEF); 474170869Skmacy 475167514Skmacy sc->bt = rman_get_bustag(sc->regs_res); 476167514Skmacy sc->bh = rman_get_bushandle(sc->regs_res); 477167514Skmacy sc->mmio_len = rman_get_size(sc->regs_res); 478167769Skmacy 479167769Skmacy if (t3_prep_adapter(sc, ai, 1) < 0) { 480170654Skmacy printf("prep adapter failed\n"); 481167769Skmacy error = ENODEV; 482167769Skmacy goto out; 483167769Skmacy } 484177464Skmacy /* Allocate the BAR for doing MSI-X. If it succeeds, try to allocate 485167514Skmacy * enough messages for the queue sets. If that fails, try falling 486167514Skmacy * back to MSI. If that fails, then try falling back to the legacy 487167514Skmacy * interrupt pin model. 488167514Skmacy */ 489167514Skmacy#ifdef MSI_SUPPORTED 490167760Skmacy 491167514Skmacy sc->msix_regs_rid = 0x20; 492167514Skmacy if ((msi_allowed >= 2) && 493167514Skmacy (sc->msix_regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 494167514Skmacy &sc->msix_regs_rid, RF_ACTIVE)) != NULL) { 495167514Skmacy 496169978Skmacy msi_needed = sc->msi_count = SGE_MSIX_COUNT; 497167760Skmacy 498169978Skmacy if (((error = pci_alloc_msix(dev, &sc->msi_count)) != 0) || 499169978Skmacy (sc->msi_count != msi_needed)) { 500169978Skmacy device_printf(dev, "msix allocation failed - msi_count = %d" 501169978Skmacy " msi_needed=%d will try msi err=%d\n", sc->msi_count, 502169978Skmacy msi_needed, error); 503169978Skmacy sc->msi_count = 0; 504167514Skmacy pci_release_msi(dev); 505167514Skmacy bus_release_resource(dev, SYS_RES_MEMORY, 506167514Skmacy sc->msix_regs_rid, sc->msix_regs_res); 507167514Skmacy sc->msix_regs_res = NULL; 508167514Skmacy } else { 509167514Skmacy sc->flags |= USING_MSIX; 510170081Skmacy sc->cxgb_intr = t3_intr_msix; 511167514Skmacy } 512167514Skmacy } 513167514Skmacy 514169978Skmacy if ((msi_allowed >= 1) && (sc->msi_count == 0)) { 515169978Skmacy sc->msi_count = 1; 516169978Skmacy if (pci_alloc_msi(dev, &sc->msi_count)) { 517167760Skmacy device_printf(dev, "alloc msi failed - will try INTx\n"); 518169978Skmacy sc->msi_count = 0; 519167514Skmacy pci_release_msi(dev); 520167514Skmacy } else { 521167514Skmacy sc->flags |= USING_MSI; 522167514Skmacy sc->irq_rid = 1; 523170081Skmacy sc->cxgb_intr = t3_intr_msi; 524167514Skmacy } 525167514Skmacy } 526167514Skmacy#endif 527169978Skmacy if (sc->msi_count == 0) { 528167760Skmacy device_printf(dev, "using line interrupts\n"); 529167514Skmacy sc->irq_rid = 0; 530170081Skmacy sc->cxgb_intr = t3b_intr; 531167514Skmacy } 532167514Skmacy 533177464Skmacy if ((sc->flags & USING_MSIX) && !singleq) 534177464Skmacy port_qsets = min((SGE_QSETS/(sc)->params.nports), mp_ncpus); 535177464Skmacy 536167514Skmacy /* Create a private taskqueue thread for handling driver events */ 537167514Skmacy#ifdef TASKQUEUE_CURRENT 538167514Skmacy sc->tq = taskqueue_create("cxgb_taskq", M_NOWAIT, 539167514Skmacy taskqueue_thread_enqueue, &sc->tq); 540167514Skmacy#else 541167514Skmacy sc->tq = taskqueue_create_fast("cxgb_taskq", M_NOWAIT, 542167514Skmacy taskqueue_thread_enqueue, &sc->tq); 543167514Skmacy#endif 544167514Skmacy if (sc->tq == NULL) { 545167514Skmacy device_printf(dev, "failed to allocate controller task queue\n"); 546167514Skmacy goto out; 547167514Skmacy } 548171804Skmacy 549167514Skmacy taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq", 550167514Skmacy device_get_nameunit(dev)); 551167514Skmacy TASK_INIT(&sc->ext_intr_task, 0, cxgb_ext_intr_handler, sc); 552170869Skmacy TASK_INIT(&sc->tick_task, 0, cxgb_tick_handler, sc); 553167514Skmacy 554167514Skmacy 555167514Skmacy /* Create a periodic callout for checking adapter status */ 556170869Skmacy callout_init(&sc->cxgb_tick_ch, TRUE); 557167514Skmacy 558176572Skmacy if ((t3_check_fw_version(sc, &must_load) != 0 && must_load) || force_fw_update) { 559167514Skmacy /* 560167514Skmacy * Warn user that a firmware update will be attempted in init. 561167514Skmacy */ 562169978Skmacy device_printf(dev, "firmware needs to be updated to version %d.%d.%d\n", 563169978Skmacy FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO); 564167514Skmacy sc->flags &= ~FW_UPTODATE; 565167514Skmacy } else { 566167514Skmacy sc->flags |= FW_UPTODATE; 567167514Skmacy } 568171471Skmacy 569176472Skmacy if (t3_check_tpsram_version(sc, &must_load) != 0 && must_load) { 570171471Skmacy /* 571171471Skmacy * Warn user that a firmware update will be attempted in init. 572171471Skmacy */ 573171471Skmacy device_printf(dev, "SRAM needs to be updated to version %c-%d.%d.%d\n", 574171471Skmacy t3rev2char(sc), TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); 575171471Skmacy sc->flags &= ~TPS_UPTODATE; 576171471Skmacy } else { 577171471Skmacy sc->flags |= TPS_UPTODATE; 578171471Skmacy } 579167514Skmacy 580167514Skmacy /* 581167514Skmacy * Create a child device for each MAC. The ethernet attachment 582167514Skmacy * will be done in these children. 583167760Skmacy */ 584167760Skmacy for (i = 0; i < (sc)->params.nports; i++) { 585171978Skmacy struct port_info *pi; 586171978Skmacy 587167514Skmacy if ((child = device_add_child(dev, "cxgb", -1)) == NULL) { 588167514Skmacy device_printf(dev, "failed to add child port\n"); 589167514Skmacy error = EINVAL; 590167514Skmacy goto out; 591167514Skmacy } 592171978Skmacy pi = &sc->port[i]; 593171978Skmacy pi->adapter = sc; 594171978Skmacy pi->nqsets = port_qsets; 595171978Skmacy pi->first_qset = i*port_qsets; 596171978Skmacy pi->port_id = i; 597171978Skmacy pi->tx_chan = i >= ai->nports0; 598171978Skmacy pi->txpkt_intf = pi->tx_chan ? 2 * (i - ai->nports0) + 1 : 2 * i; 599171978Skmacy sc->rxpkt_map[pi->txpkt_intf] = i; 600174708Skmacy sc->port[i].tx_chan = i >= ai->nports0; 601171471Skmacy sc->portdev[i] = child; 602171978Skmacy device_set_softc(child, pi); 603167514Skmacy } 604167514Skmacy if ((error = bus_generic_attach(dev)) != 0) 605167514Skmacy goto out; 606167514Skmacy 607167514Skmacy /* initialize sge private state */ 608170654Skmacy t3_sge_init_adapter(sc); 609167514Skmacy 610167514Skmacy t3_led_ready(sc); 611169978Skmacy 612169978Skmacy cxgb_offload_init(); 613169978Skmacy if (is_offload(sc)) { 614169978Skmacy setbit(&sc->registered_device_map, OFFLOAD_DEVMAP_BIT); 615169978Skmacy cxgb_adapter_ofld(sc); 616169978Skmacy } 617167514Skmacy error = t3_get_fw_version(sc, &vers); 618167514Skmacy if (error) 619167514Skmacy goto out; 620167514Skmacy 621169978Skmacy snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d.%d", 622169978Skmacy G_FW_VERSION_MAJOR(vers), G_FW_VERSION_MINOR(vers), 623169978Skmacy G_FW_VERSION_MICRO(vers)); 624169978Skmacy 625176472Skmacy device_printf(sc->dev, "Firmware Version %s\n", &sc->fw_version[0]); 626181652Skmacy callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc); 627174708Skmacy t3_add_attach_sysctls(sc); 628167514Skmacyout: 629167514Skmacy if (error) 630167514Skmacy cxgb_free(sc); 631167514Skmacy 632167514Skmacy return (error); 633167514Skmacy} 634167514Skmacy 635167514Skmacystatic int 636167514Skmacycxgb_controller_detach(device_t dev) 637167514Skmacy{ 638167514Skmacy struct adapter *sc; 639167514Skmacy 640167514Skmacy sc = device_get_softc(dev); 641167514Skmacy 642167514Skmacy cxgb_free(sc); 643167514Skmacy 644167514Skmacy return (0); 645167514Skmacy} 646167514Skmacy 647167514Skmacystatic void 648167514Skmacycxgb_free(struct adapter *sc) 649167514Skmacy{ 650167514Skmacy int i; 651167514Skmacy 652176472Skmacy ADAPTER_LOCK(sc); 653176472Skmacy sc->flags |= CXGB_SHUTDOWN; 654176472Skmacy ADAPTER_UNLOCK(sc); 655174708Skmacy cxgb_pcpu_shutdown_threads(sc); 656170869Skmacy ADAPTER_LOCK(sc); 657176472Skmacy 658174708Skmacy/* 659174708Skmacy * drops the lock 660174708Skmacy */ 661170869Skmacy cxgb_down_locked(sc); 662169978Skmacy 663169978Skmacy#ifdef MSI_SUPPORTED 664169978Skmacy if (sc->flags & (USING_MSI | USING_MSIX)) { 665169978Skmacy device_printf(sc->dev, "releasing msi message(s)\n"); 666169978Skmacy pci_release_msi(sc->dev); 667169978Skmacy } else { 668169978Skmacy device_printf(sc->dev, "no msi message to release\n"); 669169978Skmacy } 670169978Skmacy#endif 671169978Skmacy if (sc->msix_regs_res != NULL) { 672169978Skmacy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid, 673169978Skmacy sc->msix_regs_res); 674169978Skmacy } 675176472Skmacy 676171978Skmacy t3_sge_deinit_sw(sc); 677171978Skmacy /* 678171978Skmacy * Wait for last callout 679171978Skmacy */ 680171978Skmacy 681174708Skmacy DELAY(hz*100); 682170869Skmacy 683167760Skmacy for (i = 0; i < (sc)->params.nports; ++i) { 684167760Skmacy if (sc->portdev[i] != NULL) 685167760Skmacy device_delete_child(sc->dev, sc->portdev[i]); 686167760Skmacy } 687167760Skmacy 688167514Skmacy bus_generic_detach(sc->dev); 689176472Skmacy if (sc->tq != NULL) { 690171978Skmacy taskqueue_free(sc->tq); 691176472Skmacy sc->tq = NULL; 692176472Skmacy } 693176472Skmacy 694169978Skmacy if (is_offload(sc)) { 695169978Skmacy cxgb_adapter_unofld(sc); 696169978Skmacy if (isset(&sc->open_device_map, OFFLOAD_DEVMAP_BIT)) 697169978Skmacy offload_close(&sc->tdev); 698174708Skmacy else 699174708Skmacy printf("cxgb_free: DEVMAP_BIT not set\n"); 700174708Skmacy } else 701174708Skmacy printf("not offloading set\n"); 702183059Skmacy#ifdef notyet 703176472Skmacy if (sc->flags & CXGB_OFLD_INIT) 704176472Skmacy cxgb_offload_deactivate(sc); 705178302Skmacy#endif 706171471Skmacy free(sc->filters, M_DEVBUF); 707167514Skmacy t3_sge_free(sc); 708170869Skmacy 709170869Skmacy cxgb_offload_exit(); 710176472Skmacy 711176472Skmacy if (sc->udbs_res != NULL) 712176472Skmacy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->udbs_rid, 713176472Skmacy sc->udbs_res); 714176472Skmacy 715167514Skmacy if (sc->regs_res != NULL) 716167514Skmacy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->regs_rid, 717167514Skmacy sc->regs_res); 718167514Skmacy 719170869Skmacy MTX_DESTROY(&sc->mdio_lock); 720170869Skmacy MTX_DESTROY(&sc->sge.reg_lock); 721170869Skmacy MTX_DESTROY(&sc->elmer_lock); 722170869Skmacy ADAPTER_LOCK_DEINIT(sc); 723167514Skmacy} 724167514Skmacy 725167514Skmacy/** 726167514Skmacy * setup_sge_qsets - configure SGE Tx/Rx/response queues 727167514Skmacy * @sc: the controller softc 728167514Skmacy * 729167514Skmacy * Determines how many sets of SGE queues to use and initializes them. 730167514Skmacy * We support multiple queue sets per port if we have MSI-X, otherwise 731167514Skmacy * just one queue set per port. 732167514Skmacy */ 733167514Skmacystatic int 734167514Skmacysetup_sge_qsets(adapter_t *sc) 735167514Skmacy{ 736172096Skmacy int i, j, err, irq_idx = 0, qset_idx = 0; 737169978Skmacy u_int ntxq = SGE_TXQ_PER_SET; 738167514Skmacy 739167514Skmacy if ((err = t3_sge_alloc(sc)) != 0) { 740167760Skmacy device_printf(sc->dev, "t3_sge_alloc returned %d\n", err); 741167514Skmacy return (err); 742167514Skmacy } 743167514Skmacy 744167514Skmacy if (sc->params.rev > 0 && !(sc->flags & USING_MSI)) 745167514Skmacy irq_idx = -1; 746167514Skmacy 747172096Skmacy for (i = 0; i < (sc)->params.nports; i++) { 748167514Skmacy struct port_info *pi = &sc->port[i]; 749167514Skmacy 750171978Skmacy for (j = 0; j < pi->nqsets; j++, qset_idx++) { 751167760Skmacy err = t3_sge_alloc_qset(sc, qset_idx, (sc)->params.nports, 752167514Skmacy (sc->flags & USING_MSIX) ? qset_idx + 1 : irq_idx, 753167514Skmacy &sc->params.sge.qset[qset_idx], ntxq, pi); 754167514Skmacy if (err) { 755167514Skmacy t3_free_sge_resources(sc); 756171978Skmacy device_printf(sc->dev, "t3_sge_alloc_qset failed with %d\n", 757171978Skmacy err); 758167514Skmacy return (err); 759167514Skmacy } 760167514Skmacy } 761167514Skmacy } 762167514Skmacy 763167514Skmacy return (0); 764167514Skmacy} 765167514Skmacy 766170654Skmacystatic void 767170654Skmacycxgb_teardown_msix(adapter_t *sc) 768170654Skmacy{ 769170654Skmacy int i, nqsets; 770170654Skmacy 771170654Skmacy for (nqsets = i = 0; i < (sc)->params.nports; i++) 772170654Skmacy nqsets += sc->port[i].nqsets; 773170654Skmacy 774170654Skmacy for (i = 0; i < nqsets; i++) { 775170654Skmacy if (sc->msix_intr_tag[i] != NULL) { 776170654Skmacy bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 777170654Skmacy sc->msix_intr_tag[i]); 778170654Skmacy sc->msix_intr_tag[i] = NULL; 779170654Skmacy } 780170654Skmacy if (sc->msix_irq_res[i] != NULL) { 781170654Skmacy bus_release_resource(sc->dev, SYS_RES_IRQ, 782170654Skmacy sc->msix_irq_rid[i], sc->msix_irq_res[i]); 783170654Skmacy sc->msix_irq_res[i] = NULL; 784170654Skmacy } 785170654Skmacy } 786170654Skmacy} 787170654Skmacy 788167514Skmacystatic int 789167514Skmacycxgb_setup_msix(adapter_t *sc, int msix_count) 790167514Skmacy{ 791167514Skmacy int i, j, k, nqsets, rid; 792167514Skmacy 793167514Skmacy /* The first message indicates link changes and error conditions */ 794167514Skmacy sc->irq_rid = 1; 795167514Skmacy if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 796167514Skmacy &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 797167514Skmacy device_printf(sc->dev, "Cannot allocate msix interrupt\n"); 798167514Skmacy return (EINVAL); 799167514Skmacy } 800167760Skmacy 801167514Skmacy if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET, 802167514Skmacy#ifdef INTR_FILTERS 803171978Skmacy NULL, 804167514Skmacy#endif 805167514Skmacy cxgb_async_intr, sc, &sc->intr_tag)) { 806167514Skmacy device_printf(sc->dev, "Cannot set up interrupt\n"); 807167514Skmacy return (EINVAL); 808167514Skmacy } 809170654Skmacy for (i = k = 0; i < (sc)->params.nports; i++) { 810167514Skmacy nqsets = sc->port[i].nqsets; 811170654Skmacy for (j = 0; j < nqsets; j++, k++) { 812167514Skmacy struct sge_qset *qs = &sc->sge.qs[k]; 813171804Skmacy 814167514Skmacy rid = k + 2; 815167514Skmacy if (cxgb_debug) 816167514Skmacy printf("rid=%d ", rid); 817167514Skmacy if ((sc->msix_irq_res[k] = bus_alloc_resource_any( 818167514Skmacy sc->dev, SYS_RES_IRQ, &rid, 819167514Skmacy RF_SHAREABLE | RF_ACTIVE)) == NULL) { 820167514Skmacy device_printf(sc->dev, "Cannot allocate " 821167514Skmacy "interrupt for message %d\n", rid); 822167514Skmacy return (EINVAL); 823167514Skmacy } 824167514Skmacy sc->msix_irq_rid[k] = rid; 825170654Skmacy if (bus_setup_intr(sc->dev, sc->msix_irq_res[k], 826174708Skmacy INTR_MPSAFE|INTR_TYPE_NET, 827167514Skmacy#ifdef INTR_FILTERS 828171978Skmacy NULL, 829167514Skmacy#endif 830167514Skmacy t3_intr_msix, qs, &sc->msix_intr_tag[k])) { 831167514Skmacy device_printf(sc->dev, "Cannot set up " 832167514Skmacy "interrupt for message %d\n", rid); 833167514Skmacy return (EINVAL); 834167514Skmacy } 835174708Skmacy#ifdef IFNET_MULTIQUEUE 836174708Skmacy if (singleq == 0) { 837174708Skmacy int vector = rman_get_start(sc->msix_irq_res[k]); 838174708Skmacy if (bootverbose) 839174708Skmacy device_printf(sc->dev, "binding vector=%d to cpu=%d\n", vector, k % mp_ncpus); 840174708Skmacy intr_bind(vector, k % mp_ncpus); 841174708Skmacy } 842174708Skmacy#endif 843167514Skmacy } 844167514Skmacy } 845167760Skmacy 846167514Skmacy return (0); 847167514Skmacy} 848167514Skmacy 849167514Skmacystatic int 850167514Skmacycxgb_port_probe(device_t dev) 851167514Skmacy{ 852167514Skmacy struct port_info *p; 853167514Skmacy char buf[80]; 854176472Skmacy const char *desc; 855176472Skmacy 856167514Skmacy p = device_get_softc(dev); 857176472Skmacy desc = p->phy.desc; 858176472Skmacy snprintf(buf, sizeof(buf), "Port %d %s", p->port_id, desc); 859167514Skmacy device_set_desc_copy(dev, buf); 860167514Skmacy return (0); 861167514Skmacy} 862167514Skmacy 863167514Skmacy 864167514Skmacystatic int 865167514Skmacycxgb_makedev(struct port_info *pi) 866167514Skmacy{ 867167514Skmacy 868170654Skmacy pi->port_cdev = make_dev(&cxgb_cdevsw, pi->ifp->if_dunit, 869170654Skmacy UID_ROOT, GID_WHEEL, 0600, if_name(pi->ifp)); 870167514Skmacy 871167514Skmacy if (pi->port_cdev == NULL) 872167514Skmacy return (ENOMEM); 873167514Skmacy 874167514Skmacy pi->port_cdev->si_drv1 = (void *)pi; 875167514Skmacy 876167514Skmacy return (0); 877167514Skmacy} 878167514Skmacy 879167514Skmacy 880167514Skmacy#ifdef TSO_SUPPORTED 881181616Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO) 882167514Skmacy/* Don't enable TSO6 yet */ 883181616Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO4 | IFCAP_JUMBO_MTU | IFCAP_LRO) 884167514Skmacy#else 885167514Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU) 886167514Skmacy/* Don't enable TSO6 yet */ 887167514Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU) 888167514Skmacy#define IFCAP_TSO4 0x0 889171868Skmacy#define IFCAP_TSO6 0x0 890167514Skmacy#define CSUM_TSO 0x0 891167514Skmacy#endif 892167514Skmacy 893167514Skmacy 894167514Skmacystatic int 895167514Skmacycxgb_port_attach(device_t dev) 896167514Skmacy{ 897167514Skmacy struct port_info *p; 898167514Skmacy struct ifnet *ifp; 899170654Skmacy int err, media_flags; 900176472Skmacy struct adapter *sc; 901167514Skmacy 902176472Skmacy 903167514Skmacy p = device_get_softc(dev); 904176472Skmacy sc = p->adapter; 905170869Skmacy snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d", 906171803Skmacy device_get_unit(device_get_parent(dev)), p->port_id); 907170869Skmacy PORT_LOCK_INIT(p, p->lockbuf); 908167514Skmacy 909167514Skmacy /* Allocate an ifnet object and set it up */ 910167514Skmacy ifp = p->ifp = if_alloc(IFT_ETHER); 911167514Skmacy if (ifp == NULL) { 912167514Skmacy device_printf(dev, "Cannot allocate ifnet\n"); 913167514Skmacy return (ENOMEM); 914167514Skmacy } 915167514Skmacy 916167514Skmacy /* 917167514Skmacy * Note that there is currently no watchdog timer. 918167514Skmacy */ 919167514Skmacy if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 920167514Skmacy ifp->if_init = cxgb_init; 921167514Skmacy ifp->if_softc = p; 922167514Skmacy ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 923167514Skmacy ifp->if_ioctl = cxgb_ioctl; 924167514Skmacy ifp->if_start = cxgb_start; 925174708Skmacy 926176472Skmacy#if 0 927174708Skmacy#ifdef IFNET_MULTIQUEUE 928174708Skmacy ifp->if_flags |= IFF_MULTIQ; 929174708Skmacy ifp->if_mq_start = cxgb_pcpu_start; 930174708Skmacy#endif 931176472Skmacy#endif 932167514Skmacy ifp->if_timer = 0; /* Disable ifnet watchdog */ 933167514Skmacy ifp->if_watchdog = NULL; 934167514Skmacy 935175312Skmacy ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 936167514Skmacy IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 937167514Skmacy IFQ_SET_READY(&ifp->if_snd); 938167514Skmacy 939167514Skmacy ifp->if_hwassist = ifp->if_capabilities = ifp->if_capenable = 0; 940167514Skmacy ifp->if_capabilities |= CXGB_CAP; 941167514Skmacy ifp->if_capenable |= CXGB_CAP_ENABLE; 942167514Skmacy ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO); 943171471Skmacy /* 944171471Skmacy * disable TSO on 4-port - it isn't supported by the firmware yet 945171471Skmacy */ 946171471Skmacy if (p->adapter->params.nports > 2) { 947171471Skmacy ifp->if_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6); 948171471Skmacy ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TSO6); 949171471Skmacy ifp->if_hwassist &= ~CSUM_TSO; 950171471Skmacy } 951171471Skmacy 952167514Skmacy ether_ifattach(ifp, p->hw_addr); 953171471Skmacy /* 954171471Skmacy * Only default to jumbo frames on 10GigE 955171471Skmacy */ 956171471Skmacy if (p->adapter->params.nports <= 2) 957180583Skmacy ifp->if_mtu = ETHERMTU_JUMBO; 958167514Skmacy if ((err = cxgb_makedev(p)) != 0) { 959167514Skmacy printf("makedev failed %d\n", err); 960167514Skmacy return (err); 961167514Skmacy } 962167514Skmacy ifmedia_init(&p->media, IFM_IMASK, cxgb_media_change, 963167514Skmacy cxgb_media_status); 964176472Skmacy 965176472Skmacy if (!strcmp(p->phy.desc, "10GBASE-CX4")) { 966170654Skmacy media_flags = IFM_ETHER | IFM_10G_CX4 | IFM_FDX; 967176472Skmacy } else if (!strcmp(p->phy.desc, "10GBASE-SR")) { 968170654Skmacy media_flags = IFM_ETHER | IFM_10G_SR | IFM_FDX; 969177340Skmacy } else if (!strcmp(p->phy.desc, "10GBASE-R")) { 970170654Skmacy media_flags = IFM_ETHER | IFM_10G_LR | IFM_FDX; 971176472Skmacy } else if (!strcmp(p->phy.desc, "10/100/1000BASE-T")) { 972170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_10_T, 0, NULL); 973170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_10_T | IFM_FDX, 974170654Skmacy 0, NULL); 975170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX, 976170654Skmacy 0, NULL); 977170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX | IFM_FDX, 978170654Skmacy 0, NULL); 979170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_1000_T | IFM_FDX, 980170654Skmacy 0, NULL); 981170654Skmacy media_flags = 0; 982170654Skmacy } else { 983176472Skmacy printf("unsupported media type %s\n", p->phy.desc); 984167514Skmacy return (ENXIO); 985167514Skmacy } 986170654Skmacy if (media_flags) { 987170654Skmacy ifmedia_add(&p->media, media_flags, 0, NULL); 988170654Skmacy ifmedia_set(&p->media, media_flags); 989170654Skmacy } else { 990170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL); 991170654Skmacy ifmedia_set(&p->media, IFM_ETHER | IFM_AUTO); 992170654Skmacy } 993167514Skmacy 994177340Skmacy /* Get the latest mac address, User can use a LAA */ 995177340Skmacy bcopy(IF_LLADDR(p->ifp), p->hw_addr, ETHER_ADDR_LEN); 996170654Skmacy t3_sge_init_port(p); 997177415Skmacy#if defined(LINK_ATTACH) 998176472Skmacy cxgb_link_start(p); 999176472Skmacy t3_link_changed(sc, p->port_id); 1000177415Skmacy#endif 1001167514Skmacy return (0); 1002167514Skmacy} 1003167514Skmacy 1004167514Skmacystatic int 1005167514Skmacycxgb_port_detach(device_t dev) 1006167514Skmacy{ 1007167514Skmacy struct port_info *p; 1008167514Skmacy 1009167514Skmacy p = device_get_softc(dev); 1010169978Skmacy 1011169978Skmacy PORT_LOCK(p); 1012170654Skmacy if (p->ifp->if_drv_flags & IFF_DRV_RUNNING) 1013170654Skmacy cxgb_stop_locked(p); 1014169978Skmacy PORT_UNLOCK(p); 1015169978Skmacy 1016171978Skmacy ether_ifdetach(p->ifp); 1017174708Skmacy printf("waiting for callout to stop ..."); 1018174708Skmacy DELAY(1000000); 1019174708Skmacy printf("done\n"); 1020171978Skmacy /* 1021171978Skmacy * the lock may be acquired in ifdetach 1022171978Skmacy */ 1023170869Skmacy PORT_LOCK_DEINIT(p); 1024167514Skmacy if_free(p->ifp); 1025167514Skmacy 1026170654Skmacy if (p->port_cdev != NULL) 1027170654Skmacy destroy_dev(p->port_cdev); 1028170654Skmacy 1029167514Skmacy return (0); 1030167514Skmacy} 1031167514Skmacy 1032167514Skmacyvoid 1033167514Skmacyt3_fatal_err(struct adapter *sc) 1034167514Skmacy{ 1035167514Skmacy u_int fw_status[4]; 1036183062Skmacy 1037172096Skmacy if (sc->flags & FULL_INIT_DONE) { 1038172096Skmacy t3_sge_stop(sc); 1039172096Skmacy t3_write_reg(sc, A_XGM_TX_CTRL, 0); 1040172096Skmacy t3_write_reg(sc, A_XGM_RX_CTRL, 0); 1041172096Skmacy t3_write_reg(sc, XGM_REG(A_XGM_TX_CTRL, 1), 0); 1042172096Skmacy t3_write_reg(sc, XGM_REG(A_XGM_RX_CTRL, 1), 0); 1043172096Skmacy t3_intr_disable(sc); 1044172096Skmacy } 1045167514Skmacy device_printf(sc->dev,"encountered fatal error, operation suspended\n"); 1046167514Skmacy if (!t3_cim_ctl_blk_read(sc, 0xa0, 4, fw_status)) 1047167514Skmacy device_printf(sc->dev, "FW_ status: 0x%x, 0x%x, 0x%x, 0x%x\n", 1048167514Skmacy fw_status[0], fw_status[1], fw_status[2], fw_status[3]); 1049167514Skmacy} 1050167514Skmacy 1051167514Skmacyint 1052167514Skmacyt3_os_find_pci_capability(adapter_t *sc, int cap) 1053167514Skmacy{ 1054167514Skmacy device_t dev; 1055167514Skmacy struct pci_devinfo *dinfo; 1056167514Skmacy pcicfgregs *cfg; 1057167514Skmacy uint32_t status; 1058167514Skmacy uint8_t ptr; 1059167514Skmacy 1060167514Skmacy dev = sc->dev; 1061167514Skmacy dinfo = device_get_ivars(dev); 1062167514Skmacy cfg = &dinfo->cfg; 1063167514Skmacy 1064167514Skmacy status = pci_read_config(dev, PCIR_STATUS, 2); 1065167514Skmacy if (!(status & PCIM_STATUS_CAPPRESENT)) 1066167514Skmacy return (0); 1067167514Skmacy 1068167514Skmacy switch (cfg->hdrtype & PCIM_HDRTYPE) { 1069167514Skmacy case 0: 1070167514Skmacy case 1: 1071167514Skmacy ptr = PCIR_CAP_PTR; 1072167514Skmacy break; 1073167514Skmacy case 2: 1074167514Skmacy ptr = PCIR_CAP_PTR_2; 1075167514Skmacy break; 1076167514Skmacy default: 1077167514Skmacy return (0); 1078167514Skmacy break; 1079167514Skmacy } 1080167514Skmacy ptr = pci_read_config(dev, ptr, 1); 1081167514Skmacy 1082167514Skmacy while (ptr != 0) { 1083167514Skmacy if (pci_read_config(dev, ptr + PCICAP_ID, 1) == cap) 1084167514Skmacy return (ptr); 1085167514Skmacy ptr = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1); 1086167514Skmacy } 1087167514Skmacy 1088167514Skmacy return (0); 1089167514Skmacy} 1090167514Skmacy 1091167514Skmacyint 1092167514Skmacyt3_os_pci_save_state(struct adapter *sc) 1093167514Skmacy{ 1094167514Skmacy device_t dev; 1095167514Skmacy struct pci_devinfo *dinfo; 1096167514Skmacy 1097167514Skmacy dev = sc->dev; 1098167514Skmacy dinfo = device_get_ivars(dev); 1099167514Skmacy 1100167514Skmacy pci_cfg_save(dev, dinfo, 0); 1101167514Skmacy return (0); 1102167514Skmacy} 1103167514Skmacy 1104167514Skmacyint 1105167514Skmacyt3_os_pci_restore_state(struct adapter *sc) 1106167514Skmacy{ 1107167514Skmacy device_t dev; 1108167514Skmacy struct pci_devinfo *dinfo; 1109167514Skmacy 1110167514Skmacy dev = sc->dev; 1111167514Skmacy dinfo = device_get_ivars(dev); 1112167514Skmacy 1113167514Skmacy pci_cfg_restore(dev, dinfo); 1114167514Skmacy return (0); 1115167514Skmacy} 1116167514Skmacy 1117167514Skmacy/** 1118167514Skmacy * t3_os_link_changed - handle link status changes 1119167514Skmacy * @adapter: the adapter associated with the link change 1120167514Skmacy * @port_id: the port index whose limk status has changed 1121177340Skmacy * @link_status: the new status of the link 1122167514Skmacy * @speed: the new speed setting 1123167514Skmacy * @duplex: the new duplex setting 1124167514Skmacy * @fc: the new flow-control setting 1125167514Skmacy * 1126167514Skmacy * This is the OS-dependent handler for link status changes. The OS 1127167514Skmacy * neutral handler takes care of most of the processing for these events, 1128167514Skmacy * then calls this handler for any OS-specific processing. 1129167514Skmacy */ 1130167514Skmacyvoid 1131167514Skmacyt3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed, 1132167514Skmacy int duplex, int fc) 1133167514Skmacy{ 1134167514Skmacy struct port_info *pi = &adapter->port[port_id]; 1135169978Skmacy struct cmac *mac = &adapter->port[port_id].mac; 1136167514Skmacy 1137169978Skmacy if (link_status) { 1138177340Skmacy DELAY(10); 1139177340Skmacy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 1140177340Skmacy /* Clear errors created by MAC enable */ 1141177340Skmacy t3_set_reg_field(adapter, 1142177340Skmacy A_XGM_STAT_CTRL + pi->mac.offset, 1143177340Skmacy F_CLRSTATS, 1); 1144167514Skmacy if_link_state_change(pi->ifp, LINK_STATE_UP); 1145177340Skmacy 1146169978Skmacy } else { 1147169978Skmacy pi->phy.ops->power_down(&pi->phy, 1); 1148169978Skmacy t3_mac_disable(mac, MAC_DIRECTION_RX); 1149169978Skmacy t3_link_start(&pi->phy, mac, &pi->link_config); 1150177340Skmacy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 1151176472Skmacy if_link_state_change(pi->ifp, LINK_STATE_DOWN); 1152169978Skmacy } 1153167514Skmacy} 1154167514Skmacy 1155181614Skmacy/** 1156181614Skmacy * t3_os_phymod_changed - handle PHY module changes 1157181614Skmacy * @phy: the PHY reporting the module change 1158181614Skmacy * @mod_type: new module type 1159181614Skmacy * 1160181614Skmacy * This is the OS-dependent handler for PHY module changes. It is 1161181614Skmacy * invoked when a PHY module is removed or inserted for any OS-specific 1162181614Skmacy * processing. 1163181614Skmacy */ 1164181614Skmacyvoid t3_os_phymod_changed(struct adapter *adap, int port_id) 1165181614Skmacy{ 1166181614Skmacy static const char *mod_str[] = { 1167181614Skmacy NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown" 1168181614Skmacy }; 1169181614Skmacy 1170181614Skmacy struct port_info *pi = &adap->port[port_id]; 1171181614Skmacy 1172181614Skmacy if (pi->phy.modtype == phy_modtype_none) 1173181614Skmacy device_printf(adap->dev, "PHY module unplugged\n"); 1174181614Skmacy else { 1175181614Skmacy KASSERT(pi->phy.modtype < ARRAY_SIZE(mod_str), 1176181614Skmacy ("invalid PHY module type %d", pi->phy.modtype)); 1177181614Skmacy device_printf(adap->dev, "%s PHY module inserted\n", 1178181614Skmacy mod_str[pi->phy.modtype]); 1179181614Skmacy } 1180181614Skmacy} 1181181614Skmacy 1182167514Skmacy/* 1183167514Skmacy * Interrupt-context handler for external (PHY) interrupts. 1184167514Skmacy */ 1185167514Skmacyvoid 1186167514Skmacyt3_os_ext_intr_handler(adapter_t *sc) 1187167514Skmacy{ 1188167514Skmacy if (cxgb_debug) 1189167514Skmacy printf("t3_os_ext_intr_handler\n"); 1190167514Skmacy /* 1191167514Skmacy * Schedule a task to handle external interrupts as they may be slow 1192167514Skmacy * and we use a mutex to protect MDIO registers. We disable PHY 1193167514Skmacy * interrupts in the meantime and let the task reenable them when 1194167514Skmacy * it's done. 1195167514Skmacy */ 1196169978Skmacy ADAPTER_LOCK(sc); 1197167514Skmacy if (sc->slow_intr_mask) { 1198167514Skmacy sc->slow_intr_mask &= ~F_T3DBG; 1199167514Skmacy t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask); 1200167514Skmacy taskqueue_enqueue(sc->tq, &sc->ext_intr_task); 1201167514Skmacy } 1202169978Skmacy ADAPTER_UNLOCK(sc); 1203167514Skmacy} 1204167514Skmacy 1205167514Skmacyvoid 1206167514Skmacyt3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[]) 1207167514Skmacy{ 1208167514Skmacy 1209167514Skmacy /* 1210167514Skmacy * The ifnet might not be allocated before this gets called, 1211167514Skmacy * as this is called early on in attach by t3_prep_adapter 1212167514Skmacy * save the address off in the port structure 1213167514Skmacy */ 1214167514Skmacy if (cxgb_debug) 1215167514Skmacy printf("set_hw_addr on idx %d addr %6D\n", port_idx, hw_addr, ":"); 1216167514Skmacy bcopy(hw_addr, adapter->port[port_idx].hw_addr, ETHER_ADDR_LEN); 1217167514Skmacy} 1218167514Skmacy 1219167514Skmacy/** 1220167514Skmacy * link_start - enable a port 1221167514Skmacy * @p: the port to enable 1222167514Skmacy * 1223167514Skmacy * Performs the MAC and PHY actions needed to enable a port. 1224167514Skmacy */ 1225167514Skmacystatic void 1226167514Skmacycxgb_link_start(struct port_info *p) 1227167514Skmacy{ 1228167514Skmacy struct ifnet *ifp; 1229167514Skmacy struct t3_rx_mode rm; 1230167514Skmacy struct cmac *mac = &p->mac; 1231180583Skmacy int mtu, hwtagging; 1232167514Skmacy 1233167514Skmacy ifp = p->ifp; 1234167514Skmacy 1235180583Skmacy bcopy(IF_LLADDR(ifp), p->hw_addr, ETHER_ADDR_LEN); 1236180583Skmacy 1237180583Skmacy mtu = ifp->if_mtu; 1238180583Skmacy if (ifp->if_capenable & IFCAP_VLAN_MTU) 1239180583Skmacy mtu += ETHER_VLAN_ENCAP_LEN; 1240180583Skmacy 1241180583Skmacy hwtagging = (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0; 1242180583Skmacy 1243167514Skmacy t3_init_rx_mode(&rm, p); 1244172096Skmacy if (!mac->multiport) 1245171978Skmacy t3_mac_reset(mac); 1246180583Skmacy t3_mac_set_mtu(mac, mtu); 1247180583Skmacy t3_set_vlan_accel(p->adapter, 1 << p->tx_chan, hwtagging); 1248167514Skmacy t3_mac_set_address(mac, 0, p->hw_addr); 1249167514Skmacy t3_mac_set_rx_mode(mac, &rm); 1250167514Skmacy t3_link_start(&p->phy, mac, &p->link_config); 1251167514Skmacy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 1252167514Skmacy} 1253167514Skmacy 1254176472Skmacy 1255176472Skmacystatic int 1256176472Skmacyawait_mgmt_replies(struct adapter *adap, unsigned long init_cnt, 1257176472Skmacy unsigned long n) 1258176472Skmacy{ 1259176472Skmacy int attempts = 5; 1260176472Skmacy 1261176472Skmacy while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) { 1262176472Skmacy if (!--attempts) 1263176472Skmacy return (ETIMEDOUT); 1264176472Skmacy t3_os_sleep(10); 1265176472Skmacy } 1266176472Skmacy return 0; 1267176472Skmacy} 1268176472Skmacy 1269176472Skmacystatic int 1270176472Skmacyinit_tp_parity(struct adapter *adap) 1271176472Skmacy{ 1272176472Skmacy int i; 1273176472Skmacy struct mbuf *m; 1274176472Skmacy struct cpl_set_tcb_field *greq; 1275176472Skmacy unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts; 1276176472Skmacy 1277176472Skmacy t3_tp_set_offload_mode(adap, 1); 1278176472Skmacy 1279176472Skmacy for (i = 0; i < 16; i++) { 1280176472Skmacy struct cpl_smt_write_req *req; 1281176472Skmacy 1282176472Skmacy m = m_gethdr(M_WAITOK, MT_DATA); 1283176472Skmacy req = mtod(m, struct cpl_smt_write_req *); 1284176472Skmacy m->m_len = m->m_pkthdr.len = sizeof(*req); 1285176472Skmacy memset(req, 0, sizeof(*req)); 1286176472Skmacy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1287176472Skmacy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); 1288176472Skmacy req->iff = i; 1289176472Skmacy t3_mgmt_tx(adap, m); 1290176472Skmacy } 1291176472Skmacy 1292176472Skmacy for (i = 0; i < 2048; i++) { 1293176472Skmacy struct cpl_l2t_write_req *req; 1294176472Skmacy 1295176472Skmacy m = m_gethdr(M_WAITOK, MT_DATA); 1296176472Skmacy req = mtod(m, struct cpl_l2t_write_req *); 1297176472Skmacy m->m_len = m->m_pkthdr.len = sizeof(*req); 1298176472Skmacy memset(req, 0, sizeof(*req)); 1299176472Skmacy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1300176472Skmacy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i)); 1301176472Skmacy req->params = htonl(V_L2T_W_IDX(i)); 1302176472Skmacy t3_mgmt_tx(adap, m); 1303176472Skmacy } 1304176472Skmacy 1305176472Skmacy for (i = 0; i < 2048; i++) { 1306176472Skmacy struct cpl_rte_write_req *req; 1307176472Skmacy 1308176472Skmacy m = m_gethdr(M_WAITOK, MT_DATA); 1309176472Skmacy req = mtod(m, struct cpl_rte_write_req *); 1310176472Skmacy m->m_len = m->m_pkthdr.len = sizeof(*req); 1311176472Skmacy memset(req, 0, sizeof(*req)); 1312176472Skmacy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1313176472Skmacy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i)); 1314176472Skmacy req->l2t_idx = htonl(V_L2T_W_IDX(i)); 1315176472Skmacy t3_mgmt_tx(adap, m); 1316176472Skmacy } 1317176472Skmacy 1318176472Skmacy m = m_gethdr(M_WAITOK, MT_DATA); 1319176472Skmacy greq = mtod(m, struct cpl_set_tcb_field *); 1320176472Skmacy m->m_len = m->m_pkthdr.len = sizeof(*greq); 1321176472Skmacy memset(greq, 0, sizeof(*greq)); 1322176472Skmacy greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1323176472Skmacy OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0)); 1324176472Skmacy greq->mask = htobe64(1); 1325176472Skmacy t3_mgmt_tx(adap, m); 1326176472Skmacy 1327176472Skmacy i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); 1328176472Skmacy t3_tp_set_offload_mode(adap, 0); 1329176472Skmacy return (i); 1330176472Skmacy} 1331176472Skmacy 1332167514Skmacy/** 1333167514Skmacy * setup_rss - configure Receive Side Steering (per-queue connection demux) 1334167514Skmacy * @adap: the adapter 1335167514Skmacy * 1336167514Skmacy * Sets up RSS to distribute packets to multiple receive queues. We 1337167514Skmacy * configure the RSS CPU lookup table to distribute to the number of HW 1338167514Skmacy * receive queues, and the response queue lookup table to narrow that 1339167514Skmacy * down to the response queues actually configured for each port. 1340167514Skmacy * We always configure the RSS mapping for two ports since the mapping 1341167514Skmacy * table has plenty of entries. 1342167514Skmacy */ 1343167514Skmacystatic void 1344167514Skmacysetup_rss(adapter_t *adap) 1345167514Skmacy{ 1346167514Skmacy int i; 1347171471Skmacy u_int nq[2]; 1348167514Skmacy uint8_t cpus[SGE_QSETS + 1]; 1349167514Skmacy uint16_t rspq_map[RSS_TABLE_SIZE]; 1350171471Skmacy 1351167514Skmacy for (i = 0; i < SGE_QSETS; ++i) 1352167514Skmacy cpus[i] = i; 1353167514Skmacy cpus[SGE_QSETS] = 0xff; 1354167514Skmacy 1355171978Skmacy nq[0] = nq[1] = 0; 1356171978Skmacy for_each_port(adap, i) { 1357171978Skmacy const struct port_info *pi = adap2pinfo(adap, i); 1358171978Skmacy 1359171978Skmacy nq[pi->tx_chan] += pi->nqsets; 1360171978Skmacy } 1361167514Skmacy for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) { 1362176472Skmacy rspq_map[i] = nq[0] ? i % nq[0] : 0; 1363176472Skmacy rspq_map[i + RSS_TABLE_SIZE / 2] = nq[1] ? i % nq[1] + nq[0] : 0; 1364167514Skmacy } 1365171471Skmacy /* Calculate the reverse RSS map table */ 1366171471Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) 1367171471Skmacy if (adap->rrss_map[rspq_map[i]] == 0xff) 1368171471Skmacy adap->rrss_map[rspq_map[i]] = i; 1369167514Skmacy 1370167514Skmacy t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN | 1371171471Skmacy F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | F_OFDMAPEN | 1372176472Skmacy F_RRCPLMAPEN | V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, 1373176472Skmacy cpus, rspq_map); 1374171471Skmacy 1375167514Skmacy} 1376167514Skmacy 1377169978Skmacy/* 1378169978Skmacy * Sends an mbuf to an offload queue driver 1379169978Skmacy * after dealing with any active network taps. 1380169978Skmacy */ 1381169978Skmacystatic inline int 1382174626Skmacyoffload_tx(struct t3cdev *tdev, struct mbuf *m) 1383169978Skmacy{ 1384169978Skmacy int ret; 1385169978Skmacy 1386169978Skmacy ret = t3_offload_tx(tdev, m); 1387170654Skmacy return (ret); 1388169978Skmacy} 1389169978Skmacy 1390169978Skmacystatic int 1391169978Skmacywrite_smt_entry(struct adapter *adapter, int idx) 1392169978Skmacy{ 1393169978Skmacy struct port_info *pi = &adapter->port[idx]; 1394169978Skmacy struct cpl_smt_write_req *req; 1395169978Skmacy struct mbuf *m; 1396169978Skmacy 1397169978Skmacy if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL) 1398169978Skmacy return (ENOMEM); 1399169978Skmacy 1400169978Skmacy req = mtod(m, struct cpl_smt_write_req *); 1401174708Skmacy m->m_pkthdr.len = m->m_len = sizeof(struct cpl_smt_write_req); 1402174708Skmacy 1403169978Skmacy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1404169978Skmacy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx)); 1405169978Skmacy req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */ 1406169978Skmacy req->iff = idx; 1407169978Skmacy memset(req->src_mac1, 0, sizeof(req->src_mac1)); 1408169978Skmacy memcpy(req->src_mac0, pi->hw_addr, ETHER_ADDR_LEN); 1409169978Skmacy 1410169978Skmacy m_set_priority(m, 1); 1411169978Skmacy 1412169978Skmacy offload_tx(&adapter->tdev, m); 1413169978Skmacy 1414169978Skmacy return (0); 1415169978Skmacy} 1416169978Skmacy 1417169978Skmacystatic int 1418169978Skmacyinit_smt(struct adapter *adapter) 1419169978Skmacy{ 1420169978Skmacy int i; 1421169978Skmacy 1422169978Skmacy for_each_port(adapter, i) 1423169978Skmacy write_smt_entry(adapter, i); 1424169978Skmacy return 0; 1425169978Skmacy} 1426169978Skmacy 1427167514Skmacystatic void 1428169978Skmacyinit_port_mtus(adapter_t *adapter) 1429169978Skmacy{ 1430169978Skmacy unsigned int mtus = adapter->port[0].ifp->if_mtu; 1431169978Skmacy 1432169978Skmacy if (adapter->port[1].ifp) 1433169978Skmacy mtus |= adapter->port[1].ifp->if_mtu << 16; 1434169978Skmacy t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus); 1435169978Skmacy} 1436169978Skmacy 1437169978Skmacystatic void 1438167514Skmacysend_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, 1439167514Skmacy int hi, int port) 1440167514Skmacy{ 1441167514Skmacy struct mbuf *m; 1442167514Skmacy struct mngt_pktsched_wr *req; 1443167514Skmacy 1444171471Skmacy m = m_gethdr(M_DONTWAIT, MT_DATA); 1445167848Skmacy if (m) { 1446169978Skmacy req = mtod(m, struct mngt_pktsched_wr *); 1447167848Skmacy req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); 1448167848Skmacy req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET; 1449167848Skmacy req->sched = sched; 1450167848Skmacy req->idx = qidx; 1451167848Skmacy req->min = lo; 1452167848Skmacy req->max = hi; 1453167848Skmacy req->binding = port; 1454167848Skmacy m->m_len = m->m_pkthdr.len = sizeof(*req); 1455167848Skmacy t3_mgmt_tx(adap, m); 1456167848Skmacy } 1457167514Skmacy} 1458167514Skmacy 1459167514Skmacystatic void 1460167514Skmacybind_qsets(adapter_t *sc) 1461167514Skmacy{ 1462167514Skmacy int i, j; 1463167514Skmacy 1464174708Skmacy cxgb_pcpu_startup_threads(sc); 1465167514Skmacy for (i = 0; i < (sc)->params.nports; ++i) { 1466167514Skmacy const struct port_info *pi = adap2pinfo(sc, i); 1467167514Skmacy 1468172096Skmacy for (j = 0; j < pi->nqsets; ++j) { 1469167514Skmacy send_pktsched_cmd(sc, 1, pi->first_qset + j, -1, 1470172096Skmacy -1, pi->tx_chan); 1471172096Skmacy 1472172096Skmacy } 1473167514Skmacy } 1474167514Skmacy} 1475167514Skmacy 1476171471Skmacystatic void 1477171471Skmacyupdate_tpeeprom(struct adapter *adap) 1478171471Skmacy{ 1479172109Skmacy#ifdef FIRMWARE_LATEST 1480171471Skmacy const struct firmware *tpeeprom; 1481172109Skmacy#else 1482172109Skmacy struct firmware *tpeeprom; 1483172109Skmacy#endif 1484172109Skmacy 1485171471Skmacy uint32_t version; 1486171471Skmacy unsigned int major, minor; 1487171471Skmacy int ret, len; 1488171471Skmacy char rev; 1489171471Skmacy 1490171471Skmacy t3_seeprom_read(adap, TP_SRAM_OFFSET, &version); 1491171471Skmacy 1492171471Skmacy major = G_TP_VERSION_MAJOR(version); 1493171471Skmacy minor = G_TP_VERSION_MINOR(version); 1494171471Skmacy if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) 1495171471Skmacy return; 1496171471Skmacy 1497171471Skmacy rev = t3rev2char(adap); 1498171471Skmacy 1499176613Skmacy tpeeprom = firmware_get(TPEEPROM_NAME); 1500171471Skmacy if (tpeeprom == NULL) { 1501171471Skmacy device_printf(adap->dev, "could not load TP EEPROM: unable to load %s\n", 1502176613Skmacy TPEEPROM_NAME); 1503171471Skmacy return; 1504171471Skmacy } 1505171471Skmacy 1506171471Skmacy len = tpeeprom->datasize - 4; 1507171471Skmacy 1508171471Skmacy ret = t3_check_tpsram(adap, tpeeprom->data, tpeeprom->datasize); 1509171471Skmacy if (ret) 1510171471Skmacy goto release_tpeeprom; 1511171471Skmacy 1512171471Skmacy if (len != TP_SRAM_LEN) { 1513176613Skmacy device_printf(adap->dev, "%s length is wrong len=%d expected=%d\n", TPEEPROM_NAME, len, TP_SRAM_LEN); 1514171471Skmacy return; 1515171471Skmacy } 1516171471Skmacy 1517171471Skmacy ret = set_eeprom(&adap->port[0], tpeeprom->data, tpeeprom->datasize, 1518171471Skmacy TP_SRAM_OFFSET); 1519171471Skmacy 1520171471Skmacy if (!ret) { 1521171471Skmacy device_printf(adap->dev, 1522171471Skmacy "Protocol SRAM image updated in EEPROM to %d.%d.%d\n", 1523171471Skmacy TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); 1524171471Skmacy } else 1525171471Skmacy device_printf(adap->dev, "Protocol SRAM image update in EEPROM failed\n"); 1526171471Skmacy 1527171471Skmacyrelease_tpeeprom: 1528171471Skmacy firmware_put(tpeeprom, FIRMWARE_UNLOAD); 1529171471Skmacy 1530171471Skmacy return; 1531171471Skmacy} 1532171471Skmacy 1533171471Skmacystatic int 1534171471Skmacyupdate_tpsram(struct adapter *adap) 1535171471Skmacy{ 1536172109Skmacy#ifdef FIRMWARE_LATEST 1537171471Skmacy const struct firmware *tpsram; 1538172109Skmacy#else 1539172109Skmacy struct firmware *tpsram; 1540172109Skmacy#endif 1541171471Skmacy int ret; 1542171471Skmacy char rev; 1543171471Skmacy 1544171471Skmacy rev = t3rev2char(adap); 1545171471Skmacy if (!rev) 1546171471Skmacy return 0; 1547171471Skmacy 1548171471Skmacy update_tpeeprom(adap); 1549171471Skmacy 1550176613Skmacy tpsram = firmware_get(TPSRAM_NAME); 1551171471Skmacy if (tpsram == NULL){ 1552176613Skmacy device_printf(adap->dev, "could not load TP SRAM\n"); 1553171471Skmacy return (EINVAL); 1554171471Skmacy } else 1555176613Skmacy device_printf(adap->dev, "updating TP SRAM\n"); 1556171471Skmacy 1557171471Skmacy ret = t3_check_tpsram(adap, tpsram->data, tpsram->datasize); 1558171471Skmacy if (ret) 1559171471Skmacy goto release_tpsram; 1560171471Skmacy 1561171471Skmacy ret = t3_set_proto_sram(adap, tpsram->data); 1562171471Skmacy if (ret) 1563171471Skmacy device_printf(adap->dev, "loading protocol SRAM failed\n"); 1564171471Skmacy 1565171471Skmacyrelease_tpsram: 1566171471Skmacy firmware_put(tpsram, FIRMWARE_UNLOAD); 1567171471Skmacy 1568171471Skmacy return ret; 1569171471Skmacy} 1570171471Skmacy 1571169978Skmacy/** 1572169978Skmacy * cxgb_up - enable the adapter 1573169978Skmacy * @adap: adapter being enabled 1574169978Skmacy * 1575169978Skmacy * Called when the first port is enabled, this function performs the 1576169978Skmacy * actions necessary to make an adapter operational, such as completing 1577169978Skmacy * the initialization of HW modules, and enabling interrupts. 1578169978Skmacy * 1579169978Skmacy */ 1580169978Skmacystatic int 1581169978Skmacycxgb_up(struct adapter *sc) 1582169978Skmacy{ 1583169978Skmacy int err = 0; 1584169978Skmacy 1585169978Skmacy if ((sc->flags & FULL_INIT_DONE) == 0) { 1586169978Skmacy 1587169978Skmacy if ((sc->flags & FW_UPTODATE) == 0) 1588171471Skmacy if ((err = upgrade_fw(sc))) 1589171471Skmacy goto out; 1590171471Skmacy if ((sc->flags & TPS_UPTODATE) == 0) 1591171471Skmacy if ((err = update_tpsram(sc))) 1592171471Skmacy goto out; 1593169978Skmacy err = t3_init_hw(sc, 0); 1594169978Skmacy if (err) 1595169978Skmacy goto out; 1596169978Skmacy 1597176472Skmacy t3_set_reg_field(sc, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT); 1598169978Skmacy t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12)); 1599169978Skmacy 1600169978Skmacy err = setup_sge_qsets(sc); 1601169978Skmacy if (err) 1602169978Skmacy goto out; 1603169978Skmacy 1604169978Skmacy setup_rss(sc); 1605174708Skmacy t3_add_configured_sysctls(sc); 1606169978Skmacy sc->flags |= FULL_INIT_DONE; 1607169978Skmacy } 1608169978Skmacy 1609169978Skmacy t3_intr_clear(sc); 1610169978Skmacy 1611169978Skmacy /* If it's MSI or INTx, allocate a single interrupt for everything */ 1612169978Skmacy if ((sc->flags & USING_MSIX) == 0) { 1613169978Skmacy if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 1614169978Skmacy &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 1615171978Skmacy device_printf(sc->dev, "Cannot allocate interrupt rid=%d\n", 1616171978Skmacy sc->irq_rid); 1617169978Skmacy err = EINVAL; 1618169978Skmacy goto out; 1619169978Skmacy } 1620169978Skmacy device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res); 1621169978Skmacy 1622169978Skmacy if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET, 1623169978Skmacy#ifdef INTR_FILTERS 1624169978Skmacy NULL, 1625169978Skmacy#endif 1626169978Skmacy sc->cxgb_intr, sc, &sc->intr_tag)) { 1627169978Skmacy device_printf(sc->dev, "Cannot set up interrupt\n"); 1628169978Skmacy err = EINVAL; 1629169978Skmacy goto irq_err; 1630169978Skmacy } 1631169978Skmacy } else { 1632169978Skmacy cxgb_setup_msix(sc, sc->msi_count); 1633169978Skmacy } 1634169978Skmacy 1635169978Skmacy t3_sge_start(sc); 1636169978Skmacy t3_intr_enable(sc); 1637169978Skmacy 1638176472Skmacy if (sc->params.rev >= T3_REV_C && !(sc->flags & TP_PARITY_INIT) && 1639176472Skmacy is_offload(sc) && init_tp_parity(sc) == 0) 1640176472Skmacy sc->flags |= TP_PARITY_INIT; 1641176472Skmacy 1642176472Skmacy if (sc->flags & TP_PARITY_INIT) { 1643176472Skmacy t3_write_reg(sc, A_TP_INT_CAUSE, 1644176472Skmacy F_CMCACHEPERR | F_ARPLUTPERR); 1645176472Skmacy t3_write_reg(sc, A_TP_INT_ENABLE, 0x7fbfffff); 1646176472Skmacy } 1647176472Skmacy 1648176472Skmacy 1649172096Skmacy if (!(sc->flags & QUEUES_BOUND)) { 1650169978Skmacy bind_qsets(sc); 1651171471Skmacy sc->flags |= QUEUES_BOUND; 1652171471Skmacy } 1653169978Skmacyout: 1654169978Skmacy return (err); 1655169978Skmacyirq_err: 1656169978Skmacy CH_ERR(sc, "request_irq failed, err %d\n", err); 1657169978Skmacy goto out; 1658169978Skmacy} 1659169978Skmacy 1660169978Skmacy 1661169978Skmacy/* 1662169978Skmacy * Release resources when all the ports and offloading have been stopped. 1663169978Skmacy */ 1664167514Skmacystatic void 1665170869Skmacycxgb_down_locked(struct adapter *sc) 1666169978Skmacy{ 1667170654Skmacy 1668169978Skmacy t3_sge_stop(sc); 1669169978Skmacy t3_intr_disable(sc); 1670170654Skmacy 1671169978Skmacy if (sc->intr_tag != NULL) { 1672169978Skmacy bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag); 1673169978Skmacy sc->intr_tag = NULL; 1674169978Skmacy } 1675169978Skmacy if (sc->irq_res != NULL) { 1676169978Skmacy device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n", 1677169978Skmacy sc->irq_rid, sc->irq_res); 1678169978Skmacy bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid, 1679169978Skmacy sc->irq_res); 1680169978Skmacy sc->irq_res = NULL; 1681169978Skmacy } 1682170654Skmacy 1683176472Skmacy if (sc->flags & USING_MSIX) 1684170654Skmacy cxgb_teardown_msix(sc); 1685176472Skmacy 1686174708Skmacy callout_stop(&sc->cxgb_tick_ch); 1687174708Skmacy callout_stop(&sc->sge_timer_ch); 1688170869Skmacy callout_drain(&sc->cxgb_tick_ch); 1689169978Skmacy callout_drain(&sc->sge_timer_ch); 1690170869Skmacy 1691171978Skmacy if (sc->tq != NULL) { 1692176472Skmacy printf("draining slow intr\n"); 1693176472Skmacy 1694170654Skmacy taskqueue_drain(sc->tq, &sc->slow_intr_task); 1695176472Skmacy printf("draining ext intr\n"); 1696176472Skmacy taskqueue_drain(sc->tq, &sc->ext_intr_task); 1697176472Skmacy printf("draining tick task\n"); 1698176472Skmacy taskqueue_drain(sc->tq, &sc->tick_task); 1699171978Skmacy } 1700176472Skmacy ADAPTER_UNLOCK(sc); 1701169978Skmacy} 1702169978Skmacy 1703169978Skmacystatic int 1704169978Skmacyoffload_open(struct port_info *pi) 1705169978Skmacy{ 1706169978Skmacy struct adapter *adapter = pi->adapter; 1707174708Skmacy struct t3cdev *tdev = &adapter->tdev; 1708183059Skmacy 1709169978Skmacy int adap_up = adapter->open_device_map & PORT_MASK; 1710169978Skmacy int err = 0; 1711169978Skmacy 1712169978Skmacy if (atomic_cmpset_int(&adapter->open_device_map, 1713174708Skmacy (adapter->open_device_map & ~(1<<OFFLOAD_DEVMAP_BIT)), 1714174708Skmacy (adapter->open_device_map | (1<<OFFLOAD_DEVMAP_BIT))) == 0) 1715169978Skmacy return (0); 1716169978Skmacy 1717174708Skmacy if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT)) 1718183059Skmacy printf("offload_open: DEVMAP_BIT did not get set 0x%x\n", 1719183059Skmacy adapter->open_device_map); 1720169978Skmacy ADAPTER_LOCK(pi->adapter); 1721169978Skmacy if (!adap_up) 1722169978Skmacy err = cxgb_up(adapter); 1723169978Skmacy ADAPTER_UNLOCK(pi->adapter); 1724171471Skmacy if (err) 1725169978Skmacy return (err); 1726169978Skmacy 1727169978Skmacy t3_tp_set_offload_mode(adapter, 1); 1728174708Skmacy tdev->lldev = pi->ifp; 1729169978Skmacy 1730169978Skmacy init_port_mtus(adapter); 1731169978Skmacy t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd, 1732169978Skmacy adapter->params.b_wnd, 1733169978Skmacy adapter->params.rev == 0 ? 1734169978Skmacy adapter->port[0].ifp->if_mtu : 0xffff); 1735169978Skmacy init_smt(adapter); 1736178767Skmacy /* Call back all registered clients */ 1737178767Skmacy cxgb_add_clients(tdev); 1738178767Skmacy 1739169978Skmacy /* restore them in case the offload module has changed them */ 1740169978Skmacy if (err) { 1741169978Skmacy t3_tp_set_offload_mode(adapter, 0); 1742169978Skmacy clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT); 1743169978Skmacy cxgb_set_dummy_ops(tdev); 1744169978Skmacy } 1745169978Skmacy return (err); 1746169978Skmacy} 1747174708Skmacy 1748169978Skmacystatic int 1749174708Skmacyoffload_close(struct t3cdev *tdev) 1750169978Skmacy{ 1751169978Skmacy struct adapter *adapter = tdev2adap(tdev); 1752169978Skmacy 1753176472Skmacy if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT)) 1754170654Skmacy return (0); 1755178767Skmacy 1756178767Skmacy /* Call back all registered clients */ 1757178767Skmacy cxgb_remove_clients(tdev); 1758178767Skmacy 1759169978Skmacy tdev->lldev = NULL; 1760169978Skmacy cxgb_set_dummy_ops(tdev); 1761169978Skmacy t3_tp_set_offload_mode(adapter, 0); 1762169978Skmacy clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT); 1763169978Skmacy 1764174708Skmacy ADAPTER_LOCK(adapter); 1765169978Skmacy if (!adapter->open_device_map) 1766174708Skmacy cxgb_down_locked(adapter); 1767174708Skmacy else 1768174708Skmacy ADAPTER_UNLOCK(adapter); 1769170654Skmacy return (0); 1770169978Skmacy} 1771169978Skmacy 1772174708Skmacy 1773169978Skmacystatic void 1774167514Skmacycxgb_init(void *arg) 1775167514Skmacy{ 1776167514Skmacy struct port_info *p = arg; 1777167514Skmacy 1778167514Skmacy PORT_LOCK(p); 1779167514Skmacy cxgb_init_locked(p); 1780167514Skmacy PORT_UNLOCK(p); 1781167514Skmacy} 1782167514Skmacy 1783167514Skmacystatic void 1784167514Skmacycxgb_init_locked(struct port_info *p) 1785167514Skmacy{ 1786167514Skmacy struct ifnet *ifp; 1787167514Skmacy adapter_t *sc = p->adapter; 1788169978Skmacy int err; 1789167514Skmacy 1790170869Skmacy PORT_LOCK_ASSERT_OWNED(p); 1791167514Skmacy ifp = p->ifp; 1792167514Skmacy 1793167514Skmacy ADAPTER_LOCK(p->adapter); 1794171471Skmacy if ((sc->open_device_map == 0) && (err = cxgb_up(sc))) { 1795169978Skmacy ADAPTER_UNLOCK(p->adapter); 1796169978Skmacy cxgb_stop_locked(p); 1797169978Skmacy return; 1798169978Skmacy } 1799170869Skmacy if (p->adapter->open_device_map == 0) { 1800167514Skmacy t3_intr_clear(sc); 1801170869Skmacy } 1802171803Skmacy setbit(&p->adapter->open_device_map, p->port_id); 1803170654Skmacy ADAPTER_UNLOCK(p->adapter); 1804169978Skmacy 1805169978Skmacy if (is_offload(sc) && !ofld_disable) { 1806169978Skmacy err = offload_open(p); 1807169978Skmacy if (err) 1808169978Skmacy log(LOG_WARNING, 1809169978Skmacy "Could not initialize offload capabilities\n"); 1810169978Skmacy } 1811177415Skmacy#if !defined(LINK_ATTACH) 1812177415Skmacy cxgb_link_start(p); 1813177415Skmacy t3_link_changed(sc, p->port_id); 1814177415Skmacy#endif 1815170654Skmacy ifp->if_baudrate = p->link_config.speed * 1000000; 1816171978Skmacy 1817172096Skmacy device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id); 1818171803Skmacy t3_port_intr_enable(sc, p->port_id); 1819167760Skmacy 1820175224Skmacy t3_sge_reset_adapter(sc); 1821170869Skmacy 1822167514Skmacy ifp->if_drv_flags |= IFF_DRV_RUNNING; 1823167514Skmacy ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1824167514Skmacy} 1825167514Skmacy 1826167514Skmacystatic void 1827167514Skmacycxgb_set_rxmode(struct port_info *p) 1828167514Skmacy{ 1829167514Skmacy struct t3_rx_mode rm; 1830167514Skmacy struct cmac *mac = &p->mac; 1831167760Skmacy 1832167514Skmacy t3_init_rx_mode(&rm, p); 1833176472Skmacy mtx_lock(&p->adapter->mdio_lock); 1834167514Skmacy t3_mac_set_rx_mode(mac, &rm); 1835176472Skmacy mtx_unlock(&p->adapter->mdio_lock); 1836167514Skmacy} 1837167514Skmacy 1838167514Skmacystatic void 1839177340Skmacycxgb_stop_locked(struct port_info *pi) 1840167514Skmacy{ 1841167514Skmacy struct ifnet *ifp; 1842167514Skmacy 1843177340Skmacy PORT_LOCK_ASSERT_OWNED(pi); 1844177340Skmacy ADAPTER_LOCK_ASSERT_NOTOWNED(pi->adapter); 1845170654Skmacy 1846177340Skmacy ifp = pi->ifp; 1847177340Skmacy t3_port_intr_disable(pi->adapter, pi->port_id); 1848169978Skmacy ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1849169978Skmacy 1850177340Skmacy /* disable pause frames */ 1851177340Skmacy t3_set_reg_field(pi->adapter, A_XGM_TX_CFG + pi->mac.offset, 1852177340Skmacy F_TXPAUSEEN, 0); 1853170869Skmacy 1854177340Skmacy /* Reset RX FIFO HWM */ 1855177340Skmacy t3_set_reg_field(pi->adapter, A_XGM_RXFIFO_CFG + pi->mac.offset, 1856177340Skmacy V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM), 0); 1857177340Skmacy 1858177340Skmacy 1859177340Skmacy ADAPTER_LOCK(pi->adapter); 1860177340Skmacy clrbit(&pi->adapter->open_device_map, pi->port_id); 1861177340Skmacy 1862177340Skmacy if (pi->adapter->open_device_map == 0) { 1863177340Skmacy cxgb_down_locked(pi->adapter); 1864170869Skmacy } else 1865177340Skmacy ADAPTER_UNLOCK(pi->adapter); 1866170869Skmacy 1867177415Skmacy#if !defined(LINK_ATTACH) 1868177340Skmacy DELAY(100); 1869177340Skmacy 1870177340Skmacy /* Wait for TXFIFO empty */ 1871177340Skmacy t3_wait_op_done(pi->adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 1872177340Skmacy F_TXFIFO_EMPTY, 1, 20, 5); 1873177340Skmacy 1874177340Skmacy DELAY(100); 1875177340Skmacy t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); 1876177340Skmacy 1877177340Skmacy pi->phy.ops->power_down(&pi->phy, 1); 1878177415Skmacy#endif 1879177340Skmacy 1880167514Skmacy} 1881167514Skmacy 1882167514Skmacystatic int 1883170654Skmacycxgb_set_mtu(struct port_info *p, int mtu) 1884170654Skmacy{ 1885170654Skmacy struct ifnet *ifp = p->ifp; 1886170654Skmacy int error = 0; 1887170654Skmacy 1888180583Skmacy if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) 1889170654Skmacy error = EINVAL; 1890170654Skmacy else if (ifp->if_mtu != mtu) { 1891170654Skmacy PORT_LOCK(p); 1892170654Skmacy ifp->if_mtu = mtu; 1893170654Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1894170654Skmacy cxgb_stop_locked(p); 1895170654Skmacy cxgb_init_locked(p); 1896170654Skmacy } 1897170654Skmacy PORT_UNLOCK(p); 1898170654Skmacy } 1899170654Skmacy return (error); 1900170654Skmacy} 1901170654Skmacy 1902181616Skmacy/* 1903181616Skmacy * Mark lro enabled or disabled in all qsets for this port 1904181616Skmacy */ 1905170654Skmacystatic int 1906181616Skmacycxgb_set_lro(struct port_info *p, int enabled) 1907181616Skmacy{ 1908181616Skmacy int i; 1909181616Skmacy struct adapter *adp = p->adapter; 1910181616Skmacy struct sge_qset *q; 1911181616Skmacy 1912181616Skmacy PORT_LOCK_ASSERT_OWNED(p); 1913181616Skmacy for (i = 0; i < p->nqsets; i++) { 1914181616Skmacy q = &adp->sge.qs[p->first_qset + i]; 1915181616Skmacy q->lro.enabled = (enabled != 0); 1916181616Skmacy } 1917181616Skmacy return (0); 1918181616Skmacy} 1919181616Skmacy 1920181616Skmacystatic int 1921167514Skmacycxgb_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data) 1922167514Skmacy{ 1923167514Skmacy struct port_info *p = ifp->if_softc; 1924167514Skmacy struct ifaddr *ifa = (struct ifaddr *)data; 1925167514Skmacy struct ifreq *ifr = (struct ifreq *)data; 1926180583Skmacy int flags, error = 0, reinit = 0; 1927167514Skmacy uint32_t mask; 1928167514Skmacy 1929168737Skmacy /* 1930168737Skmacy * XXX need to check that we aren't in the middle of an unload 1931168737Skmacy */ 1932167514Skmacy switch (command) { 1933167514Skmacy case SIOCSIFMTU: 1934170654Skmacy error = cxgb_set_mtu(p, ifr->ifr_mtu); 1935167514Skmacy break; 1936167514Skmacy case SIOCSIFADDR: 1937167514Skmacy if (ifa->ifa_addr->sa_family == AF_INET) { 1938167514Skmacy ifp->if_flags |= IFF_UP; 1939176472Skmacy if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1940176472Skmacy PORT_LOCK(p); 1941170654Skmacy cxgb_init_locked(p); 1942176472Skmacy PORT_UNLOCK(p); 1943176472Skmacy } 1944167514Skmacy arp_ifinit(ifp, ifa); 1945167514Skmacy } else 1946167514Skmacy error = ether_ioctl(ifp, command, data); 1947167514Skmacy break; 1948167514Skmacy case SIOCSIFFLAGS: 1949170869Skmacy PORT_LOCK(p); 1950167514Skmacy if (ifp->if_flags & IFF_UP) { 1951167514Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1952167514Skmacy flags = p->if_flags; 1953167514Skmacy if (((ifp->if_flags ^ flags) & IFF_PROMISC) || 1954167514Skmacy ((ifp->if_flags ^ flags) & IFF_ALLMULTI)) 1955167514Skmacy cxgb_set_rxmode(p); 1956167514Skmacy } else 1957167514Skmacy cxgb_init_locked(p); 1958167760Skmacy p->if_flags = ifp->if_flags; 1959170869Skmacy } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1960170869Skmacy cxgb_stop_locked(p); 1961170869Skmacy 1962176472Skmacy PORT_UNLOCK(p); 1963176472Skmacy break; 1964176472Skmacy case SIOCADDMULTI: 1965176472Skmacy case SIOCDELMULTI: 1966170869Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1967176472Skmacy cxgb_set_rxmode(p); 1968167514Skmacy } 1969167514Skmacy break; 1970167514Skmacy case SIOCSIFMEDIA: 1971167514Skmacy case SIOCGIFMEDIA: 1972167514Skmacy error = ifmedia_ioctl(ifp, ifr, &p->media, command); 1973167514Skmacy break; 1974167514Skmacy case SIOCSIFCAP: 1975167514Skmacy PORT_LOCK(p); 1976167514Skmacy mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1977167514Skmacy if (mask & IFCAP_TXCSUM) { 1978167514Skmacy if (IFCAP_TXCSUM & ifp->if_capenable) { 1979167514Skmacy ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 1980167514Skmacy ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 1981180583Skmacy | CSUM_IP | CSUM_TSO); 1982167514Skmacy } else { 1983167514Skmacy ifp->if_capenable |= IFCAP_TXCSUM; 1984180583Skmacy ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP 1985180583Skmacy | CSUM_IP); 1986167514Skmacy } 1987167514Skmacy } 1988180583Skmacy if (mask & IFCAP_RXCSUM) { 1989180583Skmacy ifp->if_capenable ^= IFCAP_RXCSUM; 1990180583Skmacy } 1991167514Skmacy if (mask & IFCAP_TSO4) { 1992167514Skmacy if (IFCAP_TSO4 & ifp->if_capenable) { 1993167514Skmacy ifp->if_capenable &= ~IFCAP_TSO4; 1994167514Skmacy ifp->if_hwassist &= ~CSUM_TSO; 1995167514Skmacy } else if (IFCAP_TXCSUM & ifp->if_capenable) { 1996167514Skmacy ifp->if_capenable |= IFCAP_TSO4; 1997167514Skmacy ifp->if_hwassist |= CSUM_TSO; 1998167514Skmacy } else { 1999167514Skmacy if (cxgb_debug) 2000167514Skmacy printf("cxgb requires tx checksum offload" 2001167514Skmacy " be enabled to use TSO\n"); 2002167514Skmacy error = EINVAL; 2003167514Skmacy } 2004167514Skmacy } 2005181616Skmacy if (mask & IFCAP_LRO) { 2006181616Skmacy ifp->if_capenable ^= IFCAP_LRO; 2007181616Skmacy 2008181616Skmacy /* Safe to do this even if cxgb_up not called yet */ 2009181616Skmacy cxgb_set_lro(p, ifp->if_capenable & IFCAP_LRO); 2010181616Skmacy } 2011180583Skmacy if (mask & IFCAP_VLAN_HWTAGGING) { 2012180583Skmacy ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 2013180583Skmacy reinit = ifp->if_drv_flags & IFF_DRV_RUNNING; 2014180583Skmacy } 2015180583Skmacy if (mask & IFCAP_VLAN_MTU) { 2016180583Skmacy ifp->if_capenable ^= IFCAP_VLAN_MTU; 2017180583Skmacy reinit = ifp->if_drv_flags & IFF_DRV_RUNNING; 2018180583Skmacy } 2019180583Skmacy if (mask & IFCAP_VLAN_HWCSUM) { 2020180583Skmacy ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 2021180583Skmacy } 2022180583Skmacy if (reinit) { 2023180583Skmacy cxgb_stop_locked(p); 2024180583Skmacy cxgb_init_locked(p); 2025180583Skmacy } 2026167514Skmacy PORT_UNLOCK(p); 2027180583Skmacy 2028180583Skmacy#ifdef VLAN_CAPABILITIES 2029180583Skmacy VLAN_CAPABILITIES(ifp); 2030180583Skmacy#endif 2031167514Skmacy break; 2032167514Skmacy default: 2033167514Skmacy error = ether_ioctl(ifp, command, data); 2034167514Skmacy break; 2035167514Skmacy } 2036167514Skmacy return (error); 2037167514Skmacy} 2038167514Skmacy 2039174708Skmacystatic int 2040167514Skmacycxgb_media_change(struct ifnet *ifp) 2041167514Skmacy{ 2042167514Skmacy if_printf(ifp, "media change not supported\n"); 2043167514Skmacy return (ENXIO); 2044167514Skmacy} 2045167514Skmacy 2046167514Skmacystatic void 2047167514Skmacycxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 2048167514Skmacy{ 2049167514Skmacy struct port_info *p = ifp->if_softc; 2050167514Skmacy 2051167514Skmacy ifmr->ifm_status = IFM_AVALID; 2052167514Skmacy ifmr->ifm_active = IFM_ETHER; 2053167514Skmacy 2054167514Skmacy if (!p->link_config.link_ok) 2055167514Skmacy return; 2056167514Skmacy 2057167514Skmacy ifmr->ifm_status |= IFM_ACTIVE; 2058167514Skmacy 2059170654Skmacy switch (p->link_config.speed) { 2060170654Skmacy case 10: 2061170654Skmacy ifmr->ifm_active |= IFM_10_T; 2062170654Skmacy break; 2063170654Skmacy case 100: 2064170654Skmacy ifmr->ifm_active |= IFM_100_TX; 2065170654Skmacy break; 2066170654Skmacy case 1000: 2067170654Skmacy ifmr->ifm_active |= IFM_1000_T; 2068170654Skmacy break; 2069170654Skmacy } 2070170654Skmacy 2071167514Skmacy if (p->link_config.duplex) 2072167514Skmacy ifmr->ifm_active |= IFM_FDX; 2073167514Skmacy else 2074167514Skmacy ifmr->ifm_active |= IFM_HDX; 2075167514Skmacy} 2076167514Skmacy 2077167514Skmacystatic void 2078167514Skmacycxgb_async_intr(void *data) 2079167514Skmacy{ 2080167760Skmacy adapter_t *sc = data; 2081167760Skmacy 2082167514Skmacy if (cxgb_debug) 2083167760Skmacy device_printf(sc->dev, "cxgb_async_intr\n"); 2084170869Skmacy /* 2085170869Skmacy * May need to sleep - defer to taskqueue 2086170869Skmacy */ 2087170869Skmacy taskqueue_enqueue(sc->tq, &sc->slow_intr_task); 2088167514Skmacy} 2089167514Skmacy 2090167514Skmacystatic void 2091167514Skmacycxgb_ext_intr_handler(void *arg, int count) 2092167514Skmacy{ 2093167514Skmacy adapter_t *sc = (adapter_t *)arg; 2094167514Skmacy 2095167514Skmacy if (cxgb_debug) 2096167514Skmacy printf("cxgb_ext_intr_handler\n"); 2097167514Skmacy 2098167514Skmacy t3_phy_intr_handler(sc); 2099167514Skmacy 2100167514Skmacy /* Now reenable external interrupts */ 2101169978Skmacy ADAPTER_LOCK(sc); 2102167514Skmacy if (sc->slow_intr_mask) { 2103167514Skmacy sc->slow_intr_mask |= F_T3DBG; 2104167514Skmacy t3_write_reg(sc, A_PL_INT_CAUSE0, F_T3DBG); 2105167514Skmacy t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask); 2106167514Skmacy } 2107169978Skmacy ADAPTER_UNLOCK(sc); 2108167514Skmacy} 2109167514Skmacy 2110167514Skmacystatic void 2111167746Skmacycheck_link_status(adapter_t *sc) 2112167514Skmacy{ 2113167746Skmacy int i; 2114167514Skmacy 2115167746Skmacy for (i = 0; i < (sc)->params.nports; ++i) { 2116167746Skmacy struct port_info *p = &sc->port[i]; 2117167514Skmacy 2118176472Skmacy if (!(p->phy.caps & SUPPORTED_IRQ)) 2119167746Skmacy t3_link_changed(sc, i); 2120170654Skmacy p->ifp->if_baudrate = p->link_config.speed * 1000000; 2121167746Skmacy } 2122167514Skmacy} 2123167514Skmacy 2124167514Skmacystatic void 2125167746Skmacycheck_t3b2_mac(struct adapter *adapter) 2126167514Skmacy{ 2127167514Skmacy int i; 2128167514Skmacy 2129176472Skmacy if(adapter->flags & CXGB_SHUTDOWN) 2130176472Skmacy return; 2131176472Skmacy 2132167746Skmacy for_each_port(adapter, i) { 2133167746Skmacy struct port_info *p = &adapter->port[i]; 2134167746Skmacy struct ifnet *ifp = p->ifp; 2135167746Skmacy int status; 2136176472Skmacy 2137176472Skmacy if(adapter->flags & CXGB_SHUTDOWN) 2138176472Skmacy return; 2139176472Skmacy 2140167746Skmacy if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 2141167746Skmacy continue; 2142167746Skmacy 2143167746Skmacy status = 0; 2144167746Skmacy PORT_LOCK(p); 2145167746Skmacy if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) 2146167746Skmacy status = t3b2_mac_watchdog_task(&p->mac); 2147167746Skmacy if (status == 1) 2148167746Skmacy p->mac.stats.num_toggled++; 2149167746Skmacy else if (status == 2) { 2150167746Skmacy struct cmac *mac = &p->mac; 2151180583Skmacy int mtu = ifp->if_mtu; 2152167746Skmacy 2153180583Skmacy if (ifp->if_capenable & IFCAP_VLAN_MTU) 2154180583Skmacy mtu += ETHER_VLAN_ENCAP_LEN; 2155180583Skmacy t3_mac_set_mtu(mac, mtu); 2156167746Skmacy t3_mac_set_address(mac, 0, p->hw_addr); 2157167746Skmacy cxgb_set_rxmode(p); 2158167746Skmacy t3_link_start(&p->phy, mac, &p->link_config); 2159167746Skmacy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 2160171803Skmacy t3_port_intr_enable(adapter, p->port_id); 2161167746Skmacy p->mac.stats.num_resets++; 2162167746Skmacy } 2163167746Skmacy PORT_UNLOCK(p); 2164167514Skmacy } 2165167514Skmacy} 2166167514Skmacy 2167167746Skmacystatic void 2168167746Skmacycxgb_tick(void *arg) 2169167746Skmacy{ 2170167746Skmacy adapter_t *sc = (adapter_t *)arg; 2171170869Skmacy 2172176472Skmacy if(sc->flags & CXGB_SHUTDOWN) 2173176472Skmacy return; 2174174708Skmacy 2175170869Skmacy taskqueue_enqueue(sc->tq, &sc->tick_task); 2176181652Skmacy callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc); 2177170869Skmacy} 2178170869Skmacy 2179170869Skmacystatic void 2180170869Skmacycxgb_tick_handler(void *arg, int count) 2181170869Skmacy{ 2182170869Skmacy adapter_t *sc = (adapter_t *)arg; 2183167746Skmacy const struct adapter_params *p = &sc->params; 2184181652Skmacy int i; 2185167746Skmacy 2186176472Skmacy if(sc->flags & CXGB_SHUTDOWN) 2187176472Skmacy return; 2188176472Skmacy 2189170869Skmacy ADAPTER_LOCK(sc); 2190167746Skmacy if (p->linkpoll_period) 2191167746Skmacy check_link_status(sc); 2192167746Skmacy 2193181652Skmacy sc->check_task_cnt++; 2194181652Skmacy 2195167746Skmacy /* 2196176472Skmacy * adapter lock can currently only be acquired after the 2197167746Skmacy * port lock 2198167746Skmacy */ 2199167746Skmacy ADAPTER_UNLOCK(sc); 2200170654Skmacy 2201176472Skmacy if (p->rev == T3_REV_B2 && p->nports < 4 && sc->open_device_map) 2202167746Skmacy check_t3b2_mac(sc); 2203181652Skmacy 2204181652Skmacy /* Update MAC stats if it's time to do so */ 2205181652Skmacy if (!p->linkpoll_period || 2206181652Skmacy (sc->check_task_cnt * p->linkpoll_period) / 10 >= 2207181652Skmacy p->stats_update_period) { 2208181652Skmacy for_each_port(sc, i) { 2209181652Skmacy struct port_info *port = &sc->port[i]; 2210181652Skmacy PORT_LOCK(port); 2211181652Skmacy t3_mac_update_stats(&port->mac); 2212181652Skmacy PORT_UNLOCK(port); 2213181652Skmacy } 2214181652Skmacy sc->check_task_cnt = 0; 2215181652Skmacy } 2216167746Skmacy} 2217167746Skmacy 2218171978Skmacystatic void 2219171978Skmacytouch_bars(device_t dev) 2220171978Skmacy{ 2221171978Skmacy /* 2222171978Skmacy * Don't enable yet 2223171978Skmacy */ 2224171978Skmacy#if !defined(__LP64__) && 0 2225171978Skmacy u32 v; 2226171978Skmacy 2227171978Skmacy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &v); 2228171978Skmacy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, v); 2229171978Skmacy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3, &v); 2230171978Skmacy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_3, v); 2231171978Skmacy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &v); 2232171978Skmacy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_5, v); 2233171978Skmacy#endif 2234171978Skmacy} 2235171978Skmacy 2236167514Skmacystatic int 2237171471Skmacyset_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset) 2238171471Skmacy{ 2239171471Skmacy uint8_t *buf; 2240171471Skmacy int err = 0; 2241171471Skmacy u32 aligned_offset, aligned_len, *p; 2242171471Skmacy struct adapter *adapter = pi->adapter; 2243171471Skmacy 2244171471Skmacy 2245171471Skmacy aligned_offset = offset & ~3; 2246171471Skmacy aligned_len = (len + (offset & 3) + 3) & ~3; 2247171471Skmacy 2248171471Skmacy if (aligned_offset != offset || aligned_len != len) { 2249171471Skmacy buf = malloc(aligned_len, M_DEVBUF, M_WAITOK|M_ZERO); 2250171471Skmacy if (!buf) 2251171471Skmacy return (ENOMEM); 2252171471Skmacy err = t3_seeprom_read(adapter, aligned_offset, (u32 *)buf); 2253171471Skmacy if (!err && aligned_len > 4) 2254171471Skmacy err = t3_seeprom_read(adapter, 2255171471Skmacy aligned_offset + aligned_len - 4, 2256171471Skmacy (u32 *)&buf[aligned_len - 4]); 2257171471Skmacy if (err) 2258171471Skmacy goto out; 2259171471Skmacy memcpy(buf + (offset & 3), data, len); 2260171471Skmacy } else 2261171471Skmacy buf = (uint8_t *)(uintptr_t)data; 2262171471Skmacy 2263171471Skmacy err = t3_seeprom_wp(adapter, 0); 2264171471Skmacy if (err) 2265171471Skmacy goto out; 2266171471Skmacy 2267171471Skmacy for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { 2268171471Skmacy err = t3_seeprom_write(adapter, aligned_offset, *p); 2269171471Skmacy aligned_offset += 4; 2270171471Skmacy } 2271171471Skmacy 2272171471Skmacy if (!err) 2273171471Skmacy err = t3_seeprom_wp(adapter, 1); 2274171471Skmacyout: 2275171471Skmacy if (buf != data) 2276171471Skmacy free(buf, M_DEVBUF); 2277171471Skmacy return err; 2278171471Skmacy} 2279171471Skmacy 2280171471Skmacy 2281171471Skmacystatic int 2282167514Skmacyin_range(int val, int lo, int hi) 2283167514Skmacy{ 2284167514Skmacy return val < 0 || (val <= hi && val >= lo); 2285167514Skmacy} 2286167514Skmacy 2287167514Skmacystatic int 2288170654Skmacycxgb_extension_open(struct cdev *dev, int flags, int fmp, d_thread_t *td) 2289170654Skmacy{ 2290170654Skmacy return (0); 2291170654Skmacy} 2292170654Skmacy 2293170654Skmacystatic int 2294170654Skmacycxgb_extension_close(struct cdev *dev, int flags, int fmt, d_thread_t *td) 2295170654Skmacy{ 2296170654Skmacy return (0); 2297170654Skmacy} 2298170654Skmacy 2299170654Skmacystatic int 2300167514Skmacycxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, 2301167514Skmacy int fflag, struct thread *td) 2302167514Skmacy{ 2303167514Skmacy int mmd, error = 0; 2304167514Skmacy struct port_info *pi = dev->si_drv1; 2305167514Skmacy adapter_t *sc = pi->adapter; 2306167514Skmacy 2307167514Skmacy#ifdef PRIV_SUPPORTED 2308167514Skmacy if (priv_check(td, PRIV_DRIVER)) { 2309167514Skmacy if (cxgb_debug) 2310167514Skmacy printf("user does not have access to privileged ioctls\n"); 2311167514Skmacy return (EPERM); 2312167514Skmacy } 2313167514Skmacy#else 2314167514Skmacy if (suser(td)) { 2315167514Skmacy if (cxgb_debug) 2316167514Skmacy printf("user does not have access to privileged ioctls\n"); 2317167514Skmacy return (EPERM); 2318167514Skmacy } 2319167514Skmacy#endif 2320167514Skmacy 2321167514Skmacy switch (cmd) { 2322182679Skmacy case CHELSIO_GET_MIIREG: { 2323167514Skmacy uint32_t val; 2324167514Skmacy struct cphy *phy = &pi->phy; 2325182679Skmacy struct ch_mii_data *mid = (struct ch_mii_data *)data; 2326167514Skmacy 2327167514Skmacy if (!phy->mdio_read) 2328167514Skmacy return (EOPNOTSUPP); 2329167514Skmacy if (is_10G(sc)) { 2330167514Skmacy mmd = mid->phy_id >> 8; 2331167514Skmacy if (!mmd) 2332167514Skmacy mmd = MDIO_DEV_PCS; 2333167514Skmacy else if (mmd > MDIO_DEV_XGXS) 2334171471Skmacy return (EINVAL); 2335167514Skmacy 2336167514Skmacy error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd, 2337167514Skmacy mid->reg_num, &val); 2338167514Skmacy } else 2339167514Skmacy error = phy->mdio_read(sc, mid->phy_id & 0x1f, 0, 2340167514Skmacy mid->reg_num & 0x1f, &val); 2341167514Skmacy if (error == 0) 2342167514Skmacy mid->val_out = val; 2343167514Skmacy break; 2344167514Skmacy } 2345182679Skmacy case CHELSIO_SET_MIIREG: { 2346167514Skmacy struct cphy *phy = &pi->phy; 2347182679Skmacy struct ch_mii_data *mid = (struct ch_mii_data *)data; 2348167514Skmacy 2349167514Skmacy if (!phy->mdio_write) 2350167514Skmacy return (EOPNOTSUPP); 2351167514Skmacy if (is_10G(sc)) { 2352167514Skmacy mmd = mid->phy_id >> 8; 2353167514Skmacy if (!mmd) 2354167514Skmacy mmd = MDIO_DEV_PCS; 2355167514Skmacy else if (mmd > MDIO_DEV_XGXS) 2356167514Skmacy return (EINVAL); 2357167514Skmacy 2358167514Skmacy error = phy->mdio_write(sc, mid->phy_id & 0x1f, 2359167514Skmacy mmd, mid->reg_num, mid->val_in); 2360167514Skmacy } else 2361167514Skmacy error = phy->mdio_write(sc, mid->phy_id & 0x1f, 0, 2362167514Skmacy mid->reg_num & 0x1f, 2363167514Skmacy mid->val_in); 2364167514Skmacy break; 2365167514Skmacy } 2366167514Skmacy case CHELSIO_SETREG: { 2367167514Skmacy struct ch_reg *edata = (struct ch_reg *)data; 2368167514Skmacy if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 2369167514Skmacy return (EFAULT); 2370167514Skmacy t3_write_reg(sc, edata->addr, edata->val); 2371167514Skmacy break; 2372167514Skmacy } 2373167514Skmacy case CHELSIO_GETREG: { 2374167514Skmacy struct ch_reg *edata = (struct ch_reg *)data; 2375167514Skmacy if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 2376167514Skmacy return (EFAULT); 2377167514Skmacy edata->val = t3_read_reg(sc, edata->addr); 2378167514Skmacy break; 2379167514Skmacy } 2380167514Skmacy case CHELSIO_GET_SGE_CONTEXT: { 2381167514Skmacy struct ch_cntxt *ecntxt = (struct ch_cntxt *)data; 2382176472Skmacy mtx_lock_spin(&sc->sge.reg_lock); 2383167514Skmacy switch (ecntxt->cntxt_type) { 2384167514Skmacy case CNTXT_TYPE_EGRESS: 2385182679Skmacy error = -t3_sge_read_ecntxt(sc, ecntxt->cntxt_id, 2386167514Skmacy ecntxt->data); 2387167514Skmacy break; 2388167514Skmacy case CNTXT_TYPE_FL: 2389182679Skmacy error = -t3_sge_read_fl(sc, ecntxt->cntxt_id, 2390167514Skmacy ecntxt->data); 2391167514Skmacy break; 2392167514Skmacy case CNTXT_TYPE_RSP: 2393182679Skmacy error = -t3_sge_read_rspq(sc, ecntxt->cntxt_id, 2394167514Skmacy ecntxt->data); 2395167514Skmacy break; 2396167514Skmacy case CNTXT_TYPE_CQ: 2397182679Skmacy error = -t3_sge_read_cq(sc, ecntxt->cntxt_id, 2398167514Skmacy ecntxt->data); 2399167514Skmacy break; 2400167514Skmacy default: 2401167514Skmacy error = EINVAL; 2402167514Skmacy break; 2403167514Skmacy } 2404176472Skmacy mtx_unlock_spin(&sc->sge.reg_lock); 2405167514Skmacy break; 2406167514Skmacy } 2407167514Skmacy case CHELSIO_GET_SGE_DESC: { 2408167514Skmacy struct ch_desc *edesc = (struct ch_desc *)data; 2409167514Skmacy int ret; 2410167514Skmacy if (edesc->queue_num >= SGE_QSETS * 6) 2411167514Skmacy return (EINVAL); 2412167514Skmacy ret = t3_get_desc(&sc->sge.qs[edesc->queue_num / 6], 2413167514Skmacy edesc->queue_num % 6, edesc->idx, edesc->data); 2414167514Skmacy if (ret < 0) 2415167514Skmacy return (EINVAL); 2416167514Skmacy edesc->size = ret; 2417167514Skmacy break; 2418167514Skmacy } 2419182679Skmacy case CHELSIO_GET_QSET_PARAMS: { 2420167514Skmacy struct qset_params *q; 2421167514Skmacy struct ch_qset_params *t = (struct ch_qset_params *)data; 2422182679Skmacy int q1 = pi->first_qset; 2423182679Skmacy int nqsets = pi->nqsets; 2424176472Skmacy int i; 2425176472Skmacy 2426182679Skmacy if (t->qset_idx >= nqsets) 2427182679Skmacy return EINVAL; 2428167514Skmacy 2429182679Skmacy i = q1 + t->qset_idx; 2430182679Skmacy q = &sc->params.sge.qset[i]; 2431167514Skmacy t->rspq_size = q->rspq_size; 2432167514Skmacy t->txq_size[0] = q->txq_size[0]; 2433167514Skmacy t->txq_size[1] = q->txq_size[1]; 2434167514Skmacy t->txq_size[2] = q->txq_size[2]; 2435167514Skmacy t->fl_size[0] = q->fl_size; 2436167514Skmacy t->fl_size[1] = q->jumbo_size; 2437167514Skmacy t->polling = q->polling; 2438182679Skmacy t->lro = q->lro; 2439180583Skmacy t->intr_lat = q->coalesce_usecs; 2440167514Skmacy t->cong_thres = q->cong_thres; 2441182679Skmacy t->qnum = i; 2442182679Skmacy 2443182679Skmacy if (sc->flags & USING_MSIX) 2444182679Skmacy t->vector = rman_get_start(sc->msix_irq_res[i]); 2445182679Skmacy else 2446182679Skmacy t->vector = rman_get_start(sc->irq_res); 2447182679Skmacy 2448167514Skmacy break; 2449167514Skmacy } 2450182679Skmacy case CHELSIO_GET_QSET_NUM: { 2451167514Skmacy struct ch_reg *edata = (struct ch_reg *)data; 2452182679Skmacy edata->val = pi->nqsets; 2453182679Skmacy break; 2454182679Skmacy } 2455182679Skmacy case CHELSIO_LOAD_FW: { 2456182679Skmacy uint8_t *fw_data; 2457182679Skmacy uint32_t vers; 2458182679Skmacy struct ch_mem_range *t = (struct ch_mem_range *)data; 2459182679Skmacy 2460167514Skmacy /* 2461182679Skmacy * You're allowed to load a firmware only before FULL_INIT_DONE 2462182679Skmacy * 2463182679Skmacy * FW_UPTODATE is also set so the rest of the initialization 2464182679Skmacy * will not overwrite what was loaded here. This gives you the 2465182679Skmacy * flexibility to load any firmware (and maybe shoot yourself in 2466182679Skmacy * the foot). 2467167514Skmacy */ 2468182679Skmacy 2469182679Skmacy ADAPTER_LOCK(sc); 2470182679Skmacy if (sc->open_device_map || sc->flags & FULL_INIT_DONE) { 2471182679Skmacy ADAPTER_UNLOCK(sc); 2472182679Skmacy return (EBUSY); 2473182679Skmacy } 2474182679Skmacy 2475182679Skmacy fw_data = malloc(t->len, M_DEVBUF, M_NOWAIT); 2476182679Skmacy if (!fw_data) 2477182679Skmacy error = ENOMEM; 2478182679Skmacy else 2479182679Skmacy error = copyin(t->buf, fw_data, t->len); 2480182679Skmacy 2481182679Skmacy if (!error) 2482182679Skmacy error = -t3_load_fw(sc, fw_data, t->len); 2483182679Skmacy 2484182679Skmacy if (t3_get_fw_version(sc, &vers) == 0) { 2485182679Skmacy snprintf(&sc->fw_version[0], sizeof(sc->fw_version), 2486182679Skmacy "%d.%d.%d", G_FW_VERSION_MAJOR(vers), 2487182679Skmacy G_FW_VERSION_MINOR(vers), G_FW_VERSION_MICRO(vers)); 2488182679Skmacy } 2489182679Skmacy 2490182679Skmacy if (!error) 2491182679Skmacy sc->flags |= FW_UPTODATE; 2492182679Skmacy 2493182679Skmacy free(fw_data, M_DEVBUF); 2494182679Skmacy ADAPTER_UNLOCK(sc); 2495167514Skmacy break; 2496167514Skmacy } 2497182679Skmacy case CHELSIO_LOAD_BOOT: { 2498182679Skmacy uint8_t *boot_data; 2499182679Skmacy struct ch_mem_range *t = (struct ch_mem_range *)data; 2500182679Skmacy 2501182679Skmacy boot_data = malloc(t->len, M_DEVBUF, M_NOWAIT); 2502182679Skmacy if (!boot_data) 2503182679Skmacy return ENOMEM; 2504182679Skmacy 2505182679Skmacy error = copyin(t->buf, boot_data, t->len); 2506182679Skmacy if (!error) 2507182679Skmacy error = -t3_load_boot(sc, boot_data, t->len); 2508182679Skmacy 2509182679Skmacy free(boot_data, M_DEVBUF); 2510167514Skmacy break; 2511167514Skmacy } 2512182679Skmacy case CHELSIO_GET_PM: { 2513182679Skmacy struct ch_pm *m = (struct ch_pm *)data; 2514182679Skmacy struct tp_params *p = &sc->params.tp; 2515182679Skmacy 2516182679Skmacy if (!is_offload(sc)) 2517182679Skmacy return (EOPNOTSUPP); 2518182679Skmacy 2519182679Skmacy m->tx_pg_sz = p->tx_pg_size; 2520182679Skmacy m->tx_num_pg = p->tx_num_pgs; 2521182679Skmacy m->rx_pg_sz = p->rx_pg_size; 2522182679Skmacy m->rx_num_pg = p->rx_num_pgs; 2523182679Skmacy m->pm_total = p->pmtx_size + p->chan_rx_size * p->nchan; 2524182679Skmacy 2525167514Skmacy break; 2526182679Skmacy } 2527182679Skmacy case CHELSIO_SET_PM: { 2528182679Skmacy struct ch_pm *m = (struct ch_pm *)data; 2529182679Skmacy struct tp_params *p = &sc->params.tp; 2530182679Skmacy 2531182679Skmacy if (!is_offload(sc)) 2532182679Skmacy return (EOPNOTSUPP); 2533182679Skmacy if (sc->flags & FULL_INIT_DONE) 2534182679Skmacy return (EBUSY); 2535182679Skmacy 2536182679Skmacy if (!m->rx_pg_sz || (m->rx_pg_sz & (m->rx_pg_sz - 1)) || 2537182679Skmacy !m->tx_pg_sz || (m->tx_pg_sz & (m->tx_pg_sz - 1))) 2538182679Skmacy return (EINVAL); /* not power of 2 */ 2539182679Skmacy if (!(m->rx_pg_sz & 0x14000)) 2540182679Skmacy return (EINVAL); /* not 16KB or 64KB */ 2541182679Skmacy if (!(m->tx_pg_sz & 0x1554000)) 2542182679Skmacy return (EINVAL); 2543182679Skmacy if (m->tx_num_pg == -1) 2544182679Skmacy m->tx_num_pg = p->tx_num_pgs; 2545182679Skmacy if (m->rx_num_pg == -1) 2546182679Skmacy m->rx_num_pg = p->rx_num_pgs; 2547182679Skmacy if (m->tx_num_pg % 24 || m->rx_num_pg % 24) 2548182679Skmacy return (EINVAL); 2549182679Skmacy if (m->rx_num_pg * m->rx_pg_sz > p->chan_rx_size || 2550182679Skmacy m->tx_num_pg * m->tx_pg_sz > p->chan_tx_size) 2551182679Skmacy return (EINVAL); 2552182679Skmacy 2553182679Skmacy p->rx_pg_size = m->rx_pg_sz; 2554182679Skmacy p->tx_pg_size = m->tx_pg_sz; 2555182679Skmacy p->rx_num_pgs = m->rx_num_pg; 2556182679Skmacy p->tx_num_pgs = m->tx_num_pg; 2557182679Skmacy break; 2558182679Skmacy } 2559169978Skmacy case CHELSIO_SETMTUTAB: { 2560169978Skmacy struct ch_mtus *m = (struct ch_mtus *)data; 2561169978Skmacy int i; 2562169978Skmacy 2563169978Skmacy if (!is_offload(sc)) 2564169978Skmacy return (EOPNOTSUPP); 2565169978Skmacy if (offload_running(sc)) 2566169978Skmacy return (EBUSY); 2567169978Skmacy if (m->nmtus != NMTUS) 2568169978Skmacy return (EINVAL); 2569169978Skmacy if (m->mtus[0] < 81) /* accommodate SACK */ 2570169978Skmacy return (EINVAL); 2571169978Skmacy 2572169978Skmacy /* 2573169978Skmacy * MTUs must be in ascending order 2574169978Skmacy */ 2575169978Skmacy for (i = 1; i < NMTUS; ++i) 2576169978Skmacy if (m->mtus[i] < m->mtus[i - 1]) 2577169978Skmacy return (EINVAL); 2578169978Skmacy 2579182679Skmacy memcpy(sc->params.mtus, m->mtus, sizeof(sc->params.mtus)); 2580169978Skmacy break; 2581169978Skmacy } 2582169978Skmacy case CHELSIO_GETMTUTAB: { 2583169978Skmacy struct ch_mtus *m = (struct ch_mtus *)data; 2584169978Skmacy 2585169978Skmacy if (!is_offload(sc)) 2586169978Skmacy return (EOPNOTSUPP); 2587169978Skmacy 2588169978Skmacy memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus)); 2589169978Skmacy m->nmtus = NMTUS; 2590169978Skmacy break; 2591171471Skmacy } 2592167514Skmacy case CHELSIO_GET_MEM: { 2593167514Skmacy struct ch_mem_range *t = (struct ch_mem_range *)data; 2594167514Skmacy struct mc7 *mem; 2595167514Skmacy uint8_t *useraddr; 2596167514Skmacy u64 buf[32]; 2597182679Skmacy 2598182679Skmacy /* 2599182679Skmacy * Use these to avoid modifying len/addr in the the return 2600182679Skmacy * struct 2601182679Skmacy */ 2602182679Skmacy uint32_t len = t->len, addr = t->addr; 2603182679Skmacy 2604167514Skmacy if (!is_offload(sc)) 2605167514Skmacy return (EOPNOTSUPP); 2606167514Skmacy if (!(sc->flags & FULL_INIT_DONE)) 2607167514Skmacy return (EIO); /* need the memory controllers */ 2608182679Skmacy if ((addr & 0x7) || (len & 0x7)) 2609167514Skmacy return (EINVAL); 2610167514Skmacy if (t->mem_id == MEM_CM) 2611167514Skmacy mem = &sc->cm; 2612167514Skmacy else if (t->mem_id == MEM_PMRX) 2613167514Skmacy mem = &sc->pmrx; 2614167514Skmacy else if (t->mem_id == MEM_PMTX) 2615167514Skmacy mem = &sc->pmtx; 2616167514Skmacy else 2617167514Skmacy return (EINVAL); 2618167514Skmacy 2619167514Skmacy /* 2620167514Skmacy * Version scheme: 2621167514Skmacy * bits 0..9: chip version 2622167514Skmacy * bits 10..15: chip revision 2623167514Skmacy */ 2624167514Skmacy t->version = 3 | (sc->params.rev << 10); 2625167514Skmacy 2626167514Skmacy /* 2627167514Skmacy * Read 256 bytes at a time as len can be large and we don't 2628167514Skmacy * want to use huge intermediate buffers. 2629167514Skmacy */ 2630174708Skmacy useraddr = (uint8_t *)t->buf; 2631182679Skmacy while (len) { 2632182679Skmacy unsigned int chunk = min(len, sizeof(buf)); 2633167514Skmacy 2634182679Skmacy error = t3_mc7_bd_read(mem, addr / 8, chunk / 8, buf); 2635167514Skmacy if (error) 2636167514Skmacy return (-error); 2637167514Skmacy if (copyout(buf, useraddr, chunk)) 2638167514Skmacy return (EFAULT); 2639167514Skmacy useraddr += chunk; 2640182679Skmacy addr += chunk; 2641182679Skmacy len -= chunk; 2642167514Skmacy } 2643167514Skmacy break; 2644167514Skmacy } 2645169978Skmacy case CHELSIO_READ_TCAM_WORD: { 2646169978Skmacy struct ch_tcam_word *t = (struct ch_tcam_word *)data; 2647169978Skmacy 2648169978Skmacy if (!is_offload(sc)) 2649169978Skmacy return (EOPNOTSUPP); 2650171471Skmacy if (!(sc->flags & FULL_INIT_DONE)) 2651171471Skmacy return (EIO); /* need MC5 */ 2652169978Skmacy return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf); 2653169978Skmacy break; 2654169978Skmacy } 2655167514Skmacy case CHELSIO_SET_TRACE_FILTER: { 2656167514Skmacy struct ch_trace *t = (struct ch_trace *)data; 2657167514Skmacy const struct trace_params *tp; 2658167514Skmacy 2659167514Skmacy tp = (const struct trace_params *)&t->sip; 2660167514Skmacy if (t->config_tx) 2661167514Skmacy t3_config_trace_filter(sc, tp, 0, t->invert_match, 2662167514Skmacy t->trace_tx); 2663167514Skmacy if (t->config_rx) 2664167514Skmacy t3_config_trace_filter(sc, tp, 1, t->invert_match, 2665167514Skmacy t->trace_rx); 2666167514Skmacy break; 2667167514Skmacy } 2668167514Skmacy case CHELSIO_SET_PKTSCHED: { 2669167514Skmacy struct ch_pktsched_params *p = (struct ch_pktsched_params *)data; 2670167514Skmacy if (sc->open_device_map == 0) 2671167514Skmacy return (EAGAIN); 2672167514Skmacy send_pktsched_cmd(sc, p->sched, p->idx, p->min, p->max, 2673167514Skmacy p->binding); 2674167514Skmacy break; 2675167514Skmacy } 2676167514Skmacy case CHELSIO_IFCONF_GETREGS: { 2677182679Skmacy struct ch_ifconf_regs *regs = (struct ch_ifconf_regs *)data; 2678167514Skmacy int reglen = cxgb_get_regs_len(); 2679182679Skmacy uint8_t *buf = malloc(reglen, M_DEVBUF, M_NOWAIT); 2680167514Skmacy if (buf == NULL) { 2681167514Skmacy return (ENOMEM); 2682182679Skmacy } 2683182679Skmacy if (regs->len > reglen) 2684167514Skmacy regs->len = reglen; 2685182679Skmacy else if (regs->len < reglen) 2686167514Skmacy error = E2BIG; 2687182679Skmacy 2688182679Skmacy if (!error) { 2689182679Skmacy cxgb_get_regs(sc, regs, buf); 2690182679Skmacy error = copyout(buf, regs->data, reglen); 2691167514Skmacy } 2692167514Skmacy free(buf, M_DEVBUF); 2693167514Skmacy 2694167514Skmacy break; 2695167514Skmacy } 2696169978Skmacy case CHELSIO_SET_HW_SCHED: { 2697169978Skmacy struct ch_hw_sched *t = (struct ch_hw_sched *)data; 2698169978Skmacy unsigned int ticks_per_usec = core_ticks_per_usec(sc); 2699169978Skmacy 2700169978Skmacy if ((sc->flags & FULL_INIT_DONE) == 0) 2701169978Skmacy return (EAGAIN); /* need TP to be initialized */ 2702169978Skmacy if (t->sched >= NTX_SCHED || !in_range(t->mode, 0, 1) || 2703169978Skmacy !in_range(t->channel, 0, 1) || 2704169978Skmacy !in_range(t->kbps, 0, 10000000) || 2705169978Skmacy !in_range(t->class_ipg, 0, 10000 * 65535 / ticks_per_usec) || 2706169978Skmacy !in_range(t->flow_ipg, 0, 2707169978Skmacy dack_ticks_to_usec(sc, 0x7ff))) 2708169978Skmacy return (EINVAL); 2709169978Skmacy 2710169978Skmacy if (t->kbps >= 0) { 2711169978Skmacy error = t3_config_sched(sc, t->kbps, t->sched); 2712169978Skmacy if (error < 0) 2713169978Skmacy return (-error); 2714169978Skmacy } 2715169978Skmacy if (t->class_ipg >= 0) 2716169978Skmacy t3_set_sched_ipg(sc, t->sched, t->class_ipg); 2717169978Skmacy if (t->flow_ipg >= 0) { 2718169978Skmacy t->flow_ipg *= 1000; /* us -> ns */ 2719169978Skmacy t3_set_pace_tbl(sc, &t->flow_ipg, t->sched, 1); 2720169978Skmacy } 2721169978Skmacy if (t->mode >= 0) { 2722169978Skmacy int bit = 1 << (S_TX_MOD_TIMER_MODE + t->sched); 2723169978Skmacy 2724169978Skmacy t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP, 2725169978Skmacy bit, t->mode ? bit : 0); 2726169978Skmacy } 2727169978Skmacy if (t->channel >= 0) 2728169978Skmacy t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP, 2729169978Skmacy 1 << t->sched, t->channel << t->sched); 2730169978Skmacy break; 2731182679Skmacy } 2732182679Skmacy case CHELSIO_GET_EEPROM: { 2733182679Skmacy int i; 2734182679Skmacy struct ch_eeprom *e = (struct ch_eeprom *)data; 2735182679Skmacy uint8_t *buf = malloc(EEPROMSIZE, M_DEVBUF, M_NOWAIT); 2736182679Skmacy 2737182679Skmacy if (buf == NULL) { 2738182679Skmacy return (ENOMEM); 2739182679Skmacy } 2740182679Skmacy e->magic = EEPROM_MAGIC; 2741182679Skmacy for (i = e->offset & ~3; !error && i < e->offset + e->len; i += 4) 2742182679Skmacy error = -t3_seeprom_read(sc, i, (uint32_t *)&buf[i]); 2743182679Skmacy 2744182679Skmacy if (!error) 2745182679Skmacy error = copyout(buf + e->offset, e->data, e->len); 2746182679Skmacy 2747182679Skmacy free(buf, M_DEVBUF); 2748182679Skmacy break; 2749182679Skmacy } 2750182679Skmacy case CHELSIO_CLEAR_STATS: { 2751182679Skmacy if (!(sc->flags & FULL_INIT_DONE)) 2752182679Skmacy return EAGAIN; 2753182679Skmacy 2754182679Skmacy PORT_LOCK(pi); 2755182679Skmacy t3_mac_update_stats(&pi->mac); 2756182679Skmacy memset(&pi->mac.stats, 0, sizeof(pi->mac.stats)); 2757182679Skmacy PORT_UNLOCK(pi); 2758182679Skmacy break; 2759182679Skmacy } 2760167514Skmacy default: 2761167514Skmacy return (EOPNOTSUPP); 2762167514Skmacy break; 2763167514Skmacy } 2764167514Skmacy 2765167514Skmacy return (error); 2766167514Skmacy} 2767167514Skmacy 2768167514Skmacystatic __inline void 2769167514Skmacyreg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start, 2770167514Skmacy unsigned int end) 2771167514Skmacy{ 2772182679Skmacy uint32_t *p = (uint32_t *)(buf + start); 2773167514Skmacy 2774167514Skmacy for ( ; start <= end; start += sizeof(uint32_t)) 2775167514Skmacy *p++ = t3_read_reg(ap, start); 2776167514Skmacy} 2777167514Skmacy 2778167514Skmacy#define T3_REGMAP_SIZE (3 * 1024) 2779167514Skmacystatic int 2780167514Skmacycxgb_get_regs_len(void) 2781167514Skmacy{ 2782167514Skmacy return T3_REGMAP_SIZE; 2783167514Skmacy} 2784167514Skmacy 2785167514Skmacystatic void 2786182679Skmacycxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf) 2787167514Skmacy{ 2788167514Skmacy 2789167514Skmacy /* 2790167514Skmacy * Version scheme: 2791167514Skmacy * bits 0..9: chip version 2792167514Skmacy * bits 10..15: chip revision 2793167514Skmacy * bit 31: set for PCIe cards 2794167514Skmacy */ 2795167514Skmacy regs->version = 3 | (sc->params.rev << 10) | (is_pcie(sc) << 31); 2796167514Skmacy 2797167514Skmacy /* 2798167514Skmacy * We skip the MAC statistics registers because they are clear-on-read. 2799167514Skmacy * Also reading multi-register stats would need to synchronize with the 2800167514Skmacy * periodic mac stats accumulation. Hard to justify the complexity. 2801167514Skmacy */ 2802182679Skmacy memset(buf, 0, cxgb_get_regs_len()); 2803167514Skmacy reg_block_dump(sc, buf, 0, A_SG_RSPQ_CREDIT_RETURN); 2804167514Skmacy reg_block_dump(sc, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT); 2805167514Skmacy reg_block_dump(sc, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE); 2806167514Skmacy reg_block_dump(sc, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA); 2807167514Skmacy reg_block_dump(sc, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3); 2808167514Skmacy reg_block_dump(sc, buf, A_XGM_SERDES_STATUS0, 2809167514Skmacy XGM_REG(A_XGM_SERDES_STAT3, 1)); 2810167514Skmacy reg_block_dump(sc, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1), 2811167514Skmacy XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1)); 2812167514Skmacy} 2813176572Skmacy 2814176572Skmacy 2815176572SkmacyMODULE_DEPEND(if_cxgb, cxgb_t3fw, 1, 1, 1); 2816