1b6d90eb7SKip Macy /************************************************************************** 2b6d90eb7SKip Macy 3f2d8ff04SGeorge V. Neville-Neil Copyright (c) 2007-2009, Chelsio Inc. 4b6d90eb7SKip Macy All rights reserved. 5b6d90eb7SKip Macy 6b6d90eb7SKip Macy Redistribution and use in source and binary forms, with or without 7b6d90eb7SKip Macy modification, are permitted provided that the following conditions are met: 8b6d90eb7SKip Macy 9b6d90eb7SKip Macy 1. Redistributions of source code must retain the above copyright notice, 10b6d90eb7SKip Macy this list of conditions and the following disclaimer. 11b6d90eb7SKip Macy 12d722cab4SKip Macy 2. Neither the name of the Chelsio Corporation nor the names of its 13b6d90eb7SKip Macy contributors may be used to endorse or promote products derived from 14b6d90eb7SKip Macy this software without specific prior written permission. 15b6d90eb7SKip Macy 16b6d90eb7SKip Macy THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17b6d90eb7SKip Macy AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18b6d90eb7SKip Macy IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19b6d90eb7SKip Macy ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20b6d90eb7SKip Macy LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21b6d90eb7SKip Macy CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22b6d90eb7SKip Macy SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23b6d90eb7SKip Macy INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24b6d90eb7SKip Macy CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25b6d90eb7SKip Macy ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26b6d90eb7SKip Macy POSSIBILITY OF SUCH DAMAGE. 27b6d90eb7SKip Macy 28b6d90eb7SKip Macy ***************************************************************************/ 29b6d90eb7SKip Macy 30b6d90eb7SKip Macy #include <sys/cdefs.h> 31b6d90eb7SKip Macy __FBSDID("$FreeBSD$"); 32b6d90eb7SKip Macy 33b6d90eb7SKip Macy #include <sys/param.h> 34b6d90eb7SKip Macy #include <sys/systm.h> 35b6d90eb7SKip Macy #include <sys/kernel.h> 36b6d90eb7SKip Macy #include <sys/bus.h> 37b6d90eb7SKip Macy #include <sys/module.h> 38b6d90eb7SKip Macy #include <sys/pciio.h> 39b6d90eb7SKip Macy #include <sys/conf.h> 40b6d90eb7SKip Macy #include <machine/bus.h> 41b6d90eb7SKip Macy #include <machine/resource.h> 42b6d90eb7SKip Macy #include <sys/bus_dma.h> 438e10660fSKip Macy #include <sys/ktr.h> 44b6d90eb7SKip Macy #include <sys/rman.h> 45b6d90eb7SKip Macy #include <sys/ioccom.h> 46b6d90eb7SKip Macy #include <sys/mbuf.h> 47b6d90eb7SKip Macy #include <sys/linker.h> 48b6d90eb7SKip Macy #include <sys/firmware.h> 49b6d90eb7SKip Macy #include <sys/socket.h> 50b6d90eb7SKip Macy #include <sys/sockio.h> 51b6d90eb7SKip Macy #include <sys/smp.h> 52b6d90eb7SKip Macy #include <sys/sysctl.h> 538090c9f5SKip Macy #include <sys/syslog.h> 54b6d90eb7SKip Macy #include <sys/queue.h> 55b6d90eb7SKip Macy #include <sys/taskqueue.h> 568090c9f5SKip Macy #include <sys/proc.h> 57b6d90eb7SKip Macy 58b6d90eb7SKip Macy #include <net/bpf.h> 59b6d90eb7SKip Macy #include <net/ethernet.h> 60b6d90eb7SKip Macy #include <net/if.h> 61b6d90eb7SKip Macy #include <net/if_arp.h> 62b6d90eb7SKip Macy #include <net/if_dl.h> 63b6d90eb7SKip Macy #include <net/if_media.h> 64b6d90eb7SKip Macy #include <net/if_types.h> 654af83c8cSKip Macy #include <net/if_vlan_var.h> 66b6d90eb7SKip Macy 67b6d90eb7SKip Macy #include <netinet/in_systm.h> 68b6d90eb7SKip Macy #include <netinet/in.h> 69b6d90eb7SKip Macy #include <netinet/if_ether.h> 70b6d90eb7SKip Macy #include <netinet/ip.h> 71b6d90eb7SKip Macy #include <netinet/ip.h> 72b6d90eb7SKip Macy #include <netinet/tcp.h> 73b6d90eb7SKip Macy #include <netinet/udp.h> 74b6d90eb7SKip Macy 75b6d90eb7SKip Macy #include <dev/pci/pcireg.h> 76b6d90eb7SKip Macy #include <dev/pci/pcivar.h> 77b6d90eb7SKip Macy #include <dev/pci/pci_private.h> 78b6d90eb7SKip Macy 7910faa568SKip Macy #include <cxgb_include.h> 80b6d90eb7SKip Macy 81b6d90eb7SKip Macy #ifdef PRIV_SUPPORTED 82b6d90eb7SKip Macy #include <sys/priv.h> 83b6d90eb7SKip Macy #endif 84b6d90eb7SKip Macy 85b6d90eb7SKip Macy static int cxgb_setup_msix(adapter_t *, int); 86ef72318fSKip Macy static void cxgb_teardown_msix(adapter_t *); 87b6d90eb7SKip Macy static void cxgb_init(void *); 88b6d90eb7SKip Macy static void cxgb_init_locked(struct port_info *); 8977f07749SKip Macy static void cxgb_stop_locked(struct port_info *); 90b6d90eb7SKip Macy static void cxgb_set_rxmode(struct port_info *); 91b6d90eb7SKip Macy static int cxgb_ioctl(struct ifnet *, unsigned long, caddr_t); 92b6d90eb7SKip Macy static int cxgb_media_change(struct ifnet *); 93837f41b0SGeorge V. Neville-Neil static int cxgb_ifm_type(int); 94b6d90eb7SKip Macy static void cxgb_media_status(struct ifnet *, struct ifmediareq *); 95b6d90eb7SKip Macy static int setup_sge_qsets(adapter_t *); 96b6d90eb7SKip Macy static void cxgb_async_intr(void *); 97b6d90eb7SKip Macy static void cxgb_ext_intr_handler(void *, int); 98bb38cd2fSKip Macy static void cxgb_tick_handler(void *, int); 99bb38cd2fSKip Macy static void cxgb_down_locked(struct adapter *sc); 100b6d90eb7SKip Macy static void cxgb_tick(void *); 101b6d90eb7SKip Macy static void setup_rss(adapter_t *sc); 102b6d90eb7SKip Macy 103b6d90eb7SKip Macy /* Attachment glue for the PCI controller end of the device. Each port of 104b6d90eb7SKip Macy * the device is attached separately, as defined later. 105b6d90eb7SKip Macy */ 106b6d90eb7SKip Macy static int cxgb_controller_probe(device_t); 107b6d90eb7SKip Macy static int cxgb_controller_attach(device_t); 108b6d90eb7SKip Macy static int cxgb_controller_detach(device_t); 109b6d90eb7SKip Macy static void cxgb_free(struct adapter *); 110b6d90eb7SKip Macy static __inline void reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start, 111b6d90eb7SKip Macy unsigned int end); 1121ffd6e58SKip Macy static void cxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf); 113b6d90eb7SKip Macy static int cxgb_get_regs_len(void); 114d722cab4SKip Macy static int offload_open(struct port_info *pi); 1157ac2e6c3SKip Macy static void touch_bars(device_t dev); 1163e96c7e7SKip Macy static int offload_close(struct t3cdev *tdev); 1178e10660fSKip Macy static void cxgb_link_start(struct port_info *p); 118f2d8ff04SGeorge V. Neville-Neil static void cxgb_link_fault(void *arg, int ncount); 119b6d90eb7SKip Macy 120b6d90eb7SKip Macy static device_method_t cxgb_controller_methods[] = { 121b6d90eb7SKip Macy DEVMETHOD(device_probe, cxgb_controller_probe), 122b6d90eb7SKip Macy DEVMETHOD(device_attach, cxgb_controller_attach), 123b6d90eb7SKip Macy DEVMETHOD(device_detach, cxgb_controller_detach), 124b6d90eb7SKip Macy 125b6d90eb7SKip Macy /* bus interface */ 126b6d90eb7SKip Macy DEVMETHOD(bus_print_child, bus_generic_print_child), 127b6d90eb7SKip Macy DEVMETHOD(bus_driver_added, bus_generic_driver_added), 128b6d90eb7SKip Macy 129b6d90eb7SKip Macy { 0, 0 } 130b6d90eb7SKip Macy }; 131b6d90eb7SKip Macy 132b6d90eb7SKip Macy static driver_t cxgb_controller_driver = { 133b6d90eb7SKip Macy "cxgbc", 134b6d90eb7SKip Macy cxgb_controller_methods, 135b6d90eb7SKip Macy sizeof(struct adapter) 136b6d90eb7SKip Macy }; 137b6d90eb7SKip Macy 138b6d90eb7SKip Macy static devclass_t cxgb_controller_devclass; 139b6d90eb7SKip Macy DRIVER_MODULE(cxgbc, pci, cxgb_controller_driver, cxgb_controller_devclass, 0, 0); 140b6d90eb7SKip Macy 141b6d90eb7SKip Macy /* 142b6d90eb7SKip Macy * Attachment glue for the ports. Attachment is done directly to the 143b6d90eb7SKip Macy * controller device. 144b6d90eb7SKip Macy */ 145b6d90eb7SKip Macy static int cxgb_port_probe(device_t); 146b6d90eb7SKip Macy static int cxgb_port_attach(device_t); 147b6d90eb7SKip Macy static int cxgb_port_detach(device_t); 148b6d90eb7SKip Macy 149b6d90eb7SKip Macy static device_method_t cxgb_port_methods[] = { 150b6d90eb7SKip Macy DEVMETHOD(device_probe, cxgb_port_probe), 151b6d90eb7SKip Macy DEVMETHOD(device_attach, cxgb_port_attach), 152b6d90eb7SKip Macy DEVMETHOD(device_detach, cxgb_port_detach), 153b6d90eb7SKip Macy { 0, 0 } 154b6d90eb7SKip Macy }; 155b6d90eb7SKip Macy 156b6d90eb7SKip Macy static driver_t cxgb_port_driver = { 157b6d90eb7SKip Macy "cxgb", 158b6d90eb7SKip Macy cxgb_port_methods, 159b6d90eb7SKip Macy 0 160b6d90eb7SKip Macy }; 161b6d90eb7SKip Macy 162b6d90eb7SKip Macy static d_ioctl_t cxgb_extension_ioctl; 163ef72318fSKip Macy static d_open_t cxgb_extension_open; 164ef72318fSKip Macy static d_close_t cxgb_extension_close; 165ef72318fSKip Macy 166ef72318fSKip Macy static struct cdevsw cxgb_cdevsw = { 167ef72318fSKip Macy .d_version = D_VERSION, 168ef72318fSKip Macy .d_flags = 0, 169ef72318fSKip Macy .d_open = cxgb_extension_open, 170ef72318fSKip Macy .d_close = cxgb_extension_close, 171ef72318fSKip Macy .d_ioctl = cxgb_extension_ioctl, 172ef72318fSKip Macy .d_name = "cxgb", 173ef72318fSKip Macy }; 174b6d90eb7SKip Macy 175b6d90eb7SKip Macy static devclass_t cxgb_port_devclass; 176b6d90eb7SKip Macy DRIVER_MODULE(cxgb, cxgbc, cxgb_port_driver, cxgb_port_devclass, 0, 0); 177b6d90eb7SKip Macy 178b6d90eb7SKip Macy #define SGE_MSIX_COUNT (SGE_QSETS + 1) 179b6d90eb7SKip Macy 180b6d90eb7SKip Macy /* 181b6d90eb7SKip Macy * The driver uses the best interrupt scheme available on a platform in the 182b6d90eb7SKip Macy * order MSI-X, MSI, legacy pin interrupts. This parameter determines which 183b6d90eb7SKip Macy * of these schemes the driver may consider as follows: 184b6d90eb7SKip Macy * 185b6d90eb7SKip Macy * msi = 2: choose from among all three options 186b6d90eb7SKip Macy * msi = 1 : only consider MSI and pin interrupts 187b6d90eb7SKip Macy * msi = 0: force pin interrupts 188b6d90eb7SKip Macy */ 189693d746cSKip Macy static int msi_allowed = 2; 190cebf6b9fSKip Macy 191b6d90eb7SKip Macy TUNABLE_INT("hw.cxgb.msi_allowed", &msi_allowed); 192b6d90eb7SKip Macy SYSCTL_NODE(_hw, OID_AUTO, cxgb, CTLFLAG_RD, 0, "CXGB driver parameters"); 193b6d90eb7SKip Macy SYSCTL_UINT(_hw_cxgb, OID_AUTO, msi_allowed, CTLFLAG_RDTUN, &msi_allowed, 0, 194b6d90eb7SKip Macy "MSI-X, MSI, INTx selector"); 195d722cab4SKip Macy 19664c43db5SKip Macy /* 197d722cab4SKip Macy * The driver enables offload as a default. 198d722cab4SKip Macy * To disable it, use ofld_disable = 1. 199d722cab4SKip Macy */ 200d722cab4SKip Macy static int ofld_disable = 0; 201d722cab4SKip Macy TUNABLE_INT("hw.cxgb.ofld_disable", &ofld_disable); 202d722cab4SKip Macy SYSCTL_UINT(_hw_cxgb, OID_AUTO, ofld_disable, CTLFLAG_RDTUN, &ofld_disable, 0, 203d722cab4SKip Macy "disable ULP offload"); 204d722cab4SKip Macy 205d722cab4SKip Macy /* 206d722cab4SKip Macy * The driver uses an auto-queue algorithm by default. 207a02573bcSKip Macy * To disable it and force a single queue-set per port, use multiq = 0 20864c43db5SKip Macy */ 209a02573bcSKip Macy static int multiq = 1; 210a02573bcSKip Macy TUNABLE_INT("hw.cxgb.multiq", &multiq); 211a02573bcSKip Macy SYSCTL_UINT(_hw_cxgb, OID_AUTO, multiq, CTLFLAG_RDTUN, &multiq, 0, 212a02573bcSKip Macy "use min(ncpus/ports, 8) queue-sets per port"); 213f001b63dSKip Macy 214404825a7SKip Macy /* 215a02573bcSKip Macy * By default the driver will not update the firmware unless 216a02573bcSKip Macy * it was compiled against a newer version 217a02573bcSKip Macy * 218404825a7SKip Macy */ 219404825a7SKip Macy static int force_fw_update = 0; 220404825a7SKip Macy TUNABLE_INT("hw.cxgb.force_fw_update", &force_fw_update); 221404825a7SKip Macy SYSCTL_UINT(_hw_cxgb, OID_AUTO, force_fw_update, CTLFLAG_RDTUN, &force_fw_update, 0, 222404825a7SKip Macy "update firmware even if up to date"); 223f001b63dSKip Macy 224af9b081cSKip Macy int cxgb_use_16k_clusters = 1; 225f001b63dSKip Macy TUNABLE_INT("hw.cxgb.use_16k_clusters", &cxgb_use_16k_clusters); 226f001b63dSKip Macy SYSCTL_UINT(_hw_cxgb, OID_AUTO, use_16k_clusters, CTLFLAG_RDTUN, 227f001b63dSKip Macy &cxgb_use_16k_clusters, 0, "use 16kB clusters for the jumbo queue "); 228f001b63dSKip Macy 229b6d90eb7SKip Macy enum { 230b6d90eb7SKip Macy MAX_TXQ_ENTRIES = 16384, 231b6d90eb7SKip Macy MAX_CTRL_TXQ_ENTRIES = 1024, 232b6d90eb7SKip Macy MAX_RSPQ_ENTRIES = 16384, 233b6d90eb7SKip Macy MAX_RX_BUFFERS = 16384, 234b6d90eb7SKip Macy MAX_RX_JUMBO_BUFFERS = 16384, 235b6d90eb7SKip Macy MIN_TXQ_ENTRIES = 4, 236b6d90eb7SKip Macy MIN_CTRL_TXQ_ENTRIES = 4, 237b6d90eb7SKip Macy MIN_RSPQ_ENTRIES = 32, 2385c5df3daSKip Macy MIN_FL_ENTRIES = 32, 2395c5df3daSKip Macy MIN_FL_JUMBO_ENTRIES = 32 240b6d90eb7SKip Macy }; 241b6d90eb7SKip Macy 242ac3a6d9cSKip Macy struct filter_info { 243ac3a6d9cSKip Macy u32 sip; 244ac3a6d9cSKip Macy u32 sip_mask; 245ac3a6d9cSKip Macy u32 dip; 246ac3a6d9cSKip Macy u16 sport; 247ac3a6d9cSKip Macy u16 dport; 248ac3a6d9cSKip Macy u32 vlan:12; 249ac3a6d9cSKip Macy u32 vlan_prio:3; 250ac3a6d9cSKip Macy u32 mac_hit:1; 251ac3a6d9cSKip Macy u32 mac_idx:4; 252ac3a6d9cSKip Macy u32 mac_vld:1; 253ac3a6d9cSKip Macy u32 pkt_type:2; 254ac3a6d9cSKip Macy u32 report_filter_id:1; 255ac3a6d9cSKip Macy u32 pass:1; 256ac3a6d9cSKip Macy u32 rss:1; 257ac3a6d9cSKip Macy u32 qset:3; 258ac3a6d9cSKip Macy u32 locked:1; 259ac3a6d9cSKip Macy u32 valid:1; 260ac3a6d9cSKip Macy }; 261ac3a6d9cSKip Macy 262ac3a6d9cSKip Macy enum { FILTER_NO_VLAN_PRI = 7 }; 263ac3a6d9cSKip Macy 2641ffd6e58SKip Macy #define EEPROM_MAGIC 0x38E2F10C 2651ffd6e58SKip Macy 266b6d90eb7SKip Macy #define PORT_MASK ((1 << MAX_NPORTS) - 1) 267b6d90eb7SKip Macy 268b6d90eb7SKip Macy /* Table for probing the cards. The desc field isn't actually used */ 269b6d90eb7SKip Macy struct cxgb_ident { 270b6d90eb7SKip Macy uint16_t vendor; 271b6d90eb7SKip Macy uint16_t device; 272b6d90eb7SKip Macy int index; 273b6d90eb7SKip Macy char *desc; 274b6d90eb7SKip Macy } cxgb_identifiers[] = { 275b6d90eb7SKip Macy {PCI_VENDOR_ID_CHELSIO, 0x0020, 0, "PE9000"}, 276b6d90eb7SKip Macy {PCI_VENDOR_ID_CHELSIO, 0x0021, 1, "T302E"}, 277b6d90eb7SKip Macy {PCI_VENDOR_ID_CHELSIO, 0x0022, 2, "T310E"}, 278b6d90eb7SKip Macy {PCI_VENDOR_ID_CHELSIO, 0x0023, 3, "T320X"}, 279b6d90eb7SKip Macy {PCI_VENDOR_ID_CHELSIO, 0x0024, 1, "T302X"}, 280b6d90eb7SKip Macy {PCI_VENDOR_ID_CHELSIO, 0x0025, 3, "T320E"}, 281b6d90eb7SKip Macy {PCI_VENDOR_ID_CHELSIO, 0x0026, 2, "T310X"}, 282b6d90eb7SKip Macy {PCI_VENDOR_ID_CHELSIO, 0x0030, 2, "T3B10"}, 283b6d90eb7SKip Macy {PCI_VENDOR_ID_CHELSIO, 0x0031, 3, "T3B20"}, 284b6d90eb7SKip Macy {PCI_VENDOR_ID_CHELSIO, 0x0032, 1, "T3B02"}, 285ef72318fSKip Macy {PCI_VENDOR_ID_CHELSIO, 0x0033, 4, "T3B04"}, 2867f15419bSGeorge V. Neville-Neil {PCI_VENDOR_ID_CHELSIO, 0x0035, 6, "N310E"}, 287b6d90eb7SKip Macy {0, 0, 0, NULL} 288b6d90eb7SKip Macy }; 289b6d90eb7SKip Macy 290ac3a6d9cSKip Macy static int set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset); 291ac3a6d9cSKip Macy 2928e10660fSKip Macy 2938090c9f5SKip Macy static __inline char 294ac3a6d9cSKip Macy t3rev2char(struct adapter *adapter) 295ac3a6d9cSKip Macy { 296ac3a6d9cSKip Macy char rev = 'z'; 297ac3a6d9cSKip Macy 298ac3a6d9cSKip Macy switch(adapter->params.rev) { 299ac3a6d9cSKip Macy case T3_REV_A: 300ac3a6d9cSKip Macy rev = 'a'; 301ac3a6d9cSKip Macy break; 302ac3a6d9cSKip Macy case T3_REV_B: 303ac3a6d9cSKip Macy case T3_REV_B2: 304ac3a6d9cSKip Macy rev = 'b'; 305ac3a6d9cSKip Macy break; 306ac3a6d9cSKip Macy case T3_REV_C: 307ac3a6d9cSKip Macy rev = 'c'; 308ac3a6d9cSKip Macy break; 309ac3a6d9cSKip Macy } 310ac3a6d9cSKip Macy return rev; 311ac3a6d9cSKip Macy } 312ac3a6d9cSKip Macy 313b6d90eb7SKip Macy static struct cxgb_ident * 314b6d90eb7SKip Macy cxgb_get_ident(device_t dev) 315b6d90eb7SKip Macy { 316b6d90eb7SKip Macy struct cxgb_ident *id; 317b6d90eb7SKip Macy 318b6d90eb7SKip Macy for (id = cxgb_identifiers; id->desc != NULL; id++) { 319b6d90eb7SKip Macy if ((id->vendor == pci_get_vendor(dev)) && 320b6d90eb7SKip Macy (id->device == pci_get_device(dev))) { 321b6d90eb7SKip Macy return (id); 322b6d90eb7SKip Macy } 323b6d90eb7SKip Macy } 324b6d90eb7SKip Macy return (NULL); 325b6d90eb7SKip Macy } 326b6d90eb7SKip Macy 327b6d90eb7SKip Macy static const struct adapter_info * 328b6d90eb7SKip Macy cxgb_get_adapter_info(device_t dev) 329b6d90eb7SKip Macy { 330b6d90eb7SKip Macy struct cxgb_ident *id; 331b6d90eb7SKip Macy const struct adapter_info *ai; 332b6d90eb7SKip Macy 333b6d90eb7SKip Macy id = cxgb_get_ident(dev); 334b6d90eb7SKip Macy if (id == NULL) 335b6d90eb7SKip Macy return (NULL); 336b6d90eb7SKip Macy 337b6d90eb7SKip Macy ai = t3_get_adapter_info(id->index); 338b6d90eb7SKip Macy 339b6d90eb7SKip Macy return (ai); 340b6d90eb7SKip Macy } 341b6d90eb7SKip Macy 342b6d90eb7SKip Macy static int 343b6d90eb7SKip Macy cxgb_controller_probe(device_t dev) 344b6d90eb7SKip Macy { 345b6d90eb7SKip Macy const struct adapter_info *ai; 346b6d90eb7SKip Macy char *ports, buf[80]; 347ef72318fSKip Macy int nports; 3486eb15755SKip Macy struct adapter *sc = device_get_softc(dev); 349b6d90eb7SKip Macy 350b6d90eb7SKip Macy ai = cxgb_get_adapter_info(dev); 351b6d90eb7SKip Macy if (ai == NULL) 352b6d90eb7SKip Macy return (ENXIO); 353b6d90eb7SKip Macy 354ef72318fSKip Macy nports = ai->nports0 + ai->nports1; 355ef72318fSKip Macy if (nports == 1) 356b6d90eb7SKip Macy ports = "port"; 357b6d90eb7SKip Macy else 358b6d90eb7SKip Macy ports = "ports"; 359b6d90eb7SKip Macy 3606eb15755SKip Macy snprintf(buf, sizeof(buf), "%s %sNIC, rev: %d nports: %d %s", 3616eb15755SKip Macy ai->desc, is_offload(sc) ? "R" : "", 3626eb15755SKip Macy sc->params.rev, nports, ports); 363b6d90eb7SKip Macy device_set_desc_copy(dev, buf); 364b6d90eb7SKip Macy return (BUS_PROBE_DEFAULT); 365b6d90eb7SKip Macy } 366b6d90eb7SKip Macy 367404825a7SKip Macy #define FW_FNAME "cxgb_t3fw" 368f2d8ff04SGeorge V. Neville-Neil #define TPEEPROM_NAME "t3%c_tp_eeprom" 369f2d8ff04SGeorge V. Neville-Neil #define TPSRAM_NAME "t3%c_protocol_sram" 370ac3a6d9cSKip Macy 371b6d90eb7SKip Macy static int 372d722cab4SKip Macy upgrade_fw(adapter_t *sc) 373b6d90eb7SKip Macy { 374b6d90eb7SKip Macy #ifdef FIRMWARE_LATEST 375b6d90eb7SKip Macy const struct firmware *fw; 376b6d90eb7SKip Macy #else 377b6d90eb7SKip Macy struct firmware *fw; 378b6d90eb7SKip Macy #endif 379b6d90eb7SKip Macy int status; 380b6d90eb7SKip Macy 381404825a7SKip Macy if ((fw = firmware_get(FW_FNAME)) == NULL) { 382404825a7SKip Macy device_printf(sc->dev, "Could not find firmware image %s\n", FW_FNAME); 383d722cab4SKip Macy return (ENOENT); 384ac3a6d9cSKip Macy } else 385404825a7SKip Macy device_printf(sc->dev, "updating firmware on card\n"); 386b6d90eb7SKip Macy status = t3_load_fw(sc, (const uint8_t *)fw->data, fw->datasize); 387b6d90eb7SKip Macy 388ac3a6d9cSKip Macy device_printf(sc->dev, "firmware update returned %s %d\n", (status == 0) ? "success" : "fail", status); 389ac3a6d9cSKip Macy 390b6d90eb7SKip Macy firmware_put(fw, FIRMWARE_UNLOAD); 391b6d90eb7SKip Macy 392b6d90eb7SKip Macy return (status); 393b6d90eb7SKip Macy } 394b6d90eb7SKip Macy 395b6d90eb7SKip Macy static int 396b6d90eb7SKip Macy cxgb_controller_attach(device_t dev) 397b6d90eb7SKip Macy { 398b6d90eb7SKip Macy device_t child; 399b6d90eb7SKip Macy const struct adapter_info *ai; 400b6d90eb7SKip Macy struct adapter *sc; 4012de1fa86SKip Macy int i, error = 0; 402b6d90eb7SKip Macy uint32_t vers; 403693d746cSKip Macy int port_qsets = 1; 4047aff6d8eSKip Macy #ifdef MSI_SUPPORTED 4052de1fa86SKip Macy int msi_needed, reg; 4067aff6d8eSKip Macy #endif 4075197f3abSGeorge V. Neville-Neil char buf[80]; 4085197f3abSGeorge V. Neville-Neil 409b6d90eb7SKip Macy sc = device_get_softc(dev); 410b6d90eb7SKip Macy sc->dev = dev; 411d722cab4SKip Macy sc->msi_count = 0; 4122de1fa86SKip Macy ai = cxgb_get_adapter_info(dev); 413b6d90eb7SKip Macy 4142de1fa86SKip Macy /* 4152de1fa86SKip Macy * XXX not really related but a recent addition 4162de1fa86SKip Macy */ 4172de1fa86SKip Macy #ifdef MSI_SUPPORTED 418fc01c613SKip Macy /* find the PCIe link width and set max read request to 4KB*/ 419fc01c613SKip Macy if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 420fc01c613SKip Macy uint16_t lnk, pectl; 421fc01c613SKip Macy lnk = pci_read_config(dev, reg + 0x12, 2); 422fc01c613SKip Macy sc->link_width = (lnk >> 4) & 0x3f; 423fc01c613SKip Macy 424fc01c613SKip Macy pectl = pci_read_config(dev, reg + 0x8, 2); 425fc01c613SKip Macy pectl = (pectl & ~0x7000) | (5 << 12); 426fc01c613SKip Macy pci_write_config(dev, reg + 0x8, pectl, 2); 427fc01c613SKip Macy } 428ac3a6d9cSKip Macy 429ac3a6d9cSKip Macy if (sc->link_width != 0 && sc->link_width <= 4 && 430ac3a6d9cSKip Macy (ai->nports0 + ai->nports1) <= 2) { 431fc01c613SKip Macy device_printf(sc->dev, 432ac6b4cf1SKip Macy "PCIe x%d Link, expect reduced performance\n", 433fc01c613SKip Macy sc->link_width); 434fc01c613SKip Macy } 4352de1fa86SKip Macy #endif 4367ac2e6c3SKip Macy touch_bars(dev); 437b6d90eb7SKip Macy pci_enable_busmaster(dev); 438b6d90eb7SKip Macy /* 439b6d90eb7SKip Macy * Allocate the registers and make them available to the driver. 440b6d90eb7SKip Macy * The registers that we care about for NIC mode are in BAR 0 441b6d90eb7SKip Macy */ 442b6d90eb7SKip Macy sc->regs_rid = PCIR_BAR(0); 443b6d90eb7SKip Macy if ((sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 444b6d90eb7SKip Macy &sc->regs_rid, RF_ACTIVE)) == NULL) { 4458e10660fSKip Macy device_printf(dev, "Cannot allocate BAR region 0\n"); 446b6d90eb7SKip Macy return (ENXIO); 447b6d90eb7SKip Macy } 4488e10660fSKip Macy sc->udbs_rid = PCIR_BAR(2); 4497f15419bSGeorge V. Neville-Neil sc->udbs_res = NULL; 4507f15419bSGeorge V. Neville-Neil if (is_offload(sc) && 4517f15419bSGeorge V. Neville-Neil ((sc->udbs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 4527f15419bSGeorge V. Neville-Neil &sc->udbs_rid, RF_ACTIVE)) == NULL)) { 4538e10660fSKip Macy device_printf(dev, "Cannot allocate BAR region 1\n"); 4548e10660fSKip Macy error = ENXIO; 4558e10660fSKip Macy goto out; 4568e10660fSKip Macy } 457b6d90eb7SKip Macy 458bb38cd2fSKip Macy snprintf(sc->lockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb controller lock %d", 459bb38cd2fSKip Macy device_get_unit(dev)); 460bb38cd2fSKip Macy ADAPTER_LOCK_INIT(sc, sc->lockbuf); 461bb38cd2fSKip Macy 462bb38cd2fSKip Macy snprintf(sc->reglockbuf, ADAPTER_LOCK_NAME_LEN, "SGE reg lock %d", 463bb38cd2fSKip Macy device_get_unit(dev)); 464bb38cd2fSKip Macy snprintf(sc->mdiolockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb mdio lock %d", 465bb38cd2fSKip Macy device_get_unit(dev)); 466bb38cd2fSKip Macy snprintf(sc->elmerlockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb elmer lock %d", 467bb38cd2fSKip Macy device_get_unit(dev)); 468bb38cd2fSKip Macy 4698e10660fSKip Macy MTX_INIT(&sc->sge.reg_lock, sc->reglockbuf, NULL, MTX_SPIN); 470bb38cd2fSKip Macy MTX_INIT(&sc->mdio_lock, sc->mdiolockbuf, NULL, MTX_DEF); 471bb38cd2fSKip Macy MTX_INIT(&sc->elmer_lock, sc->elmerlockbuf, NULL, MTX_DEF); 472b6d90eb7SKip Macy 473b6d90eb7SKip Macy sc->bt = rman_get_bustag(sc->regs_res); 474b6d90eb7SKip Macy sc->bh = rman_get_bushandle(sc->regs_res); 475b6d90eb7SKip Macy sc->mmio_len = rman_get_size(sc->regs_res); 476b6d90eb7SKip Macy 47724cdd067SKip Macy if (t3_prep_adapter(sc, ai, 1) < 0) { 478ef72318fSKip Macy printf("prep adapter failed\n"); 47924cdd067SKip Macy error = ENODEV; 48024cdd067SKip Macy goto out; 48124cdd067SKip Macy } 482b6d90eb7SKip Macy /* Allocate the BAR for doing MSI-X. If it succeeds, try to allocate 483b6d90eb7SKip Macy * enough messages for the queue sets. If that fails, try falling 484b6d90eb7SKip Macy * back to MSI. If that fails, then try falling back to the legacy 485b6d90eb7SKip Macy * interrupt pin model. 486b6d90eb7SKip Macy */ 487b6d90eb7SKip Macy #ifdef MSI_SUPPORTED 488693d746cSKip Macy 489b6d90eb7SKip Macy sc->msix_regs_rid = 0x20; 490b6d90eb7SKip Macy if ((msi_allowed >= 2) && 491b6d90eb7SKip Macy (sc->msix_regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 492b6d90eb7SKip Macy &sc->msix_regs_rid, RF_ACTIVE)) != NULL) { 493b6d90eb7SKip Macy 494d722cab4SKip Macy msi_needed = sc->msi_count = SGE_MSIX_COUNT; 495693d746cSKip Macy 496d722cab4SKip Macy if (((error = pci_alloc_msix(dev, &sc->msi_count)) != 0) || 497d722cab4SKip Macy (sc->msi_count != msi_needed)) { 498d722cab4SKip Macy device_printf(dev, "msix allocation failed - msi_count = %d" 499d722cab4SKip Macy " msi_needed=%d will try msi err=%d\n", sc->msi_count, 500d722cab4SKip Macy msi_needed, error); 501d722cab4SKip Macy sc->msi_count = 0; 502b6d90eb7SKip Macy pci_release_msi(dev); 503b6d90eb7SKip Macy bus_release_resource(dev, SYS_RES_MEMORY, 504b6d90eb7SKip Macy sc->msix_regs_rid, sc->msix_regs_res); 505b6d90eb7SKip Macy sc->msix_regs_res = NULL; 506b6d90eb7SKip Macy } else { 507b6d90eb7SKip Macy sc->flags |= USING_MSIX; 508f0a542f8SKip Macy sc->cxgb_intr = t3_intr_msix; 509b6d90eb7SKip Macy } 510b6d90eb7SKip Macy } 511b6d90eb7SKip Macy 512d722cab4SKip Macy if ((msi_allowed >= 1) && (sc->msi_count == 0)) { 513d722cab4SKip Macy sc->msi_count = 1; 514d722cab4SKip Macy if (pci_alloc_msi(dev, &sc->msi_count)) { 515693d746cSKip Macy device_printf(dev, "alloc msi failed - will try INTx\n"); 516d722cab4SKip Macy sc->msi_count = 0; 517b6d90eb7SKip Macy pci_release_msi(dev); 518b6d90eb7SKip Macy } else { 519b6d90eb7SKip Macy sc->flags |= USING_MSI; 520b6d90eb7SKip Macy sc->irq_rid = 1; 521f0a542f8SKip Macy sc->cxgb_intr = t3_intr_msi; 522b6d90eb7SKip Macy } 523b6d90eb7SKip Macy } 524b6d90eb7SKip Macy #endif 525d722cab4SKip Macy if (sc->msi_count == 0) { 526693d746cSKip Macy device_printf(dev, "using line interrupts\n"); 527b6d90eb7SKip Macy sc->irq_rid = 0; 528f0a542f8SKip Macy sc->cxgb_intr = t3b_intr; 529b6d90eb7SKip Macy } 530b6d90eb7SKip Macy 531a02573bcSKip Macy if ((sc->flags & USING_MSIX) && multiq) 532f705d735SKip Macy port_qsets = min((SGE_QSETS/(sc)->params.nports), mp_ncpus); 533b6d90eb7SKip Macy 534b6d90eb7SKip Macy /* Create a private taskqueue thread for handling driver events */ 535b6d90eb7SKip Macy #ifdef TASKQUEUE_CURRENT 536b6d90eb7SKip Macy sc->tq = taskqueue_create("cxgb_taskq", M_NOWAIT, 537b6d90eb7SKip Macy taskqueue_thread_enqueue, &sc->tq); 538b6d90eb7SKip Macy #else 539b6d90eb7SKip Macy sc->tq = taskqueue_create_fast("cxgb_taskq", M_NOWAIT, 540b6d90eb7SKip Macy taskqueue_thread_enqueue, &sc->tq); 541b6d90eb7SKip Macy #endif 542b6d90eb7SKip Macy if (sc->tq == NULL) { 543b6d90eb7SKip Macy device_printf(dev, "failed to allocate controller task queue\n"); 544b6d90eb7SKip Macy goto out; 545b6d90eb7SKip Macy } 546b6d90eb7SKip Macy 547b6d90eb7SKip Macy taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq", 548b6d90eb7SKip Macy device_get_nameunit(dev)); 549b6d90eb7SKip Macy TASK_INIT(&sc->ext_intr_task, 0, cxgb_ext_intr_handler, sc); 550bb38cd2fSKip Macy TASK_INIT(&sc->tick_task, 0, cxgb_tick_handler, sc); 551b6d90eb7SKip Macy 552b6d90eb7SKip Macy 553b6d90eb7SKip Macy /* Create a periodic callout for checking adapter status */ 554bb38cd2fSKip Macy callout_init(&sc->cxgb_tick_ch, TRUE); 555b6d90eb7SKip Macy 556f2d8ff04SGeorge V. Neville-Neil if (t3_check_fw_version(sc) < 0 || force_fw_update) { 557b6d90eb7SKip Macy /* 558b6d90eb7SKip Macy * Warn user that a firmware update will be attempted in init. 559b6d90eb7SKip Macy */ 560d722cab4SKip Macy device_printf(dev, "firmware needs to be updated to version %d.%d.%d\n", 561d722cab4SKip Macy FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO); 562b6d90eb7SKip Macy sc->flags &= ~FW_UPTODATE; 563b6d90eb7SKip Macy } else { 564b6d90eb7SKip Macy sc->flags |= FW_UPTODATE; 565b6d90eb7SKip Macy } 566b6d90eb7SKip Macy 567f2d8ff04SGeorge V. Neville-Neil if (t3_check_tpsram_version(sc) < 0) { 568ac3a6d9cSKip Macy /* 569ac3a6d9cSKip Macy * Warn user that a firmware update will be attempted in init. 570ac3a6d9cSKip Macy */ 571ac3a6d9cSKip Macy device_printf(dev, "SRAM needs to be updated to version %c-%d.%d.%d\n", 572ac3a6d9cSKip Macy t3rev2char(sc), TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); 573ac3a6d9cSKip Macy sc->flags &= ~TPS_UPTODATE; 574ac3a6d9cSKip Macy } else { 575ac3a6d9cSKip Macy sc->flags |= TPS_UPTODATE; 576ac3a6d9cSKip Macy } 577ac3a6d9cSKip Macy 578b6d90eb7SKip Macy /* 579b6d90eb7SKip Macy * Create a child device for each MAC. The ethernet attachment 580b6d90eb7SKip Macy * will be done in these children. 581b6d90eb7SKip Macy */ 582693d746cSKip Macy for (i = 0; i < (sc)->params.nports; i++) { 5837ac2e6c3SKip Macy struct port_info *pi; 5847ac2e6c3SKip Macy 585b6d90eb7SKip Macy if ((child = device_add_child(dev, "cxgb", -1)) == NULL) { 586b6d90eb7SKip Macy device_printf(dev, "failed to add child port\n"); 587b6d90eb7SKip Macy error = EINVAL; 588b6d90eb7SKip Macy goto out; 589b6d90eb7SKip Macy } 5907ac2e6c3SKip Macy pi = &sc->port[i]; 5917ac2e6c3SKip Macy pi->adapter = sc; 5927ac2e6c3SKip Macy pi->nqsets = port_qsets; 5937ac2e6c3SKip Macy pi->first_qset = i*port_qsets; 5947ac2e6c3SKip Macy pi->port_id = i; 5957ac2e6c3SKip Macy pi->tx_chan = i >= ai->nports0; 5967ac2e6c3SKip Macy pi->txpkt_intf = pi->tx_chan ? 2 * (i - ai->nports0) + 1 : 2 * i; 5977ac2e6c3SKip Macy sc->rxpkt_map[pi->txpkt_intf] = i; 5988090c9f5SKip Macy sc->port[i].tx_chan = i >= ai->nports0; 599ac3a6d9cSKip Macy sc->portdev[i] = child; 6007ac2e6c3SKip Macy device_set_softc(child, pi); 601b6d90eb7SKip Macy } 602b6d90eb7SKip Macy if ((error = bus_generic_attach(dev)) != 0) 603b6d90eb7SKip Macy goto out; 604b6d90eb7SKip Macy 605b6d90eb7SKip Macy /* initialize sge private state */ 606ef72318fSKip Macy t3_sge_init_adapter(sc); 607b6d90eb7SKip Macy 608b6d90eb7SKip Macy t3_led_ready(sc); 609b6d90eb7SKip Macy 610d722cab4SKip Macy cxgb_offload_init(); 611d722cab4SKip Macy if (is_offload(sc)) { 612d722cab4SKip Macy setbit(&sc->registered_device_map, OFFLOAD_DEVMAP_BIT); 613d722cab4SKip Macy cxgb_adapter_ofld(sc); 614d722cab4SKip Macy } 615b6d90eb7SKip Macy error = t3_get_fw_version(sc, &vers); 616b6d90eb7SKip Macy if (error) 617b6d90eb7SKip Macy goto out; 618b6d90eb7SKip Macy 619d722cab4SKip Macy snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d.%d", 620d722cab4SKip Macy G_FW_VERSION_MAJOR(vers), G_FW_VERSION_MINOR(vers), 621d722cab4SKip Macy G_FW_VERSION_MICRO(vers)); 622b6d90eb7SKip Macy 6235197f3abSGeorge V. Neville-Neil snprintf(buf, sizeof(buf), "%s\t E/C: %s S/N: %s", 6245197f3abSGeorge V. Neville-Neil ai->desc, 6255197f3abSGeorge V. Neville-Neil sc->params.vpd.ec, sc->params.vpd.sn); 6265197f3abSGeorge V. Neville-Neil device_set_desc_copy(dev, buf); 6275197f3abSGeorge V. Neville-Neil 6288e10660fSKip Macy device_printf(sc->dev, "Firmware Version %s\n", &sc->fw_version[0]); 629706cb31fSKip Macy callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc); 6308090c9f5SKip Macy t3_add_attach_sysctls(sc); 631b6d90eb7SKip Macy out: 632b6d90eb7SKip Macy if (error) 633b6d90eb7SKip Macy cxgb_free(sc); 634b6d90eb7SKip Macy 635b6d90eb7SKip Macy return (error); 636b6d90eb7SKip Macy } 637b6d90eb7SKip Macy 638b6d90eb7SKip Macy static int 639b6d90eb7SKip Macy cxgb_controller_detach(device_t dev) 640b6d90eb7SKip Macy { 641b6d90eb7SKip Macy struct adapter *sc; 642b6d90eb7SKip Macy 643b6d90eb7SKip Macy sc = device_get_softc(dev); 644b6d90eb7SKip Macy 645b6d90eb7SKip Macy cxgb_free(sc); 646b6d90eb7SKip Macy 647b6d90eb7SKip Macy return (0); 648b6d90eb7SKip Macy } 649b6d90eb7SKip Macy 650b6d90eb7SKip Macy static void 651b6d90eb7SKip Macy cxgb_free(struct adapter *sc) 652b6d90eb7SKip Macy { 653b6d90eb7SKip Macy int i; 654b6d90eb7SKip Macy 6558e10660fSKip Macy ADAPTER_LOCK(sc); 6568e10660fSKip Macy sc->flags |= CXGB_SHUTDOWN; 6578e10660fSKip Macy ADAPTER_UNLOCK(sc); 6588090c9f5SKip Macy cxgb_pcpu_shutdown_threads(sc); 659bb38cd2fSKip Macy ADAPTER_LOCK(sc); 6608e10660fSKip Macy 661bb38cd2fSKip Macy /* 662bb38cd2fSKip Macy * drops the lock 663bb38cd2fSKip Macy */ 664bb38cd2fSKip Macy cxgb_down_locked(sc); 665d722cab4SKip Macy 666d722cab4SKip Macy #ifdef MSI_SUPPORTED 667d722cab4SKip Macy if (sc->flags & (USING_MSI | USING_MSIX)) { 668d722cab4SKip Macy device_printf(sc->dev, "releasing msi message(s)\n"); 669d722cab4SKip Macy pci_release_msi(sc->dev); 670d722cab4SKip Macy } else { 671d722cab4SKip Macy device_printf(sc->dev, "no msi message to release\n"); 672d722cab4SKip Macy } 673d722cab4SKip Macy #endif 674d722cab4SKip Macy if (sc->msix_regs_res != NULL) { 675d722cab4SKip Macy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid, 676d722cab4SKip Macy sc->msix_regs_res); 677d722cab4SKip Macy } 678d722cab4SKip Macy 6797ac2e6c3SKip Macy t3_sge_deinit_sw(sc); 6807ac2e6c3SKip Macy /* 6817ac2e6c3SKip Macy * Wait for last callout 6827ac2e6c3SKip Macy */ 683b6d90eb7SKip Macy 6848090c9f5SKip Macy DELAY(hz*100); 685bb38cd2fSKip Macy 686693d746cSKip Macy for (i = 0; i < (sc)->params.nports; ++i) { 687693d746cSKip Macy if (sc->portdev[i] != NULL) 688693d746cSKip Macy device_delete_child(sc->dev, sc->portdev[i]); 689693d746cSKip Macy } 690b6d90eb7SKip Macy 691b6d90eb7SKip Macy bus_generic_detach(sc->dev); 6928e10660fSKip Macy if (sc->tq != NULL) { 6937ac2e6c3SKip Macy taskqueue_free(sc->tq); 6948e10660fSKip Macy sc->tq = NULL; 6958e10660fSKip Macy } 6968e10660fSKip Macy 697d722cab4SKip Macy if (is_offload(sc)) { 698d722cab4SKip Macy cxgb_adapter_unofld(sc); 699d722cab4SKip Macy if (isset(&sc->open_device_map, OFFLOAD_DEVMAP_BIT)) 700d722cab4SKip Macy offload_close(&sc->tdev); 7018090c9f5SKip Macy else 7028090c9f5SKip Macy printf("cxgb_free: DEVMAP_BIT not set\n"); 7038090c9f5SKip Macy } else 7048090c9f5SKip Macy printf("not offloading set\n"); 70546b0a854SKip Macy #ifdef notyet 7068e10660fSKip Macy if (sc->flags & CXGB_OFLD_INIT) 7078e10660fSKip Macy cxgb_offload_deactivate(sc); 70846b0a854SKip Macy #endif 709ac3a6d9cSKip Macy free(sc->filters, M_DEVBUF); 710b6d90eb7SKip Macy t3_sge_free(sc); 711b6d90eb7SKip Macy 712bb38cd2fSKip Macy cxgb_offload_exit(); 713bb38cd2fSKip Macy 7148e10660fSKip Macy if (sc->udbs_res != NULL) 7158e10660fSKip Macy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->udbs_rid, 7168e10660fSKip Macy sc->udbs_res); 7178e10660fSKip Macy 718b6d90eb7SKip Macy if (sc->regs_res != NULL) 719b6d90eb7SKip Macy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->regs_rid, 720b6d90eb7SKip Macy sc->regs_res); 721b6d90eb7SKip Macy 722bb38cd2fSKip Macy MTX_DESTROY(&sc->mdio_lock); 723bb38cd2fSKip Macy MTX_DESTROY(&sc->sge.reg_lock); 724bb38cd2fSKip Macy MTX_DESTROY(&sc->elmer_lock); 725bb38cd2fSKip Macy ADAPTER_LOCK_DEINIT(sc); 726b6d90eb7SKip Macy } 727b6d90eb7SKip Macy 728b6d90eb7SKip Macy /** 729b6d90eb7SKip Macy * setup_sge_qsets - configure SGE Tx/Rx/response queues 730b6d90eb7SKip Macy * @sc: the controller softc 731b6d90eb7SKip Macy * 732b6d90eb7SKip Macy * Determines how many sets of SGE queues to use and initializes them. 733b6d90eb7SKip Macy * We support multiple queue sets per port if we have MSI-X, otherwise 734b6d90eb7SKip Macy * just one queue set per port. 735b6d90eb7SKip Macy */ 736b6d90eb7SKip Macy static int 737b6d90eb7SKip Macy setup_sge_qsets(adapter_t *sc) 738b6d90eb7SKip Macy { 7395c5df3daSKip Macy int i, j, err, irq_idx = 0, qset_idx = 0; 740d722cab4SKip Macy u_int ntxq = SGE_TXQ_PER_SET; 741b6d90eb7SKip Macy 742b6d90eb7SKip Macy if ((err = t3_sge_alloc(sc)) != 0) { 743693d746cSKip Macy device_printf(sc->dev, "t3_sge_alloc returned %d\n", err); 744b6d90eb7SKip Macy return (err); 745b6d90eb7SKip Macy } 746b6d90eb7SKip Macy 747b6d90eb7SKip Macy if (sc->params.rev > 0 && !(sc->flags & USING_MSI)) 748b6d90eb7SKip Macy irq_idx = -1; 749b6d90eb7SKip Macy 7505c5df3daSKip Macy for (i = 0; i < (sc)->params.nports; i++) { 751b6d90eb7SKip Macy struct port_info *pi = &sc->port[i]; 752b6d90eb7SKip Macy 7537ac2e6c3SKip Macy for (j = 0; j < pi->nqsets; j++, qset_idx++) { 754693d746cSKip Macy err = t3_sge_alloc_qset(sc, qset_idx, (sc)->params.nports, 755b6d90eb7SKip Macy (sc->flags & USING_MSIX) ? qset_idx + 1 : irq_idx, 756b6d90eb7SKip Macy &sc->params.sge.qset[qset_idx], ntxq, pi); 757b6d90eb7SKip Macy if (err) { 758b6d90eb7SKip Macy t3_free_sge_resources(sc); 7597ac2e6c3SKip Macy device_printf(sc->dev, "t3_sge_alloc_qset failed with %d\n", 7607ac2e6c3SKip Macy err); 761b6d90eb7SKip Macy return (err); 762b6d90eb7SKip Macy } 763b6d90eb7SKip Macy } 764b6d90eb7SKip Macy } 765b6d90eb7SKip Macy 766b6d90eb7SKip Macy return (0); 767b6d90eb7SKip Macy } 768b6d90eb7SKip Macy 769ef72318fSKip Macy static void 770ef72318fSKip Macy cxgb_teardown_msix(adapter_t *sc) 771ef72318fSKip Macy { 772ef72318fSKip Macy int i, nqsets; 773ef72318fSKip Macy 774ef72318fSKip Macy for (nqsets = i = 0; i < (sc)->params.nports; i++) 775ef72318fSKip Macy nqsets += sc->port[i].nqsets; 776ef72318fSKip Macy 777ef72318fSKip Macy for (i = 0; i < nqsets; i++) { 778ef72318fSKip Macy if (sc->msix_intr_tag[i] != NULL) { 779ef72318fSKip Macy bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 780ef72318fSKip Macy sc->msix_intr_tag[i]); 781ef72318fSKip Macy sc->msix_intr_tag[i] = NULL; 782ef72318fSKip Macy } 783ef72318fSKip Macy if (sc->msix_irq_res[i] != NULL) { 784ef72318fSKip Macy bus_release_resource(sc->dev, SYS_RES_IRQ, 785ef72318fSKip Macy sc->msix_irq_rid[i], sc->msix_irq_res[i]); 786ef72318fSKip Macy sc->msix_irq_res[i] = NULL; 787ef72318fSKip Macy } 788ef72318fSKip Macy } 789ef72318fSKip Macy } 790ef72318fSKip Macy 791b6d90eb7SKip Macy static int 792b6d90eb7SKip Macy cxgb_setup_msix(adapter_t *sc, int msix_count) 793b6d90eb7SKip Macy { 794b6d90eb7SKip Macy int i, j, k, nqsets, rid; 795b6d90eb7SKip Macy 796b6d90eb7SKip Macy /* The first message indicates link changes and error conditions */ 797b6d90eb7SKip Macy sc->irq_rid = 1; 798b6d90eb7SKip Macy if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 799b6d90eb7SKip Macy &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 800b6d90eb7SKip Macy device_printf(sc->dev, "Cannot allocate msix interrupt\n"); 801b6d90eb7SKip Macy return (EINVAL); 802b6d90eb7SKip Macy } 803693d746cSKip Macy 804b6d90eb7SKip Macy if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET, 805b6d90eb7SKip Macy #ifdef INTR_FILTERS 806b6d90eb7SKip Macy NULL, 807b6d90eb7SKip Macy #endif 808b6d90eb7SKip Macy cxgb_async_intr, sc, &sc->intr_tag)) { 809b6d90eb7SKip Macy device_printf(sc->dev, "Cannot set up interrupt\n"); 810b6d90eb7SKip Macy return (EINVAL); 811b6d90eb7SKip Macy } 812ef72318fSKip Macy for (i = k = 0; i < (sc)->params.nports; i++) { 813b6d90eb7SKip Macy nqsets = sc->port[i].nqsets; 814ef72318fSKip Macy for (j = 0; j < nqsets; j++, k++) { 815b6d90eb7SKip Macy struct sge_qset *qs = &sc->sge.qs[k]; 816b6d90eb7SKip Macy 817b6d90eb7SKip Macy rid = k + 2; 818b6d90eb7SKip Macy if (cxgb_debug) 819b6d90eb7SKip Macy printf("rid=%d ", rid); 820b6d90eb7SKip Macy if ((sc->msix_irq_res[k] = bus_alloc_resource_any( 821b6d90eb7SKip Macy sc->dev, SYS_RES_IRQ, &rid, 822b6d90eb7SKip Macy RF_SHAREABLE | RF_ACTIVE)) == NULL) { 823b6d90eb7SKip Macy device_printf(sc->dev, "Cannot allocate " 824b6d90eb7SKip Macy "interrupt for message %d\n", rid); 825b6d90eb7SKip Macy return (EINVAL); 826b6d90eb7SKip Macy } 827b6d90eb7SKip Macy sc->msix_irq_rid[k] = rid; 828ef72318fSKip Macy if (bus_setup_intr(sc->dev, sc->msix_irq_res[k], 829b6d90eb7SKip Macy INTR_MPSAFE|INTR_TYPE_NET, 830b6d90eb7SKip Macy #ifdef INTR_FILTERS 831b6d90eb7SKip Macy NULL, 832b6d90eb7SKip Macy #endif 833b6d90eb7SKip Macy t3_intr_msix, qs, &sc->msix_intr_tag[k])) { 834b6d90eb7SKip Macy device_printf(sc->dev, "Cannot set up " 835b6d90eb7SKip Macy "interrupt for message %d\n", rid); 836b6d90eb7SKip Macy return (EINVAL); 837a02573bcSKip Macy 838b6d90eb7SKip Macy } 839a02573bcSKip Macy #if 0 8408090c9f5SKip Macy #ifdef IFNET_MULTIQUEUE 841a02573bcSKip Macy if (multiq) { 8428090c9f5SKip Macy int vector = rman_get_start(sc->msix_irq_res[k]); 8438090c9f5SKip Macy if (bootverbose) 8448090c9f5SKip Macy device_printf(sc->dev, "binding vector=%d to cpu=%d\n", vector, k % mp_ncpus); 8458090c9f5SKip Macy intr_bind(vector, k % mp_ncpus); 8468090c9f5SKip Macy } 8478090c9f5SKip Macy #endif 848a02573bcSKip Macy #endif 849b6d90eb7SKip Macy } 850b6d90eb7SKip Macy } 851693d746cSKip Macy 852b6d90eb7SKip Macy return (0); 853b6d90eb7SKip Macy } 854b6d90eb7SKip Macy 855b6d90eb7SKip Macy static int 856b6d90eb7SKip Macy cxgb_port_probe(device_t dev) 857b6d90eb7SKip Macy { 858b6d90eb7SKip Macy struct port_info *p; 859b6d90eb7SKip Macy char buf[80]; 8608e10660fSKip Macy const char *desc; 861b6d90eb7SKip Macy 862b6d90eb7SKip Macy p = device_get_softc(dev); 8638e10660fSKip Macy desc = p->phy.desc; 8648e10660fSKip Macy snprintf(buf, sizeof(buf), "Port %d %s", p->port_id, desc); 865b6d90eb7SKip Macy device_set_desc_copy(dev, buf); 866b6d90eb7SKip Macy return (0); 867b6d90eb7SKip Macy } 868b6d90eb7SKip Macy 869b6d90eb7SKip Macy 870b6d90eb7SKip Macy static int 871b6d90eb7SKip Macy cxgb_makedev(struct port_info *pi) 872b6d90eb7SKip Macy { 873b6d90eb7SKip Macy 874ef72318fSKip Macy pi->port_cdev = make_dev(&cxgb_cdevsw, pi->ifp->if_dunit, 875ef72318fSKip Macy UID_ROOT, GID_WHEEL, 0600, if_name(pi->ifp)); 876b6d90eb7SKip Macy 877b6d90eb7SKip Macy if (pi->port_cdev == NULL) 878b6d90eb7SKip Macy return (ENOMEM); 879b6d90eb7SKip Macy 880b6d90eb7SKip Macy pi->port_cdev->si_drv1 = (void *)pi; 881b6d90eb7SKip Macy 882b6d90eb7SKip Macy return (0); 883b6d90eb7SKip Macy } 884b6d90eb7SKip Macy 885e97121daSKip Macy #ifndef LRO_SUPPORTED 886e97121daSKip Macy #ifdef IFCAP_LRO 887e97121daSKip Macy #undef IFCAP_LRO 888e97121daSKip Macy #endif 889e97121daSKip Macy #define IFCAP_LRO 0x0 890e97121daSKip Macy #endif 891b6d90eb7SKip Macy 892b6d90eb7SKip Macy #ifdef TSO_SUPPORTED 89325292debSKip Macy #define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO) 894b6d90eb7SKip Macy /* Don't enable TSO6 yet */ 89525292debSKip Macy #define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO4 | IFCAP_JUMBO_MTU | IFCAP_LRO) 896b6d90eb7SKip Macy #else 897b6d90eb7SKip Macy #define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU) 898b6d90eb7SKip Macy /* Don't enable TSO6 yet */ 899b6d90eb7SKip Macy #define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU) 900b6d90eb7SKip Macy #define IFCAP_TSO4 0x0 9017aff6d8eSKip Macy #define IFCAP_TSO6 0x0 902b6d90eb7SKip Macy #define CSUM_TSO 0x0 903b6d90eb7SKip Macy #endif 904b6d90eb7SKip Macy 905b6d90eb7SKip Macy 906b6d90eb7SKip Macy static int 907b6d90eb7SKip Macy cxgb_port_attach(device_t dev) 908b6d90eb7SKip Macy { 909b6d90eb7SKip Macy struct port_info *p; 910b6d90eb7SKip Macy struct ifnet *ifp; 911ef72318fSKip Macy int err, media_flags; 9128e10660fSKip Macy struct adapter *sc; 9138e10660fSKip Macy 914b6d90eb7SKip Macy 915b6d90eb7SKip Macy p = device_get_softc(dev); 9168e10660fSKip Macy sc = p->adapter; 917bb38cd2fSKip Macy snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d", 9186b68e276SKip Macy device_get_unit(device_get_parent(dev)), p->port_id); 919bb38cd2fSKip Macy PORT_LOCK_INIT(p, p->lockbuf); 920b6d90eb7SKip Macy 921b6d90eb7SKip Macy /* Allocate an ifnet object and set it up */ 922b6d90eb7SKip Macy ifp = p->ifp = if_alloc(IFT_ETHER); 923b6d90eb7SKip Macy if (ifp == NULL) { 924b6d90eb7SKip Macy device_printf(dev, "Cannot allocate ifnet\n"); 925b6d90eb7SKip Macy return (ENOMEM); 926b6d90eb7SKip Macy } 927b6d90eb7SKip Macy 928b6d90eb7SKip Macy /* 929b6d90eb7SKip Macy * Note that there is currently no watchdog timer. 930b6d90eb7SKip Macy */ 931b6d90eb7SKip Macy if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 932b6d90eb7SKip Macy ifp->if_init = cxgb_init; 933b6d90eb7SKip Macy ifp->if_softc = p; 934b6d90eb7SKip Macy ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 935b6d90eb7SKip Macy ifp->if_ioctl = cxgb_ioctl; 936b6d90eb7SKip Macy ifp->if_start = cxgb_start; 9378090c9f5SKip Macy 938a02573bcSKip Macy 939b6d90eb7SKip Macy ifp->if_timer = 0; /* Disable ifnet watchdog */ 940b6d90eb7SKip Macy ifp->if_watchdog = NULL; 941b6d90eb7SKip Macy 942a02573bcSKip Macy ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 943b6d90eb7SKip Macy IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 944b6d90eb7SKip Macy IFQ_SET_READY(&ifp->if_snd); 945b6d90eb7SKip Macy 946b6d90eb7SKip Macy ifp->if_hwassist = ifp->if_capabilities = ifp->if_capenable = 0; 947b6d90eb7SKip Macy ifp->if_capabilities |= CXGB_CAP; 948b6d90eb7SKip Macy ifp->if_capenable |= CXGB_CAP_ENABLE; 949b6d90eb7SKip Macy ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO); 950ac3a6d9cSKip Macy /* 951ac3a6d9cSKip Macy * disable TSO on 4-port - it isn't supported by the firmware yet 952ac3a6d9cSKip Macy */ 953ac3a6d9cSKip Macy if (p->adapter->params.nports > 2) { 954ac3a6d9cSKip Macy ifp->if_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6); 955ac3a6d9cSKip Macy ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TSO6); 956ac3a6d9cSKip Macy ifp->if_hwassist &= ~CSUM_TSO; 957ac3a6d9cSKip Macy } 958b6d90eb7SKip Macy 959b6d90eb7SKip Macy ether_ifattach(ifp, p->hw_addr); 9605eba27feSKip Macy #ifdef IFNET_MULTIQUEUE 961a02573bcSKip Macy ifp->if_transmit = cxgb_pcpu_transmit; 9625eba27feSKip Macy #endif 963ac3a6d9cSKip Macy /* 964ac3a6d9cSKip Macy * Only default to jumbo frames on 10GigE 965ac3a6d9cSKip Macy */ 966ac3a6d9cSKip Macy if (p->adapter->params.nports <= 2) 9674af83c8cSKip Macy ifp->if_mtu = ETHERMTU_JUMBO; 968b6d90eb7SKip Macy if ((err = cxgb_makedev(p)) != 0) { 969b6d90eb7SKip Macy printf("makedev failed %d\n", err); 970b6d90eb7SKip Macy return (err); 971b6d90eb7SKip Macy } 972b6d90eb7SKip Macy ifmedia_init(&p->media, IFM_IMASK, cxgb_media_change, 973b6d90eb7SKip Macy cxgb_media_status); 974b6d90eb7SKip Macy 9758e10660fSKip Macy if (!strcmp(p->phy.desc, "10GBASE-CX4")) { 976ef72318fSKip Macy media_flags = IFM_ETHER | IFM_10G_CX4 | IFM_FDX; 9778e10660fSKip Macy } else if (!strcmp(p->phy.desc, "10GBASE-SR")) { 978ef72318fSKip Macy media_flags = IFM_ETHER | IFM_10G_SR | IFM_FDX; 97919905d6dSKip Macy } else if (!strcmp(p->phy.desc, "10GBASE-R")) { 980837f41b0SGeorge V. Neville-Neil media_flags = cxgb_ifm_type(p->phy.modtype); 9818e10660fSKip Macy } else if (!strcmp(p->phy.desc, "10/100/1000BASE-T")) { 982ef72318fSKip Macy ifmedia_add(&p->media, IFM_ETHER | IFM_10_T, 0, NULL); 983ef72318fSKip Macy ifmedia_add(&p->media, IFM_ETHER | IFM_10_T | IFM_FDX, 984ef72318fSKip Macy 0, NULL); 985ef72318fSKip Macy ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX, 986ef72318fSKip Macy 0, NULL); 987ef72318fSKip Macy ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX | IFM_FDX, 988ef72318fSKip Macy 0, NULL); 989ef72318fSKip Macy ifmedia_add(&p->media, IFM_ETHER | IFM_1000_T | IFM_FDX, 990ef72318fSKip Macy 0, NULL); 991ef72318fSKip Macy media_flags = 0; 99241509ecdSKip Macy } else if (!strcmp(p->phy.desc, "1000BASE-X")) { 99341509ecdSKip Macy /* 99441509ecdSKip Macy * XXX: This is not very accurate. Fix when common code 99541509ecdSKip Macy * returns more specific value - eg 1000BASE-SX, LX, etc. 996837f41b0SGeorge V. Neville-Neil * 997837f41b0SGeorge V. Neville-Neil * XXX: In the meantime, don't lie. Consider setting IFM_AUTO 998837f41b0SGeorge V. Neville-Neil * instead of SX. 99941509ecdSKip Macy */ 100041509ecdSKip Macy media_flags = IFM_ETHER | IFM_1000_SX | IFM_FDX; 1001ef72318fSKip Macy } else { 10028e10660fSKip Macy printf("unsupported media type %s\n", p->phy.desc); 1003b6d90eb7SKip Macy return (ENXIO); 1004b6d90eb7SKip Macy } 1005ef72318fSKip Macy if (media_flags) { 1006837f41b0SGeorge V. Neville-Neil /* 1007837f41b0SGeorge V. Neville-Neil * Note the modtype on which we based our flags. If modtype 1008837f41b0SGeorge V. Neville-Neil * changes, we'll redo the ifmedia for this ifp. modtype may 1009837f41b0SGeorge V. Neville-Neil * change when transceivers are plugged in/out, and in other 1010837f41b0SGeorge V. Neville-Neil * situations. 1011837f41b0SGeorge V. Neville-Neil */ 1012837f41b0SGeorge V. Neville-Neil ifmedia_add(&p->media, media_flags, p->phy.modtype, NULL); 1013b6d90eb7SKip Macy ifmedia_set(&p->media, media_flags); 1014ef72318fSKip Macy } else { 1015ef72318fSKip Macy ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL); 1016ef72318fSKip Macy ifmedia_set(&p->media, IFM_ETHER | IFM_AUTO); 1017ef72318fSKip Macy } 1018ef72318fSKip Macy 101919905d6dSKip Macy /* Get the latest mac address, User can use a LAA */ 102019905d6dSKip Macy bcopy(IF_LLADDR(p->ifp), p->hw_addr, ETHER_ADDR_LEN); 1021ef72318fSKip Macy t3_sge_init_port(p); 1022f2d8ff04SGeorge V. Neville-Neil 1023f2d8ff04SGeorge V. Neville-Neil TASK_INIT(&p->link_fault_task, 0, cxgb_link_fault, p); 1024f2d8ff04SGeorge V. Neville-Neil 1025ef027c52SKip Macy #if defined(LINK_ATTACH) 10268e10660fSKip Macy cxgb_link_start(p); 10278e10660fSKip Macy t3_link_changed(sc, p->port_id); 1028ef027c52SKip Macy #endif 1029b6d90eb7SKip Macy return (0); 1030b6d90eb7SKip Macy } 1031b6d90eb7SKip Macy 1032b6d90eb7SKip Macy static int 1033b6d90eb7SKip Macy cxgb_port_detach(device_t dev) 1034b6d90eb7SKip Macy { 1035b6d90eb7SKip Macy struct port_info *p; 1036b6d90eb7SKip Macy 1037b6d90eb7SKip Macy p = device_get_softc(dev); 1038d722cab4SKip Macy 1039d722cab4SKip Macy PORT_LOCK(p); 1040ef72318fSKip Macy if (p->ifp->if_drv_flags & IFF_DRV_RUNNING) 1041d722cab4SKip Macy cxgb_stop_locked(p); 1042d722cab4SKip Macy PORT_UNLOCK(p); 1043d722cab4SKip Macy 1044b6d90eb7SKip Macy ether_ifdetach(p->ifp); 10458090c9f5SKip Macy printf("waiting for callout to stop ..."); 10468090c9f5SKip Macy DELAY(1000000); 10478090c9f5SKip Macy printf("done\n"); 10487ac2e6c3SKip Macy /* 10497ac2e6c3SKip Macy * the lock may be acquired in ifdetach 10507ac2e6c3SKip Macy */ 10517ac2e6c3SKip Macy PORT_LOCK_DEINIT(p); 1052b6d90eb7SKip Macy if_free(p->ifp); 1053b6d90eb7SKip Macy 1054ef72318fSKip Macy if (p->port_cdev != NULL) 1055b6d90eb7SKip Macy destroy_dev(p->port_cdev); 1056b6d90eb7SKip Macy 1057b6d90eb7SKip Macy return (0); 1058b6d90eb7SKip Macy } 1059b6d90eb7SKip Macy 1060b6d90eb7SKip Macy void 1061b6d90eb7SKip Macy t3_fatal_err(struct adapter *sc) 1062b6d90eb7SKip Macy { 1063b6d90eb7SKip Macy u_int fw_status[4]; 1064b6d90eb7SKip Macy 10655c5df3daSKip Macy if (sc->flags & FULL_INIT_DONE) { 10665c5df3daSKip Macy t3_sge_stop(sc); 10675c5df3daSKip Macy t3_write_reg(sc, A_XGM_TX_CTRL, 0); 10685c5df3daSKip Macy t3_write_reg(sc, A_XGM_RX_CTRL, 0); 10695c5df3daSKip Macy t3_write_reg(sc, XGM_REG(A_XGM_TX_CTRL, 1), 0); 10705c5df3daSKip Macy t3_write_reg(sc, XGM_REG(A_XGM_RX_CTRL, 1), 0); 10715c5df3daSKip Macy t3_intr_disable(sc); 10725c5df3daSKip Macy } 1073b6d90eb7SKip Macy device_printf(sc->dev,"encountered fatal error, operation suspended\n"); 1074b6d90eb7SKip Macy if (!t3_cim_ctl_blk_read(sc, 0xa0, 4, fw_status)) 1075b6d90eb7SKip Macy device_printf(sc->dev, "FW_ status: 0x%x, 0x%x, 0x%x, 0x%x\n", 1076b6d90eb7SKip Macy fw_status[0], fw_status[1], fw_status[2], fw_status[3]); 1077b6d90eb7SKip Macy } 1078b6d90eb7SKip Macy 1079b6d90eb7SKip Macy int 1080b6d90eb7SKip Macy t3_os_find_pci_capability(adapter_t *sc, int cap) 1081b6d90eb7SKip Macy { 1082b6d90eb7SKip Macy device_t dev; 1083b6d90eb7SKip Macy struct pci_devinfo *dinfo; 1084b6d90eb7SKip Macy pcicfgregs *cfg; 1085b6d90eb7SKip Macy uint32_t status; 1086b6d90eb7SKip Macy uint8_t ptr; 1087b6d90eb7SKip Macy 1088b6d90eb7SKip Macy dev = sc->dev; 1089b6d90eb7SKip Macy dinfo = device_get_ivars(dev); 1090b6d90eb7SKip Macy cfg = &dinfo->cfg; 1091b6d90eb7SKip Macy 1092b6d90eb7SKip Macy status = pci_read_config(dev, PCIR_STATUS, 2); 1093b6d90eb7SKip Macy if (!(status & PCIM_STATUS_CAPPRESENT)) 1094b6d90eb7SKip Macy return (0); 1095b6d90eb7SKip Macy 1096b6d90eb7SKip Macy switch (cfg->hdrtype & PCIM_HDRTYPE) { 1097b6d90eb7SKip Macy case 0: 1098b6d90eb7SKip Macy case 1: 1099b6d90eb7SKip Macy ptr = PCIR_CAP_PTR; 1100b6d90eb7SKip Macy break; 1101b6d90eb7SKip Macy case 2: 1102b6d90eb7SKip Macy ptr = PCIR_CAP_PTR_2; 1103b6d90eb7SKip Macy break; 1104b6d90eb7SKip Macy default: 1105b6d90eb7SKip Macy return (0); 1106b6d90eb7SKip Macy break; 1107b6d90eb7SKip Macy } 1108b6d90eb7SKip Macy ptr = pci_read_config(dev, ptr, 1); 1109b6d90eb7SKip Macy 1110b6d90eb7SKip Macy while (ptr != 0) { 1111b6d90eb7SKip Macy if (pci_read_config(dev, ptr + PCICAP_ID, 1) == cap) 1112b6d90eb7SKip Macy return (ptr); 1113b6d90eb7SKip Macy ptr = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1); 1114b6d90eb7SKip Macy } 1115b6d90eb7SKip Macy 1116b6d90eb7SKip Macy return (0); 1117b6d90eb7SKip Macy } 1118b6d90eb7SKip Macy 1119b6d90eb7SKip Macy int 1120b6d90eb7SKip Macy t3_os_pci_save_state(struct adapter *sc) 1121b6d90eb7SKip Macy { 1122b6d90eb7SKip Macy device_t dev; 1123b6d90eb7SKip Macy struct pci_devinfo *dinfo; 1124b6d90eb7SKip Macy 1125b6d90eb7SKip Macy dev = sc->dev; 1126b6d90eb7SKip Macy dinfo = device_get_ivars(dev); 1127b6d90eb7SKip Macy 1128b6d90eb7SKip Macy pci_cfg_save(dev, dinfo, 0); 1129b6d90eb7SKip Macy return (0); 1130b6d90eb7SKip Macy } 1131b6d90eb7SKip Macy 1132b6d90eb7SKip Macy int 1133b6d90eb7SKip Macy t3_os_pci_restore_state(struct adapter *sc) 1134b6d90eb7SKip Macy { 1135b6d90eb7SKip Macy device_t dev; 1136b6d90eb7SKip Macy struct pci_devinfo *dinfo; 1137b6d90eb7SKip Macy 1138b6d90eb7SKip Macy dev = sc->dev; 1139b6d90eb7SKip Macy dinfo = device_get_ivars(dev); 1140b6d90eb7SKip Macy 1141b6d90eb7SKip Macy pci_cfg_restore(dev, dinfo); 1142b6d90eb7SKip Macy return (0); 1143b6d90eb7SKip Macy } 1144b6d90eb7SKip Macy 1145f2d8ff04SGeorge V. Neville-Neil void t3_os_link_fault(struct adapter *adap, int port_id, int state) 1146f2d8ff04SGeorge V. Neville-Neil { 1147f2d8ff04SGeorge V. Neville-Neil struct port_info *pi = &adap->port[port_id]; 1148f2d8ff04SGeorge V. Neville-Neil 1149f2d8ff04SGeorge V. Neville-Neil if (!state) { 1150f2d8ff04SGeorge V. Neville-Neil if_link_state_change(pi->ifp, LINK_STATE_DOWN); 1151f2d8ff04SGeorge V. Neville-Neil return; 1152f2d8ff04SGeorge V. Neville-Neil } 1153f2d8ff04SGeorge V. Neville-Neil 1154f2d8ff04SGeorge V. Neville-Neil if (adap->params.nports <= 2) { 1155f2d8ff04SGeorge V. Neville-Neil struct cmac *mac = &pi->mac; 1156f2d8ff04SGeorge V. Neville-Neil 1157f2d8ff04SGeorge V. Neville-Neil /* Clear local faults */ 1158f2d8ff04SGeorge V. Neville-Neil t3_xgm_intr_disable(adap, port_id); 1159f2d8ff04SGeorge V. Neville-Neil t3_read_reg(adap, A_XGM_INT_STATUS + pi->mac.offset); 1160f2d8ff04SGeorge V. Neville-Neil t3_write_reg(adap, A_XGM_INT_CAUSE + pi->mac.offset, F_XGM_INT); 1161f2d8ff04SGeorge V. Neville-Neil 1162f2d8ff04SGeorge V. Neville-Neil t3_set_reg_field(adap, A_XGM_INT_ENABLE + pi->mac.offset, 1163f2d8ff04SGeorge V. Neville-Neil F_XGM_INT, F_XGM_INT); 1164f2d8ff04SGeorge V. Neville-Neil t3_xgm_intr_enable(adap, pi->port_id); 1165f2d8ff04SGeorge V. Neville-Neil t3_mac_enable(mac, MAC_DIRECTION_TX); 1166f2d8ff04SGeorge V. Neville-Neil } 1167f2d8ff04SGeorge V. Neville-Neil 1168f2d8ff04SGeorge V. Neville-Neil if_link_state_change(pi->ifp, LINK_STATE_UP); 1169f2d8ff04SGeorge V. Neville-Neil } 1170f2d8ff04SGeorge V. Neville-Neil 1171b6d90eb7SKip Macy /** 1172b6d90eb7SKip Macy * t3_os_link_changed - handle link status changes 1173b6d90eb7SKip Macy * @adapter: the adapter associated with the link change 1174b6d90eb7SKip Macy * @port_id: the port index whose limk status has changed 117519905d6dSKip Macy * @link_status: the new status of the link 1176b6d90eb7SKip Macy * @speed: the new speed setting 1177b6d90eb7SKip Macy * @duplex: the new duplex setting 1178b6d90eb7SKip Macy * @fc: the new flow-control setting 1179b6d90eb7SKip Macy * 1180b6d90eb7SKip Macy * This is the OS-dependent handler for link status changes. The OS 1181b6d90eb7SKip Macy * neutral handler takes care of most of the processing for these events, 1182b6d90eb7SKip Macy * then calls this handler for any OS-specific processing. 1183b6d90eb7SKip Macy */ 1184b6d90eb7SKip Macy void 1185b6d90eb7SKip Macy t3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed, 1186b6d90eb7SKip Macy int duplex, int fc) 1187b6d90eb7SKip Macy { 1188b6d90eb7SKip Macy struct port_info *pi = &adapter->port[port_id]; 1189d722cab4SKip Macy struct cmac *mac = &adapter->port[port_id].mac; 1190b6d90eb7SKip Macy 1191d722cab4SKip Macy if (link_status) { 119219905d6dSKip Macy DELAY(10); 119319905d6dSKip Macy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 119419905d6dSKip Macy /* Clear errors created by MAC enable */ 1195f2d8ff04SGeorge V. Neville-Neil t3_set_reg_field(adapter, A_XGM_STAT_CTRL + pi->mac.offset, 119619905d6dSKip Macy F_CLRSTATS, 1); 119719905d6dSKip Macy 1198f2d8ff04SGeorge V. Neville-Neil if (adapter->params.nports <= 2) { 1199f2d8ff04SGeorge V. Neville-Neil /* Clear local faults */ 1200f2d8ff04SGeorge V. Neville-Neil t3_xgm_intr_disable(adapter, pi->port_id); 1201f2d8ff04SGeorge V. Neville-Neil t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); 1202f2d8ff04SGeorge V. Neville-Neil t3_write_reg(adapter, A_XGM_INT_CAUSE + pi->mac.offset, 1203f2d8ff04SGeorge V. Neville-Neil F_XGM_INT); 1204f2d8ff04SGeorge V. Neville-Neil 1205f2d8ff04SGeorge V. Neville-Neil t3_set_reg_field(adapter, 1206f2d8ff04SGeorge V. Neville-Neil A_XGM_INT_ENABLE + pi->mac.offset, 1207f2d8ff04SGeorge V. Neville-Neil F_XGM_INT, F_XGM_INT); 1208f2d8ff04SGeorge V. Neville-Neil t3_xgm_intr_enable(adapter, pi->port_id); 1209f2d8ff04SGeorge V. Neville-Neil } 1210f2d8ff04SGeorge V. Neville-Neil 1211f2d8ff04SGeorge V. Neville-Neil if_link_state_change(pi->ifp, LINK_STATE_UP); 1212d722cab4SKip Macy } else { 1213f2d8ff04SGeorge V. Neville-Neil t3_xgm_intr_disable(adapter, pi->port_id); 1214f2d8ff04SGeorge V. Neville-Neil t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); 1215f2d8ff04SGeorge V. Neville-Neil if (adapter->params.nports <= 2) { 1216f2d8ff04SGeorge V. Neville-Neil t3_set_reg_field(adapter, 1217f2d8ff04SGeorge V. Neville-Neil A_XGM_INT_ENABLE + pi->mac.offset, 1218f2d8ff04SGeorge V. Neville-Neil F_XGM_INT, 0); 1219f2d8ff04SGeorge V. Neville-Neil } 1220f2d8ff04SGeorge V. Neville-Neil 1221f2d8ff04SGeorge V. Neville-Neil /* PR 5666. We shouldn't power down 1G phys */ 1222f2d8ff04SGeorge V. Neville-Neil if (is_10G(adapter)) 1223d722cab4SKip Macy pi->phy.ops->power_down(&pi->phy, 1); 1224f2d8ff04SGeorge V. Neville-Neil 1225f2d8ff04SGeorge V. Neville-Neil t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset); 1226d722cab4SKip Macy t3_mac_disable(mac, MAC_DIRECTION_RX); 1227d722cab4SKip Macy t3_link_start(&pi->phy, mac, &pi->link_config); 1228f2d8ff04SGeorge V. Neville-Neil 12298e10660fSKip Macy if_link_state_change(pi->ifp, LINK_STATE_DOWN); 1230d722cab4SKip Macy } 1231b6d90eb7SKip Macy } 1232b6d90eb7SKip Macy 12339b4de886SKip Macy /** 12349b4de886SKip Macy * t3_os_phymod_changed - handle PHY module changes 12359b4de886SKip Macy * @phy: the PHY reporting the module change 12369b4de886SKip Macy * @mod_type: new module type 12379b4de886SKip Macy * 12389b4de886SKip Macy * This is the OS-dependent handler for PHY module changes. It is 12399b4de886SKip Macy * invoked when a PHY module is removed or inserted for any OS-specific 12409b4de886SKip Macy * processing. 12419b4de886SKip Macy */ 12429b4de886SKip Macy void t3_os_phymod_changed(struct adapter *adap, int port_id) 12439b4de886SKip Macy { 12449b4de886SKip Macy static const char *mod_str[] = { 12459b4de886SKip Macy NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown" 12469b4de886SKip Macy }; 12479b4de886SKip Macy 12489b4de886SKip Macy struct port_info *pi = &adap->port[port_id]; 12499b4de886SKip Macy 12509b4de886SKip Macy if (pi->phy.modtype == phy_modtype_none) 12519b4de886SKip Macy device_printf(adap->dev, "PHY module unplugged\n"); 12529b4de886SKip Macy else { 12539b4de886SKip Macy KASSERT(pi->phy.modtype < ARRAY_SIZE(mod_str), 12549b4de886SKip Macy ("invalid PHY module type %d", pi->phy.modtype)); 12559b4de886SKip Macy device_printf(adap->dev, "%s PHY module inserted\n", 12569b4de886SKip Macy mod_str[pi->phy.modtype]); 12579b4de886SKip Macy } 12589b4de886SKip Macy } 12599b4de886SKip Macy 1260b6d90eb7SKip Macy /* 1261b6d90eb7SKip Macy * Interrupt-context handler for external (PHY) interrupts. 1262b6d90eb7SKip Macy */ 1263b6d90eb7SKip Macy void 1264b6d90eb7SKip Macy t3_os_ext_intr_handler(adapter_t *sc) 1265b6d90eb7SKip Macy { 1266b6d90eb7SKip Macy if (cxgb_debug) 1267b6d90eb7SKip Macy printf("t3_os_ext_intr_handler\n"); 1268b6d90eb7SKip Macy /* 1269b6d90eb7SKip Macy * Schedule a task to handle external interrupts as they may be slow 1270b6d90eb7SKip Macy * and we use a mutex to protect MDIO registers. We disable PHY 1271b6d90eb7SKip Macy * interrupts in the meantime and let the task reenable them when 1272b6d90eb7SKip Macy * it's done. 1273b6d90eb7SKip Macy */ 1274d722cab4SKip Macy ADAPTER_LOCK(sc); 1275b6d90eb7SKip Macy if (sc->slow_intr_mask) { 1276b6d90eb7SKip Macy sc->slow_intr_mask &= ~F_T3DBG; 1277b6d90eb7SKip Macy t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask); 1278b6d90eb7SKip Macy taskqueue_enqueue(sc->tq, &sc->ext_intr_task); 1279b6d90eb7SKip Macy } 1280d722cab4SKip Macy ADAPTER_UNLOCK(sc); 1281b6d90eb7SKip Macy } 1282b6d90eb7SKip Macy 1283f2d8ff04SGeorge V. Neville-Neil static void 1284f2d8ff04SGeorge V. Neville-Neil cxgb_link_fault(void *arg, int ncount) 1285f2d8ff04SGeorge V. Neville-Neil { 1286f2d8ff04SGeorge V. Neville-Neil struct port_info *pi = arg; 1287f2d8ff04SGeorge V. Neville-Neil 1288f2d8ff04SGeorge V. Neville-Neil t3_link_fault(pi->adapter, pi->port_id); 1289f2d8ff04SGeorge V. Neville-Neil } 1290f2d8ff04SGeorge V. Neville-Neil 1291f2d8ff04SGeorge V. Neville-Neil void t3_os_link_fault_handler(struct adapter *sc, int port_id) 1292f2d8ff04SGeorge V. Neville-Neil { 1293f2d8ff04SGeorge V. Neville-Neil struct port_info *pi = &sc->port[port_id]; 1294f2d8ff04SGeorge V. Neville-Neil 1295f2d8ff04SGeorge V. Neville-Neil ADAPTER_LOCK(sc); 1296f2d8ff04SGeorge V. Neville-Neil pi->link_fault = 1; 1297f2d8ff04SGeorge V. Neville-Neil taskqueue_enqueue(sc->tq, &pi->link_fault_task); 1298f2d8ff04SGeorge V. Neville-Neil ADAPTER_UNLOCK(sc); 1299f2d8ff04SGeorge V. Neville-Neil } 1300f2d8ff04SGeorge V. Neville-Neil 1301b6d90eb7SKip Macy void 1302b6d90eb7SKip Macy t3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[]) 1303b6d90eb7SKip Macy { 1304b6d90eb7SKip Macy 1305b6d90eb7SKip Macy /* 1306b6d90eb7SKip Macy * The ifnet might not be allocated before this gets called, 1307b6d90eb7SKip Macy * as this is called early on in attach by t3_prep_adapter 1308b6d90eb7SKip Macy * save the address off in the port structure 1309b6d90eb7SKip Macy */ 1310b6d90eb7SKip Macy if (cxgb_debug) 1311b6d90eb7SKip Macy printf("set_hw_addr on idx %d addr %6D\n", port_idx, hw_addr, ":"); 1312b6d90eb7SKip Macy bcopy(hw_addr, adapter->port[port_idx].hw_addr, ETHER_ADDR_LEN); 1313b6d90eb7SKip Macy } 1314b6d90eb7SKip Macy 1315b6d90eb7SKip Macy /** 1316b6d90eb7SKip Macy * link_start - enable a port 1317b6d90eb7SKip Macy * @p: the port to enable 1318b6d90eb7SKip Macy * 1319b6d90eb7SKip Macy * Performs the MAC and PHY actions needed to enable a port. 1320b6d90eb7SKip Macy */ 1321b6d90eb7SKip Macy static void 1322b6d90eb7SKip Macy cxgb_link_start(struct port_info *p) 1323b6d90eb7SKip Macy { 1324b6d90eb7SKip Macy struct ifnet *ifp; 1325b6d90eb7SKip Macy struct t3_rx_mode rm; 1326b6d90eb7SKip Macy struct cmac *mac = &p->mac; 13274af83c8cSKip Macy int mtu, hwtagging; 1328b6d90eb7SKip Macy 1329b6d90eb7SKip Macy ifp = p->ifp; 1330b6d90eb7SKip Macy 13314af83c8cSKip Macy bcopy(IF_LLADDR(ifp), p->hw_addr, ETHER_ADDR_LEN); 13324af83c8cSKip Macy 13334af83c8cSKip Macy mtu = ifp->if_mtu; 13344af83c8cSKip Macy if (ifp->if_capenable & IFCAP_VLAN_MTU) 13354af83c8cSKip Macy mtu += ETHER_VLAN_ENCAP_LEN; 13364af83c8cSKip Macy 13374af83c8cSKip Macy hwtagging = (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0; 13384af83c8cSKip Macy 1339b6d90eb7SKip Macy t3_init_rx_mode(&rm, p); 13407ac2e6c3SKip Macy if (!mac->multiport) 1341b6d90eb7SKip Macy t3_mac_reset(mac); 13424af83c8cSKip Macy t3_mac_set_mtu(mac, mtu); 13434af83c8cSKip Macy t3_set_vlan_accel(p->adapter, 1 << p->tx_chan, hwtagging); 1344b6d90eb7SKip Macy t3_mac_set_address(mac, 0, p->hw_addr); 1345b6d90eb7SKip Macy t3_mac_set_rx_mode(mac, &rm); 1346b6d90eb7SKip Macy t3_link_start(&p->phy, mac, &p->link_config); 1347b6d90eb7SKip Macy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 1348b6d90eb7SKip Macy } 1349b6d90eb7SKip Macy 13508e10660fSKip Macy 13518e10660fSKip Macy static int 13528e10660fSKip Macy await_mgmt_replies(struct adapter *adap, unsigned long init_cnt, 13538e10660fSKip Macy unsigned long n) 13548e10660fSKip Macy { 13558e10660fSKip Macy int attempts = 5; 13568e10660fSKip Macy 13578e10660fSKip Macy while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) { 13588e10660fSKip Macy if (!--attempts) 13598e10660fSKip Macy return (ETIMEDOUT); 13608e10660fSKip Macy t3_os_sleep(10); 13618e10660fSKip Macy } 13628e10660fSKip Macy return 0; 13638e10660fSKip Macy } 13648e10660fSKip Macy 13658e10660fSKip Macy static int 13668e10660fSKip Macy init_tp_parity(struct adapter *adap) 13678e10660fSKip Macy { 13688e10660fSKip Macy int i; 13698e10660fSKip Macy struct mbuf *m; 13708e10660fSKip Macy struct cpl_set_tcb_field *greq; 13718e10660fSKip Macy unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts; 13728e10660fSKip Macy 13738e10660fSKip Macy t3_tp_set_offload_mode(adap, 1); 13748e10660fSKip Macy 13758e10660fSKip Macy for (i = 0; i < 16; i++) { 13768e10660fSKip Macy struct cpl_smt_write_req *req; 13778e10660fSKip Macy 13788e10660fSKip Macy m = m_gethdr(M_WAITOK, MT_DATA); 13798e10660fSKip Macy req = mtod(m, struct cpl_smt_write_req *); 13808e10660fSKip Macy m->m_len = m->m_pkthdr.len = sizeof(*req); 13818e10660fSKip Macy memset(req, 0, sizeof(*req)); 13828e10660fSKip Macy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 13838e10660fSKip Macy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); 13848e10660fSKip Macy req->iff = i; 13858e10660fSKip Macy t3_mgmt_tx(adap, m); 13868e10660fSKip Macy } 13878e10660fSKip Macy 13888e10660fSKip Macy for (i = 0; i < 2048; i++) { 13898e10660fSKip Macy struct cpl_l2t_write_req *req; 13908e10660fSKip Macy 13918e10660fSKip Macy m = m_gethdr(M_WAITOK, MT_DATA); 13928e10660fSKip Macy req = mtod(m, struct cpl_l2t_write_req *); 13938e10660fSKip Macy m->m_len = m->m_pkthdr.len = sizeof(*req); 13948e10660fSKip Macy memset(req, 0, sizeof(*req)); 13958e10660fSKip Macy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 13968e10660fSKip Macy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i)); 13978e10660fSKip Macy req->params = htonl(V_L2T_W_IDX(i)); 13988e10660fSKip Macy t3_mgmt_tx(adap, m); 13998e10660fSKip Macy } 14008e10660fSKip Macy 14018e10660fSKip Macy for (i = 0; i < 2048; i++) { 14028e10660fSKip Macy struct cpl_rte_write_req *req; 14038e10660fSKip Macy 14048e10660fSKip Macy m = m_gethdr(M_WAITOK, MT_DATA); 14058e10660fSKip Macy req = mtod(m, struct cpl_rte_write_req *); 14068e10660fSKip Macy m->m_len = m->m_pkthdr.len = sizeof(*req); 14078e10660fSKip Macy memset(req, 0, sizeof(*req)); 14088e10660fSKip Macy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 14098e10660fSKip Macy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i)); 14108e10660fSKip Macy req->l2t_idx = htonl(V_L2T_W_IDX(i)); 14118e10660fSKip Macy t3_mgmt_tx(adap, m); 14128e10660fSKip Macy } 14138e10660fSKip Macy 14148e10660fSKip Macy m = m_gethdr(M_WAITOK, MT_DATA); 14158e10660fSKip Macy greq = mtod(m, struct cpl_set_tcb_field *); 14168e10660fSKip Macy m->m_len = m->m_pkthdr.len = sizeof(*greq); 14178e10660fSKip Macy memset(greq, 0, sizeof(*greq)); 14188e10660fSKip Macy greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 14198e10660fSKip Macy OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0)); 14208e10660fSKip Macy greq->mask = htobe64(1); 14218e10660fSKip Macy t3_mgmt_tx(adap, m); 14228e10660fSKip Macy 14238e10660fSKip Macy i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); 14248e10660fSKip Macy t3_tp_set_offload_mode(adap, 0); 14258e10660fSKip Macy return (i); 14268e10660fSKip Macy } 14278e10660fSKip Macy 1428b6d90eb7SKip Macy /** 1429b6d90eb7SKip Macy * setup_rss - configure Receive Side Steering (per-queue connection demux) 1430b6d90eb7SKip Macy * @adap: the adapter 1431b6d90eb7SKip Macy * 1432b6d90eb7SKip Macy * Sets up RSS to distribute packets to multiple receive queues. We 1433b6d90eb7SKip Macy * configure the RSS CPU lookup table to distribute to the number of HW 1434b6d90eb7SKip Macy * receive queues, and the response queue lookup table to narrow that 1435b6d90eb7SKip Macy * down to the response queues actually configured for each port. 1436b6d90eb7SKip Macy * We always configure the RSS mapping for two ports since the mapping 1437b6d90eb7SKip Macy * table has plenty of entries. 1438b6d90eb7SKip Macy */ 1439b6d90eb7SKip Macy static void 1440b6d90eb7SKip Macy setup_rss(adapter_t *adap) 1441b6d90eb7SKip Macy { 1442b6d90eb7SKip Macy int i; 1443ac3a6d9cSKip Macy u_int nq[2]; 1444b6d90eb7SKip Macy uint8_t cpus[SGE_QSETS + 1]; 1445b6d90eb7SKip Macy uint16_t rspq_map[RSS_TABLE_SIZE]; 14465c5df3daSKip Macy 1447b6d90eb7SKip Macy for (i = 0; i < SGE_QSETS; ++i) 1448b6d90eb7SKip Macy cpus[i] = i; 1449b6d90eb7SKip Macy cpus[SGE_QSETS] = 0xff; 1450b6d90eb7SKip Macy 14517ac2e6c3SKip Macy nq[0] = nq[1] = 0; 14527ac2e6c3SKip Macy for_each_port(adap, i) { 14537ac2e6c3SKip Macy const struct port_info *pi = adap2pinfo(adap, i); 14547ac2e6c3SKip Macy 14557ac2e6c3SKip Macy nq[pi->tx_chan] += pi->nqsets; 14567ac2e6c3SKip Macy } 1457b6d90eb7SKip Macy for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) { 14588e10660fSKip Macy rspq_map[i] = nq[0] ? i % nq[0] : 0; 14598e10660fSKip Macy rspq_map[i + RSS_TABLE_SIZE / 2] = nq[1] ? i % nq[1] + nq[0] : 0; 1460b6d90eb7SKip Macy } 1461ac3a6d9cSKip Macy /* Calculate the reverse RSS map table */ 1462ac3a6d9cSKip Macy for (i = 0; i < RSS_TABLE_SIZE; ++i) 1463ac3a6d9cSKip Macy if (adap->rrss_map[rspq_map[i]] == 0xff) 1464ac3a6d9cSKip Macy adap->rrss_map[rspq_map[i]] = i; 1465b6d90eb7SKip Macy 1466b6d90eb7SKip Macy t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN | 1467ac3a6d9cSKip Macy F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | F_OFDMAPEN | 14688e10660fSKip Macy F_RRCPLMAPEN | V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, 14698e10660fSKip Macy cpus, rspq_map); 1470ac3a6d9cSKip Macy 1471b6d90eb7SKip Macy } 1472b6d90eb7SKip Macy 1473d722cab4SKip Macy /* 1474d722cab4SKip Macy * Sends an mbuf to an offload queue driver 1475d722cab4SKip Macy * after dealing with any active network taps. 1476d722cab4SKip Macy */ 1477d722cab4SKip Macy static inline int 14783e96c7e7SKip Macy offload_tx(struct t3cdev *tdev, struct mbuf *m) 1479d722cab4SKip Macy { 1480d722cab4SKip Macy int ret; 1481d722cab4SKip Macy 1482d722cab4SKip Macy ret = t3_offload_tx(tdev, m); 1483ef72318fSKip Macy return (ret); 1484d722cab4SKip Macy } 1485d722cab4SKip Macy 1486d722cab4SKip Macy static int 1487d722cab4SKip Macy write_smt_entry(struct adapter *adapter, int idx) 1488d722cab4SKip Macy { 1489d722cab4SKip Macy struct port_info *pi = &adapter->port[idx]; 1490d722cab4SKip Macy struct cpl_smt_write_req *req; 1491d722cab4SKip Macy struct mbuf *m; 1492d722cab4SKip Macy 1493d722cab4SKip Macy if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL) 1494d722cab4SKip Macy return (ENOMEM); 1495d722cab4SKip Macy 1496d722cab4SKip Macy req = mtod(m, struct cpl_smt_write_req *); 14978090c9f5SKip Macy m->m_pkthdr.len = m->m_len = sizeof(struct cpl_smt_write_req); 14988090c9f5SKip Macy 1499d722cab4SKip Macy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1500d722cab4SKip Macy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx)); 1501d722cab4SKip Macy req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */ 1502d722cab4SKip Macy req->iff = idx; 1503d722cab4SKip Macy memset(req->src_mac1, 0, sizeof(req->src_mac1)); 1504d722cab4SKip Macy memcpy(req->src_mac0, pi->hw_addr, ETHER_ADDR_LEN); 1505d722cab4SKip Macy 1506d722cab4SKip Macy m_set_priority(m, 1); 1507d722cab4SKip Macy 1508d722cab4SKip Macy offload_tx(&adapter->tdev, m); 1509d722cab4SKip Macy 1510d722cab4SKip Macy return (0); 1511d722cab4SKip Macy } 1512d722cab4SKip Macy 1513d722cab4SKip Macy static int 1514d722cab4SKip Macy init_smt(struct adapter *adapter) 1515d722cab4SKip Macy { 1516d722cab4SKip Macy int i; 1517d722cab4SKip Macy 1518d722cab4SKip Macy for_each_port(adapter, i) 1519d722cab4SKip Macy write_smt_entry(adapter, i); 1520d722cab4SKip Macy return 0; 1521d722cab4SKip Macy } 1522d722cab4SKip Macy 1523d722cab4SKip Macy static void 1524d722cab4SKip Macy init_port_mtus(adapter_t *adapter) 1525d722cab4SKip Macy { 1526d722cab4SKip Macy unsigned int mtus = adapter->port[0].ifp->if_mtu; 1527d722cab4SKip Macy 1528d722cab4SKip Macy if (adapter->port[1].ifp) 1529d722cab4SKip Macy mtus |= adapter->port[1].ifp->if_mtu << 16; 1530d722cab4SKip Macy t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus); 1531d722cab4SKip Macy } 1532d722cab4SKip Macy 1533b6d90eb7SKip Macy static void 1534b6d90eb7SKip Macy send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, 1535b6d90eb7SKip Macy int hi, int port) 1536b6d90eb7SKip Macy { 1537b6d90eb7SKip Macy struct mbuf *m; 1538b6d90eb7SKip Macy struct mngt_pktsched_wr *req; 1539b6d90eb7SKip Macy 1540ac3a6d9cSKip Macy m = m_gethdr(M_DONTWAIT, MT_DATA); 154120fe52b8SKip Macy if (m) { 1542d722cab4SKip Macy req = mtod(m, struct mngt_pktsched_wr *); 1543b6d90eb7SKip Macy req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); 1544b6d90eb7SKip Macy req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET; 1545b6d90eb7SKip Macy req->sched = sched; 1546b6d90eb7SKip Macy req->idx = qidx; 1547b6d90eb7SKip Macy req->min = lo; 1548b6d90eb7SKip Macy req->max = hi; 1549b6d90eb7SKip Macy req->binding = port; 1550b6d90eb7SKip Macy m->m_len = m->m_pkthdr.len = sizeof(*req); 1551b6d90eb7SKip Macy t3_mgmt_tx(adap, m); 1552b6d90eb7SKip Macy } 155320fe52b8SKip Macy } 1554b6d90eb7SKip Macy 1555b6d90eb7SKip Macy static void 1556b6d90eb7SKip Macy bind_qsets(adapter_t *sc) 1557b6d90eb7SKip Macy { 1558b6d90eb7SKip Macy int i, j; 1559b6d90eb7SKip Macy 15608090c9f5SKip Macy cxgb_pcpu_startup_threads(sc); 1561b6d90eb7SKip Macy for (i = 0; i < (sc)->params.nports; ++i) { 1562b6d90eb7SKip Macy const struct port_info *pi = adap2pinfo(sc, i); 1563b6d90eb7SKip Macy 15645c5df3daSKip Macy for (j = 0; j < pi->nqsets; ++j) { 1565b6d90eb7SKip Macy send_pktsched_cmd(sc, 1, pi->first_qset + j, -1, 15665c5df3daSKip Macy -1, pi->tx_chan); 15675c5df3daSKip Macy 15685c5df3daSKip Macy } 1569b6d90eb7SKip Macy } 1570b6d90eb7SKip Macy } 1571b6d90eb7SKip Macy 1572ac3a6d9cSKip Macy static void 1573ac3a6d9cSKip Macy update_tpeeprom(struct adapter *adap) 1574ac3a6d9cSKip Macy { 15752de1fa86SKip Macy #ifdef FIRMWARE_LATEST 1576ac3a6d9cSKip Macy const struct firmware *tpeeprom; 15772de1fa86SKip Macy #else 15782de1fa86SKip Macy struct firmware *tpeeprom; 15792de1fa86SKip Macy #endif 15802de1fa86SKip Macy 1581ac3a6d9cSKip Macy uint32_t version; 1582ac3a6d9cSKip Macy unsigned int major, minor; 1583ac3a6d9cSKip Macy int ret, len; 1584f2d8ff04SGeorge V. Neville-Neil char rev, name[32]; 1585ac3a6d9cSKip Macy 1586ac3a6d9cSKip Macy t3_seeprom_read(adap, TP_SRAM_OFFSET, &version); 1587ac3a6d9cSKip Macy 1588ac3a6d9cSKip Macy major = G_TP_VERSION_MAJOR(version); 1589ac3a6d9cSKip Macy minor = G_TP_VERSION_MINOR(version); 1590ac3a6d9cSKip Macy if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) 1591ac3a6d9cSKip Macy return; 1592ac3a6d9cSKip Macy 1593ac3a6d9cSKip Macy rev = t3rev2char(adap); 1594f2d8ff04SGeorge V. Neville-Neil snprintf(name, sizeof(name), TPEEPROM_NAME, rev); 1595ac3a6d9cSKip Macy 1596f2d8ff04SGeorge V. Neville-Neil tpeeprom = firmware_get(name); 1597ac3a6d9cSKip Macy if (tpeeprom == NULL) { 1598ac3a6d9cSKip Macy device_printf(adap->dev, "could not load TP EEPROM: unable to load %s\n", 159964a37133SKip Macy TPEEPROM_NAME); 1600ac3a6d9cSKip Macy return; 1601ac3a6d9cSKip Macy } 1602ac3a6d9cSKip Macy 1603ac3a6d9cSKip Macy len = tpeeprom->datasize - 4; 1604ac3a6d9cSKip Macy 1605ac3a6d9cSKip Macy ret = t3_check_tpsram(adap, tpeeprom->data, tpeeprom->datasize); 1606ac3a6d9cSKip Macy if (ret) 1607ac3a6d9cSKip Macy goto release_tpeeprom; 1608ac3a6d9cSKip Macy 1609ac3a6d9cSKip Macy if (len != TP_SRAM_LEN) { 161064a37133SKip Macy device_printf(adap->dev, "%s length is wrong len=%d expected=%d\n", TPEEPROM_NAME, len, TP_SRAM_LEN); 1611ac3a6d9cSKip Macy return; 1612ac3a6d9cSKip Macy } 1613ac3a6d9cSKip Macy 1614ac3a6d9cSKip Macy ret = set_eeprom(&adap->port[0], tpeeprom->data, tpeeprom->datasize, 1615ac3a6d9cSKip Macy TP_SRAM_OFFSET); 1616ac3a6d9cSKip Macy 1617ac3a6d9cSKip Macy if (!ret) { 1618ac3a6d9cSKip Macy device_printf(adap->dev, 1619ac3a6d9cSKip Macy "Protocol SRAM image updated in EEPROM to %d.%d.%d\n", 1620ac3a6d9cSKip Macy TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); 1621ac3a6d9cSKip Macy } else 1622ac3a6d9cSKip Macy device_printf(adap->dev, "Protocol SRAM image update in EEPROM failed\n"); 1623ac3a6d9cSKip Macy 1624ac3a6d9cSKip Macy release_tpeeprom: 1625ac3a6d9cSKip Macy firmware_put(tpeeprom, FIRMWARE_UNLOAD); 1626ac3a6d9cSKip Macy 1627ac3a6d9cSKip Macy return; 1628ac3a6d9cSKip Macy } 1629ac3a6d9cSKip Macy 1630ac3a6d9cSKip Macy static int 1631ac3a6d9cSKip Macy update_tpsram(struct adapter *adap) 1632ac3a6d9cSKip Macy { 16332de1fa86SKip Macy #ifdef FIRMWARE_LATEST 1634ac3a6d9cSKip Macy const struct firmware *tpsram; 16352de1fa86SKip Macy #else 16362de1fa86SKip Macy struct firmware *tpsram; 16372de1fa86SKip Macy #endif 1638ac3a6d9cSKip Macy int ret; 1639f2d8ff04SGeorge V. Neville-Neil char rev, name[32]; 1640ac3a6d9cSKip Macy 1641ac3a6d9cSKip Macy rev = t3rev2char(adap); 1642f2d8ff04SGeorge V. Neville-Neil snprintf(name, sizeof(name), TPSRAM_NAME, rev); 1643ac3a6d9cSKip Macy 1644ac3a6d9cSKip Macy update_tpeeprom(adap); 1645ac3a6d9cSKip Macy 1646f2d8ff04SGeorge V. Neville-Neil tpsram = firmware_get(name); 1647ac3a6d9cSKip Macy if (tpsram == NULL){ 164864a37133SKip Macy device_printf(adap->dev, "could not load TP SRAM\n"); 1649ac3a6d9cSKip Macy return (EINVAL); 1650ac3a6d9cSKip Macy } else 165164a37133SKip Macy device_printf(adap->dev, "updating TP SRAM\n"); 1652ac3a6d9cSKip Macy 1653ac3a6d9cSKip Macy ret = t3_check_tpsram(adap, tpsram->data, tpsram->datasize); 1654ac3a6d9cSKip Macy if (ret) 1655ac3a6d9cSKip Macy goto release_tpsram; 1656ac3a6d9cSKip Macy 1657ac3a6d9cSKip Macy ret = t3_set_proto_sram(adap, tpsram->data); 1658ac3a6d9cSKip Macy if (ret) 1659ac3a6d9cSKip Macy device_printf(adap->dev, "loading protocol SRAM failed\n"); 1660ac3a6d9cSKip Macy 1661ac3a6d9cSKip Macy release_tpsram: 1662ac3a6d9cSKip Macy firmware_put(tpsram, FIRMWARE_UNLOAD); 1663ac3a6d9cSKip Macy 1664ac3a6d9cSKip Macy return ret; 1665ac3a6d9cSKip Macy } 1666ac3a6d9cSKip Macy 1667d722cab4SKip Macy /** 1668d722cab4SKip Macy * cxgb_up - enable the adapter 1669d722cab4SKip Macy * @adap: adapter being enabled 1670d722cab4SKip Macy * 1671d722cab4SKip Macy * Called when the first port is enabled, this function performs the 1672d722cab4SKip Macy * actions necessary to make an adapter operational, such as completing 1673d722cab4SKip Macy * the initialization of HW modules, and enabling interrupts. 1674d722cab4SKip Macy */ 1675d722cab4SKip Macy static int 1676d722cab4SKip Macy cxgb_up(struct adapter *sc) 1677d722cab4SKip Macy { 1678d722cab4SKip Macy int err = 0; 1679d722cab4SKip Macy 1680d722cab4SKip Macy if ((sc->flags & FULL_INIT_DONE) == 0) { 1681d722cab4SKip Macy 1682d722cab4SKip Macy if ((sc->flags & FW_UPTODATE) == 0) 1683ac3a6d9cSKip Macy if ((err = upgrade_fw(sc))) 1684d722cab4SKip Macy goto out; 1685ac3a6d9cSKip Macy if ((sc->flags & TPS_UPTODATE) == 0) 1686ac3a6d9cSKip Macy if ((err = update_tpsram(sc))) 1687ac3a6d9cSKip Macy goto out; 1688d722cab4SKip Macy err = t3_init_hw(sc, 0); 1689d722cab4SKip Macy if (err) 1690d722cab4SKip Macy goto out; 1691d722cab4SKip Macy 16928e10660fSKip Macy t3_set_reg_field(sc, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT); 1693d722cab4SKip Macy t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12)); 1694d722cab4SKip Macy 1695d722cab4SKip Macy err = setup_sge_qsets(sc); 1696d722cab4SKip Macy if (err) 1697d722cab4SKip Macy goto out; 1698d722cab4SKip Macy 1699d722cab4SKip Macy setup_rss(sc); 17008090c9f5SKip Macy t3_add_configured_sysctls(sc); 1701d722cab4SKip Macy sc->flags |= FULL_INIT_DONE; 1702d722cab4SKip Macy } 1703d722cab4SKip Macy 1704d722cab4SKip Macy t3_intr_clear(sc); 1705d722cab4SKip Macy 1706d722cab4SKip Macy /* If it's MSI or INTx, allocate a single interrupt for everything */ 1707d722cab4SKip Macy if ((sc->flags & USING_MSIX) == 0) { 1708d722cab4SKip Macy if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 1709d722cab4SKip Macy &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 17107ac2e6c3SKip Macy device_printf(sc->dev, "Cannot allocate interrupt rid=%d\n", 17117ac2e6c3SKip Macy sc->irq_rid); 1712d722cab4SKip Macy err = EINVAL; 1713d722cab4SKip Macy goto out; 1714d722cab4SKip Macy } 1715d722cab4SKip Macy device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res); 1716d722cab4SKip Macy 1717d722cab4SKip Macy if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET, 1718d722cab4SKip Macy #ifdef INTR_FILTERS 1719d722cab4SKip Macy NULL, 1720d722cab4SKip Macy #endif 1721d722cab4SKip Macy sc->cxgb_intr, sc, &sc->intr_tag)) { 1722d722cab4SKip Macy device_printf(sc->dev, "Cannot set up interrupt\n"); 1723d722cab4SKip Macy err = EINVAL; 1724d722cab4SKip Macy goto irq_err; 1725d722cab4SKip Macy } 1726d722cab4SKip Macy } else { 1727d722cab4SKip Macy cxgb_setup_msix(sc, sc->msi_count); 1728d722cab4SKip Macy } 1729d722cab4SKip Macy 1730d722cab4SKip Macy t3_sge_start(sc); 1731d722cab4SKip Macy t3_intr_enable(sc); 1732d722cab4SKip Macy 17338e10660fSKip Macy if (sc->params.rev >= T3_REV_C && !(sc->flags & TP_PARITY_INIT) && 17348e10660fSKip Macy is_offload(sc) && init_tp_parity(sc) == 0) 17358e10660fSKip Macy sc->flags |= TP_PARITY_INIT; 17368e10660fSKip Macy 17378e10660fSKip Macy if (sc->flags & TP_PARITY_INIT) { 17388e10660fSKip Macy t3_write_reg(sc, A_TP_INT_CAUSE, 17398e10660fSKip Macy F_CMCACHEPERR | F_ARPLUTPERR); 17408e10660fSKip Macy t3_write_reg(sc, A_TP_INT_ENABLE, 0x7fbfffff); 17418e10660fSKip Macy } 17428e10660fSKip Macy 17438e10660fSKip Macy 17445c5df3daSKip Macy if (!(sc->flags & QUEUES_BOUND)) { 1745d722cab4SKip Macy bind_qsets(sc); 1746d722cab4SKip Macy sc->flags |= QUEUES_BOUND; 1747ac3a6d9cSKip Macy } 1748d722cab4SKip Macy out: 1749d722cab4SKip Macy return (err); 1750d722cab4SKip Macy irq_err: 1751d722cab4SKip Macy CH_ERR(sc, "request_irq failed, err %d\n", err); 1752d722cab4SKip Macy goto out; 1753d722cab4SKip Macy } 1754d722cab4SKip Macy 1755d722cab4SKip Macy 1756d722cab4SKip Macy /* 1757d722cab4SKip Macy * Release resources when all the ports and offloading have been stopped. 1758d722cab4SKip Macy */ 1759d722cab4SKip Macy static void 1760bb38cd2fSKip Macy cxgb_down_locked(struct adapter *sc) 1761d722cab4SKip Macy { 1762d722cab4SKip Macy 1763d722cab4SKip Macy t3_sge_stop(sc); 1764d722cab4SKip Macy t3_intr_disable(sc); 1765d722cab4SKip Macy 1766d722cab4SKip Macy if (sc->intr_tag != NULL) { 1767d722cab4SKip Macy bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag); 1768d722cab4SKip Macy sc->intr_tag = NULL; 1769d722cab4SKip Macy } 1770d722cab4SKip Macy if (sc->irq_res != NULL) { 1771d722cab4SKip Macy device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n", 1772d722cab4SKip Macy sc->irq_rid, sc->irq_res); 1773d722cab4SKip Macy bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid, 1774d722cab4SKip Macy sc->irq_res); 1775d722cab4SKip Macy sc->irq_res = NULL; 1776d722cab4SKip Macy } 1777d722cab4SKip Macy 1778ef72318fSKip Macy if (sc->flags & USING_MSIX) 1779ef72318fSKip Macy cxgb_teardown_msix(sc); 1780ef72318fSKip Macy 17818090c9f5SKip Macy callout_stop(&sc->cxgb_tick_ch); 17828090c9f5SKip Macy callout_stop(&sc->sge_timer_ch); 1783bb38cd2fSKip Macy callout_drain(&sc->cxgb_tick_ch); 1784d722cab4SKip Macy callout_drain(&sc->sge_timer_ch); 1785bb38cd2fSKip Macy 17867ac2e6c3SKip Macy if (sc->tq != NULL) { 17878e10660fSKip Macy printf("draining slow intr\n"); 17888e10660fSKip Macy 1789d722cab4SKip Macy taskqueue_drain(sc->tq, &sc->slow_intr_task); 17908e10660fSKip Macy printf("draining ext intr\n"); 17918e10660fSKip Macy taskqueue_drain(sc->tq, &sc->ext_intr_task); 17928e10660fSKip Macy printf("draining tick task\n"); 17938e10660fSKip Macy taskqueue_drain(sc->tq, &sc->tick_task); 17947ac2e6c3SKip Macy } 17958e10660fSKip Macy ADAPTER_UNLOCK(sc); 1796d722cab4SKip Macy } 1797d722cab4SKip Macy 1798d722cab4SKip Macy static int 1799d722cab4SKip Macy offload_open(struct port_info *pi) 1800d722cab4SKip Macy { 1801d722cab4SKip Macy struct adapter *adapter = pi->adapter; 18028090c9f5SKip Macy struct t3cdev *tdev = &adapter->tdev; 1803af9b081cSKip Macy 1804d722cab4SKip Macy int adap_up = adapter->open_device_map & PORT_MASK; 1805d722cab4SKip Macy int err = 0; 1806d722cab4SKip Macy 1807d722cab4SKip Macy if (atomic_cmpset_int(&adapter->open_device_map, 18088090c9f5SKip Macy (adapter->open_device_map & ~(1<<OFFLOAD_DEVMAP_BIT)), 18098090c9f5SKip Macy (adapter->open_device_map | (1<<OFFLOAD_DEVMAP_BIT))) == 0) 1810d722cab4SKip Macy return (0); 1811d722cab4SKip Macy 18128090c9f5SKip Macy if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT)) 1813af9b081cSKip Macy printf("offload_open: DEVMAP_BIT did not get set 0x%x\n", 1814af9b081cSKip Macy adapter->open_device_map); 1815d722cab4SKip Macy ADAPTER_LOCK(pi->adapter); 1816d722cab4SKip Macy if (!adap_up) 1817d722cab4SKip Macy err = cxgb_up(adapter); 1818d722cab4SKip Macy ADAPTER_UNLOCK(pi->adapter); 1819ac3a6d9cSKip Macy if (err) 1820d722cab4SKip Macy return (err); 1821d722cab4SKip Macy 1822d722cab4SKip Macy t3_tp_set_offload_mode(adapter, 1); 18238090c9f5SKip Macy tdev->lldev = pi->ifp; 1824d722cab4SKip Macy 1825d722cab4SKip Macy init_port_mtus(adapter); 1826d722cab4SKip Macy t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd, 1827d722cab4SKip Macy adapter->params.b_wnd, 1828d722cab4SKip Macy adapter->params.rev == 0 ? 1829d722cab4SKip Macy adapter->port[0].ifp->if_mtu : 0xffff); 1830d722cab4SKip Macy init_smt(adapter); 1831ed0fb18dSKip Macy /* Call back all registered clients */ 1832ed0fb18dSKip Macy cxgb_add_clients(tdev); 1833ed0fb18dSKip Macy 1834d722cab4SKip Macy /* restore them in case the offload module has changed them */ 1835d722cab4SKip Macy if (err) { 1836d722cab4SKip Macy t3_tp_set_offload_mode(adapter, 0); 1837d722cab4SKip Macy clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT); 1838d722cab4SKip Macy cxgb_set_dummy_ops(tdev); 1839d722cab4SKip Macy } 1840d722cab4SKip Macy return (err); 1841d722cab4SKip Macy } 18428090c9f5SKip Macy 1843d722cab4SKip Macy static int 18448090c9f5SKip Macy offload_close(struct t3cdev *tdev) 1845d722cab4SKip Macy { 1846d722cab4SKip Macy struct adapter *adapter = tdev2adap(tdev); 1847d722cab4SKip Macy 18488e10660fSKip Macy if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT)) 1849ef72318fSKip Macy return (0); 1850d722cab4SKip Macy 1851ed0fb18dSKip Macy /* Call back all registered clients */ 1852ed0fb18dSKip Macy cxgb_remove_clients(tdev); 1853ed0fb18dSKip Macy 1854d722cab4SKip Macy tdev->lldev = NULL; 1855d722cab4SKip Macy cxgb_set_dummy_ops(tdev); 1856d722cab4SKip Macy t3_tp_set_offload_mode(adapter, 0); 1857d722cab4SKip Macy clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT); 1858d722cab4SKip Macy 18598090c9f5SKip Macy ADAPTER_LOCK(adapter); 1860d722cab4SKip Macy if (!adapter->open_device_map) 18618090c9f5SKip Macy cxgb_down_locked(adapter); 18628090c9f5SKip Macy else 18638090c9f5SKip Macy ADAPTER_UNLOCK(adapter); 1864ef72318fSKip Macy return (0); 1865d722cab4SKip Macy } 18668090c9f5SKip Macy 1867d722cab4SKip Macy 1868b6d90eb7SKip Macy static void 1869b6d90eb7SKip Macy cxgb_init(void *arg) 1870b6d90eb7SKip Macy { 1871b6d90eb7SKip Macy struct port_info *p = arg; 1872b6d90eb7SKip Macy 1873b6d90eb7SKip Macy PORT_LOCK(p); 1874b6d90eb7SKip Macy cxgb_init_locked(p); 1875b6d90eb7SKip Macy PORT_UNLOCK(p); 1876b6d90eb7SKip Macy } 1877b6d90eb7SKip Macy 1878b6d90eb7SKip Macy static void 1879b6d90eb7SKip Macy cxgb_init_locked(struct port_info *p) 1880b6d90eb7SKip Macy { 1881b6d90eb7SKip Macy struct ifnet *ifp; 1882b6d90eb7SKip Macy adapter_t *sc = p->adapter; 1883d722cab4SKip Macy int err; 1884b6d90eb7SKip Macy 1885bb38cd2fSKip Macy PORT_LOCK_ASSERT_OWNED(p); 1886b6d90eb7SKip Macy ifp = p->ifp; 1887d722cab4SKip Macy 1888d722cab4SKip Macy ADAPTER_LOCK(p->adapter); 1889ac3a6d9cSKip Macy if ((sc->open_device_map == 0) && (err = cxgb_up(sc))) { 1890d722cab4SKip Macy ADAPTER_UNLOCK(p->adapter); 1891d722cab4SKip Macy cxgb_stop_locked(p); 1892b6d90eb7SKip Macy return; 1893b6d90eb7SKip Macy } 1894bb38cd2fSKip Macy if (p->adapter->open_device_map == 0) { 1895b6d90eb7SKip Macy t3_intr_clear(sc); 1896bb38cd2fSKip Macy } 18976b68e276SKip Macy setbit(&p->adapter->open_device_map, p->port_id); 1898b6d90eb7SKip Macy ADAPTER_UNLOCK(p->adapter); 1899ef72318fSKip Macy 1900d722cab4SKip Macy if (is_offload(sc) && !ofld_disable) { 1901d722cab4SKip Macy err = offload_open(p); 1902d722cab4SKip Macy if (err) 1903d722cab4SKip Macy log(LOG_WARNING, 1904d722cab4SKip Macy "Could not initialize offload capabilities\n"); 1905d722cab4SKip Macy } 1906ef027c52SKip Macy #if !defined(LINK_ATTACH) 1907ef027c52SKip Macy cxgb_link_start(p); 1908ef027c52SKip Macy t3_link_changed(sc, p->port_id); 1909ef027c52SKip Macy #endif 1910837f41b0SGeorge V. Neville-Neil ifp->if_baudrate = IF_Mbps(p->link_config.speed); 1911ef72318fSKip Macy 19125c5df3daSKip Macy device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id); 19136b68e276SKip Macy t3_port_intr_enable(sc, p->port_id); 1914693d746cSKip Macy 19159330dbc3SKip Macy t3_sge_reset_adapter(sc); 1916b6d90eb7SKip Macy 1917b6d90eb7SKip Macy ifp->if_drv_flags |= IFF_DRV_RUNNING; 1918b6d90eb7SKip Macy ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1919b6d90eb7SKip Macy } 1920b6d90eb7SKip Macy 1921b6d90eb7SKip Macy static void 1922b6d90eb7SKip Macy cxgb_set_rxmode(struct port_info *p) 1923b6d90eb7SKip Macy { 1924b6d90eb7SKip Macy struct t3_rx_mode rm; 1925b6d90eb7SKip Macy struct cmac *mac = &p->mac; 1926b6d90eb7SKip Macy 1927b6d90eb7SKip Macy t3_init_rx_mode(&rm, p); 19288e10660fSKip Macy mtx_lock(&p->adapter->mdio_lock); 1929b6d90eb7SKip Macy t3_mac_set_rx_mode(mac, &rm); 19308e10660fSKip Macy mtx_unlock(&p->adapter->mdio_lock); 1931b6d90eb7SKip Macy } 1932b6d90eb7SKip Macy 1933b6d90eb7SKip Macy static void 193419905d6dSKip Macy cxgb_stop_locked(struct port_info *pi) 1935b6d90eb7SKip Macy { 1936b6d90eb7SKip Macy struct ifnet *ifp; 1937b6d90eb7SKip Macy 193819905d6dSKip Macy PORT_LOCK_ASSERT_OWNED(pi); 193919905d6dSKip Macy ADAPTER_LOCK_ASSERT_NOTOWNED(pi->adapter); 194077f07749SKip Macy 194119905d6dSKip Macy ifp = pi->ifp; 194219905d6dSKip Macy t3_port_intr_disable(pi->adapter, pi->port_id); 1943d722cab4SKip Macy ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1944b6d90eb7SKip Macy 194519905d6dSKip Macy /* disable pause frames */ 194619905d6dSKip Macy t3_set_reg_field(pi->adapter, A_XGM_TX_CFG + pi->mac.offset, 194719905d6dSKip Macy F_TXPAUSEEN, 0); 1948bb38cd2fSKip Macy 194919905d6dSKip Macy /* Reset RX FIFO HWM */ 195019905d6dSKip Macy t3_set_reg_field(pi->adapter, A_XGM_RXFIFO_CFG + pi->mac.offset, 195119905d6dSKip Macy V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM), 0); 195219905d6dSKip Macy 195319905d6dSKip Macy 195419905d6dSKip Macy ADAPTER_LOCK(pi->adapter); 195519905d6dSKip Macy clrbit(&pi->adapter->open_device_map, pi->port_id); 195619905d6dSKip Macy 195719905d6dSKip Macy if (pi->adapter->open_device_map == 0) { 195819905d6dSKip Macy cxgb_down_locked(pi->adapter); 1959bb38cd2fSKip Macy } else 196019905d6dSKip Macy ADAPTER_UNLOCK(pi->adapter); 196119905d6dSKip Macy 1962ef027c52SKip Macy #if !defined(LINK_ATTACH) 196319905d6dSKip Macy DELAY(100); 196419905d6dSKip Macy 196519905d6dSKip Macy /* Wait for TXFIFO empty */ 196619905d6dSKip Macy t3_wait_op_done(pi->adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 196719905d6dSKip Macy F_TXFIFO_EMPTY, 1, 20, 5); 196819905d6dSKip Macy 196919905d6dSKip Macy DELAY(100); 197019905d6dSKip Macy t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); 197119905d6dSKip Macy 197219905d6dSKip Macy pi->phy.ops->power_down(&pi->phy, 1); 1973ef027c52SKip Macy #endif 1974bb38cd2fSKip Macy 1975b6d90eb7SKip Macy } 1976b6d90eb7SKip Macy 1977b6d90eb7SKip Macy static int 1978ef72318fSKip Macy cxgb_set_mtu(struct port_info *p, int mtu) 1979ef72318fSKip Macy { 1980ef72318fSKip Macy struct ifnet *ifp = p->ifp; 1981ef72318fSKip Macy int error = 0; 1982ef72318fSKip Macy 19834af83c8cSKip Macy if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) 1984ef72318fSKip Macy error = EINVAL; 1985ef72318fSKip Macy else if (ifp->if_mtu != mtu) { 1986ef72318fSKip Macy PORT_LOCK(p); 1987ef72318fSKip Macy ifp->if_mtu = mtu; 1988ef72318fSKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1989ef72318fSKip Macy cxgb_stop_locked(p); 1990ef72318fSKip Macy cxgb_init_locked(p); 1991ef72318fSKip Macy } 1992ef72318fSKip Macy PORT_UNLOCK(p); 1993ef72318fSKip Macy } 1994ef72318fSKip Macy return (error); 1995ef72318fSKip Macy } 1996ef72318fSKip Macy 1997e97121daSKip Macy #ifdef LRO_SUPPORTED 199825292debSKip Macy /* 199925292debSKip Macy * Mark lro enabled or disabled in all qsets for this port 200025292debSKip Macy */ 200125292debSKip Macy static int 200225292debSKip Macy cxgb_set_lro(struct port_info *p, int enabled) 200325292debSKip Macy { 200425292debSKip Macy int i; 200525292debSKip Macy struct adapter *adp = p->adapter; 200625292debSKip Macy struct sge_qset *q; 200725292debSKip Macy 200825292debSKip Macy PORT_LOCK_ASSERT_OWNED(p); 200925292debSKip Macy for (i = 0; i < p->nqsets; i++) { 201025292debSKip Macy q = &adp->sge.qs[p->first_qset + i]; 201125292debSKip Macy q->lro.enabled = (enabled != 0); 201225292debSKip Macy } 201325292debSKip Macy return (0); 201425292debSKip Macy } 2015e97121daSKip Macy #endif 201625292debSKip Macy 2017ef72318fSKip Macy static int 2018b6d90eb7SKip Macy cxgb_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data) 2019b6d90eb7SKip Macy { 2020b6d90eb7SKip Macy struct port_info *p = ifp->if_softc; 202134627f93SBjoern A. Zeeb #ifdef INET 2022b6d90eb7SKip Macy struct ifaddr *ifa = (struct ifaddr *)data; 202334627f93SBjoern A. Zeeb #endif 2024b6d90eb7SKip Macy struct ifreq *ifr = (struct ifreq *)data; 20254af83c8cSKip Macy int flags, error = 0, reinit = 0; 2026b6d90eb7SKip Macy uint32_t mask; 2027b6d90eb7SKip Macy 202851580731SKip Macy /* 202951580731SKip Macy * XXX need to check that we aren't in the middle of an unload 203051580731SKip Macy */ 2031b6d90eb7SKip Macy switch (command) { 2032b6d90eb7SKip Macy case SIOCSIFMTU: 2033ef72318fSKip Macy error = cxgb_set_mtu(p, ifr->ifr_mtu); 2034b6d90eb7SKip Macy break; 2035b6d90eb7SKip Macy case SIOCSIFADDR: 203634627f93SBjoern A. Zeeb #ifdef INET 2037b6d90eb7SKip Macy if (ifa->ifa_addr->sa_family == AF_INET) { 2038b6d90eb7SKip Macy ifp->if_flags |= IFF_UP; 20398e10660fSKip Macy if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 20408e10660fSKip Macy PORT_LOCK(p); 2041ef72318fSKip Macy cxgb_init_locked(p); 20424f6a96aeSKip Macy PORT_UNLOCK(p); 20438e10660fSKip Macy } 20448e10660fSKip Macy arp_ifinit(ifp, ifa); 2045b6d90eb7SKip Macy } else 204634627f93SBjoern A. Zeeb #endif 2047b6d90eb7SKip Macy error = ether_ioctl(ifp, command, data); 2048b6d90eb7SKip Macy break; 2049b6d90eb7SKip Macy case SIOCSIFFLAGS: 2050693d746cSKip Macy PORT_LOCK(p); 2051ef72318fSKip Macy if (ifp->if_flags & IFF_UP) { 2052b6d90eb7SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2053b6d90eb7SKip Macy flags = p->if_flags; 2054b6d90eb7SKip Macy if (((ifp->if_flags ^ flags) & IFF_PROMISC) || 2055b6d90eb7SKip Macy ((ifp->if_flags ^ flags) & IFF_ALLMULTI)) 2056b6d90eb7SKip Macy cxgb_set_rxmode(p); 2057b6d90eb7SKip Macy } else 2058b6d90eb7SKip Macy cxgb_init_locked(p); 2059b6d90eb7SKip Macy p->if_flags = ifp->if_flags; 2060bb38cd2fSKip Macy } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2061693d746cSKip Macy cxgb_stop_locked(p); 2062bb38cd2fSKip Macy 2063ef72318fSKip Macy PORT_UNLOCK(p); 2064b6d90eb7SKip Macy break; 20658e10660fSKip Macy case SIOCADDMULTI: 20668e10660fSKip Macy case SIOCDELMULTI: 20678e10660fSKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 20688e10660fSKip Macy cxgb_set_rxmode(p); 20698e10660fSKip Macy } 20708e10660fSKip Macy break; 2071b6d90eb7SKip Macy case SIOCSIFMEDIA: 2072b6d90eb7SKip Macy case SIOCGIFMEDIA: 2073837f41b0SGeorge V. Neville-Neil PORT_LOCK(p); 2074b6d90eb7SKip Macy error = ifmedia_ioctl(ifp, ifr, &p->media, command); 2075837f41b0SGeorge V. Neville-Neil PORT_UNLOCK(p); 2076b6d90eb7SKip Macy break; 2077b6d90eb7SKip Macy case SIOCSIFCAP: 2078b6d90eb7SKip Macy PORT_LOCK(p); 2079b6d90eb7SKip Macy mask = ifr->ifr_reqcap ^ ifp->if_capenable; 2080b6d90eb7SKip Macy if (mask & IFCAP_TXCSUM) { 2081b6d90eb7SKip Macy if (IFCAP_TXCSUM & ifp->if_capenable) { 2082b6d90eb7SKip Macy ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 2083b6d90eb7SKip Macy ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 20844af83c8cSKip Macy | CSUM_IP | CSUM_TSO); 2085b6d90eb7SKip Macy } else { 2086b6d90eb7SKip Macy ifp->if_capenable |= IFCAP_TXCSUM; 20874af83c8cSKip Macy ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP 20884af83c8cSKip Macy | CSUM_IP); 2089b6d90eb7SKip Macy } 2090b6d90eb7SKip Macy } 20914af83c8cSKip Macy if (mask & IFCAP_RXCSUM) { 20924af83c8cSKip Macy ifp->if_capenable ^= IFCAP_RXCSUM; 2093b6d90eb7SKip Macy } 2094b6d90eb7SKip Macy if (mask & IFCAP_TSO4) { 2095b6d90eb7SKip Macy if (IFCAP_TSO4 & ifp->if_capenable) { 2096b6d90eb7SKip Macy ifp->if_capenable &= ~IFCAP_TSO4; 2097b6d90eb7SKip Macy ifp->if_hwassist &= ~CSUM_TSO; 2098b6d90eb7SKip Macy } else if (IFCAP_TXCSUM & ifp->if_capenable) { 2099b6d90eb7SKip Macy ifp->if_capenable |= IFCAP_TSO4; 2100b6d90eb7SKip Macy ifp->if_hwassist |= CSUM_TSO; 2101b6d90eb7SKip Macy } else { 2102b6d90eb7SKip Macy if (cxgb_debug) 2103b6d90eb7SKip Macy printf("cxgb requires tx checksum offload" 2104b6d90eb7SKip Macy " be enabled to use TSO\n"); 2105b6d90eb7SKip Macy error = EINVAL; 2106b6d90eb7SKip Macy } 2107b6d90eb7SKip Macy } 2108e97121daSKip Macy #ifdef LRO_SUPPORTED 210925292debSKip Macy if (mask & IFCAP_LRO) { 211025292debSKip Macy ifp->if_capenable ^= IFCAP_LRO; 211125292debSKip Macy 211225292debSKip Macy /* Safe to do this even if cxgb_up not called yet */ 211325292debSKip Macy cxgb_set_lro(p, ifp->if_capenable & IFCAP_LRO); 211425292debSKip Macy } 2115e97121daSKip Macy #endif 21164af83c8cSKip Macy if (mask & IFCAP_VLAN_HWTAGGING) { 21174af83c8cSKip Macy ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 21184af83c8cSKip Macy reinit = ifp->if_drv_flags & IFF_DRV_RUNNING; 21194af83c8cSKip Macy } 21204af83c8cSKip Macy if (mask & IFCAP_VLAN_MTU) { 21214af83c8cSKip Macy ifp->if_capenable ^= IFCAP_VLAN_MTU; 21224af83c8cSKip Macy reinit = ifp->if_drv_flags & IFF_DRV_RUNNING; 21234af83c8cSKip Macy } 21244af83c8cSKip Macy if (mask & IFCAP_VLAN_HWCSUM) { 21254af83c8cSKip Macy ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 21264af83c8cSKip Macy } 21274af83c8cSKip Macy if (reinit) { 21284af83c8cSKip Macy cxgb_stop_locked(p); 21294af83c8cSKip Macy cxgb_init_locked(p); 21304af83c8cSKip Macy } 2131b6d90eb7SKip Macy PORT_UNLOCK(p); 21324af83c8cSKip Macy 21334af83c8cSKip Macy #ifdef VLAN_CAPABILITIES 21344af83c8cSKip Macy VLAN_CAPABILITIES(ifp); 21354af83c8cSKip Macy #endif 2136b6d90eb7SKip Macy break; 2137b6d90eb7SKip Macy default: 2138b6d90eb7SKip Macy error = ether_ioctl(ifp, command, data); 2139b6d90eb7SKip Macy break; 2140b6d90eb7SKip Macy } 2141b6d90eb7SKip Macy return (error); 2142b6d90eb7SKip Macy } 2143b6d90eb7SKip Macy 2144b6d90eb7SKip Macy static int 2145b6d90eb7SKip Macy cxgb_media_change(struct ifnet *ifp) 2146b6d90eb7SKip Macy { 2147b6d90eb7SKip Macy if_printf(ifp, "media change not supported\n"); 2148b6d90eb7SKip Macy return (ENXIO); 2149b6d90eb7SKip Macy } 2150b6d90eb7SKip Macy 2151837f41b0SGeorge V. Neville-Neil /* 2152837f41b0SGeorge V. Neville-Neil * Translates from phy->modtype to IFM_TYPE. 2153837f41b0SGeorge V. Neville-Neil */ 2154837f41b0SGeorge V. Neville-Neil static int 2155837f41b0SGeorge V. Neville-Neil cxgb_ifm_type(int phymod) 2156837f41b0SGeorge V. Neville-Neil { 2157837f41b0SGeorge V. Neville-Neil int rc = IFM_ETHER | IFM_FDX; 2158837f41b0SGeorge V. Neville-Neil 2159837f41b0SGeorge V. Neville-Neil switch (phymod) { 2160837f41b0SGeorge V. Neville-Neil case phy_modtype_sr: 2161837f41b0SGeorge V. Neville-Neil rc |= IFM_10G_SR; 2162837f41b0SGeorge V. Neville-Neil break; 2163837f41b0SGeorge V. Neville-Neil case phy_modtype_lr: 2164837f41b0SGeorge V. Neville-Neil rc |= IFM_10G_LR; 2165837f41b0SGeorge V. Neville-Neil break; 2166837f41b0SGeorge V. Neville-Neil case phy_modtype_lrm: 2167837f41b0SGeorge V. Neville-Neil #ifdef IFM_10G_LRM 2168837f41b0SGeorge V. Neville-Neil rc |= IFM_10G_LRM; 2169837f41b0SGeorge V. Neville-Neil #endif 2170837f41b0SGeorge V. Neville-Neil break; 2171837f41b0SGeorge V. Neville-Neil case phy_modtype_twinax: 2172837f41b0SGeorge V. Neville-Neil #ifdef IFM_10G_TWINAX 2173837f41b0SGeorge V. Neville-Neil rc |= IFM_10G_TWINAX; 2174837f41b0SGeorge V. Neville-Neil #endif 2175837f41b0SGeorge V. Neville-Neil break; 2176837f41b0SGeorge V. Neville-Neil case phy_modtype_twinax_long: 2177837f41b0SGeorge V. Neville-Neil #ifdef IFM_10G_TWINAX_LONG 2178837f41b0SGeorge V. Neville-Neil rc |= IFM_10G_TWINAX_LONG; 2179837f41b0SGeorge V. Neville-Neil #endif 2180837f41b0SGeorge V. Neville-Neil break; 2181837f41b0SGeorge V. Neville-Neil case phy_modtype_none: 2182837f41b0SGeorge V. Neville-Neil rc = IFM_ETHER | IFM_NONE; 2183837f41b0SGeorge V. Neville-Neil break; 2184837f41b0SGeorge V. Neville-Neil case phy_modtype_unknown: 2185837f41b0SGeorge V. Neville-Neil break; 2186837f41b0SGeorge V. Neville-Neil } 2187837f41b0SGeorge V. Neville-Neil 2188837f41b0SGeorge V. Neville-Neil return (rc); 2189837f41b0SGeorge V. Neville-Neil } 2190837f41b0SGeorge V. Neville-Neil 2191b6d90eb7SKip Macy static void 2192b6d90eb7SKip Macy cxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 2193b6d90eb7SKip Macy { 2194b6d90eb7SKip Macy struct port_info *p = ifp->if_softc; 2195837f41b0SGeorge V. Neville-Neil struct ifmedia_entry *cur = p->media.ifm_cur; 2196837f41b0SGeorge V. Neville-Neil int m; 2197837f41b0SGeorge V. Neville-Neil 2198837f41b0SGeorge V. Neville-Neil if (cur->ifm_data != p->phy.modtype) { 2199837f41b0SGeorge V. Neville-Neil /* p->media about to be rebuilt, must hold lock */ 2200837f41b0SGeorge V. Neville-Neil PORT_LOCK_ASSERT_OWNED(p); 2201837f41b0SGeorge V. Neville-Neil 2202837f41b0SGeorge V. Neville-Neil m = cxgb_ifm_type(p->phy.modtype); 2203837f41b0SGeorge V. Neville-Neil ifmedia_removeall(&p->media); 2204837f41b0SGeorge V. Neville-Neil ifmedia_add(&p->media, m, p->phy.modtype, NULL); 2205837f41b0SGeorge V. Neville-Neil ifmedia_set(&p->media, m); 2206837f41b0SGeorge V. Neville-Neil cur = p->media.ifm_cur; /* ifmedia_set modified ifm_cur */ 2207837f41b0SGeorge V. Neville-Neil ifmr->ifm_current = m; 2208837f41b0SGeorge V. Neville-Neil } 2209b6d90eb7SKip Macy 2210b6d90eb7SKip Macy ifmr->ifm_status = IFM_AVALID; 2211b6d90eb7SKip Macy ifmr->ifm_active = IFM_ETHER; 2212b6d90eb7SKip Macy 2213b6d90eb7SKip Macy if (!p->link_config.link_ok) 2214b6d90eb7SKip Macy return; 2215b6d90eb7SKip Macy 2216b6d90eb7SKip Macy ifmr->ifm_status |= IFM_ACTIVE; 2217b6d90eb7SKip Macy 2218ef72318fSKip Macy switch (p->link_config.speed) { 2219ef72318fSKip Macy case 10: 2220ef72318fSKip Macy ifmr->ifm_active |= IFM_10_T; 2221ef72318fSKip Macy break; 2222ef72318fSKip Macy case 100: 2223ef72318fSKip Macy ifmr->ifm_active |= IFM_100_TX; 2224ef72318fSKip Macy break; 2225ef72318fSKip Macy case 1000: 2226ef72318fSKip Macy ifmr->ifm_active |= IFM_1000_T; 2227ef72318fSKip Macy break; 2228837f41b0SGeorge V. Neville-Neil case 10000: 2229837f41b0SGeorge V. Neville-Neil ifmr->ifm_active |= IFM_SUBTYPE(cur->ifm_media); 2230837f41b0SGeorge V. Neville-Neil break; 2231ef72318fSKip Macy } 2232ef72318fSKip Macy 2233b6d90eb7SKip Macy if (p->link_config.duplex) 2234b6d90eb7SKip Macy ifmr->ifm_active |= IFM_FDX; 2235b6d90eb7SKip Macy else 2236b6d90eb7SKip Macy ifmr->ifm_active |= IFM_HDX; 2237b6d90eb7SKip Macy } 2238b6d90eb7SKip Macy 2239b6d90eb7SKip Macy static void 2240b6d90eb7SKip Macy cxgb_async_intr(void *data) 2241b6d90eb7SKip Macy { 2242693d746cSKip Macy adapter_t *sc = data; 2243693d746cSKip Macy 2244b6d90eb7SKip Macy if (cxgb_debug) 2245693d746cSKip Macy device_printf(sc->dev, "cxgb_async_intr\n"); 2246bb38cd2fSKip Macy /* 2247bb38cd2fSKip Macy * May need to sleep - defer to taskqueue 2248bb38cd2fSKip Macy */ 2249bb38cd2fSKip Macy taskqueue_enqueue(sc->tq, &sc->slow_intr_task); 2250b6d90eb7SKip Macy } 2251b6d90eb7SKip Macy 2252b6d90eb7SKip Macy static void 2253b6d90eb7SKip Macy cxgb_ext_intr_handler(void *arg, int count) 2254b6d90eb7SKip Macy { 2255b6d90eb7SKip Macy adapter_t *sc = (adapter_t *)arg; 2256b6d90eb7SKip Macy 2257b6d90eb7SKip Macy if (cxgb_debug) 2258b6d90eb7SKip Macy printf("cxgb_ext_intr_handler\n"); 2259b6d90eb7SKip Macy 2260b6d90eb7SKip Macy t3_phy_intr_handler(sc); 2261b6d90eb7SKip Macy 2262b6d90eb7SKip Macy /* Now reenable external interrupts */ 2263d722cab4SKip Macy ADAPTER_LOCK(sc); 2264b6d90eb7SKip Macy if (sc->slow_intr_mask) { 2265b6d90eb7SKip Macy sc->slow_intr_mask |= F_T3DBG; 2266b6d90eb7SKip Macy t3_write_reg(sc, A_PL_INT_CAUSE0, F_T3DBG); 2267b6d90eb7SKip Macy t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask); 2268b6d90eb7SKip Macy } 2269d722cab4SKip Macy ADAPTER_UNLOCK(sc); 2270b6d90eb7SKip Macy } 2271b6d90eb7SKip Macy 2272b6d90eb7SKip Macy static void 2273b6d90eb7SKip Macy check_link_status(adapter_t *sc) 2274b6d90eb7SKip Macy { 2275b6d90eb7SKip Macy int i; 2276b6d90eb7SKip Macy 2277b6d90eb7SKip Macy for (i = 0; i < (sc)->params.nports; ++i) { 2278b6d90eb7SKip Macy struct port_info *p = &sc->port[i]; 2279b6d90eb7SKip Macy 22808e10660fSKip Macy if (!(p->phy.caps & SUPPORTED_IRQ)) 2281b6d90eb7SKip Macy t3_link_changed(sc, i); 2282837f41b0SGeorge V. Neville-Neil p->ifp->if_baudrate = IF_Mbps(p->link_config.speed); 2283b6d90eb7SKip Macy } 2284b6d90eb7SKip Macy } 2285b6d90eb7SKip Macy 2286577e9bbeSKip Macy static void 2287577e9bbeSKip Macy check_t3b2_mac(struct adapter *adapter) 2288577e9bbeSKip Macy { 2289577e9bbeSKip Macy int i; 2290577e9bbeSKip Macy 22918e10660fSKip Macy if(adapter->flags & CXGB_SHUTDOWN) 22928e10660fSKip Macy return; 22938e10660fSKip Macy 2294577e9bbeSKip Macy for_each_port(adapter, i) { 2295577e9bbeSKip Macy struct port_info *p = &adapter->port[i]; 2296577e9bbeSKip Macy struct ifnet *ifp = p->ifp; 2297577e9bbeSKip Macy int status; 2298577e9bbeSKip Macy 22998e10660fSKip Macy if(adapter->flags & CXGB_SHUTDOWN) 23008e10660fSKip Macy return; 23018e10660fSKip Macy 2302577e9bbeSKip Macy if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 2303577e9bbeSKip Macy continue; 2304577e9bbeSKip Macy 2305577e9bbeSKip Macy status = 0; 2306577e9bbeSKip Macy PORT_LOCK(p); 2307577e9bbeSKip Macy if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) 2308577e9bbeSKip Macy status = t3b2_mac_watchdog_task(&p->mac); 2309577e9bbeSKip Macy if (status == 1) 2310577e9bbeSKip Macy p->mac.stats.num_toggled++; 2311577e9bbeSKip Macy else if (status == 2) { 2312577e9bbeSKip Macy struct cmac *mac = &p->mac; 23134af83c8cSKip Macy int mtu = ifp->if_mtu; 2314577e9bbeSKip Macy 23154af83c8cSKip Macy if (ifp->if_capenable & IFCAP_VLAN_MTU) 23164af83c8cSKip Macy mtu += ETHER_VLAN_ENCAP_LEN; 23174af83c8cSKip Macy t3_mac_set_mtu(mac, mtu); 2318577e9bbeSKip Macy t3_mac_set_address(mac, 0, p->hw_addr); 2319577e9bbeSKip Macy cxgb_set_rxmode(p); 2320577e9bbeSKip Macy t3_link_start(&p->phy, mac, &p->link_config); 2321577e9bbeSKip Macy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 23226b68e276SKip Macy t3_port_intr_enable(adapter, p->port_id); 2323577e9bbeSKip Macy p->mac.stats.num_resets++; 2324577e9bbeSKip Macy } 2325577e9bbeSKip Macy PORT_UNLOCK(p); 2326577e9bbeSKip Macy } 2327577e9bbeSKip Macy } 2328577e9bbeSKip Macy 2329577e9bbeSKip Macy static void 2330577e9bbeSKip Macy cxgb_tick(void *arg) 2331577e9bbeSKip Macy { 2332577e9bbeSKip Macy adapter_t *sc = (adapter_t *)arg; 23338090c9f5SKip Macy 23348e10660fSKip Macy if(sc->flags & CXGB_SHUTDOWN) 23358090c9f5SKip Macy return; 2336577e9bbeSKip Macy 2337bb38cd2fSKip Macy taskqueue_enqueue(sc->tq, &sc->tick_task); 2338706cb31fSKip Macy callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc); 2339bb38cd2fSKip Macy } 2340bb38cd2fSKip Macy 2341bb38cd2fSKip Macy static void 2342bb38cd2fSKip Macy cxgb_tick_handler(void *arg, int count) 2343bb38cd2fSKip Macy { 2344bb38cd2fSKip Macy adapter_t *sc = (adapter_t *)arg; 2345bb38cd2fSKip Macy const struct adapter_params *p = &sc->params; 2346706cb31fSKip Macy int i; 2347f2d8ff04SGeorge V. Neville-Neil uint32_t cause, reset; 2348bb38cd2fSKip Macy 23498e10660fSKip Macy if(sc->flags & CXGB_SHUTDOWN) 23508e10660fSKip Macy return; 23518e10660fSKip Macy 2352bb38cd2fSKip Macy ADAPTER_LOCK(sc); 2353bb38cd2fSKip Macy if (p->linkpoll_period) 2354bb38cd2fSKip Macy check_link_status(sc); 2355577e9bbeSKip Macy 2356f35c2d65SKip Macy sc->check_task_cnt++; 2357f35c2d65SKip Macy 2358f35c2d65SKip Macy /* 2359f35c2d65SKip Macy * adapter lock can currently only be acquired after the 2360f35c2d65SKip Macy * port lock 2361f35c2d65SKip Macy */ 2362f35c2d65SKip Macy ADAPTER_UNLOCK(sc); 2363f35c2d65SKip Macy 2364f35c2d65SKip Macy if (p->rev == T3_REV_B2 && p->nports < 4 && sc->open_device_map) 2365f35c2d65SKip Macy check_t3b2_mac(sc); 2366f35c2d65SKip Macy 2367f2d8ff04SGeorge V. Neville-Neil cause = t3_read_reg(sc, A_SG_INT_CAUSE); 2368f2d8ff04SGeorge V. Neville-Neil reset = 0; 2369f2d8ff04SGeorge V. Neville-Neil if (cause & F_FLEMPTY) { 2370f2d8ff04SGeorge V. Neville-Neil struct sge_qset *qs = &sc->sge.qs[0]; 2371f2d8ff04SGeorge V. Neville-Neil 2372f2d8ff04SGeorge V. Neville-Neil i = 0; 2373f2d8ff04SGeorge V. Neville-Neil reset |= F_FLEMPTY; 2374f2d8ff04SGeorge V. Neville-Neil 2375f2d8ff04SGeorge V. Neville-Neil cause = (t3_read_reg(sc, A_SG_RSPQ_FL_STATUS) >> 2376f2d8ff04SGeorge V. Neville-Neil S_FL0EMPTY) & 0xffff; 2377f2d8ff04SGeorge V. Neville-Neil while (cause) { 2378f2d8ff04SGeorge V. Neville-Neil qs->fl[i].empty += (cause & 1); 2379f2d8ff04SGeorge V. Neville-Neil if (i) 2380f2d8ff04SGeorge V. Neville-Neil qs++; 2381f2d8ff04SGeorge V. Neville-Neil i ^= 1; 2382f2d8ff04SGeorge V. Neville-Neil cause >>= 1; 2383f2d8ff04SGeorge V. Neville-Neil } 2384f2d8ff04SGeorge V. Neville-Neil } 2385f2d8ff04SGeorge V. Neville-Neil t3_write_reg(sc, A_SG_INT_CAUSE, reset); 2386f2d8ff04SGeorge V. Neville-Neil 2387ceac50ebSKip Macy for (i = 0; i < sc->params.nports; i++) { 2388ceac50ebSKip Macy struct port_info *pi = &sc->port[i]; 2389ceac50ebSKip Macy struct ifnet *ifp = pi->ifp; 2390f2d8ff04SGeorge V. Neville-Neil struct cmac *mac = &pi->mac; 2391f2d8ff04SGeorge V. Neville-Neil struct mac_stats *mstats = &mac->stats; 2392f35c2d65SKip Macy PORT_LOCK(pi); 2393f2d8ff04SGeorge V. Neville-Neil t3_mac_update_stats(mac); 2394f35c2d65SKip Macy PORT_UNLOCK(pi); 2395f35c2d65SKip Macy 2396f2d8ff04SGeorge V. Neville-Neil if (pi->link_fault) 2397f2d8ff04SGeorge V. Neville-Neil taskqueue_enqueue(sc->tq, &pi->link_fault_task); 2398ceac50ebSKip Macy 2399ceac50ebSKip Macy ifp->if_opackets = 2400ceac50ebSKip Macy mstats->tx_frames_64 + 2401ceac50ebSKip Macy mstats->tx_frames_65_127 + 2402ceac50ebSKip Macy mstats->tx_frames_128_255 + 2403ceac50ebSKip Macy mstats->tx_frames_256_511 + 2404ceac50ebSKip Macy mstats->tx_frames_512_1023 + 2405ceac50ebSKip Macy mstats->tx_frames_1024_1518 + 2406ceac50ebSKip Macy mstats->tx_frames_1519_max; 2407ceac50ebSKip Macy 2408ceac50ebSKip Macy ifp->if_ipackets = 2409ceac50ebSKip Macy mstats->rx_frames_64 + 2410ceac50ebSKip Macy mstats->rx_frames_65_127 + 2411ceac50ebSKip Macy mstats->rx_frames_128_255 + 2412ceac50ebSKip Macy mstats->rx_frames_256_511 + 2413ceac50ebSKip Macy mstats->rx_frames_512_1023 + 2414ceac50ebSKip Macy mstats->rx_frames_1024_1518 + 2415ceac50ebSKip Macy mstats->rx_frames_1519_max; 2416ceac50ebSKip Macy 2417ceac50ebSKip Macy ifp->if_obytes = mstats->tx_octets; 2418ceac50ebSKip Macy ifp->if_ibytes = mstats->rx_octets; 2419ceac50ebSKip Macy ifp->if_omcasts = mstats->tx_mcast_frames; 2420ceac50ebSKip Macy ifp->if_imcasts = mstats->rx_mcast_frames; 2421ceac50ebSKip Macy 2422ceac50ebSKip Macy ifp->if_collisions = 2423ceac50ebSKip Macy mstats->tx_total_collisions; 2424ceac50ebSKip Macy 2425ceac50ebSKip Macy ifp->if_iqdrops = mstats->rx_cong_drops; 2426ceac50ebSKip Macy 2427ceac50ebSKip Macy ifp->if_oerrors = 2428ceac50ebSKip Macy mstats->tx_excess_collisions + 2429ceac50ebSKip Macy mstats->tx_underrun + 2430ceac50ebSKip Macy mstats->tx_len_errs + 2431ceac50ebSKip Macy mstats->tx_mac_internal_errs + 2432ceac50ebSKip Macy mstats->tx_excess_deferral + 2433ceac50ebSKip Macy mstats->tx_fcs_errs; 2434ceac50ebSKip Macy ifp->if_ierrors = 2435ceac50ebSKip Macy mstats->rx_jabber + 2436ceac50ebSKip Macy mstats->rx_data_errs + 2437ceac50ebSKip Macy mstats->rx_sequence_errs + 2438ceac50ebSKip Macy mstats->rx_runt + 2439ceac50ebSKip Macy mstats->rx_too_long + 2440ceac50ebSKip Macy mstats->rx_mac_internal_errs + 2441ceac50ebSKip Macy mstats->rx_short + 2442ceac50ebSKip Macy mstats->rx_fcs_errs; 2443f2d8ff04SGeorge V. Neville-Neil 2444f2d8ff04SGeorge V. Neville-Neil if (mac->multiport) 2445f2d8ff04SGeorge V. Neville-Neil continue; 2446f2d8ff04SGeorge V. Neville-Neil 2447f2d8ff04SGeorge V. Neville-Neil /* Count rx fifo overflows, once per second */ 2448f2d8ff04SGeorge V. Neville-Neil cause = t3_read_reg(sc, A_XGM_INT_CAUSE + mac->offset); 2449f2d8ff04SGeorge V. Neville-Neil reset = 0; 2450f2d8ff04SGeorge V. Neville-Neil if (cause & F_RXFIFO_OVERFLOW) { 2451f2d8ff04SGeorge V. Neville-Neil mac->stats.rx_fifo_ovfl++; 2452f2d8ff04SGeorge V. Neville-Neil reset |= F_RXFIFO_OVERFLOW; 2453f2d8ff04SGeorge V. Neville-Neil } 2454f2d8ff04SGeorge V. Neville-Neil t3_write_reg(sc, A_XGM_INT_CAUSE + mac->offset, reset); 2455ceac50ebSKip Macy } 2456577e9bbeSKip Macy } 2457577e9bbeSKip Macy 24587ac2e6c3SKip Macy static void 24597ac2e6c3SKip Macy touch_bars(device_t dev) 24607ac2e6c3SKip Macy { 24617ac2e6c3SKip Macy /* 24627ac2e6c3SKip Macy * Don't enable yet 24637ac2e6c3SKip Macy */ 24647ac2e6c3SKip Macy #if !defined(__LP64__) && 0 24657ac2e6c3SKip Macy u32 v; 24667ac2e6c3SKip Macy 24677ac2e6c3SKip Macy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &v); 24687ac2e6c3SKip Macy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, v); 24697ac2e6c3SKip Macy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3, &v); 24707ac2e6c3SKip Macy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_3, v); 24717ac2e6c3SKip Macy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &v); 24727ac2e6c3SKip Macy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_5, v); 24737ac2e6c3SKip Macy #endif 24747ac2e6c3SKip Macy } 24757ac2e6c3SKip Macy 2476ac3a6d9cSKip Macy static int 2477ac3a6d9cSKip Macy set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset) 2478ac3a6d9cSKip Macy { 2479ac3a6d9cSKip Macy uint8_t *buf; 2480ac3a6d9cSKip Macy int err = 0; 2481ac3a6d9cSKip Macy u32 aligned_offset, aligned_len, *p; 2482ac3a6d9cSKip Macy struct adapter *adapter = pi->adapter; 2483ac3a6d9cSKip Macy 2484ac3a6d9cSKip Macy 2485ac3a6d9cSKip Macy aligned_offset = offset & ~3; 2486ac3a6d9cSKip Macy aligned_len = (len + (offset & 3) + 3) & ~3; 2487ac3a6d9cSKip Macy 2488ac3a6d9cSKip Macy if (aligned_offset != offset || aligned_len != len) { 2489ac3a6d9cSKip Macy buf = malloc(aligned_len, M_DEVBUF, M_WAITOK|M_ZERO); 2490ac3a6d9cSKip Macy if (!buf) 2491ac3a6d9cSKip Macy return (ENOMEM); 2492ac3a6d9cSKip Macy err = t3_seeprom_read(adapter, aligned_offset, (u32 *)buf); 2493ac3a6d9cSKip Macy if (!err && aligned_len > 4) 2494ac3a6d9cSKip Macy err = t3_seeprom_read(adapter, 2495ac3a6d9cSKip Macy aligned_offset + aligned_len - 4, 2496ac3a6d9cSKip Macy (u32 *)&buf[aligned_len - 4]); 2497ac3a6d9cSKip Macy if (err) 2498ac3a6d9cSKip Macy goto out; 2499ac3a6d9cSKip Macy memcpy(buf + (offset & 3), data, len); 2500ac3a6d9cSKip Macy } else 2501ac3a6d9cSKip Macy buf = (uint8_t *)(uintptr_t)data; 2502ac3a6d9cSKip Macy 2503ac3a6d9cSKip Macy err = t3_seeprom_wp(adapter, 0); 2504ac3a6d9cSKip Macy if (err) 2505ac3a6d9cSKip Macy goto out; 2506ac3a6d9cSKip Macy 2507ac3a6d9cSKip Macy for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { 2508ac3a6d9cSKip Macy err = t3_seeprom_write(adapter, aligned_offset, *p); 2509ac3a6d9cSKip Macy aligned_offset += 4; 2510ac3a6d9cSKip Macy } 2511ac3a6d9cSKip Macy 2512ac3a6d9cSKip Macy if (!err) 2513ac3a6d9cSKip Macy err = t3_seeprom_wp(adapter, 1); 2514ac3a6d9cSKip Macy out: 2515ac3a6d9cSKip Macy if (buf != data) 2516ac3a6d9cSKip Macy free(buf, M_DEVBUF); 2517ac3a6d9cSKip Macy return err; 2518ac3a6d9cSKip Macy } 2519ac3a6d9cSKip Macy 2520ac3a6d9cSKip Macy 2521b6d90eb7SKip Macy static int 2522b6d90eb7SKip Macy in_range(int val, int lo, int hi) 2523b6d90eb7SKip Macy { 2524b6d90eb7SKip Macy return val < 0 || (val <= hi && val >= lo); 2525b6d90eb7SKip Macy } 2526b6d90eb7SKip Macy 2527b6d90eb7SKip Macy static int 2528ef72318fSKip Macy cxgb_extension_open(struct cdev *dev, int flags, int fmp, d_thread_t *td) 2529ef72318fSKip Macy { 2530ef72318fSKip Macy return (0); 2531ef72318fSKip Macy } 2532ef72318fSKip Macy 2533ef72318fSKip Macy static int 2534ef72318fSKip Macy cxgb_extension_close(struct cdev *dev, int flags, int fmt, d_thread_t *td) 2535ef72318fSKip Macy { 2536ef72318fSKip Macy return (0); 2537ef72318fSKip Macy } 2538ef72318fSKip Macy 2539ef72318fSKip Macy static int 2540b6d90eb7SKip Macy cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, 2541b6d90eb7SKip Macy int fflag, struct thread *td) 2542b6d90eb7SKip Macy { 2543b6d90eb7SKip Macy int mmd, error = 0; 2544b6d90eb7SKip Macy struct port_info *pi = dev->si_drv1; 2545b6d90eb7SKip Macy adapter_t *sc = pi->adapter; 2546b6d90eb7SKip Macy 2547b6d90eb7SKip Macy #ifdef PRIV_SUPPORTED 2548b6d90eb7SKip Macy if (priv_check(td, PRIV_DRIVER)) { 2549b6d90eb7SKip Macy if (cxgb_debug) 2550b6d90eb7SKip Macy printf("user does not have access to privileged ioctls\n"); 2551b6d90eb7SKip Macy return (EPERM); 2552b6d90eb7SKip Macy } 2553b6d90eb7SKip Macy #else 2554b6d90eb7SKip Macy if (suser(td)) { 2555b6d90eb7SKip Macy if (cxgb_debug) 2556b6d90eb7SKip Macy printf("user does not have access to privileged ioctls\n"); 2557b6d90eb7SKip Macy return (EPERM); 2558b6d90eb7SKip Macy } 2559b6d90eb7SKip Macy #endif 2560b6d90eb7SKip Macy 2561b6d90eb7SKip Macy switch (cmd) { 25621ffd6e58SKip Macy case CHELSIO_GET_MIIREG: { 2563b6d90eb7SKip Macy uint32_t val; 2564b6d90eb7SKip Macy struct cphy *phy = &pi->phy; 25651ffd6e58SKip Macy struct ch_mii_data *mid = (struct ch_mii_data *)data; 2566b6d90eb7SKip Macy 2567b6d90eb7SKip Macy if (!phy->mdio_read) 2568b6d90eb7SKip Macy return (EOPNOTSUPP); 2569b6d90eb7SKip Macy if (is_10G(sc)) { 2570b6d90eb7SKip Macy mmd = mid->phy_id >> 8; 2571b6d90eb7SKip Macy if (!mmd) 2572b6d90eb7SKip Macy mmd = MDIO_DEV_PCS; 2573b6d90eb7SKip Macy else if (mmd > MDIO_DEV_XGXS) 2574ac3a6d9cSKip Macy return (EINVAL); 2575b6d90eb7SKip Macy 2576b6d90eb7SKip Macy error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd, 2577b6d90eb7SKip Macy mid->reg_num, &val); 2578b6d90eb7SKip Macy } else 2579b6d90eb7SKip Macy error = phy->mdio_read(sc, mid->phy_id & 0x1f, 0, 2580b6d90eb7SKip Macy mid->reg_num & 0x1f, &val); 2581b6d90eb7SKip Macy if (error == 0) 2582b6d90eb7SKip Macy mid->val_out = val; 2583b6d90eb7SKip Macy break; 2584b6d90eb7SKip Macy } 25851ffd6e58SKip Macy case CHELSIO_SET_MIIREG: { 2586b6d90eb7SKip Macy struct cphy *phy = &pi->phy; 25871ffd6e58SKip Macy struct ch_mii_data *mid = (struct ch_mii_data *)data; 2588b6d90eb7SKip Macy 2589b6d90eb7SKip Macy if (!phy->mdio_write) 2590b6d90eb7SKip Macy return (EOPNOTSUPP); 2591b6d90eb7SKip Macy if (is_10G(sc)) { 2592b6d90eb7SKip Macy mmd = mid->phy_id >> 8; 2593b6d90eb7SKip Macy if (!mmd) 2594b6d90eb7SKip Macy mmd = MDIO_DEV_PCS; 2595b6d90eb7SKip Macy else if (mmd > MDIO_DEV_XGXS) 2596b6d90eb7SKip Macy return (EINVAL); 2597b6d90eb7SKip Macy 2598b6d90eb7SKip Macy error = phy->mdio_write(sc, mid->phy_id & 0x1f, 2599b6d90eb7SKip Macy mmd, mid->reg_num, mid->val_in); 2600b6d90eb7SKip Macy } else 2601b6d90eb7SKip Macy error = phy->mdio_write(sc, mid->phy_id & 0x1f, 0, 2602b6d90eb7SKip Macy mid->reg_num & 0x1f, 2603b6d90eb7SKip Macy mid->val_in); 2604b6d90eb7SKip Macy break; 2605b6d90eb7SKip Macy } 2606b6d90eb7SKip Macy case CHELSIO_SETREG: { 2607b6d90eb7SKip Macy struct ch_reg *edata = (struct ch_reg *)data; 2608b6d90eb7SKip Macy if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 2609b6d90eb7SKip Macy return (EFAULT); 2610b6d90eb7SKip Macy t3_write_reg(sc, edata->addr, edata->val); 2611b6d90eb7SKip Macy break; 2612b6d90eb7SKip Macy } 2613b6d90eb7SKip Macy case CHELSIO_GETREG: { 2614b6d90eb7SKip Macy struct ch_reg *edata = (struct ch_reg *)data; 2615b6d90eb7SKip Macy if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 2616b6d90eb7SKip Macy return (EFAULT); 2617b6d90eb7SKip Macy edata->val = t3_read_reg(sc, edata->addr); 2618b6d90eb7SKip Macy break; 2619b6d90eb7SKip Macy } 2620b6d90eb7SKip Macy case CHELSIO_GET_SGE_CONTEXT: { 2621b6d90eb7SKip Macy struct ch_cntxt *ecntxt = (struct ch_cntxt *)data; 26228e10660fSKip Macy mtx_lock_spin(&sc->sge.reg_lock); 2623b6d90eb7SKip Macy switch (ecntxt->cntxt_type) { 2624b6d90eb7SKip Macy case CNTXT_TYPE_EGRESS: 26251ffd6e58SKip Macy error = -t3_sge_read_ecntxt(sc, ecntxt->cntxt_id, 2626b6d90eb7SKip Macy ecntxt->data); 2627b6d90eb7SKip Macy break; 2628b6d90eb7SKip Macy case CNTXT_TYPE_FL: 26291ffd6e58SKip Macy error = -t3_sge_read_fl(sc, ecntxt->cntxt_id, 2630b6d90eb7SKip Macy ecntxt->data); 2631b6d90eb7SKip Macy break; 2632b6d90eb7SKip Macy case CNTXT_TYPE_RSP: 26331ffd6e58SKip Macy error = -t3_sge_read_rspq(sc, ecntxt->cntxt_id, 2634b6d90eb7SKip Macy ecntxt->data); 2635b6d90eb7SKip Macy break; 2636b6d90eb7SKip Macy case CNTXT_TYPE_CQ: 26371ffd6e58SKip Macy error = -t3_sge_read_cq(sc, ecntxt->cntxt_id, 2638b6d90eb7SKip Macy ecntxt->data); 2639b6d90eb7SKip Macy break; 2640b6d90eb7SKip Macy default: 2641b6d90eb7SKip Macy error = EINVAL; 2642b6d90eb7SKip Macy break; 2643b6d90eb7SKip Macy } 26448e10660fSKip Macy mtx_unlock_spin(&sc->sge.reg_lock); 2645b6d90eb7SKip Macy break; 2646b6d90eb7SKip Macy } 2647b6d90eb7SKip Macy case CHELSIO_GET_SGE_DESC: { 2648b6d90eb7SKip Macy struct ch_desc *edesc = (struct ch_desc *)data; 2649b6d90eb7SKip Macy int ret; 2650b6d90eb7SKip Macy if (edesc->queue_num >= SGE_QSETS * 6) 2651b6d90eb7SKip Macy return (EINVAL); 2652b6d90eb7SKip Macy ret = t3_get_desc(&sc->sge.qs[edesc->queue_num / 6], 2653b6d90eb7SKip Macy edesc->queue_num % 6, edesc->idx, edesc->data); 2654b6d90eb7SKip Macy if (ret < 0) 2655b6d90eb7SKip Macy return (EINVAL); 2656b6d90eb7SKip Macy edesc->size = ret; 2657b6d90eb7SKip Macy break; 2658b6d90eb7SKip Macy } 2659b6d90eb7SKip Macy case CHELSIO_GET_QSET_PARAMS: { 2660b6d90eb7SKip Macy struct qset_params *q; 2661b6d90eb7SKip Macy struct ch_qset_params *t = (struct ch_qset_params *)data; 26621ffd6e58SKip Macy int q1 = pi->first_qset; 26631ffd6e58SKip Macy int nqsets = pi->nqsets; 26641ffd6e58SKip Macy int i; 2665b6d90eb7SKip Macy 26661ffd6e58SKip Macy if (t->qset_idx >= nqsets) 26671ffd6e58SKip Macy return EINVAL; 2668b6d90eb7SKip Macy 26691ffd6e58SKip Macy i = q1 + t->qset_idx; 26701ffd6e58SKip Macy q = &sc->params.sge.qset[i]; 2671b6d90eb7SKip Macy t->rspq_size = q->rspq_size; 2672b6d90eb7SKip Macy t->txq_size[0] = q->txq_size[0]; 2673b6d90eb7SKip Macy t->txq_size[1] = q->txq_size[1]; 2674b6d90eb7SKip Macy t->txq_size[2] = q->txq_size[2]; 2675b6d90eb7SKip Macy t->fl_size[0] = q->fl_size; 2676b6d90eb7SKip Macy t->fl_size[1] = q->jumbo_size; 2677b6d90eb7SKip Macy t->polling = q->polling; 26781ffd6e58SKip Macy t->lro = q->lro; 26794af83c8cSKip Macy t->intr_lat = q->coalesce_usecs; 2680b6d90eb7SKip Macy t->cong_thres = q->cong_thres; 26811ffd6e58SKip Macy t->qnum = i; 2682b6d90eb7SKip Macy 26831ffd6e58SKip Macy if (sc->flags & USING_MSIX) 26841ffd6e58SKip Macy t->vector = rman_get_start(sc->msix_irq_res[i]); 26851ffd6e58SKip Macy else 26861ffd6e58SKip Macy t->vector = rman_get_start(sc->irq_res); 26871ffd6e58SKip Macy 2688b6d90eb7SKip Macy break; 2689b6d90eb7SKip Macy } 2690b6d90eb7SKip Macy case CHELSIO_GET_QSET_NUM: { 2691b6d90eb7SKip Macy struct ch_reg *edata = (struct ch_reg *)data; 2692b6d90eb7SKip Macy edata->val = pi->nqsets; 2693b6d90eb7SKip Macy break; 2694b6d90eb7SKip Macy } 26951ffd6e58SKip Macy case CHELSIO_LOAD_FW: { 26961ffd6e58SKip Macy uint8_t *fw_data; 26971ffd6e58SKip Macy uint32_t vers; 26981ffd6e58SKip Macy struct ch_mem_range *t = (struct ch_mem_range *)data; 26991ffd6e58SKip Macy 27001ffd6e58SKip Macy /* 27011ffd6e58SKip Macy * You're allowed to load a firmware only before FULL_INIT_DONE 27021ffd6e58SKip Macy * 27031ffd6e58SKip Macy * FW_UPTODATE is also set so the rest of the initialization 27041ffd6e58SKip Macy * will not overwrite what was loaded here. This gives you the 27051ffd6e58SKip Macy * flexibility to load any firmware (and maybe shoot yourself in 27061ffd6e58SKip Macy * the foot). 27071ffd6e58SKip Macy */ 27081ffd6e58SKip Macy 27091ffd6e58SKip Macy ADAPTER_LOCK(sc); 27101ffd6e58SKip Macy if (sc->open_device_map || sc->flags & FULL_INIT_DONE) { 27111ffd6e58SKip Macy ADAPTER_UNLOCK(sc); 27121ffd6e58SKip Macy return (EBUSY); 27131ffd6e58SKip Macy } 27141ffd6e58SKip Macy 27151ffd6e58SKip Macy fw_data = malloc(t->len, M_DEVBUF, M_NOWAIT); 27161ffd6e58SKip Macy if (!fw_data) 27171ffd6e58SKip Macy error = ENOMEM; 27181ffd6e58SKip Macy else 27191ffd6e58SKip Macy error = copyin(t->buf, fw_data, t->len); 27201ffd6e58SKip Macy 27211ffd6e58SKip Macy if (!error) 27221ffd6e58SKip Macy error = -t3_load_fw(sc, fw_data, t->len); 27231ffd6e58SKip Macy 27241ffd6e58SKip Macy if (t3_get_fw_version(sc, &vers) == 0) { 27251ffd6e58SKip Macy snprintf(&sc->fw_version[0], sizeof(sc->fw_version), 27261ffd6e58SKip Macy "%d.%d.%d", G_FW_VERSION_MAJOR(vers), 27271ffd6e58SKip Macy G_FW_VERSION_MINOR(vers), G_FW_VERSION_MICRO(vers)); 27281ffd6e58SKip Macy } 27291ffd6e58SKip Macy 27301ffd6e58SKip Macy if (!error) 27311ffd6e58SKip Macy sc->flags |= FW_UPTODATE; 27321ffd6e58SKip Macy 27331ffd6e58SKip Macy free(fw_data, M_DEVBUF); 27341ffd6e58SKip Macy ADAPTER_UNLOCK(sc); 2735b6d90eb7SKip Macy break; 27361ffd6e58SKip Macy } 27371ffd6e58SKip Macy case CHELSIO_LOAD_BOOT: { 27381ffd6e58SKip Macy uint8_t *boot_data; 27391ffd6e58SKip Macy struct ch_mem_range *t = (struct ch_mem_range *)data; 27401ffd6e58SKip Macy 27411ffd6e58SKip Macy boot_data = malloc(t->len, M_DEVBUF, M_NOWAIT); 27421ffd6e58SKip Macy if (!boot_data) 27431ffd6e58SKip Macy return ENOMEM; 27441ffd6e58SKip Macy 27451ffd6e58SKip Macy error = copyin(t->buf, boot_data, t->len); 27461ffd6e58SKip Macy if (!error) 27471ffd6e58SKip Macy error = -t3_load_boot(sc, boot_data, t->len); 27481ffd6e58SKip Macy 27491ffd6e58SKip Macy free(boot_data, M_DEVBUF); 27501ffd6e58SKip Macy break; 27511ffd6e58SKip Macy } 27521ffd6e58SKip Macy case CHELSIO_GET_PM: { 27531ffd6e58SKip Macy struct ch_pm *m = (struct ch_pm *)data; 27541ffd6e58SKip Macy struct tp_params *p = &sc->params.tp; 27551ffd6e58SKip Macy 27561ffd6e58SKip Macy if (!is_offload(sc)) 27571ffd6e58SKip Macy return (EOPNOTSUPP); 27581ffd6e58SKip Macy 27591ffd6e58SKip Macy m->tx_pg_sz = p->tx_pg_size; 27601ffd6e58SKip Macy m->tx_num_pg = p->tx_num_pgs; 27611ffd6e58SKip Macy m->rx_pg_sz = p->rx_pg_size; 27621ffd6e58SKip Macy m->rx_num_pg = p->rx_num_pgs; 27631ffd6e58SKip Macy m->pm_total = p->pmtx_size + p->chan_rx_size * p->nchan; 27641ffd6e58SKip Macy 27651ffd6e58SKip Macy break; 27661ffd6e58SKip Macy } 27671ffd6e58SKip Macy case CHELSIO_SET_PM: { 27681ffd6e58SKip Macy struct ch_pm *m = (struct ch_pm *)data; 27691ffd6e58SKip Macy struct tp_params *p = &sc->params.tp; 27701ffd6e58SKip Macy 27711ffd6e58SKip Macy if (!is_offload(sc)) 27721ffd6e58SKip Macy return (EOPNOTSUPP); 27731ffd6e58SKip Macy if (sc->flags & FULL_INIT_DONE) 27741ffd6e58SKip Macy return (EBUSY); 27751ffd6e58SKip Macy 27761ffd6e58SKip Macy if (!m->rx_pg_sz || (m->rx_pg_sz & (m->rx_pg_sz - 1)) || 27771ffd6e58SKip Macy !m->tx_pg_sz || (m->tx_pg_sz & (m->tx_pg_sz - 1))) 27781ffd6e58SKip Macy return (EINVAL); /* not power of 2 */ 27791ffd6e58SKip Macy if (!(m->rx_pg_sz & 0x14000)) 27801ffd6e58SKip Macy return (EINVAL); /* not 16KB or 64KB */ 27811ffd6e58SKip Macy if (!(m->tx_pg_sz & 0x1554000)) 27821ffd6e58SKip Macy return (EINVAL); 27831ffd6e58SKip Macy if (m->tx_num_pg == -1) 27841ffd6e58SKip Macy m->tx_num_pg = p->tx_num_pgs; 27851ffd6e58SKip Macy if (m->rx_num_pg == -1) 27861ffd6e58SKip Macy m->rx_num_pg = p->rx_num_pgs; 27871ffd6e58SKip Macy if (m->tx_num_pg % 24 || m->rx_num_pg % 24) 27881ffd6e58SKip Macy return (EINVAL); 27891ffd6e58SKip Macy if (m->rx_num_pg * m->rx_pg_sz > p->chan_rx_size || 27901ffd6e58SKip Macy m->tx_num_pg * m->tx_pg_sz > p->chan_tx_size) 27911ffd6e58SKip Macy return (EINVAL); 27921ffd6e58SKip Macy 27931ffd6e58SKip Macy p->rx_pg_size = m->rx_pg_sz; 27941ffd6e58SKip Macy p->tx_pg_size = m->tx_pg_sz; 27951ffd6e58SKip Macy p->rx_num_pgs = m->rx_num_pg; 27961ffd6e58SKip Macy p->tx_num_pgs = m->tx_num_pg; 27971ffd6e58SKip Macy break; 27981ffd6e58SKip Macy } 2799d722cab4SKip Macy case CHELSIO_SETMTUTAB: { 2800d722cab4SKip Macy struct ch_mtus *m = (struct ch_mtus *)data; 2801d722cab4SKip Macy int i; 2802d722cab4SKip Macy 2803d722cab4SKip Macy if (!is_offload(sc)) 2804d722cab4SKip Macy return (EOPNOTSUPP); 2805d722cab4SKip Macy if (offload_running(sc)) 2806d722cab4SKip Macy return (EBUSY); 2807d722cab4SKip Macy if (m->nmtus != NMTUS) 2808d722cab4SKip Macy return (EINVAL); 2809d722cab4SKip Macy if (m->mtus[0] < 81) /* accommodate SACK */ 2810d722cab4SKip Macy return (EINVAL); 2811d722cab4SKip Macy 2812d722cab4SKip Macy /* 2813d722cab4SKip Macy * MTUs must be in ascending order 2814d722cab4SKip Macy */ 2815d722cab4SKip Macy for (i = 1; i < NMTUS; ++i) 2816d722cab4SKip Macy if (m->mtus[i] < m->mtus[i - 1]) 2817d722cab4SKip Macy return (EINVAL); 2818d722cab4SKip Macy 28191ffd6e58SKip Macy memcpy(sc->params.mtus, m->mtus, sizeof(sc->params.mtus)); 2820d722cab4SKip Macy break; 2821d722cab4SKip Macy } 2822d722cab4SKip Macy case CHELSIO_GETMTUTAB: { 2823d722cab4SKip Macy struct ch_mtus *m = (struct ch_mtus *)data; 2824d722cab4SKip Macy 2825d722cab4SKip Macy if (!is_offload(sc)) 2826d722cab4SKip Macy return (EOPNOTSUPP); 2827d722cab4SKip Macy 2828d722cab4SKip Macy memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus)); 2829d722cab4SKip Macy m->nmtus = NMTUS; 2830d722cab4SKip Macy break; 2831d722cab4SKip Macy } 2832b6d90eb7SKip Macy case CHELSIO_GET_MEM: { 2833b6d90eb7SKip Macy struct ch_mem_range *t = (struct ch_mem_range *)data; 2834b6d90eb7SKip Macy struct mc7 *mem; 2835b6d90eb7SKip Macy uint8_t *useraddr; 2836b6d90eb7SKip Macy u64 buf[32]; 2837b6d90eb7SKip Macy 28381ffd6e58SKip Macy /* 28391ffd6e58SKip Macy * Use these to avoid modifying len/addr in the the return 28401ffd6e58SKip Macy * struct 28411ffd6e58SKip Macy */ 28421ffd6e58SKip Macy uint32_t len = t->len, addr = t->addr; 28431ffd6e58SKip Macy 2844b6d90eb7SKip Macy if (!is_offload(sc)) 2845b6d90eb7SKip Macy return (EOPNOTSUPP); 2846b6d90eb7SKip Macy if (!(sc->flags & FULL_INIT_DONE)) 2847b6d90eb7SKip Macy return (EIO); /* need the memory controllers */ 28481ffd6e58SKip Macy if ((addr & 0x7) || (len & 0x7)) 2849b6d90eb7SKip Macy return (EINVAL); 2850b6d90eb7SKip Macy if (t->mem_id == MEM_CM) 2851b6d90eb7SKip Macy mem = &sc->cm; 2852b6d90eb7SKip Macy else if (t->mem_id == MEM_PMRX) 2853b6d90eb7SKip Macy mem = &sc->pmrx; 2854b6d90eb7SKip Macy else if (t->mem_id == MEM_PMTX) 2855b6d90eb7SKip Macy mem = &sc->pmtx; 2856b6d90eb7SKip Macy else 2857b6d90eb7SKip Macy return (EINVAL); 2858b6d90eb7SKip Macy 2859b6d90eb7SKip Macy /* 2860b6d90eb7SKip Macy * Version scheme: 2861b6d90eb7SKip Macy * bits 0..9: chip version 2862b6d90eb7SKip Macy * bits 10..15: chip revision 2863b6d90eb7SKip Macy */ 2864b6d90eb7SKip Macy t->version = 3 | (sc->params.rev << 10); 2865b6d90eb7SKip Macy 2866b6d90eb7SKip Macy /* 2867b6d90eb7SKip Macy * Read 256 bytes at a time as len can be large and we don't 2868b6d90eb7SKip Macy * want to use huge intermediate buffers. 2869b6d90eb7SKip Macy */ 28708090c9f5SKip Macy useraddr = (uint8_t *)t->buf; 28711ffd6e58SKip Macy while (len) { 28721ffd6e58SKip Macy unsigned int chunk = min(len, sizeof(buf)); 2873b6d90eb7SKip Macy 28741ffd6e58SKip Macy error = t3_mc7_bd_read(mem, addr / 8, chunk / 8, buf); 2875b6d90eb7SKip Macy if (error) 2876b6d90eb7SKip Macy return (-error); 2877b6d90eb7SKip Macy if (copyout(buf, useraddr, chunk)) 2878b6d90eb7SKip Macy return (EFAULT); 2879b6d90eb7SKip Macy useraddr += chunk; 28801ffd6e58SKip Macy addr += chunk; 28811ffd6e58SKip Macy len -= chunk; 2882b6d90eb7SKip Macy } 2883b6d90eb7SKip Macy break; 2884b6d90eb7SKip Macy } 2885d722cab4SKip Macy case CHELSIO_READ_TCAM_WORD: { 2886d722cab4SKip Macy struct ch_tcam_word *t = (struct ch_tcam_word *)data; 2887d722cab4SKip Macy 2888d722cab4SKip Macy if (!is_offload(sc)) 2889d722cab4SKip Macy return (EOPNOTSUPP); 2890ac3a6d9cSKip Macy if (!(sc->flags & FULL_INIT_DONE)) 2891ac3a6d9cSKip Macy return (EIO); /* need MC5 */ 2892d722cab4SKip Macy return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf); 2893d722cab4SKip Macy break; 2894d722cab4SKip Macy } 2895b6d90eb7SKip Macy case CHELSIO_SET_TRACE_FILTER: { 2896b6d90eb7SKip Macy struct ch_trace *t = (struct ch_trace *)data; 2897b6d90eb7SKip Macy const struct trace_params *tp; 2898b6d90eb7SKip Macy 2899b6d90eb7SKip Macy tp = (const struct trace_params *)&t->sip; 2900b6d90eb7SKip Macy if (t->config_tx) 2901b6d90eb7SKip Macy t3_config_trace_filter(sc, tp, 0, t->invert_match, 2902b6d90eb7SKip Macy t->trace_tx); 2903b6d90eb7SKip Macy if (t->config_rx) 2904b6d90eb7SKip Macy t3_config_trace_filter(sc, tp, 1, t->invert_match, 2905b6d90eb7SKip Macy t->trace_rx); 2906b6d90eb7SKip Macy break; 2907b6d90eb7SKip Macy } 2908b6d90eb7SKip Macy case CHELSIO_SET_PKTSCHED: { 2909b6d90eb7SKip Macy struct ch_pktsched_params *p = (struct ch_pktsched_params *)data; 2910b6d90eb7SKip Macy if (sc->open_device_map == 0) 2911b6d90eb7SKip Macy return (EAGAIN); 2912b6d90eb7SKip Macy send_pktsched_cmd(sc, p->sched, p->idx, p->min, p->max, 2913b6d90eb7SKip Macy p->binding); 2914b6d90eb7SKip Macy break; 2915b6d90eb7SKip Macy } 2916b6d90eb7SKip Macy case CHELSIO_IFCONF_GETREGS: { 29171ffd6e58SKip Macy struct ch_ifconf_regs *regs = (struct ch_ifconf_regs *)data; 2918b6d90eb7SKip Macy int reglen = cxgb_get_regs_len(); 29191ffd6e58SKip Macy uint8_t *buf = malloc(reglen, M_DEVBUF, M_NOWAIT); 2920b6d90eb7SKip Macy if (buf == NULL) { 2921b6d90eb7SKip Macy return (ENOMEM); 2922b6d90eb7SKip Macy } 29231ffd6e58SKip Macy if (regs->len > reglen) 29241ffd6e58SKip Macy regs->len = reglen; 29251ffd6e58SKip Macy else if (regs->len < reglen) 2926f2d8ff04SGeorge V. Neville-Neil error = ENOBUFS; 29271ffd6e58SKip Macy 29281ffd6e58SKip Macy if (!error) { 2929b6d90eb7SKip Macy cxgb_get_regs(sc, regs, buf); 2930b6d90eb7SKip Macy error = copyout(buf, regs->data, reglen); 29311ffd6e58SKip Macy } 2932b6d90eb7SKip Macy free(buf, M_DEVBUF); 2933b6d90eb7SKip Macy 2934b6d90eb7SKip Macy break; 2935b6d90eb7SKip Macy } 2936d722cab4SKip Macy case CHELSIO_SET_HW_SCHED: { 2937d722cab4SKip Macy struct ch_hw_sched *t = (struct ch_hw_sched *)data; 2938d722cab4SKip Macy unsigned int ticks_per_usec = core_ticks_per_usec(sc); 2939d722cab4SKip Macy 2940d722cab4SKip Macy if ((sc->flags & FULL_INIT_DONE) == 0) 2941d722cab4SKip Macy return (EAGAIN); /* need TP to be initialized */ 2942d722cab4SKip Macy if (t->sched >= NTX_SCHED || !in_range(t->mode, 0, 1) || 2943d722cab4SKip Macy !in_range(t->channel, 0, 1) || 2944d722cab4SKip Macy !in_range(t->kbps, 0, 10000000) || 2945d722cab4SKip Macy !in_range(t->class_ipg, 0, 10000 * 65535 / ticks_per_usec) || 2946d722cab4SKip Macy !in_range(t->flow_ipg, 0, 2947d722cab4SKip Macy dack_ticks_to_usec(sc, 0x7ff))) 2948d722cab4SKip Macy return (EINVAL); 2949d722cab4SKip Macy 2950d722cab4SKip Macy if (t->kbps >= 0) { 2951d722cab4SKip Macy error = t3_config_sched(sc, t->kbps, t->sched); 2952d722cab4SKip Macy if (error < 0) 2953d722cab4SKip Macy return (-error); 2954d722cab4SKip Macy } 2955d722cab4SKip Macy if (t->class_ipg >= 0) 2956d722cab4SKip Macy t3_set_sched_ipg(sc, t->sched, t->class_ipg); 2957d722cab4SKip Macy if (t->flow_ipg >= 0) { 2958d722cab4SKip Macy t->flow_ipg *= 1000; /* us -> ns */ 2959d722cab4SKip Macy t3_set_pace_tbl(sc, &t->flow_ipg, t->sched, 1); 2960d722cab4SKip Macy } 2961d722cab4SKip Macy if (t->mode >= 0) { 2962d722cab4SKip Macy int bit = 1 << (S_TX_MOD_TIMER_MODE + t->sched); 2963d722cab4SKip Macy 2964d722cab4SKip Macy t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP, 2965d722cab4SKip Macy bit, t->mode ? bit : 0); 2966d722cab4SKip Macy } 2967d722cab4SKip Macy if (t->channel >= 0) 2968d722cab4SKip Macy t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP, 2969d722cab4SKip Macy 1 << t->sched, t->channel << t->sched); 2970d722cab4SKip Macy break; 2971d722cab4SKip Macy } 29721ffd6e58SKip Macy case CHELSIO_GET_EEPROM: { 29731ffd6e58SKip Macy int i; 29741ffd6e58SKip Macy struct ch_eeprom *e = (struct ch_eeprom *)data; 29751ffd6e58SKip Macy uint8_t *buf = malloc(EEPROMSIZE, M_DEVBUF, M_NOWAIT); 29761ffd6e58SKip Macy 29771ffd6e58SKip Macy if (buf == NULL) { 29781ffd6e58SKip Macy return (ENOMEM); 29791ffd6e58SKip Macy } 29801ffd6e58SKip Macy e->magic = EEPROM_MAGIC; 29811ffd6e58SKip Macy for (i = e->offset & ~3; !error && i < e->offset + e->len; i += 4) 29821ffd6e58SKip Macy error = -t3_seeprom_read(sc, i, (uint32_t *)&buf[i]); 29831ffd6e58SKip Macy 29841ffd6e58SKip Macy if (!error) 29851ffd6e58SKip Macy error = copyout(buf + e->offset, e->data, e->len); 29861ffd6e58SKip Macy 29871ffd6e58SKip Macy free(buf, M_DEVBUF); 29881ffd6e58SKip Macy break; 29891ffd6e58SKip Macy } 29901ffd6e58SKip Macy case CHELSIO_CLEAR_STATS: { 29911ffd6e58SKip Macy if (!(sc->flags & FULL_INIT_DONE)) 29921ffd6e58SKip Macy return EAGAIN; 29931ffd6e58SKip Macy 29941ffd6e58SKip Macy PORT_LOCK(pi); 29951ffd6e58SKip Macy t3_mac_update_stats(&pi->mac); 29961ffd6e58SKip Macy memset(&pi->mac.stats, 0, sizeof(pi->mac.stats)); 29971ffd6e58SKip Macy PORT_UNLOCK(pi); 29981ffd6e58SKip Macy break; 29991ffd6e58SKip Macy } 3000f2d8ff04SGeorge V. Neville-Neil case CHELSIO_GET_UP_LA: { 3001f2d8ff04SGeorge V. Neville-Neil struct ch_up_la *la = (struct ch_up_la *)data; 3002f2d8ff04SGeorge V. Neville-Neil uint8_t *buf = malloc(LA_BUFSIZE, M_DEVBUF, M_NOWAIT); 3003f2d8ff04SGeorge V. Neville-Neil if (buf == NULL) { 3004f2d8ff04SGeorge V. Neville-Neil return (ENOMEM); 3005f2d8ff04SGeorge V. Neville-Neil } 3006f2d8ff04SGeorge V. Neville-Neil if (la->bufsize < LA_BUFSIZE) 3007f2d8ff04SGeorge V. Neville-Neil error = ENOBUFS; 3008f2d8ff04SGeorge V. Neville-Neil 3009f2d8ff04SGeorge V. Neville-Neil if (!error) 3010f2d8ff04SGeorge V. Neville-Neil error = -t3_get_up_la(sc, &la->stopped, &la->idx, 3011f2d8ff04SGeorge V. Neville-Neil &la->bufsize, buf); 3012f2d8ff04SGeorge V. Neville-Neil if (!error) 3013f2d8ff04SGeorge V. Neville-Neil error = copyout(buf, la->data, la->bufsize); 3014f2d8ff04SGeorge V. Neville-Neil 3015f2d8ff04SGeorge V. Neville-Neil free(buf, M_DEVBUF); 3016f2d8ff04SGeorge V. Neville-Neil break; 3017f2d8ff04SGeorge V. Neville-Neil } 3018f2d8ff04SGeorge V. Neville-Neil case CHELSIO_GET_UP_IOQS: { 3019f2d8ff04SGeorge V. Neville-Neil struct ch_up_ioqs *ioqs = (struct ch_up_ioqs *)data; 3020f2d8ff04SGeorge V. Neville-Neil uint8_t *buf = malloc(IOQS_BUFSIZE, M_DEVBUF, M_NOWAIT); 3021f2d8ff04SGeorge V. Neville-Neil uint32_t *v; 3022f2d8ff04SGeorge V. Neville-Neil 3023f2d8ff04SGeorge V. Neville-Neil if (buf == NULL) { 3024f2d8ff04SGeorge V. Neville-Neil return (ENOMEM); 3025f2d8ff04SGeorge V. Neville-Neil } 3026f2d8ff04SGeorge V. Neville-Neil if (ioqs->bufsize < IOQS_BUFSIZE) 3027f2d8ff04SGeorge V. Neville-Neil error = ENOBUFS; 3028f2d8ff04SGeorge V. Neville-Neil 3029f2d8ff04SGeorge V. Neville-Neil if (!error) 3030f2d8ff04SGeorge V. Neville-Neil error = -t3_get_up_ioqs(sc, &ioqs->bufsize, buf); 3031f2d8ff04SGeorge V. Neville-Neil 3032f2d8ff04SGeorge V. Neville-Neil if (!error) { 3033f2d8ff04SGeorge V. Neville-Neil v = (uint32_t *)buf; 3034f2d8ff04SGeorge V. Neville-Neil 3035f2d8ff04SGeorge V. Neville-Neil ioqs->bufsize -= 4 * sizeof(uint32_t); 3036f2d8ff04SGeorge V. Neville-Neil ioqs->ioq_rx_enable = *v++; 3037f2d8ff04SGeorge V. Neville-Neil ioqs->ioq_tx_enable = *v++; 3038f2d8ff04SGeorge V. Neville-Neil ioqs->ioq_rx_status = *v++; 3039f2d8ff04SGeorge V. Neville-Neil ioqs->ioq_tx_status = *v++; 3040f2d8ff04SGeorge V. Neville-Neil 3041f2d8ff04SGeorge V. Neville-Neil error = copyout(v, ioqs->data, ioqs->bufsize); 3042f2d8ff04SGeorge V. Neville-Neil } 3043f2d8ff04SGeorge V. Neville-Neil 3044f2d8ff04SGeorge V. Neville-Neil free(buf, M_DEVBUF); 3045f2d8ff04SGeorge V. Neville-Neil break; 3046f2d8ff04SGeorge V. Neville-Neil } 3047b6d90eb7SKip Macy default: 3048b6d90eb7SKip Macy return (EOPNOTSUPP); 3049b6d90eb7SKip Macy break; 3050b6d90eb7SKip Macy } 3051b6d90eb7SKip Macy 3052b6d90eb7SKip Macy return (error); 3053b6d90eb7SKip Macy } 3054b6d90eb7SKip Macy 3055b6d90eb7SKip Macy static __inline void 3056b6d90eb7SKip Macy reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start, 3057b6d90eb7SKip Macy unsigned int end) 3058b6d90eb7SKip Macy { 30591ffd6e58SKip Macy uint32_t *p = (uint32_t *)(buf + start); 3060b6d90eb7SKip Macy 3061b6d90eb7SKip Macy for ( ; start <= end; start += sizeof(uint32_t)) 3062b6d90eb7SKip Macy *p++ = t3_read_reg(ap, start); 3063b6d90eb7SKip Macy } 3064b6d90eb7SKip Macy 3065b6d90eb7SKip Macy #define T3_REGMAP_SIZE (3 * 1024) 3066b6d90eb7SKip Macy static int 3067b6d90eb7SKip Macy cxgb_get_regs_len(void) 3068b6d90eb7SKip Macy { 3069b6d90eb7SKip Macy return T3_REGMAP_SIZE; 3070b6d90eb7SKip Macy } 3071b6d90eb7SKip Macy 3072b6d90eb7SKip Macy static void 30731ffd6e58SKip Macy cxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf) 3074b6d90eb7SKip Macy { 3075b6d90eb7SKip Macy 3076b6d90eb7SKip Macy /* 3077b6d90eb7SKip Macy * Version scheme: 3078b6d90eb7SKip Macy * bits 0..9: chip version 3079b6d90eb7SKip Macy * bits 10..15: chip revision 3080b6d90eb7SKip Macy * bit 31: set for PCIe cards 3081b6d90eb7SKip Macy */ 3082b6d90eb7SKip Macy regs->version = 3 | (sc->params.rev << 10) | (is_pcie(sc) << 31); 3083b6d90eb7SKip Macy 3084b6d90eb7SKip Macy /* 3085b6d90eb7SKip Macy * We skip the MAC statistics registers because they are clear-on-read. 3086b6d90eb7SKip Macy * Also reading multi-register stats would need to synchronize with the 3087b6d90eb7SKip Macy * periodic mac stats accumulation. Hard to justify the complexity. 3088b6d90eb7SKip Macy */ 30891ffd6e58SKip Macy memset(buf, 0, cxgb_get_regs_len()); 3090b6d90eb7SKip Macy reg_block_dump(sc, buf, 0, A_SG_RSPQ_CREDIT_RETURN); 3091b6d90eb7SKip Macy reg_block_dump(sc, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT); 3092b6d90eb7SKip Macy reg_block_dump(sc, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE); 3093b6d90eb7SKip Macy reg_block_dump(sc, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA); 3094b6d90eb7SKip Macy reg_block_dump(sc, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3); 3095b6d90eb7SKip Macy reg_block_dump(sc, buf, A_XGM_SERDES_STATUS0, 3096b6d90eb7SKip Macy XGM_REG(A_XGM_SERDES_STAT3, 1)); 3097b6d90eb7SKip Macy reg_block_dump(sc, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1), 3098b6d90eb7SKip Macy XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1)); 3099b6d90eb7SKip Macy } 3100404825a7SKip Macy 3101404825a7SKip Macy 3102404825a7SKip Macy MODULE_DEPEND(if_cxgb, cxgb_t3fw, 1, 1, 1); 3103