cxgb_main.c revision 183289
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 183289 2008-09-23 02:22:24Z 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; 337183063Skmacy 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); 354183063Skmacy 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 879183289Skmacy#ifndef LRO_SUPPORTED 880183289Skmacy#ifdef IFCAP_LRO 881183289Skmacy#undef IFCAP_LRO 882183289Skmacy#endif 883183289Skmacy#define IFCAP_LRO 0x0 884183289Skmacy#endif 885167514Skmacy 886167514Skmacy#ifdef TSO_SUPPORTED 887181616Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO) 888167514Skmacy/* Don't enable TSO6 yet */ 889181616Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO4 | IFCAP_JUMBO_MTU | IFCAP_LRO) 890167514Skmacy#else 891167514Skmacy#define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU) 892167514Skmacy/* Don't enable TSO6 yet */ 893167514Skmacy#define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU) 894167514Skmacy#define IFCAP_TSO4 0x0 895171868Skmacy#define IFCAP_TSO6 0x0 896167514Skmacy#define CSUM_TSO 0x0 897167514Skmacy#endif 898167514Skmacy 899167514Skmacy 900167514Skmacystatic int 901167514Skmacycxgb_port_attach(device_t dev) 902167514Skmacy{ 903167514Skmacy struct port_info *p; 904167514Skmacy struct ifnet *ifp; 905170654Skmacy int err, media_flags; 906176472Skmacy struct adapter *sc; 907167514Skmacy 908176472Skmacy 909167514Skmacy p = device_get_softc(dev); 910176472Skmacy sc = p->adapter; 911170869Skmacy snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d", 912171803Skmacy device_get_unit(device_get_parent(dev)), p->port_id); 913170869Skmacy PORT_LOCK_INIT(p, p->lockbuf); 914167514Skmacy 915167514Skmacy /* Allocate an ifnet object and set it up */ 916167514Skmacy ifp = p->ifp = if_alloc(IFT_ETHER); 917167514Skmacy if (ifp == NULL) { 918167514Skmacy device_printf(dev, "Cannot allocate ifnet\n"); 919167514Skmacy return (ENOMEM); 920167514Skmacy } 921167514Skmacy 922167514Skmacy /* 923167514Skmacy * Note that there is currently no watchdog timer. 924167514Skmacy */ 925167514Skmacy if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 926167514Skmacy ifp->if_init = cxgb_init; 927167514Skmacy ifp->if_softc = p; 928167514Skmacy ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 929167514Skmacy ifp->if_ioctl = cxgb_ioctl; 930167514Skmacy ifp->if_start = cxgb_start; 931174708Skmacy 932176472Skmacy#if 0 933174708Skmacy#ifdef IFNET_MULTIQUEUE 934174708Skmacy ifp->if_flags |= IFF_MULTIQ; 935174708Skmacy ifp->if_mq_start = cxgb_pcpu_start; 936174708Skmacy#endif 937176472Skmacy#endif 938167514Skmacy ifp->if_timer = 0; /* Disable ifnet watchdog */ 939167514Skmacy ifp->if_watchdog = NULL; 940167514Skmacy 941175312Skmacy ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 942167514Skmacy IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 943167514Skmacy IFQ_SET_READY(&ifp->if_snd); 944167514Skmacy 945167514Skmacy ifp->if_hwassist = ifp->if_capabilities = ifp->if_capenable = 0; 946167514Skmacy ifp->if_capabilities |= CXGB_CAP; 947167514Skmacy ifp->if_capenable |= CXGB_CAP_ENABLE; 948167514Skmacy ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO); 949171471Skmacy /* 950171471Skmacy * disable TSO on 4-port - it isn't supported by the firmware yet 951171471Skmacy */ 952171471Skmacy if (p->adapter->params.nports > 2) { 953171471Skmacy ifp->if_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6); 954171471Skmacy ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TSO6); 955171471Skmacy ifp->if_hwassist &= ~CSUM_TSO; 956171471Skmacy } 957171471Skmacy 958167514Skmacy ether_ifattach(ifp, p->hw_addr); 959171471Skmacy /* 960171471Skmacy * Only default to jumbo frames on 10GigE 961171471Skmacy */ 962171471Skmacy if (p->adapter->params.nports <= 2) 963180583Skmacy ifp->if_mtu = ETHERMTU_JUMBO; 964167514Skmacy if ((err = cxgb_makedev(p)) != 0) { 965167514Skmacy printf("makedev failed %d\n", err); 966167514Skmacy return (err); 967167514Skmacy } 968167514Skmacy ifmedia_init(&p->media, IFM_IMASK, cxgb_media_change, 969167514Skmacy cxgb_media_status); 970176472Skmacy 971176472Skmacy if (!strcmp(p->phy.desc, "10GBASE-CX4")) { 972170654Skmacy media_flags = IFM_ETHER | IFM_10G_CX4 | IFM_FDX; 973176472Skmacy } else if (!strcmp(p->phy.desc, "10GBASE-SR")) { 974170654Skmacy media_flags = IFM_ETHER | IFM_10G_SR | IFM_FDX; 975177340Skmacy } else if (!strcmp(p->phy.desc, "10GBASE-R")) { 976170654Skmacy media_flags = IFM_ETHER | IFM_10G_LR | IFM_FDX; 977176472Skmacy } else if (!strcmp(p->phy.desc, "10/100/1000BASE-T")) { 978170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_10_T, 0, NULL); 979170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_10_T | IFM_FDX, 980170654Skmacy 0, NULL); 981170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX, 982170654Skmacy 0, NULL); 983170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX | IFM_FDX, 984170654Skmacy 0, NULL); 985170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_1000_T | IFM_FDX, 986170654Skmacy 0, NULL); 987170654Skmacy media_flags = 0; 988170654Skmacy } else { 989176472Skmacy printf("unsupported media type %s\n", p->phy.desc); 990167514Skmacy return (ENXIO); 991167514Skmacy } 992170654Skmacy if (media_flags) { 993170654Skmacy ifmedia_add(&p->media, media_flags, 0, NULL); 994170654Skmacy ifmedia_set(&p->media, media_flags); 995170654Skmacy } else { 996170654Skmacy ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL); 997170654Skmacy ifmedia_set(&p->media, IFM_ETHER | IFM_AUTO); 998170654Skmacy } 999167514Skmacy 1000177340Skmacy /* Get the latest mac address, User can use a LAA */ 1001177340Skmacy bcopy(IF_LLADDR(p->ifp), p->hw_addr, ETHER_ADDR_LEN); 1002170654Skmacy t3_sge_init_port(p); 1003177415Skmacy#if defined(LINK_ATTACH) 1004176472Skmacy cxgb_link_start(p); 1005176472Skmacy t3_link_changed(sc, p->port_id); 1006177415Skmacy#endif 1007167514Skmacy return (0); 1008167514Skmacy} 1009167514Skmacy 1010167514Skmacystatic int 1011167514Skmacycxgb_port_detach(device_t dev) 1012167514Skmacy{ 1013167514Skmacy struct port_info *p; 1014167514Skmacy 1015167514Skmacy p = device_get_softc(dev); 1016169978Skmacy 1017169978Skmacy PORT_LOCK(p); 1018170654Skmacy if (p->ifp->if_drv_flags & IFF_DRV_RUNNING) 1019170654Skmacy cxgb_stop_locked(p); 1020169978Skmacy PORT_UNLOCK(p); 1021169978Skmacy 1022171978Skmacy ether_ifdetach(p->ifp); 1023174708Skmacy printf("waiting for callout to stop ..."); 1024174708Skmacy DELAY(1000000); 1025174708Skmacy printf("done\n"); 1026171978Skmacy /* 1027171978Skmacy * the lock may be acquired in ifdetach 1028171978Skmacy */ 1029170869Skmacy PORT_LOCK_DEINIT(p); 1030167514Skmacy if_free(p->ifp); 1031167514Skmacy 1032170654Skmacy if (p->port_cdev != NULL) 1033170654Skmacy destroy_dev(p->port_cdev); 1034170654Skmacy 1035167514Skmacy return (0); 1036167514Skmacy} 1037167514Skmacy 1038167514Skmacyvoid 1039167514Skmacyt3_fatal_err(struct adapter *sc) 1040167514Skmacy{ 1041167514Skmacy u_int fw_status[4]; 1042183062Skmacy 1043172096Skmacy if (sc->flags & FULL_INIT_DONE) { 1044172096Skmacy t3_sge_stop(sc); 1045172096Skmacy t3_write_reg(sc, A_XGM_TX_CTRL, 0); 1046172096Skmacy t3_write_reg(sc, A_XGM_RX_CTRL, 0); 1047172096Skmacy t3_write_reg(sc, XGM_REG(A_XGM_TX_CTRL, 1), 0); 1048172096Skmacy t3_write_reg(sc, XGM_REG(A_XGM_RX_CTRL, 1), 0); 1049172096Skmacy t3_intr_disable(sc); 1050172096Skmacy } 1051167514Skmacy device_printf(sc->dev,"encountered fatal error, operation suspended\n"); 1052167514Skmacy if (!t3_cim_ctl_blk_read(sc, 0xa0, 4, fw_status)) 1053167514Skmacy device_printf(sc->dev, "FW_ status: 0x%x, 0x%x, 0x%x, 0x%x\n", 1054167514Skmacy fw_status[0], fw_status[1], fw_status[2], fw_status[3]); 1055167514Skmacy} 1056167514Skmacy 1057167514Skmacyint 1058167514Skmacyt3_os_find_pci_capability(adapter_t *sc, int cap) 1059167514Skmacy{ 1060167514Skmacy device_t dev; 1061167514Skmacy struct pci_devinfo *dinfo; 1062167514Skmacy pcicfgregs *cfg; 1063167514Skmacy uint32_t status; 1064167514Skmacy uint8_t ptr; 1065167514Skmacy 1066167514Skmacy dev = sc->dev; 1067167514Skmacy dinfo = device_get_ivars(dev); 1068167514Skmacy cfg = &dinfo->cfg; 1069167514Skmacy 1070167514Skmacy status = pci_read_config(dev, PCIR_STATUS, 2); 1071167514Skmacy if (!(status & PCIM_STATUS_CAPPRESENT)) 1072167514Skmacy return (0); 1073167514Skmacy 1074167514Skmacy switch (cfg->hdrtype & PCIM_HDRTYPE) { 1075167514Skmacy case 0: 1076167514Skmacy case 1: 1077167514Skmacy ptr = PCIR_CAP_PTR; 1078167514Skmacy break; 1079167514Skmacy case 2: 1080167514Skmacy ptr = PCIR_CAP_PTR_2; 1081167514Skmacy break; 1082167514Skmacy default: 1083167514Skmacy return (0); 1084167514Skmacy break; 1085167514Skmacy } 1086167514Skmacy ptr = pci_read_config(dev, ptr, 1); 1087167514Skmacy 1088167514Skmacy while (ptr != 0) { 1089167514Skmacy if (pci_read_config(dev, ptr + PCICAP_ID, 1) == cap) 1090167514Skmacy return (ptr); 1091167514Skmacy ptr = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1); 1092167514Skmacy } 1093167514Skmacy 1094167514Skmacy return (0); 1095167514Skmacy} 1096167514Skmacy 1097167514Skmacyint 1098167514Skmacyt3_os_pci_save_state(struct adapter *sc) 1099167514Skmacy{ 1100167514Skmacy device_t dev; 1101167514Skmacy struct pci_devinfo *dinfo; 1102167514Skmacy 1103167514Skmacy dev = sc->dev; 1104167514Skmacy dinfo = device_get_ivars(dev); 1105167514Skmacy 1106167514Skmacy pci_cfg_save(dev, dinfo, 0); 1107167514Skmacy return (0); 1108167514Skmacy} 1109167514Skmacy 1110167514Skmacyint 1111167514Skmacyt3_os_pci_restore_state(struct adapter *sc) 1112167514Skmacy{ 1113167514Skmacy device_t dev; 1114167514Skmacy struct pci_devinfo *dinfo; 1115167514Skmacy 1116167514Skmacy dev = sc->dev; 1117167514Skmacy dinfo = device_get_ivars(dev); 1118167514Skmacy 1119167514Skmacy pci_cfg_restore(dev, dinfo); 1120167514Skmacy return (0); 1121167514Skmacy} 1122167514Skmacy 1123167514Skmacy/** 1124167514Skmacy * t3_os_link_changed - handle link status changes 1125167514Skmacy * @adapter: the adapter associated with the link change 1126167514Skmacy * @port_id: the port index whose limk status has changed 1127177340Skmacy * @link_status: the new status of the link 1128167514Skmacy * @speed: the new speed setting 1129167514Skmacy * @duplex: the new duplex setting 1130167514Skmacy * @fc: the new flow-control setting 1131167514Skmacy * 1132167514Skmacy * This is the OS-dependent handler for link status changes. The OS 1133167514Skmacy * neutral handler takes care of most of the processing for these events, 1134167514Skmacy * then calls this handler for any OS-specific processing. 1135167514Skmacy */ 1136167514Skmacyvoid 1137167514Skmacyt3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed, 1138167514Skmacy int duplex, int fc) 1139167514Skmacy{ 1140167514Skmacy struct port_info *pi = &adapter->port[port_id]; 1141169978Skmacy struct cmac *mac = &adapter->port[port_id].mac; 1142167514Skmacy 1143169978Skmacy if (link_status) { 1144177340Skmacy DELAY(10); 1145177340Skmacy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 1146177340Skmacy /* Clear errors created by MAC enable */ 1147177340Skmacy t3_set_reg_field(adapter, 1148177340Skmacy A_XGM_STAT_CTRL + pi->mac.offset, 1149177340Skmacy F_CLRSTATS, 1); 1150167514Skmacy if_link_state_change(pi->ifp, LINK_STATE_UP); 1151177340Skmacy 1152169978Skmacy } else { 1153169978Skmacy pi->phy.ops->power_down(&pi->phy, 1); 1154169978Skmacy t3_mac_disable(mac, MAC_DIRECTION_RX); 1155169978Skmacy t3_link_start(&pi->phy, mac, &pi->link_config); 1156177340Skmacy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 1157176472Skmacy if_link_state_change(pi->ifp, LINK_STATE_DOWN); 1158169978Skmacy } 1159167514Skmacy} 1160167514Skmacy 1161181614Skmacy/** 1162181614Skmacy * t3_os_phymod_changed - handle PHY module changes 1163181614Skmacy * @phy: the PHY reporting the module change 1164181614Skmacy * @mod_type: new module type 1165181614Skmacy * 1166181614Skmacy * This is the OS-dependent handler for PHY module changes. It is 1167181614Skmacy * invoked when a PHY module is removed or inserted for any OS-specific 1168181614Skmacy * processing. 1169181614Skmacy */ 1170181614Skmacyvoid t3_os_phymod_changed(struct adapter *adap, int port_id) 1171181614Skmacy{ 1172181614Skmacy static const char *mod_str[] = { 1173181614Skmacy NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown" 1174181614Skmacy }; 1175181614Skmacy 1176181614Skmacy struct port_info *pi = &adap->port[port_id]; 1177181614Skmacy 1178181614Skmacy if (pi->phy.modtype == phy_modtype_none) 1179181614Skmacy device_printf(adap->dev, "PHY module unplugged\n"); 1180181614Skmacy else { 1181181614Skmacy KASSERT(pi->phy.modtype < ARRAY_SIZE(mod_str), 1182181614Skmacy ("invalid PHY module type %d", pi->phy.modtype)); 1183181614Skmacy device_printf(adap->dev, "%s PHY module inserted\n", 1184181614Skmacy mod_str[pi->phy.modtype]); 1185181614Skmacy } 1186181614Skmacy} 1187181614Skmacy 1188167514Skmacy/* 1189167514Skmacy * Interrupt-context handler for external (PHY) interrupts. 1190167514Skmacy */ 1191167514Skmacyvoid 1192167514Skmacyt3_os_ext_intr_handler(adapter_t *sc) 1193167514Skmacy{ 1194167514Skmacy if (cxgb_debug) 1195167514Skmacy printf("t3_os_ext_intr_handler\n"); 1196167514Skmacy /* 1197167514Skmacy * Schedule a task to handle external interrupts as they may be slow 1198167514Skmacy * and we use a mutex to protect MDIO registers. We disable PHY 1199167514Skmacy * interrupts in the meantime and let the task reenable them when 1200167514Skmacy * it's done. 1201167514Skmacy */ 1202169978Skmacy ADAPTER_LOCK(sc); 1203167514Skmacy if (sc->slow_intr_mask) { 1204167514Skmacy sc->slow_intr_mask &= ~F_T3DBG; 1205167514Skmacy t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask); 1206167514Skmacy taskqueue_enqueue(sc->tq, &sc->ext_intr_task); 1207167514Skmacy } 1208169978Skmacy ADAPTER_UNLOCK(sc); 1209167514Skmacy} 1210167514Skmacy 1211167514Skmacyvoid 1212167514Skmacyt3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[]) 1213167514Skmacy{ 1214167514Skmacy 1215167514Skmacy /* 1216167514Skmacy * The ifnet might not be allocated before this gets called, 1217167514Skmacy * as this is called early on in attach by t3_prep_adapter 1218167514Skmacy * save the address off in the port structure 1219167514Skmacy */ 1220167514Skmacy if (cxgb_debug) 1221167514Skmacy printf("set_hw_addr on idx %d addr %6D\n", port_idx, hw_addr, ":"); 1222167514Skmacy bcopy(hw_addr, adapter->port[port_idx].hw_addr, ETHER_ADDR_LEN); 1223167514Skmacy} 1224167514Skmacy 1225167514Skmacy/** 1226167514Skmacy * link_start - enable a port 1227167514Skmacy * @p: the port to enable 1228167514Skmacy * 1229167514Skmacy * Performs the MAC and PHY actions needed to enable a port. 1230167514Skmacy */ 1231167514Skmacystatic void 1232167514Skmacycxgb_link_start(struct port_info *p) 1233167514Skmacy{ 1234167514Skmacy struct ifnet *ifp; 1235167514Skmacy struct t3_rx_mode rm; 1236167514Skmacy struct cmac *mac = &p->mac; 1237180583Skmacy int mtu, hwtagging; 1238167514Skmacy 1239167514Skmacy ifp = p->ifp; 1240167514Skmacy 1241180583Skmacy bcopy(IF_LLADDR(ifp), p->hw_addr, ETHER_ADDR_LEN); 1242180583Skmacy 1243180583Skmacy mtu = ifp->if_mtu; 1244180583Skmacy if (ifp->if_capenable & IFCAP_VLAN_MTU) 1245180583Skmacy mtu += ETHER_VLAN_ENCAP_LEN; 1246180583Skmacy 1247180583Skmacy hwtagging = (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0; 1248180583Skmacy 1249167514Skmacy t3_init_rx_mode(&rm, p); 1250172096Skmacy if (!mac->multiport) 1251171978Skmacy t3_mac_reset(mac); 1252180583Skmacy t3_mac_set_mtu(mac, mtu); 1253180583Skmacy t3_set_vlan_accel(p->adapter, 1 << p->tx_chan, hwtagging); 1254167514Skmacy t3_mac_set_address(mac, 0, p->hw_addr); 1255167514Skmacy t3_mac_set_rx_mode(mac, &rm); 1256167514Skmacy t3_link_start(&p->phy, mac, &p->link_config); 1257167514Skmacy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 1258167514Skmacy} 1259167514Skmacy 1260176472Skmacy 1261176472Skmacystatic int 1262176472Skmacyawait_mgmt_replies(struct adapter *adap, unsigned long init_cnt, 1263176472Skmacy unsigned long n) 1264176472Skmacy{ 1265176472Skmacy int attempts = 5; 1266176472Skmacy 1267176472Skmacy while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) { 1268176472Skmacy if (!--attempts) 1269176472Skmacy return (ETIMEDOUT); 1270176472Skmacy t3_os_sleep(10); 1271176472Skmacy } 1272176472Skmacy return 0; 1273176472Skmacy} 1274176472Skmacy 1275176472Skmacystatic int 1276176472Skmacyinit_tp_parity(struct adapter *adap) 1277176472Skmacy{ 1278176472Skmacy int i; 1279176472Skmacy struct mbuf *m; 1280176472Skmacy struct cpl_set_tcb_field *greq; 1281176472Skmacy unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts; 1282176472Skmacy 1283176472Skmacy t3_tp_set_offload_mode(adap, 1); 1284176472Skmacy 1285176472Skmacy for (i = 0; i < 16; i++) { 1286176472Skmacy struct cpl_smt_write_req *req; 1287176472Skmacy 1288176472Skmacy m = m_gethdr(M_WAITOK, MT_DATA); 1289176472Skmacy req = mtod(m, struct cpl_smt_write_req *); 1290176472Skmacy m->m_len = m->m_pkthdr.len = sizeof(*req); 1291176472Skmacy memset(req, 0, sizeof(*req)); 1292176472Skmacy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1293176472Skmacy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); 1294176472Skmacy req->iff = i; 1295176472Skmacy t3_mgmt_tx(adap, m); 1296176472Skmacy } 1297176472Skmacy 1298176472Skmacy for (i = 0; i < 2048; i++) { 1299176472Skmacy struct cpl_l2t_write_req *req; 1300176472Skmacy 1301176472Skmacy m = m_gethdr(M_WAITOK, MT_DATA); 1302176472Skmacy req = mtod(m, struct cpl_l2t_write_req *); 1303176472Skmacy m->m_len = m->m_pkthdr.len = sizeof(*req); 1304176472Skmacy memset(req, 0, sizeof(*req)); 1305176472Skmacy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1306176472Skmacy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i)); 1307176472Skmacy req->params = htonl(V_L2T_W_IDX(i)); 1308176472Skmacy t3_mgmt_tx(adap, m); 1309176472Skmacy } 1310176472Skmacy 1311176472Skmacy for (i = 0; i < 2048; i++) { 1312176472Skmacy struct cpl_rte_write_req *req; 1313176472Skmacy 1314176472Skmacy m = m_gethdr(M_WAITOK, MT_DATA); 1315176472Skmacy req = mtod(m, struct cpl_rte_write_req *); 1316176472Skmacy m->m_len = m->m_pkthdr.len = sizeof(*req); 1317176472Skmacy memset(req, 0, sizeof(*req)); 1318176472Skmacy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1319176472Skmacy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i)); 1320176472Skmacy req->l2t_idx = htonl(V_L2T_W_IDX(i)); 1321176472Skmacy t3_mgmt_tx(adap, m); 1322176472Skmacy } 1323176472Skmacy 1324176472Skmacy m = m_gethdr(M_WAITOK, MT_DATA); 1325176472Skmacy greq = mtod(m, struct cpl_set_tcb_field *); 1326176472Skmacy m->m_len = m->m_pkthdr.len = sizeof(*greq); 1327176472Skmacy memset(greq, 0, sizeof(*greq)); 1328176472Skmacy greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1329176472Skmacy OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0)); 1330176472Skmacy greq->mask = htobe64(1); 1331176472Skmacy t3_mgmt_tx(adap, m); 1332176472Skmacy 1333176472Skmacy i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); 1334176472Skmacy t3_tp_set_offload_mode(adap, 0); 1335176472Skmacy return (i); 1336176472Skmacy} 1337176472Skmacy 1338167514Skmacy/** 1339167514Skmacy * setup_rss - configure Receive Side Steering (per-queue connection demux) 1340167514Skmacy * @adap: the adapter 1341167514Skmacy * 1342167514Skmacy * Sets up RSS to distribute packets to multiple receive queues. We 1343167514Skmacy * configure the RSS CPU lookup table to distribute to the number of HW 1344167514Skmacy * receive queues, and the response queue lookup table to narrow that 1345167514Skmacy * down to the response queues actually configured for each port. 1346167514Skmacy * We always configure the RSS mapping for two ports since the mapping 1347167514Skmacy * table has plenty of entries. 1348167514Skmacy */ 1349167514Skmacystatic void 1350167514Skmacysetup_rss(adapter_t *adap) 1351167514Skmacy{ 1352167514Skmacy int i; 1353171471Skmacy u_int nq[2]; 1354167514Skmacy uint8_t cpus[SGE_QSETS + 1]; 1355167514Skmacy uint16_t rspq_map[RSS_TABLE_SIZE]; 1356171471Skmacy 1357167514Skmacy for (i = 0; i < SGE_QSETS; ++i) 1358167514Skmacy cpus[i] = i; 1359167514Skmacy cpus[SGE_QSETS] = 0xff; 1360167514Skmacy 1361171978Skmacy nq[0] = nq[1] = 0; 1362171978Skmacy for_each_port(adap, i) { 1363171978Skmacy const struct port_info *pi = adap2pinfo(adap, i); 1364171978Skmacy 1365171978Skmacy nq[pi->tx_chan] += pi->nqsets; 1366171978Skmacy } 1367167514Skmacy for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) { 1368176472Skmacy rspq_map[i] = nq[0] ? i % nq[0] : 0; 1369176472Skmacy rspq_map[i + RSS_TABLE_SIZE / 2] = nq[1] ? i % nq[1] + nq[0] : 0; 1370167514Skmacy } 1371171471Skmacy /* Calculate the reverse RSS map table */ 1372171471Skmacy for (i = 0; i < RSS_TABLE_SIZE; ++i) 1373171471Skmacy if (adap->rrss_map[rspq_map[i]] == 0xff) 1374171471Skmacy adap->rrss_map[rspq_map[i]] = i; 1375167514Skmacy 1376167514Skmacy t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN | 1377171471Skmacy F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | F_OFDMAPEN | 1378176472Skmacy F_RRCPLMAPEN | V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, 1379176472Skmacy cpus, rspq_map); 1380171471Skmacy 1381167514Skmacy} 1382167514Skmacy 1383169978Skmacy/* 1384169978Skmacy * Sends an mbuf to an offload queue driver 1385169978Skmacy * after dealing with any active network taps. 1386169978Skmacy */ 1387169978Skmacystatic inline int 1388174626Skmacyoffload_tx(struct t3cdev *tdev, struct mbuf *m) 1389169978Skmacy{ 1390169978Skmacy int ret; 1391169978Skmacy 1392169978Skmacy ret = t3_offload_tx(tdev, m); 1393170654Skmacy return (ret); 1394169978Skmacy} 1395169978Skmacy 1396169978Skmacystatic int 1397169978Skmacywrite_smt_entry(struct adapter *adapter, int idx) 1398169978Skmacy{ 1399169978Skmacy struct port_info *pi = &adapter->port[idx]; 1400169978Skmacy struct cpl_smt_write_req *req; 1401169978Skmacy struct mbuf *m; 1402169978Skmacy 1403169978Skmacy if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL) 1404169978Skmacy return (ENOMEM); 1405169978Skmacy 1406169978Skmacy req = mtod(m, struct cpl_smt_write_req *); 1407174708Skmacy m->m_pkthdr.len = m->m_len = sizeof(struct cpl_smt_write_req); 1408174708Skmacy 1409169978Skmacy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1410169978Skmacy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx)); 1411169978Skmacy req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */ 1412169978Skmacy req->iff = idx; 1413169978Skmacy memset(req->src_mac1, 0, sizeof(req->src_mac1)); 1414169978Skmacy memcpy(req->src_mac0, pi->hw_addr, ETHER_ADDR_LEN); 1415169978Skmacy 1416169978Skmacy m_set_priority(m, 1); 1417169978Skmacy 1418169978Skmacy offload_tx(&adapter->tdev, m); 1419169978Skmacy 1420169978Skmacy return (0); 1421169978Skmacy} 1422169978Skmacy 1423169978Skmacystatic int 1424169978Skmacyinit_smt(struct adapter *adapter) 1425169978Skmacy{ 1426169978Skmacy int i; 1427169978Skmacy 1428169978Skmacy for_each_port(adapter, i) 1429169978Skmacy write_smt_entry(adapter, i); 1430169978Skmacy return 0; 1431169978Skmacy} 1432169978Skmacy 1433167514Skmacystatic void 1434169978Skmacyinit_port_mtus(adapter_t *adapter) 1435169978Skmacy{ 1436169978Skmacy unsigned int mtus = adapter->port[0].ifp->if_mtu; 1437169978Skmacy 1438169978Skmacy if (adapter->port[1].ifp) 1439169978Skmacy mtus |= adapter->port[1].ifp->if_mtu << 16; 1440169978Skmacy t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus); 1441169978Skmacy} 1442169978Skmacy 1443169978Skmacystatic void 1444167514Skmacysend_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, 1445167514Skmacy int hi, int port) 1446167514Skmacy{ 1447167514Skmacy struct mbuf *m; 1448167514Skmacy struct mngt_pktsched_wr *req; 1449167514Skmacy 1450171471Skmacy m = m_gethdr(M_DONTWAIT, MT_DATA); 1451167848Skmacy if (m) { 1452169978Skmacy req = mtod(m, struct mngt_pktsched_wr *); 1453167848Skmacy req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); 1454167848Skmacy req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET; 1455167848Skmacy req->sched = sched; 1456167848Skmacy req->idx = qidx; 1457167848Skmacy req->min = lo; 1458167848Skmacy req->max = hi; 1459167848Skmacy req->binding = port; 1460167848Skmacy m->m_len = m->m_pkthdr.len = sizeof(*req); 1461167848Skmacy t3_mgmt_tx(adap, m); 1462167848Skmacy } 1463167514Skmacy} 1464167514Skmacy 1465167514Skmacystatic void 1466167514Skmacybind_qsets(adapter_t *sc) 1467167514Skmacy{ 1468167514Skmacy int i, j; 1469167514Skmacy 1470174708Skmacy cxgb_pcpu_startup_threads(sc); 1471167514Skmacy for (i = 0; i < (sc)->params.nports; ++i) { 1472167514Skmacy const struct port_info *pi = adap2pinfo(sc, i); 1473167514Skmacy 1474172096Skmacy for (j = 0; j < pi->nqsets; ++j) { 1475167514Skmacy send_pktsched_cmd(sc, 1, pi->first_qset + j, -1, 1476172096Skmacy -1, pi->tx_chan); 1477172096Skmacy 1478172096Skmacy } 1479167514Skmacy } 1480167514Skmacy} 1481167514Skmacy 1482171471Skmacystatic void 1483171471Skmacyupdate_tpeeprom(struct adapter *adap) 1484171471Skmacy{ 1485172109Skmacy#ifdef FIRMWARE_LATEST 1486171471Skmacy const struct firmware *tpeeprom; 1487172109Skmacy#else 1488172109Skmacy struct firmware *tpeeprom; 1489172109Skmacy#endif 1490172109Skmacy 1491171471Skmacy uint32_t version; 1492171471Skmacy unsigned int major, minor; 1493171471Skmacy int ret, len; 1494171471Skmacy char rev; 1495171471Skmacy 1496171471Skmacy t3_seeprom_read(adap, TP_SRAM_OFFSET, &version); 1497171471Skmacy 1498171471Skmacy major = G_TP_VERSION_MAJOR(version); 1499171471Skmacy minor = G_TP_VERSION_MINOR(version); 1500171471Skmacy if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) 1501171471Skmacy return; 1502171471Skmacy 1503171471Skmacy rev = t3rev2char(adap); 1504171471Skmacy 1505176613Skmacy tpeeprom = firmware_get(TPEEPROM_NAME); 1506171471Skmacy if (tpeeprom == NULL) { 1507171471Skmacy device_printf(adap->dev, "could not load TP EEPROM: unable to load %s\n", 1508176613Skmacy TPEEPROM_NAME); 1509171471Skmacy return; 1510171471Skmacy } 1511171471Skmacy 1512171471Skmacy len = tpeeprom->datasize - 4; 1513171471Skmacy 1514171471Skmacy ret = t3_check_tpsram(adap, tpeeprom->data, tpeeprom->datasize); 1515171471Skmacy if (ret) 1516171471Skmacy goto release_tpeeprom; 1517171471Skmacy 1518171471Skmacy if (len != TP_SRAM_LEN) { 1519176613Skmacy device_printf(adap->dev, "%s length is wrong len=%d expected=%d\n", TPEEPROM_NAME, len, TP_SRAM_LEN); 1520171471Skmacy return; 1521171471Skmacy } 1522171471Skmacy 1523171471Skmacy ret = set_eeprom(&adap->port[0], tpeeprom->data, tpeeprom->datasize, 1524171471Skmacy TP_SRAM_OFFSET); 1525171471Skmacy 1526171471Skmacy if (!ret) { 1527171471Skmacy device_printf(adap->dev, 1528171471Skmacy "Protocol SRAM image updated in EEPROM to %d.%d.%d\n", 1529171471Skmacy TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); 1530171471Skmacy } else 1531171471Skmacy device_printf(adap->dev, "Protocol SRAM image update in EEPROM failed\n"); 1532171471Skmacy 1533171471Skmacyrelease_tpeeprom: 1534171471Skmacy firmware_put(tpeeprom, FIRMWARE_UNLOAD); 1535171471Skmacy 1536171471Skmacy return; 1537171471Skmacy} 1538171471Skmacy 1539171471Skmacystatic int 1540171471Skmacyupdate_tpsram(struct adapter *adap) 1541171471Skmacy{ 1542172109Skmacy#ifdef FIRMWARE_LATEST 1543171471Skmacy const struct firmware *tpsram; 1544172109Skmacy#else 1545172109Skmacy struct firmware *tpsram; 1546172109Skmacy#endif 1547171471Skmacy int ret; 1548171471Skmacy char rev; 1549171471Skmacy 1550171471Skmacy rev = t3rev2char(adap); 1551171471Skmacy if (!rev) 1552171471Skmacy return 0; 1553171471Skmacy 1554171471Skmacy update_tpeeprom(adap); 1555171471Skmacy 1556176613Skmacy tpsram = firmware_get(TPSRAM_NAME); 1557171471Skmacy if (tpsram == NULL){ 1558176613Skmacy device_printf(adap->dev, "could not load TP SRAM\n"); 1559171471Skmacy return (EINVAL); 1560171471Skmacy } else 1561176613Skmacy device_printf(adap->dev, "updating TP SRAM\n"); 1562171471Skmacy 1563171471Skmacy ret = t3_check_tpsram(adap, tpsram->data, tpsram->datasize); 1564171471Skmacy if (ret) 1565171471Skmacy goto release_tpsram; 1566171471Skmacy 1567171471Skmacy ret = t3_set_proto_sram(adap, tpsram->data); 1568171471Skmacy if (ret) 1569171471Skmacy device_printf(adap->dev, "loading protocol SRAM failed\n"); 1570171471Skmacy 1571171471Skmacyrelease_tpsram: 1572171471Skmacy firmware_put(tpsram, FIRMWARE_UNLOAD); 1573171471Skmacy 1574171471Skmacy return ret; 1575171471Skmacy} 1576171471Skmacy 1577169978Skmacy/** 1578169978Skmacy * cxgb_up - enable the adapter 1579169978Skmacy * @adap: adapter being enabled 1580169978Skmacy * 1581169978Skmacy * Called when the first port is enabled, this function performs the 1582169978Skmacy * actions necessary to make an adapter operational, such as completing 1583169978Skmacy * the initialization of HW modules, and enabling interrupts. 1584169978Skmacy * 1585169978Skmacy */ 1586169978Skmacystatic int 1587169978Skmacycxgb_up(struct adapter *sc) 1588169978Skmacy{ 1589169978Skmacy int err = 0; 1590169978Skmacy 1591169978Skmacy if ((sc->flags & FULL_INIT_DONE) == 0) { 1592169978Skmacy 1593169978Skmacy if ((sc->flags & FW_UPTODATE) == 0) 1594171471Skmacy if ((err = upgrade_fw(sc))) 1595171471Skmacy goto out; 1596171471Skmacy if ((sc->flags & TPS_UPTODATE) == 0) 1597171471Skmacy if ((err = update_tpsram(sc))) 1598171471Skmacy goto out; 1599169978Skmacy err = t3_init_hw(sc, 0); 1600169978Skmacy if (err) 1601169978Skmacy goto out; 1602169978Skmacy 1603176472Skmacy t3_set_reg_field(sc, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT); 1604169978Skmacy t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12)); 1605169978Skmacy 1606169978Skmacy err = setup_sge_qsets(sc); 1607169978Skmacy if (err) 1608169978Skmacy goto out; 1609169978Skmacy 1610169978Skmacy setup_rss(sc); 1611174708Skmacy t3_add_configured_sysctls(sc); 1612169978Skmacy sc->flags |= FULL_INIT_DONE; 1613169978Skmacy } 1614169978Skmacy 1615169978Skmacy t3_intr_clear(sc); 1616169978Skmacy 1617169978Skmacy /* If it's MSI or INTx, allocate a single interrupt for everything */ 1618169978Skmacy if ((sc->flags & USING_MSIX) == 0) { 1619169978Skmacy if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 1620169978Skmacy &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 1621171978Skmacy device_printf(sc->dev, "Cannot allocate interrupt rid=%d\n", 1622171978Skmacy sc->irq_rid); 1623169978Skmacy err = EINVAL; 1624169978Skmacy goto out; 1625169978Skmacy } 1626169978Skmacy device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res); 1627169978Skmacy 1628169978Skmacy if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET, 1629169978Skmacy#ifdef INTR_FILTERS 1630169978Skmacy NULL, 1631169978Skmacy#endif 1632169978Skmacy sc->cxgb_intr, sc, &sc->intr_tag)) { 1633169978Skmacy device_printf(sc->dev, "Cannot set up interrupt\n"); 1634169978Skmacy err = EINVAL; 1635169978Skmacy goto irq_err; 1636169978Skmacy } 1637169978Skmacy } else { 1638169978Skmacy cxgb_setup_msix(sc, sc->msi_count); 1639169978Skmacy } 1640169978Skmacy 1641169978Skmacy t3_sge_start(sc); 1642169978Skmacy t3_intr_enable(sc); 1643169978Skmacy 1644176472Skmacy if (sc->params.rev >= T3_REV_C && !(sc->flags & TP_PARITY_INIT) && 1645176472Skmacy is_offload(sc) && init_tp_parity(sc) == 0) 1646176472Skmacy sc->flags |= TP_PARITY_INIT; 1647176472Skmacy 1648176472Skmacy if (sc->flags & TP_PARITY_INIT) { 1649176472Skmacy t3_write_reg(sc, A_TP_INT_CAUSE, 1650176472Skmacy F_CMCACHEPERR | F_ARPLUTPERR); 1651176472Skmacy t3_write_reg(sc, A_TP_INT_ENABLE, 0x7fbfffff); 1652176472Skmacy } 1653176472Skmacy 1654176472Skmacy 1655172096Skmacy if (!(sc->flags & QUEUES_BOUND)) { 1656169978Skmacy bind_qsets(sc); 1657171471Skmacy sc->flags |= QUEUES_BOUND; 1658171471Skmacy } 1659169978Skmacyout: 1660169978Skmacy return (err); 1661169978Skmacyirq_err: 1662169978Skmacy CH_ERR(sc, "request_irq failed, err %d\n", err); 1663169978Skmacy goto out; 1664169978Skmacy} 1665169978Skmacy 1666169978Skmacy 1667169978Skmacy/* 1668169978Skmacy * Release resources when all the ports and offloading have been stopped. 1669169978Skmacy */ 1670167514Skmacystatic void 1671170869Skmacycxgb_down_locked(struct adapter *sc) 1672169978Skmacy{ 1673170654Skmacy 1674169978Skmacy t3_sge_stop(sc); 1675169978Skmacy t3_intr_disable(sc); 1676170654Skmacy 1677169978Skmacy if (sc->intr_tag != NULL) { 1678169978Skmacy bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag); 1679169978Skmacy sc->intr_tag = NULL; 1680169978Skmacy } 1681169978Skmacy if (sc->irq_res != NULL) { 1682169978Skmacy device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n", 1683169978Skmacy sc->irq_rid, sc->irq_res); 1684169978Skmacy bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid, 1685169978Skmacy sc->irq_res); 1686169978Skmacy sc->irq_res = NULL; 1687169978Skmacy } 1688170654Skmacy 1689176472Skmacy if (sc->flags & USING_MSIX) 1690170654Skmacy cxgb_teardown_msix(sc); 1691176472Skmacy 1692174708Skmacy callout_stop(&sc->cxgb_tick_ch); 1693174708Skmacy callout_stop(&sc->sge_timer_ch); 1694170869Skmacy callout_drain(&sc->cxgb_tick_ch); 1695169978Skmacy callout_drain(&sc->sge_timer_ch); 1696170869Skmacy 1697171978Skmacy if (sc->tq != NULL) { 1698176472Skmacy printf("draining slow intr\n"); 1699176472Skmacy 1700170654Skmacy taskqueue_drain(sc->tq, &sc->slow_intr_task); 1701176472Skmacy printf("draining ext intr\n"); 1702176472Skmacy taskqueue_drain(sc->tq, &sc->ext_intr_task); 1703176472Skmacy printf("draining tick task\n"); 1704176472Skmacy taskqueue_drain(sc->tq, &sc->tick_task); 1705171978Skmacy } 1706176472Skmacy ADAPTER_UNLOCK(sc); 1707169978Skmacy} 1708169978Skmacy 1709169978Skmacystatic int 1710169978Skmacyoffload_open(struct port_info *pi) 1711169978Skmacy{ 1712169978Skmacy struct adapter *adapter = pi->adapter; 1713174708Skmacy struct t3cdev *tdev = &adapter->tdev; 1714183059Skmacy 1715169978Skmacy int adap_up = adapter->open_device_map & PORT_MASK; 1716169978Skmacy int err = 0; 1717169978Skmacy 1718169978Skmacy if (atomic_cmpset_int(&adapter->open_device_map, 1719174708Skmacy (adapter->open_device_map & ~(1<<OFFLOAD_DEVMAP_BIT)), 1720174708Skmacy (adapter->open_device_map | (1<<OFFLOAD_DEVMAP_BIT))) == 0) 1721169978Skmacy return (0); 1722169978Skmacy 1723174708Skmacy if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT)) 1724183059Skmacy printf("offload_open: DEVMAP_BIT did not get set 0x%x\n", 1725183059Skmacy adapter->open_device_map); 1726169978Skmacy ADAPTER_LOCK(pi->adapter); 1727169978Skmacy if (!adap_up) 1728169978Skmacy err = cxgb_up(adapter); 1729169978Skmacy ADAPTER_UNLOCK(pi->adapter); 1730171471Skmacy if (err) 1731169978Skmacy return (err); 1732169978Skmacy 1733169978Skmacy t3_tp_set_offload_mode(adapter, 1); 1734174708Skmacy tdev->lldev = pi->ifp; 1735169978Skmacy 1736169978Skmacy init_port_mtus(adapter); 1737169978Skmacy t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd, 1738169978Skmacy adapter->params.b_wnd, 1739169978Skmacy adapter->params.rev == 0 ? 1740169978Skmacy adapter->port[0].ifp->if_mtu : 0xffff); 1741169978Skmacy init_smt(adapter); 1742178767Skmacy /* Call back all registered clients */ 1743178767Skmacy cxgb_add_clients(tdev); 1744178767Skmacy 1745169978Skmacy /* restore them in case the offload module has changed them */ 1746169978Skmacy if (err) { 1747169978Skmacy t3_tp_set_offload_mode(adapter, 0); 1748169978Skmacy clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT); 1749169978Skmacy cxgb_set_dummy_ops(tdev); 1750169978Skmacy } 1751169978Skmacy return (err); 1752169978Skmacy} 1753174708Skmacy 1754169978Skmacystatic int 1755174708Skmacyoffload_close(struct t3cdev *tdev) 1756169978Skmacy{ 1757169978Skmacy struct adapter *adapter = tdev2adap(tdev); 1758169978Skmacy 1759176472Skmacy if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT)) 1760170654Skmacy return (0); 1761178767Skmacy 1762178767Skmacy /* Call back all registered clients */ 1763178767Skmacy cxgb_remove_clients(tdev); 1764178767Skmacy 1765169978Skmacy tdev->lldev = NULL; 1766169978Skmacy cxgb_set_dummy_ops(tdev); 1767169978Skmacy t3_tp_set_offload_mode(adapter, 0); 1768169978Skmacy clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT); 1769169978Skmacy 1770174708Skmacy ADAPTER_LOCK(adapter); 1771169978Skmacy if (!adapter->open_device_map) 1772174708Skmacy cxgb_down_locked(adapter); 1773174708Skmacy else 1774174708Skmacy ADAPTER_UNLOCK(adapter); 1775170654Skmacy return (0); 1776169978Skmacy} 1777169978Skmacy 1778174708Skmacy 1779169978Skmacystatic void 1780167514Skmacycxgb_init(void *arg) 1781167514Skmacy{ 1782167514Skmacy struct port_info *p = arg; 1783167514Skmacy 1784167514Skmacy PORT_LOCK(p); 1785167514Skmacy cxgb_init_locked(p); 1786167514Skmacy PORT_UNLOCK(p); 1787167514Skmacy} 1788167514Skmacy 1789167514Skmacystatic void 1790167514Skmacycxgb_init_locked(struct port_info *p) 1791167514Skmacy{ 1792167514Skmacy struct ifnet *ifp; 1793167514Skmacy adapter_t *sc = p->adapter; 1794169978Skmacy int err; 1795167514Skmacy 1796170869Skmacy PORT_LOCK_ASSERT_OWNED(p); 1797167514Skmacy ifp = p->ifp; 1798167514Skmacy 1799167514Skmacy ADAPTER_LOCK(p->adapter); 1800171471Skmacy if ((sc->open_device_map == 0) && (err = cxgb_up(sc))) { 1801169978Skmacy ADAPTER_UNLOCK(p->adapter); 1802169978Skmacy cxgb_stop_locked(p); 1803169978Skmacy return; 1804169978Skmacy } 1805170869Skmacy if (p->adapter->open_device_map == 0) { 1806167514Skmacy t3_intr_clear(sc); 1807170869Skmacy } 1808171803Skmacy setbit(&p->adapter->open_device_map, p->port_id); 1809170654Skmacy ADAPTER_UNLOCK(p->adapter); 1810169978Skmacy 1811169978Skmacy if (is_offload(sc) && !ofld_disable) { 1812169978Skmacy err = offload_open(p); 1813169978Skmacy if (err) 1814169978Skmacy log(LOG_WARNING, 1815169978Skmacy "Could not initialize offload capabilities\n"); 1816169978Skmacy } 1817177415Skmacy#if !defined(LINK_ATTACH) 1818177415Skmacy cxgb_link_start(p); 1819177415Skmacy t3_link_changed(sc, p->port_id); 1820177415Skmacy#endif 1821170654Skmacy ifp->if_baudrate = p->link_config.speed * 1000000; 1822171978Skmacy 1823172096Skmacy device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id); 1824171803Skmacy t3_port_intr_enable(sc, p->port_id); 1825167760Skmacy 1826175224Skmacy t3_sge_reset_adapter(sc); 1827170869Skmacy 1828167514Skmacy ifp->if_drv_flags |= IFF_DRV_RUNNING; 1829167514Skmacy ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1830167514Skmacy} 1831167514Skmacy 1832167514Skmacystatic void 1833167514Skmacycxgb_set_rxmode(struct port_info *p) 1834167514Skmacy{ 1835167514Skmacy struct t3_rx_mode rm; 1836167514Skmacy struct cmac *mac = &p->mac; 1837167760Skmacy 1838167514Skmacy t3_init_rx_mode(&rm, p); 1839176472Skmacy mtx_lock(&p->adapter->mdio_lock); 1840167514Skmacy t3_mac_set_rx_mode(mac, &rm); 1841176472Skmacy mtx_unlock(&p->adapter->mdio_lock); 1842167514Skmacy} 1843167514Skmacy 1844167514Skmacystatic void 1845177340Skmacycxgb_stop_locked(struct port_info *pi) 1846167514Skmacy{ 1847167514Skmacy struct ifnet *ifp; 1848167514Skmacy 1849177340Skmacy PORT_LOCK_ASSERT_OWNED(pi); 1850177340Skmacy ADAPTER_LOCK_ASSERT_NOTOWNED(pi->adapter); 1851170654Skmacy 1852177340Skmacy ifp = pi->ifp; 1853177340Skmacy t3_port_intr_disable(pi->adapter, pi->port_id); 1854169978Skmacy ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1855169978Skmacy 1856177340Skmacy /* disable pause frames */ 1857177340Skmacy t3_set_reg_field(pi->adapter, A_XGM_TX_CFG + pi->mac.offset, 1858177340Skmacy F_TXPAUSEEN, 0); 1859170869Skmacy 1860177340Skmacy /* Reset RX FIFO HWM */ 1861177340Skmacy t3_set_reg_field(pi->adapter, A_XGM_RXFIFO_CFG + pi->mac.offset, 1862177340Skmacy V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM), 0); 1863177340Skmacy 1864177340Skmacy 1865177340Skmacy ADAPTER_LOCK(pi->adapter); 1866177340Skmacy clrbit(&pi->adapter->open_device_map, pi->port_id); 1867177340Skmacy 1868177340Skmacy if (pi->adapter->open_device_map == 0) { 1869177340Skmacy cxgb_down_locked(pi->adapter); 1870170869Skmacy } else 1871177340Skmacy ADAPTER_UNLOCK(pi->adapter); 1872170869Skmacy 1873177415Skmacy#if !defined(LINK_ATTACH) 1874177340Skmacy DELAY(100); 1875177340Skmacy 1876177340Skmacy /* Wait for TXFIFO empty */ 1877177340Skmacy t3_wait_op_done(pi->adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 1878177340Skmacy F_TXFIFO_EMPTY, 1, 20, 5); 1879177340Skmacy 1880177340Skmacy DELAY(100); 1881177340Skmacy t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); 1882177340Skmacy 1883177340Skmacy pi->phy.ops->power_down(&pi->phy, 1); 1884177415Skmacy#endif 1885177340Skmacy 1886167514Skmacy} 1887167514Skmacy 1888167514Skmacystatic int 1889170654Skmacycxgb_set_mtu(struct port_info *p, int mtu) 1890170654Skmacy{ 1891170654Skmacy struct ifnet *ifp = p->ifp; 1892170654Skmacy int error = 0; 1893170654Skmacy 1894180583Skmacy if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) 1895170654Skmacy error = EINVAL; 1896170654Skmacy else if (ifp->if_mtu != mtu) { 1897170654Skmacy PORT_LOCK(p); 1898170654Skmacy ifp->if_mtu = mtu; 1899170654Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1900170654Skmacy cxgb_stop_locked(p); 1901170654Skmacy cxgb_init_locked(p); 1902170654Skmacy } 1903170654Skmacy PORT_UNLOCK(p); 1904170654Skmacy } 1905170654Skmacy return (error); 1906170654Skmacy} 1907170654Skmacy 1908183289Skmacy#ifdef LRO_SUPPORTED 1909181616Skmacy/* 1910181616Skmacy * Mark lro enabled or disabled in all qsets for this port 1911181616Skmacy */ 1912170654Skmacystatic int 1913181616Skmacycxgb_set_lro(struct port_info *p, int enabled) 1914181616Skmacy{ 1915181616Skmacy int i; 1916181616Skmacy struct adapter *adp = p->adapter; 1917181616Skmacy struct sge_qset *q; 1918181616Skmacy 1919181616Skmacy PORT_LOCK_ASSERT_OWNED(p); 1920181616Skmacy for (i = 0; i < p->nqsets; i++) { 1921181616Skmacy q = &adp->sge.qs[p->first_qset + i]; 1922181616Skmacy q->lro.enabled = (enabled != 0); 1923181616Skmacy } 1924181616Skmacy return (0); 1925181616Skmacy} 1926183289Skmacy#endif 1927181616Skmacy 1928181616Skmacystatic int 1929167514Skmacycxgb_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data) 1930167514Skmacy{ 1931167514Skmacy struct port_info *p = ifp->if_softc; 1932167514Skmacy struct ifaddr *ifa = (struct ifaddr *)data; 1933167514Skmacy struct ifreq *ifr = (struct ifreq *)data; 1934180583Skmacy int flags, error = 0, reinit = 0; 1935167514Skmacy uint32_t mask; 1936167514Skmacy 1937168737Skmacy /* 1938168737Skmacy * XXX need to check that we aren't in the middle of an unload 1939168737Skmacy */ 1940167514Skmacy switch (command) { 1941167514Skmacy case SIOCSIFMTU: 1942170654Skmacy error = cxgb_set_mtu(p, ifr->ifr_mtu); 1943167514Skmacy break; 1944167514Skmacy case SIOCSIFADDR: 1945167514Skmacy if (ifa->ifa_addr->sa_family == AF_INET) { 1946167514Skmacy ifp->if_flags |= IFF_UP; 1947176472Skmacy if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1948176472Skmacy PORT_LOCK(p); 1949170654Skmacy cxgb_init_locked(p); 1950176472Skmacy PORT_UNLOCK(p); 1951176472Skmacy } 1952167514Skmacy arp_ifinit(ifp, ifa); 1953167514Skmacy } else 1954167514Skmacy error = ether_ioctl(ifp, command, data); 1955167514Skmacy break; 1956167514Skmacy case SIOCSIFFLAGS: 1957170869Skmacy PORT_LOCK(p); 1958167514Skmacy if (ifp->if_flags & IFF_UP) { 1959167514Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1960167514Skmacy flags = p->if_flags; 1961167514Skmacy if (((ifp->if_flags ^ flags) & IFF_PROMISC) || 1962167514Skmacy ((ifp->if_flags ^ flags) & IFF_ALLMULTI)) 1963167514Skmacy cxgb_set_rxmode(p); 1964167514Skmacy } else 1965167514Skmacy cxgb_init_locked(p); 1966167760Skmacy p->if_flags = ifp->if_flags; 1967170869Skmacy } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 1968170869Skmacy cxgb_stop_locked(p); 1969170869Skmacy 1970176472Skmacy PORT_UNLOCK(p); 1971176472Skmacy break; 1972176472Skmacy case SIOCADDMULTI: 1973176472Skmacy case SIOCDELMULTI: 1974170869Skmacy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1975176472Skmacy cxgb_set_rxmode(p); 1976167514Skmacy } 1977167514Skmacy break; 1978167514Skmacy case SIOCSIFMEDIA: 1979167514Skmacy case SIOCGIFMEDIA: 1980167514Skmacy error = ifmedia_ioctl(ifp, ifr, &p->media, command); 1981167514Skmacy break; 1982167514Skmacy case SIOCSIFCAP: 1983167514Skmacy PORT_LOCK(p); 1984167514Skmacy mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1985167514Skmacy if (mask & IFCAP_TXCSUM) { 1986167514Skmacy if (IFCAP_TXCSUM & ifp->if_capenable) { 1987167514Skmacy ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 1988167514Skmacy ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 1989180583Skmacy | CSUM_IP | CSUM_TSO); 1990167514Skmacy } else { 1991167514Skmacy ifp->if_capenable |= IFCAP_TXCSUM; 1992180583Skmacy ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP 1993180583Skmacy | CSUM_IP); 1994167514Skmacy } 1995167514Skmacy } 1996180583Skmacy if (mask & IFCAP_RXCSUM) { 1997180583Skmacy ifp->if_capenable ^= IFCAP_RXCSUM; 1998180583Skmacy } 1999167514Skmacy if (mask & IFCAP_TSO4) { 2000167514Skmacy if (IFCAP_TSO4 & ifp->if_capenable) { 2001167514Skmacy ifp->if_capenable &= ~IFCAP_TSO4; 2002167514Skmacy ifp->if_hwassist &= ~CSUM_TSO; 2003167514Skmacy } else if (IFCAP_TXCSUM & ifp->if_capenable) { 2004167514Skmacy ifp->if_capenable |= IFCAP_TSO4; 2005167514Skmacy ifp->if_hwassist |= CSUM_TSO; 2006167514Skmacy } else { 2007167514Skmacy if (cxgb_debug) 2008167514Skmacy printf("cxgb requires tx checksum offload" 2009167514Skmacy " be enabled to use TSO\n"); 2010167514Skmacy error = EINVAL; 2011167514Skmacy } 2012167514Skmacy } 2013183289Skmacy#ifdef LRO_SUPPORTED 2014181616Skmacy if (mask & IFCAP_LRO) { 2015181616Skmacy ifp->if_capenable ^= IFCAP_LRO; 2016181616Skmacy 2017181616Skmacy /* Safe to do this even if cxgb_up not called yet */ 2018181616Skmacy cxgb_set_lro(p, ifp->if_capenable & IFCAP_LRO); 2019181616Skmacy } 2020183289Skmacy#endif 2021180583Skmacy if (mask & IFCAP_VLAN_HWTAGGING) { 2022180583Skmacy ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 2023180583Skmacy reinit = ifp->if_drv_flags & IFF_DRV_RUNNING; 2024180583Skmacy } 2025180583Skmacy if (mask & IFCAP_VLAN_MTU) { 2026180583Skmacy ifp->if_capenable ^= IFCAP_VLAN_MTU; 2027180583Skmacy reinit = ifp->if_drv_flags & IFF_DRV_RUNNING; 2028180583Skmacy } 2029180583Skmacy if (mask & IFCAP_VLAN_HWCSUM) { 2030180583Skmacy ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 2031180583Skmacy } 2032180583Skmacy if (reinit) { 2033180583Skmacy cxgb_stop_locked(p); 2034180583Skmacy cxgb_init_locked(p); 2035180583Skmacy } 2036167514Skmacy PORT_UNLOCK(p); 2037180583Skmacy 2038180583Skmacy#ifdef VLAN_CAPABILITIES 2039180583Skmacy VLAN_CAPABILITIES(ifp); 2040180583Skmacy#endif 2041167514Skmacy break; 2042167514Skmacy default: 2043167514Skmacy error = ether_ioctl(ifp, command, data); 2044167514Skmacy break; 2045167514Skmacy } 2046167514Skmacy return (error); 2047167514Skmacy} 2048167514Skmacy 2049174708Skmacystatic int 2050167514Skmacycxgb_media_change(struct ifnet *ifp) 2051167514Skmacy{ 2052167514Skmacy if_printf(ifp, "media change not supported\n"); 2053167514Skmacy return (ENXIO); 2054167514Skmacy} 2055167514Skmacy 2056167514Skmacystatic void 2057167514Skmacycxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 2058167514Skmacy{ 2059167514Skmacy struct port_info *p = ifp->if_softc; 2060167514Skmacy 2061167514Skmacy ifmr->ifm_status = IFM_AVALID; 2062167514Skmacy ifmr->ifm_active = IFM_ETHER; 2063167514Skmacy 2064167514Skmacy if (!p->link_config.link_ok) 2065167514Skmacy return; 2066167514Skmacy 2067167514Skmacy ifmr->ifm_status |= IFM_ACTIVE; 2068167514Skmacy 2069170654Skmacy switch (p->link_config.speed) { 2070170654Skmacy case 10: 2071170654Skmacy ifmr->ifm_active |= IFM_10_T; 2072170654Skmacy break; 2073170654Skmacy case 100: 2074170654Skmacy ifmr->ifm_active |= IFM_100_TX; 2075170654Skmacy break; 2076170654Skmacy case 1000: 2077170654Skmacy ifmr->ifm_active |= IFM_1000_T; 2078170654Skmacy break; 2079170654Skmacy } 2080170654Skmacy 2081167514Skmacy if (p->link_config.duplex) 2082167514Skmacy ifmr->ifm_active |= IFM_FDX; 2083167514Skmacy else 2084167514Skmacy ifmr->ifm_active |= IFM_HDX; 2085167514Skmacy} 2086167514Skmacy 2087167514Skmacystatic void 2088167514Skmacycxgb_async_intr(void *data) 2089167514Skmacy{ 2090167760Skmacy adapter_t *sc = data; 2091167760Skmacy 2092167514Skmacy if (cxgb_debug) 2093167760Skmacy device_printf(sc->dev, "cxgb_async_intr\n"); 2094170869Skmacy /* 2095170869Skmacy * May need to sleep - defer to taskqueue 2096170869Skmacy */ 2097170869Skmacy taskqueue_enqueue(sc->tq, &sc->slow_intr_task); 2098167514Skmacy} 2099167514Skmacy 2100167514Skmacystatic void 2101167514Skmacycxgb_ext_intr_handler(void *arg, int count) 2102167514Skmacy{ 2103167514Skmacy adapter_t *sc = (adapter_t *)arg; 2104167514Skmacy 2105167514Skmacy if (cxgb_debug) 2106167514Skmacy printf("cxgb_ext_intr_handler\n"); 2107167514Skmacy 2108167514Skmacy t3_phy_intr_handler(sc); 2109167514Skmacy 2110167514Skmacy /* Now reenable external interrupts */ 2111169978Skmacy ADAPTER_LOCK(sc); 2112167514Skmacy if (sc->slow_intr_mask) { 2113167514Skmacy sc->slow_intr_mask |= F_T3DBG; 2114167514Skmacy t3_write_reg(sc, A_PL_INT_CAUSE0, F_T3DBG); 2115167514Skmacy t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask); 2116167514Skmacy } 2117169978Skmacy ADAPTER_UNLOCK(sc); 2118167514Skmacy} 2119167514Skmacy 2120167514Skmacystatic void 2121167746Skmacycheck_link_status(adapter_t *sc) 2122167514Skmacy{ 2123167746Skmacy int i; 2124167514Skmacy 2125167746Skmacy for (i = 0; i < (sc)->params.nports; ++i) { 2126167746Skmacy struct port_info *p = &sc->port[i]; 2127167514Skmacy 2128176472Skmacy if (!(p->phy.caps & SUPPORTED_IRQ)) 2129167746Skmacy t3_link_changed(sc, i); 2130170654Skmacy p->ifp->if_baudrate = p->link_config.speed * 1000000; 2131167746Skmacy } 2132167514Skmacy} 2133167514Skmacy 2134167514Skmacystatic void 2135167746Skmacycheck_t3b2_mac(struct adapter *adapter) 2136167514Skmacy{ 2137167514Skmacy int i; 2138167514Skmacy 2139176472Skmacy if(adapter->flags & CXGB_SHUTDOWN) 2140176472Skmacy return; 2141176472Skmacy 2142167746Skmacy for_each_port(adapter, i) { 2143167746Skmacy struct port_info *p = &adapter->port[i]; 2144167746Skmacy struct ifnet *ifp = p->ifp; 2145167746Skmacy int status; 2146176472Skmacy 2147176472Skmacy if(adapter->flags & CXGB_SHUTDOWN) 2148176472Skmacy return; 2149176472Skmacy 2150167746Skmacy if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 2151167746Skmacy continue; 2152167746Skmacy 2153167746Skmacy status = 0; 2154167746Skmacy PORT_LOCK(p); 2155167746Skmacy if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) 2156167746Skmacy status = t3b2_mac_watchdog_task(&p->mac); 2157167746Skmacy if (status == 1) 2158167746Skmacy p->mac.stats.num_toggled++; 2159167746Skmacy else if (status == 2) { 2160167746Skmacy struct cmac *mac = &p->mac; 2161180583Skmacy int mtu = ifp->if_mtu; 2162167746Skmacy 2163180583Skmacy if (ifp->if_capenable & IFCAP_VLAN_MTU) 2164180583Skmacy mtu += ETHER_VLAN_ENCAP_LEN; 2165180583Skmacy t3_mac_set_mtu(mac, mtu); 2166167746Skmacy t3_mac_set_address(mac, 0, p->hw_addr); 2167167746Skmacy cxgb_set_rxmode(p); 2168167746Skmacy t3_link_start(&p->phy, mac, &p->link_config); 2169167746Skmacy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 2170171803Skmacy t3_port_intr_enable(adapter, p->port_id); 2171167746Skmacy p->mac.stats.num_resets++; 2172167746Skmacy } 2173167746Skmacy PORT_UNLOCK(p); 2174167514Skmacy } 2175167514Skmacy} 2176167514Skmacy 2177167746Skmacystatic void 2178167746Skmacycxgb_tick(void *arg) 2179167746Skmacy{ 2180167746Skmacy adapter_t *sc = (adapter_t *)arg; 2181170869Skmacy 2182176472Skmacy if(sc->flags & CXGB_SHUTDOWN) 2183176472Skmacy return; 2184174708Skmacy 2185170869Skmacy taskqueue_enqueue(sc->tq, &sc->tick_task); 2186181652Skmacy callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc); 2187170869Skmacy} 2188170869Skmacy 2189170869Skmacystatic void 2190170869Skmacycxgb_tick_handler(void *arg, int count) 2191170869Skmacy{ 2192170869Skmacy adapter_t *sc = (adapter_t *)arg; 2193167746Skmacy const struct adapter_params *p = &sc->params; 2194181652Skmacy int i; 2195167746Skmacy 2196176472Skmacy if(sc->flags & CXGB_SHUTDOWN) 2197176472Skmacy return; 2198176472Skmacy 2199170869Skmacy ADAPTER_LOCK(sc); 2200167746Skmacy if (p->linkpoll_period) 2201167746Skmacy check_link_status(sc); 2202167746Skmacy 2203181652Skmacy sc->check_task_cnt++; 2204181652Skmacy 2205167746Skmacy /* 2206176472Skmacy * adapter lock can currently only be acquired after the 2207167746Skmacy * port lock 2208167746Skmacy */ 2209167746Skmacy ADAPTER_UNLOCK(sc); 2210170654Skmacy 2211176472Skmacy if (p->rev == T3_REV_B2 && p->nports < 4 && sc->open_device_map) 2212167746Skmacy check_t3b2_mac(sc); 2213181652Skmacy 2214181652Skmacy /* Update MAC stats if it's time to do so */ 2215181652Skmacy if (!p->linkpoll_period || 2216181652Skmacy (sc->check_task_cnt * p->linkpoll_period) / 10 >= 2217181652Skmacy p->stats_update_period) { 2218181652Skmacy for_each_port(sc, i) { 2219181652Skmacy struct port_info *port = &sc->port[i]; 2220181652Skmacy PORT_LOCK(port); 2221181652Skmacy t3_mac_update_stats(&port->mac); 2222181652Skmacy PORT_UNLOCK(port); 2223181652Skmacy } 2224181652Skmacy sc->check_task_cnt = 0; 2225181652Skmacy } 2226167746Skmacy} 2227167746Skmacy 2228171978Skmacystatic void 2229171978Skmacytouch_bars(device_t dev) 2230171978Skmacy{ 2231171978Skmacy /* 2232171978Skmacy * Don't enable yet 2233171978Skmacy */ 2234171978Skmacy#if !defined(__LP64__) && 0 2235171978Skmacy u32 v; 2236171978Skmacy 2237171978Skmacy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &v); 2238171978Skmacy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, v); 2239171978Skmacy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3, &v); 2240171978Skmacy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_3, v); 2241171978Skmacy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &v); 2242171978Skmacy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_5, v); 2243171978Skmacy#endif 2244171978Skmacy} 2245171978Skmacy 2246167514Skmacystatic int 2247171471Skmacyset_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset) 2248171471Skmacy{ 2249171471Skmacy uint8_t *buf; 2250171471Skmacy int err = 0; 2251171471Skmacy u32 aligned_offset, aligned_len, *p; 2252171471Skmacy struct adapter *adapter = pi->adapter; 2253171471Skmacy 2254171471Skmacy 2255171471Skmacy aligned_offset = offset & ~3; 2256171471Skmacy aligned_len = (len + (offset & 3) + 3) & ~3; 2257171471Skmacy 2258171471Skmacy if (aligned_offset != offset || aligned_len != len) { 2259171471Skmacy buf = malloc(aligned_len, M_DEVBUF, M_WAITOK|M_ZERO); 2260171471Skmacy if (!buf) 2261171471Skmacy return (ENOMEM); 2262171471Skmacy err = t3_seeprom_read(adapter, aligned_offset, (u32 *)buf); 2263171471Skmacy if (!err && aligned_len > 4) 2264171471Skmacy err = t3_seeprom_read(adapter, 2265171471Skmacy aligned_offset + aligned_len - 4, 2266171471Skmacy (u32 *)&buf[aligned_len - 4]); 2267171471Skmacy if (err) 2268171471Skmacy goto out; 2269171471Skmacy memcpy(buf + (offset & 3), data, len); 2270171471Skmacy } else 2271171471Skmacy buf = (uint8_t *)(uintptr_t)data; 2272171471Skmacy 2273171471Skmacy err = t3_seeprom_wp(adapter, 0); 2274171471Skmacy if (err) 2275171471Skmacy goto out; 2276171471Skmacy 2277171471Skmacy for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { 2278171471Skmacy err = t3_seeprom_write(adapter, aligned_offset, *p); 2279171471Skmacy aligned_offset += 4; 2280171471Skmacy } 2281171471Skmacy 2282171471Skmacy if (!err) 2283171471Skmacy err = t3_seeprom_wp(adapter, 1); 2284171471Skmacyout: 2285171471Skmacy if (buf != data) 2286171471Skmacy free(buf, M_DEVBUF); 2287171471Skmacy return err; 2288171471Skmacy} 2289171471Skmacy 2290171471Skmacy 2291171471Skmacystatic int 2292167514Skmacyin_range(int val, int lo, int hi) 2293167514Skmacy{ 2294167514Skmacy return val < 0 || (val <= hi && val >= lo); 2295167514Skmacy} 2296167514Skmacy 2297167514Skmacystatic int 2298170654Skmacycxgb_extension_open(struct cdev *dev, int flags, int fmp, d_thread_t *td) 2299170654Skmacy{ 2300170654Skmacy return (0); 2301170654Skmacy} 2302170654Skmacy 2303170654Skmacystatic int 2304170654Skmacycxgb_extension_close(struct cdev *dev, int flags, int fmt, d_thread_t *td) 2305170654Skmacy{ 2306170654Skmacy return (0); 2307170654Skmacy} 2308170654Skmacy 2309170654Skmacystatic int 2310167514Skmacycxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, 2311167514Skmacy int fflag, struct thread *td) 2312167514Skmacy{ 2313167514Skmacy int mmd, error = 0; 2314167514Skmacy struct port_info *pi = dev->si_drv1; 2315167514Skmacy adapter_t *sc = pi->adapter; 2316167514Skmacy 2317167514Skmacy#ifdef PRIV_SUPPORTED 2318167514Skmacy if (priv_check(td, PRIV_DRIVER)) { 2319167514Skmacy if (cxgb_debug) 2320167514Skmacy printf("user does not have access to privileged ioctls\n"); 2321167514Skmacy return (EPERM); 2322167514Skmacy } 2323167514Skmacy#else 2324167514Skmacy if (suser(td)) { 2325167514Skmacy if (cxgb_debug) 2326167514Skmacy printf("user does not have access to privileged ioctls\n"); 2327167514Skmacy return (EPERM); 2328167514Skmacy } 2329167514Skmacy#endif 2330167514Skmacy 2331167514Skmacy switch (cmd) { 2332182679Skmacy case CHELSIO_GET_MIIREG: { 2333167514Skmacy uint32_t val; 2334167514Skmacy struct cphy *phy = &pi->phy; 2335182679Skmacy struct ch_mii_data *mid = (struct ch_mii_data *)data; 2336167514Skmacy 2337167514Skmacy if (!phy->mdio_read) 2338167514Skmacy return (EOPNOTSUPP); 2339167514Skmacy if (is_10G(sc)) { 2340167514Skmacy mmd = mid->phy_id >> 8; 2341167514Skmacy if (!mmd) 2342167514Skmacy mmd = MDIO_DEV_PCS; 2343167514Skmacy else if (mmd > MDIO_DEV_XGXS) 2344171471Skmacy return (EINVAL); 2345167514Skmacy 2346167514Skmacy error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd, 2347167514Skmacy mid->reg_num, &val); 2348167514Skmacy } else 2349167514Skmacy error = phy->mdio_read(sc, mid->phy_id & 0x1f, 0, 2350167514Skmacy mid->reg_num & 0x1f, &val); 2351167514Skmacy if (error == 0) 2352167514Skmacy mid->val_out = val; 2353167514Skmacy break; 2354167514Skmacy } 2355182679Skmacy case CHELSIO_SET_MIIREG: { 2356167514Skmacy struct cphy *phy = &pi->phy; 2357182679Skmacy struct ch_mii_data *mid = (struct ch_mii_data *)data; 2358167514Skmacy 2359167514Skmacy if (!phy->mdio_write) 2360167514Skmacy return (EOPNOTSUPP); 2361167514Skmacy if (is_10G(sc)) { 2362167514Skmacy mmd = mid->phy_id >> 8; 2363167514Skmacy if (!mmd) 2364167514Skmacy mmd = MDIO_DEV_PCS; 2365167514Skmacy else if (mmd > MDIO_DEV_XGXS) 2366167514Skmacy return (EINVAL); 2367167514Skmacy 2368167514Skmacy error = phy->mdio_write(sc, mid->phy_id & 0x1f, 2369167514Skmacy mmd, mid->reg_num, mid->val_in); 2370167514Skmacy } else 2371167514Skmacy error = phy->mdio_write(sc, mid->phy_id & 0x1f, 0, 2372167514Skmacy mid->reg_num & 0x1f, 2373167514Skmacy mid->val_in); 2374167514Skmacy break; 2375167514Skmacy } 2376167514Skmacy case CHELSIO_SETREG: { 2377167514Skmacy struct ch_reg *edata = (struct ch_reg *)data; 2378167514Skmacy if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 2379167514Skmacy return (EFAULT); 2380167514Skmacy t3_write_reg(sc, edata->addr, edata->val); 2381167514Skmacy break; 2382167514Skmacy } 2383167514Skmacy case CHELSIO_GETREG: { 2384167514Skmacy struct ch_reg *edata = (struct ch_reg *)data; 2385167514Skmacy if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 2386167514Skmacy return (EFAULT); 2387167514Skmacy edata->val = t3_read_reg(sc, edata->addr); 2388167514Skmacy break; 2389167514Skmacy } 2390167514Skmacy case CHELSIO_GET_SGE_CONTEXT: { 2391167514Skmacy struct ch_cntxt *ecntxt = (struct ch_cntxt *)data; 2392176472Skmacy mtx_lock_spin(&sc->sge.reg_lock); 2393167514Skmacy switch (ecntxt->cntxt_type) { 2394167514Skmacy case CNTXT_TYPE_EGRESS: 2395182679Skmacy error = -t3_sge_read_ecntxt(sc, ecntxt->cntxt_id, 2396167514Skmacy ecntxt->data); 2397167514Skmacy break; 2398167514Skmacy case CNTXT_TYPE_FL: 2399182679Skmacy error = -t3_sge_read_fl(sc, ecntxt->cntxt_id, 2400167514Skmacy ecntxt->data); 2401167514Skmacy break; 2402167514Skmacy case CNTXT_TYPE_RSP: 2403182679Skmacy error = -t3_sge_read_rspq(sc, ecntxt->cntxt_id, 2404167514Skmacy ecntxt->data); 2405167514Skmacy break; 2406167514Skmacy case CNTXT_TYPE_CQ: 2407182679Skmacy error = -t3_sge_read_cq(sc, ecntxt->cntxt_id, 2408167514Skmacy ecntxt->data); 2409167514Skmacy break; 2410167514Skmacy default: 2411167514Skmacy error = EINVAL; 2412167514Skmacy break; 2413167514Skmacy } 2414176472Skmacy mtx_unlock_spin(&sc->sge.reg_lock); 2415167514Skmacy break; 2416167514Skmacy } 2417167514Skmacy case CHELSIO_GET_SGE_DESC: { 2418167514Skmacy struct ch_desc *edesc = (struct ch_desc *)data; 2419167514Skmacy int ret; 2420167514Skmacy if (edesc->queue_num >= SGE_QSETS * 6) 2421167514Skmacy return (EINVAL); 2422167514Skmacy ret = t3_get_desc(&sc->sge.qs[edesc->queue_num / 6], 2423167514Skmacy edesc->queue_num % 6, edesc->idx, edesc->data); 2424167514Skmacy if (ret < 0) 2425167514Skmacy return (EINVAL); 2426167514Skmacy edesc->size = ret; 2427167514Skmacy break; 2428167514Skmacy } 2429182679Skmacy case CHELSIO_GET_QSET_PARAMS: { 2430167514Skmacy struct qset_params *q; 2431167514Skmacy struct ch_qset_params *t = (struct ch_qset_params *)data; 2432182679Skmacy int q1 = pi->first_qset; 2433182679Skmacy int nqsets = pi->nqsets; 2434176472Skmacy int i; 2435176472Skmacy 2436182679Skmacy if (t->qset_idx >= nqsets) 2437182679Skmacy return EINVAL; 2438167514Skmacy 2439182679Skmacy i = q1 + t->qset_idx; 2440182679Skmacy q = &sc->params.sge.qset[i]; 2441167514Skmacy t->rspq_size = q->rspq_size; 2442167514Skmacy t->txq_size[0] = q->txq_size[0]; 2443167514Skmacy t->txq_size[1] = q->txq_size[1]; 2444167514Skmacy t->txq_size[2] = q->txq_size[2]; 2445167514Skmacy t->fl_size[0] = q->fl_size; 2446167514Skmacy t->fl_size[1] = q->jumbo_size; 2447167514Skmacy t->polling = q->polling; 2448182679Skmacy t->lro = q->lro; 2449180583Skmacy t->intr_lat = q->coalesce_usecs; 2450167514Skmacy t->cong_thres = q->cong_thres; 2451182679Skmacy t->qnum = i; 2452182679Skmacy 2453182679Skmacy if (sc->flags & USING_MSIX) 2454182679Skmacy t->vector = rman_get_start(sc->msix_irq_res[i]); 2455182679Skmacy else 2456182679Skmacy t->vector = rman_get_start(sc->irq_res); 2457182679Skmacy 2458167514Skmacy break; 2459167514Skmacy } 2460182679Skmacy case CHELSIO_GET_QSET_NUM: { 2461167514Skmacy struct ch_reg *edata = (struct ch_reg *)data; 2462182679Skmacy edata->val = pi->nqsets; 2463182679Skmacy break; 2464182679Skmacy } 2465182679Skmacy case CHELSIO_LOAD_FW: { 2466182679Skmacy uint8_t *fw_data; 2467182679Skmacy uint32_t vers; 2468182679Skmacy struct ch_mem_range *t = (struct ch_mem_range *)data; 2469182679Skmacy 2470167514Skmacy /* 2471182679Skmacy * You're allowed to load a firmware only before FULL_INIT_DONE 2472182679Skmacy * 2473182679Skmacy * FW_UPTODATE is also set so the rest of the initialization 2474182679Skmacy * will not overwrite what was loaded here. This gives you the 2475182679Skmacy * flexibility to load any firmware (and maybe shoot yourself in 2476182679Skmacy * the foot). 2477167514Skmacy */ 2478182679Skmacy 2479182679Skmacy ADAPTER_LOCK(sc); 2480182679Skmacy if (sc->open_device_map || sc->flags & FULL_INIT_DONE) { 2481182679Skmacy ADAPTER_UNLOCK(sc); 2482182679Skmacy return (EBUSY); 2483182679Skmacy } 2484182679Skmacy 2485182679Skmacy fw_data = malloc(t->len, M_DEVBUF, M_NOWAIT); 2486182679Skmacy if (!fw_data) 2487182679Skmacy error = ENOMEM; 2488182679Skmacy else 2489182679Skmacy error = copyin(t->buf, fw_data, t->len); 2490182679Skmacy 2491182679Skmacy if (!error) 2492182679Skmacy error = -t3_load_fw(sc, fw_data, t->len); 2493182679Skmacy 2494182679Skmacy if (t3_get_fw_version(sc, &vers) == 0) { 2495182679Skmacy snprintf(&sc->fw_version[0], sizeof(sc->fw_version), 2496182679Skmacy "%d.%d.%d", G_FW_VERSION_MAJOR(vers), 2497182679Skmacy G_FW_VERSION_MINOR(vers), G_FW_VERSION_MICRO(vers)); 2498182679Skmacy } 2499182679Skmacy 2500182679Skmacy if (!error) 2501182679Skmacy sc->flags |= FW_UPTODATE; 2502182679Skmacy 2503182679Skmacy free(fw_data, M_DEVBUF); 2504182679Skmacy ADAPTER_UNLOCK(sc); 2505167514Skmacy break; 2506167514Skmacy } 2507182679Skmacy case CHELSIO_LOAD_BOOT: { 2508182679Skmacy uint8_t *boot_data; 2509182679Skmacy struct ch_mem_range *t = (struct ch_mem_range *)data; 2510182679Skmacy 2511182679Skmacy boot_data = malloc(t->len, M_DEVBUF, M_NOWAIT); 2512182679Skmacy if (!boot_data) 2513182679Skmacy return ENOMEM; 2514182679Skmacy 2515182679Skmacy error = copyin(t->buf, boot_data, t->len); 2516182679Skmacy if (!error) 2517182679Skmacy error = -t3_load_boot(sc, boot_data, t->len); 2518182679Skmacy 2519182679Skmacy free(boot_data, M_DEVBUF); 2520167514Skmacy break; 2521167514Skmacy } 2522182679Skmacy case CHELSIO_GET_PM: { 2523182679Skmacy struct ch_pm *m = (struct ch_pm *)data; 2524182679Skmacy struct tp_params *p = &sc->params.tp; 2525182679Skmacy 2526182679Skmacy if (!is_offload(sc)) 2527182679Skmacy return (EOPNOTSUPP); 2528182679Skmacy 2529182679Skmacy m->tx_pg_sz = p->tx_pg_size; 2530182679Skmacy m->tx_num_pg = p->tx_num_pgs; 2531182679Skmacy m->rx_pg_sz = p->rx_pg_size; 2532182679Skmacy m->rx_num_pg = p->rx_num_pgs; 2533182679Skmacy m->pm_total = p->pmtx_size + p->chan_rx_size * p->nchan; 2534182679Skmacy 2535167514Skmacy break; 2536182679Skmacy } 2537182679Skmacy case CHELSIO_SET_PM: { 2538182679Skmacy struct ch_pm *m = (struct ch_pm *)data; 2539182679Skmacy struct tp_params *p = &sc->params.tp; 2540182679Skmacy 2541182679Skmacy if (!is_offload(sc)) 2542182679Skmacy return (EOPNOTSUPP); 2543182679Skmacy if (sc->flags & FULL_INIT_DONE) 2544182679Skmacy return (EBUSY); 2545182679Skmacy 2546182679Skmacy if (!m->rx_pg_sz || (m->rx_pg_sz & (m->rx_pg_sz - 1)) || 2547182679Skmacy !m->tx_pg_sz || (m->tx_pg_sz & (m->tx_pg_sz - 1))) 2548182679Skmacy return (EINVAL); /* not power of 2 */ 2549182679Skmacy if (!(m->rx_pg_sz & 0x14000)) 2550182679Skmacy return (EINVAL); /* not 16KB or 64KB */ 2551182679Skmacy if (!(m->tx_pg_sz & 0x1554000)) 2552182679Skmacy return (EINVAL); 2553182679Skmacy if (m->tx_num_pg == -1) 2554182679Skmacy m->tx_num_pg = p->tx_num_pgs; 2555182679Skmacy if (m->rx_num_pg == -1) 2556182679Skmacy m->rx_num_pg = p->rx_num_pgs; 2557182679Skmacy if (m->tx_num_pg % 24 || m->rx_num_pg % 24) 2558182679Skmacy return (EINVAL); 2559182679Skmacy if (m->rx_num_pg * m->rx_pg_sz > p->chan_rx_size || 2560182679Skmacy m->tx_num_pg * m->tx_pg_sz > p->chan_tx_size) 2561182679Skmacy return (EINVAL); 2562182679Skmacy 2563182679Skmacy p->rx_pg_size = m->rx_pg_sz; 2564182679Skmacy p->tx_pg_size = m->tx_pg_sz; 2565182679Skmacy p->rx_num_pgs = m->rx_num_pg; 2566182679Skmacy p->tx_num_pgs = m->tx_num_pg; 2567182679Skmacy break; 2568182679Skmacy } 2569169978Skmacy case CHELSIO_SETMTUTAB: { 2570169978Skmacy struct ch_mtus *m = (struct ch_mtus *)data; 2571169978Skmacy int i; 2572169978Skmacy 2573169978Skmacy if (!is_offload(sc)) 2574169978Skmacy return (EOPNOTSUPP); 2575169978Skmacy if (offload_running(sc)) 2576169978Skmacy return (EBUSY); 2577169978Skmacy if (m->nmtus != NMTUS) 2578169978Skmacy return (EINVAL); 2579169978Skmacy if (m->mtus[0] < 81) /* accommodate SACK */ 2580169978Skmacy return (EINVAL); 2581169978Skmacy 2582169978Skmacy /* 2583169978Skmacy * MTUs must be in ascending order 2584169978Skmacy */ 2585169978Skmacy for (i = 1; i < NMTUS; ++i) 2586169978Skmacy if (m->mtus[i] < m->mtus[i - 1]) 2587169978Skmacy return (EINVAL); 2588169978Skmacy 2589182679Skmacy memcpy(sc->params.mtus, m->mtus, sizeof(sc->params.mtus)); 2590169978Skmacy break; 2591169978Skmacy } 2592169978Skmacy case CHELSIO_GETMTUTAB: { 2593169978Skmacy struct ch_mtus *m = (struct ch_mtus *)data; 2594169978Skmacy 2595169978Skmacy if (!is_offload(sc)) 2596169978Skmacy return (EOPNOTSUPP); 2597169978Skmacy 2598169978Skmacy memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus)); 2599169978Skmacy m->nmtus = NMTUS; 2600169978Skmacy break; 2601171471Skmacy } 2602167514Skmacy case CHELSIO_GET_MEM: { 2603167514Skmacy struct ch_mem_range *t = (struct ch_mem_range *)data; 2604167514Skmacy struct mc7 *mem; 2605167514Skmacy uint8_t *useraddr; 2606167514Skmacy u64 buf[32]; 2607182679Skmacy 2608182679Skmacy /* 2609182679Skmacy * Use these to avoid modifying len/addr in the the return 2610182679Skmacy * struct 2611182679Skmacy */ 2612182679Skmacy uint32_t len = t->len, addr = t->addr; 2613182679Skmacy 2614167514Skmacy if (!is_offload(sc)) 2615167514Skmacy return (EOPNOTSUPP); 2616167514Skmacy if (!(sc->flags & FULL_INIT_DONE)) 2617167514Skmacy return (EIO); /* need the memory controllers */ 2618182679Skmacy if ((addr & 0x7) || (len & 0x7)) 2619167514Skmacy return (EINVAL); 2620167514Skmacy if (t->mem_id == MEM_CM) 2621167514Skmacy mem = &sc->cm; 2622167514Skmacy else if (t->mem_id == MEM_PMRX) 2623167514Skmacy mem = &sc->pmrx; 2624167514Skmacy else if (t->mem_id == MEM_PMTX) 2625167514Skmacy mem = &sc->pmtx; 2626167514Skmacy else 2627167514Skmacy return (EINVAL); 2628167514Skmacy 2629167514Skmacy /* 2630167514Skmacy * Version scheme: 2631167514Skmacy * bits 0..9: chip version 2632167514Skmacy * bits 10..15: chip revision 2633167514Skmacy */ 2634167514Skmacy t->version = 3 | (sc->params.rev << 10); 2635167514Skmacy 2636167514Skmacy /* 2637167514Skmacy * Read 256 bytes at a time as len can be large and we don't 2638167514Skmacy * want to use huge intermediate buffers. 2639167514Skmacy */ 2640174708Skmacy useraddr = (uint8_t *)t->buf; 2641182679Skmacy while (len) { 2642182679Skmacy unsigned int chunk = min(len, sizeof(buf)); 2643167514Skmacy 2644182679Skmacy error = t3_mc7_bd_read(mem, addr / 8, chunk / 8, buf); 2645167514Skmacy if (error) 2646167514Skmacy return (-error); 2647167514Skmacy if (copyout(buf, useraddr, chunk)) 2648167514Skmacy return (EFAULT); 2649167514Skmacy useraddr += chunk; 2650182679Skmacy addr += chunk; 2651182679Skmacy len -= chunk; 2652167514Skmacy } 2653167514Skmacy break; 2654167514Skmacy } 2655169978Skmacy case CHELSIO_READ_TCAM_WORD: { 2656169978Skmacy struct ch_tcam_word *t = (struct ch_tcam_word *)data; 2657169978Skmacy 2658169978Skmacy if (!is_offload(sc)) 2659169978Skmacy return (EOPNOTSUPP); 2660171471Skmacy if (!(sc->flags & FULL_INIT_DONE)) 2661171471Skmacy return (EIO); /* need MC5 */ 2662169978Skmacy return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf); 2663169978Skmacy break; 2664169978Skmacy } 2665167514Skmacy case CHELSIO_SET_TRACE_FILTER: { 2666167514Skmacy struct ch_trace *t = (struct ch_trace *)data; 2667167514Skmacy const struct trace_params *tp; 2668167514Skmacy 2669167514Skmacy tp = (const struct trace_params *)&t->sip; 2670167514Skmacy if (t->config_tx) 2671167514Skmacy t3_config_trace_filter(sc, tp, 0, t->invert_match, 2672167514Skmacy t->trace_tx); 2673167514Skmacy if (t->config_rx) 2674167514Skmacy t3_config_trace_filter(sc, tp, 1, t->invert_match, 2675167514Skmacy t->trace_rx); 2676167514Skmacy break; 2677167514Skmacy } 2678167514Skmacy case CHELSIO_SET_PKTSCHED: { 2679167514Skmacy struct ch_pktsched_params *p = (struct ch_pktsched_params *)data; 2680167514Skmacy if (sc->open_device_map == 0) 2681167514Skmacy return (EAGAIN); 2682167514Skmacy send_pktsched_cmd(sc, p->sched, p->idx, p->min, p->max, 2683167514Skmacy p->binding); 2684167514Skmacy break; 2685167514Skmacy } 2686167514Skmacy case CHELSIO_IFCONF_GETREGS: { 2687182679Skmacy struct ch_ifconf_regs *regs = (struct ch_ifconf_regs *)data; 2688167514Skmacy int reglen = cxgb_get_regs_len(); 2689182679Skmacy uint8_t *buf = malloc(reglen, M_DEVBUF, M_NOWAIT); 2690167514Skmacy if (buf == NULL) { 2691167514Skmacy return (ENOMEM); 2692182679Skmacy } 2693182679Skmacy if (regs->len > reglen) 2694167514Skmacy regs->len = reglen; 2695182679Skmacy else if (regs->len < reglen) 2696167514Skmacy error = E2BIG; 2697182679Skmacy 2698182679Skmacy if (!error) { 2699182679Skmacy cxgb_get_regs(sc, regs, buf); 2700182679Skmacy error = copyout(buf, regs->data, reglen); 2701167514Skmacy } 2702167514Skmacy free(buf, M_DEVBUF); 2703167514Skmacy 2704167514Skmacy break; 2705167514Skmacy } 2706169978Skmacy case CHELSIO_SET_HW_SCHED: { 2707169978Skmacy struct ch_hw_sched *t = (struct ch_hw_sched *)data; 2708169978Skmacy unsigned int ticks_per_usec = core_ticks_per_usec(sc); 2709169978Skmacy 2710169978Skmacy if ((sc->flags & FULL_INIT_DONE) == 0) 2711169978Skmacy return (EAGAIN); /* need TP to be initialized */ 2712169978Skmacy if (t->sched >= NTX_SCHED || !in_range(t->mode, 0, 1) || 2713169978Skmacy !in_range(t->channel, 0, 1) || 2714169978Skmacy !in_range(t->kbps, 0, 10000000) || 2715169978Skmacy !in_range(t->class_ipg, 0, 10000 * 65535 / ticks_per_usec) || 2716169978Skmacy !in_range(t->flow_ipg, 0, 2717169978Skmacy dack_ticks_to_usec(sc, 0x7ff))) 2718169978Skmacy return (EINVAL); 2719169978Skmacy 2720169978Skmacy if (t->kbps >= 0) { 2721169978Skmacy error = t3_config_sched(sc, t->kbps, t->sched); 2722169978Skmacy if (error < 0) 2723169978Skmacy return (-error); 2724169978Skmacy } 2725169978Skmacy if (t->class_ipg >= 0) 2726169978Skmacy t3_set_sched_ipg(sc, t->sched, t->class_ipg); 2727169978Skmacy if (t->flow_ipg >= 0) { 2728169978Skmacy t->flow_ipg *= 1000; /* us -> ns */ 2729169978Skmacy t3_set_pace_tbl(sc, &t->flow_ipg, t->sched, 1); 2730169978Skmacy } 2731169978Skmacy if (t->mode >= 0) { 2732169978Skmacy int bit = 1 << (S_TX_MOD_TIMER_MODE + t->sched); 2733169978Skmacy 2734169978Skmacy t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP, 2735169978Skmacy bit, t->mode ? bit : 0); 2736169978Skmacy } 2737169978Skmacy if (t->channel >= 0) 2738169978Skmacy t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP, 2739169978Skmacy 1 << t->sched, t->channel << t->sched); 2740169978Skmacy break; 2741182679Skmacy } 2742182679Skmacy case CHELSIO_GET_EEPROM: { 2743182679Skmacy int i; 2744182679Skmacy struct ch_eeprom *e = (struct ch_eeprom *)data; 2745182679Skmacy uint8_t *buf = malloc(EEPROMSIZE, M_DEVBUF, M_NOWAIT); 2746182679Skmacy 2747182679Skmacy if (buf == NULL) { 2748182679Skmacy return (ENOMEM); 2749182679Skmacy } 2750182679Skmacy e->magic = EEPROM_MAGIC; 2751182679Skmacy for (i = e->offset & ~3; !error && i < e->offset + e->len; i += 4) 2752182679Skmacy error = -t3_seeprom_read(sc, i, (uint32_t *)&buf[i]); 2753182679Skmacy 2754182679Skmacy if (!error) 2755182679Skmacy error = copyout(buf + e->offset, e->data, e->len); 2756182679Skmacy 2757182679Skmacy free(buf, M_DEVBUF); 2758182679Skmacy break; 2759182679Skmacy } 2760182679Skmacy case CHELSIO_CLEAR_STATS: { 2761182679Skmacy if (!(sc->flags & FULL_INIT_DONE)) 2762182679Skmacy return EAGAIN; 2763182679Skmacy 2764182679Skmacy PORT_LOCK(pi); 2765182679Skmacy t3_mac_update_stats(&pi->mac); 2766182679Skmacy memset(&pi->mac.stats, 0, sizeof(pi->mac.stats)); 2767182679Skmacy PORT_UNLOCK(pi); 2768182679Skmacy break; 2769182679Skmacy } 2770167514Skmacy default: 2771167514Skmacy return (EOPNOTSUPP); 2772167514Skmacy break; 2773167514Skmacy } 2774167514Skmacy 2775167514Skmacy return (error); 2776167514Skmacy} 2777167514Skmacy 2778167514Skmacystatic __inline void 2779167514Skmacyreg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start, 2780167514Skmacy unsigned int end) 2781167514Skmacy{ 2782182679Skmacy uint32_t *p = (uint32_t *)(buf + start); 2783167514Skmacy 2784167514Skmacy for ( ; start <= end; start += sizeof(uint32_t)) 2785167514Skmacy *p++ = t3_read_reg(ap, start); 2786167514Skmacy} 2787167514Skmacy 2788167514Skmacy#define T3_REGMAP_SIZE (3 * 1024) 2789167514Skmacystatic int 2790167514Skmacycxgb_get_regs_len(void) 2791167514Skmacy{ 2792167514Skmacy return T3_REGMAP_SIZE; 2793167514Skmacy} 2794167514Skmacy 2795167514Skmacystatic void 2796182679Skmacycxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf) 2797167514Skmacy{ 2798167514Skmacy 2799167514Skmacy /* 2800167514Skmacy * Version scheme: 2801167514Skmacy * bits 0..9: chip version 2802167514Skmacy * bits 10..15: chip revision 2803167514Skmacy * bit 31: set for PCIe cards 2804167514Skmacy */ 2805167514Skmacy regs->version = 3 | (sc->params.rev << 10) | (is_pcie(sc) << 31); 2806167514Skmacy 2807167514Skmacy /* 2808167514Skmacy * We skip the MAC statistics registers because they are clear-on-read. 2809167514Skmacy * Also reading multi-register stats would need to synchronize with the 2810167514Skmacy * periodic mac stats accumulation. Hard to justify the complexity. 2811167514Skmacy */ 2812182679Skmacy memset(buf, 0, cxgb_get_regs_len()); 2813167514Skmacy reg_block_dump(sc, buf, 0, A_SG_RSPQ_CREDIT_RETURN); 2814167514Skmacy reg_block_dump(sc, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT); 2815167514Skmacy reg_block_dump(sc, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE); 2816167514Skmacy reg_block_dump(sc, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA); 2817167514Skmacy reg_block_dump(sc, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3); 2818167514Skmacy reg_block_dump(sc, buf, A_XGM_SERDES_STATUS0, 2819167514Skmacy XGM_REG(A_XGM_SERDES_STAT3, 1)); 2820167514Skmacy reg_block_dump(sc, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1), 2821167514Skmacy XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1)); 2822167514Skmacy} 2823176572Skmacy 2824176572Skmacy 2825176572SkmacyMODULE_DEPEND(if_cxgb, cxgb_t3fw, 1, 1, 1); 2826