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); 1180bbdea77SGeorge V. Neville-Neil int t3_detect_link_fault(adapter_t *adapter, int port_id); 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" 3680c1ff9c6SGeorge V. Neville-Neil #define TPEEPROM_NAME "cxgb_t3%c_tp_eeprom" 3690c1ff9c6SGeorge V. Neville-Neil #define TPSRAM_NAME "cxgb_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 3953cf138bbSGeorge V. Neville-Neil /* 3963cf138bbSGeorge V. Neville-Neil * The cxgb_controller_attach function is responsible for the initial 3973cf138bbSGeorge V. Neville-Neil * bringup of the device. Its responsibilities include: 3983cf138bbSGeorge V. Neville-Neil * 3993cf138bbSGeorge V. Neville-Neil * 1. Determine if the device supports MSI or MSI-X. 4003cf138bbSGeorge V. Neville-Neil * 2. Allocate bus resources so that we can access the Base Address Register 4013cf138bbSGeorge V. Neville-Neil * 3. Create and initialize mutexes for the controller and its control 4023cf138bbSGeorge V. Neville-Neil * logic such as SGE and MDIO. 4033cf138bbSGeorge V. Neville-Neil * 4. Call hardware specific setup routine for the adapter as a whole. 4043cf138bbSGeorge V. Neville-Neil * 5. Allocate the BAR for doing MSI-X. 4053cf138bbSGeorge V. Neville-Neil * 6. Setup the line interrupt iff MSI-X is not supported. 4063cf138bbSGeorge V. Neville-Neil * 7. Create the driver's taskq. 407c2009a4cSGeorge V. Neville-Neil * 8. Start one task queue service thread. 408c2009a4cSGeorge V. Neville-Neil * 9. Check if the firmware and SRAM are up-to-date. They will be 409c2009a4cSGeorge V. Neville-Neil * auto-updated later (before FULL_INIT_DONE), if required. 4103cf138bbSGeorge V. Neville-Neil * 10. Create a child device for each MAC (port) 4113cf138bbSGeorge V. Neville-Neil * 11. Initialize T3 private state. 4123cf138bbSGeorge V. Neville-Neil * 12. Trigger the LED 4133cf138bbSGeorge V. Neville-Neil * 13. Setup offload iff supported. 4143cf138bbSGeorge V. Neville-Neil * 14. Reset/restart the tick callout. 4153cf138bbSGeorge V. Neville-Neil * 15. Attach sysctls 4163cf138bbSGeorge V. Neville-Neil * 4173cf138bbSGeorge V. Neville-Neil * NOTE: Any modification or deviation from this list MUST be reflected in 4183cf138bbSGeorge V. Neville-Neil * the above comment. Failure to do so will result in problems on various 4193cf138bbSGeorge V. Neville-Neil * error conditions including link flapping. 4203cf138bbSGeorge V. Neville-Neil */ 421b6d90eb7SKip Macy static int 422b6d90eb7SKip Macy cxgb_controller_attach(device_t dev) 423b6d90eb7SKip Macy { 424b6d90eb7SKip Macy device_t child; 425b6d90eb7SKip Macy const struct adapter_info *ai; 426b6d90eb7SKip Macy struct adapter *sc; 4272de1fa86SKip Macy int i, error = 0; 428b6d90eb7SKip Macy uint32_t vers; 429693d746cSKip Macy int port_qsets = 1; 4307aff6d8eSKip Macy #ifdef MSI_SUPPORTED 4312de1fa86SKip Macy int msi_needed, reg; 4327aff6d8eSKip Macy #endif 4335197f3abSGeorge V. Neville-Neil char buf[80]; 4345197f3abSGeorge V. Neville-Neil 435b6d90eb7SKip Macy sc = device_get_softc(dev); 436b6d90eb7SKip Macy sc->dev = dev; 437d722cab4SKip Macy sc->msi_count = 0; 4382de1fa86SKip Macy ai = cxgb_get_adapter_info(dev); 439b6d90eb7SKip Macy 4402de1fa86SKip Macy /* 4412de1fa86SKip Macy * XXX not really related but a recent addition 4422de1fa86SKip Macy */ 4432de1fa86SKip Macy #ifdef MSI_SUPPORTED 444fc01c613SKip Macy /* find the PCIe link width and set max read request to 4KB*/ 445fc01c613SKip Macy if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) { 446fc01c613SKip Macy uint16_t lnk, pectl; 447fc01c613SKip Macy lnk = pci_read_config(dev, reg + 0x12, 2); 448fc01c613SKip Macy sc->link_width = (lnk >> 4) & 0x3f; 449fc01c613SKip Macy 450fc01c613SKip Macy pectl = pci_read_config(dev, reg + 0x8, 2); 451fc01c613SKip Macy pectl = (pectl & ~0x7000) | (5 << 12); 452fc01c613SKip Macy pci_write_config(dev, reg + 0x8, pectl, 2); 453fc01c613SKip Macy } 454ac3a6d9cSKip Macy 455ac3a6d9cSKip Macy if (sc->link_width != 0 && sc->link_width <= 4 && 456ac3a6d9cSKip Macy (ai->nports0 + ai->nports1) <= 2) { 457fc01c613SKip Macy device_printf(sc->dev, 458ac6b4cf1SKip Macy "PCIe x%d Link, expect reduced performance\n", 459fc01c613SKip Macy sc->link_width); 460fc01c613SKip Macy } 4612de1fa86SKip Macy #endif 4627ac2e6c3SKip Macy touch_bars(dev); 463b6d90eb7SKip Macy pci_enable_busmaster(dev); 464b6d90eb7SKip Macy /* 465b6d90eb7SKip Macy * Allocate the registers and make them available to the driver. 466b6d90eb7SKip Macy * The registers that we care about for NIC mode are in BAR 0 467b6d90eb7SKip Macy */ 468b6d90eb7SKip Macy sc->regs_rid = PCIR_BAR(0); 469b6d90eb7SKip Macy if ((sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 470b6d90eb7SKip Macy &sc->regs_rid, RF_ACTIVE)) == NULL) { 4718e10660fSKip Macy device_printf(dev, "Cannot allocate BAR region 0\n"); 472b6d90eb7SKip Macy return (ENXIO); 473b6d90eb7SKip Macy } 4748e10660fSKip Macy sc->udbs_rid = PCIR_BAR(2); 4757f15419bSGeorge V. Neville-Neil sc->udbs_res = NULL; 4767f15419bSGeorge V. Neville-Neil if (is_offload(sc) && 4777f15419bSGeorge V. Neville-Neil ((sc->udbs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 4787f15419bSGeorge V. Neville-Neil &sc->udbs_rid, RF_ACTIVE)) == NULL)) { 4798e10660fSKip Macy device_printf(dev, "Cannot allocate BAR region 1\n"); 4808e10660fSKip Macy error = ENXIO; 4818e10660fSKip Macy goto out; 4828e10660fSKip Macy } 483b6d90eb7SKip Macy 484bb38cd2fSKip Macy snprintf(sc->lockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb controller lock %d", 485bb38cd2fSKip Macy device_get_unit(dev)); 486bb38cd2fSKip Macy ADAPTER_LOCK_INIT(sc, sc->lockbuf); 487bb38cd2fSKip Macy 488bb38cd2fSKip Macy snprintf(sc->reglockbuf, ADAPTER_LOCK_NAME_LEN, "SGE reg lock %d", 489bb38cd2fSKip Macy device_get_unit(dev)); 490bb38cd2fSKip Macy snprintf(sc->mdiolockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb mdio lock %d", 491bb38cd2fSKip Macy device_get_unit(dev)); 492bb38cd2fSKip Macy snprintf(sc->elmerlockbuf, ADAPTER_LOCK_NAME_LEN, "cxgb elmer lock %d", 493bb38cd2fSKip Macy device_get_unit(dev)); 494bb38cd2fSKip Macy 4958e10660fSKip Macy MTX_INIT(&sc->sge.reg_lock, sc->reglockbuf, NULL, MTX_SPIN); 496bb38cd2fSKip Macy MTX_INIT(&sc->mdio_lock, sc->mdiolockbuf, NULL, MTX_DEF); 497bb38cd2fSKip Macy MTX_INIT(&sc->elmer_lock, sc->elmerlockbuf, NULL, MTX_DEF); 498b6d90eb7SKip Macy 499b6d90eb7SKip Macy sc->bt = rman_get_bustag(sc->regs_res); 500b6d90eb7SKip Macy sc->bh = rman_get_bushandle(sc->regs_res); 501b6d90eb7SKip Macy sc->mmio_len = rman_get_size(sc->regs_res); 502b6d90eb7SKip Macy 50324cdd067SKip Macy if (t3_prep_adapter(sc, ai, 1) < 0) { 504ef72318fSKip Macy printf("prep adapter failed\n"); 50524cdd067SKip Macy error = ENODEV; 50624cdd067SKip Macy goto out; 50724cdd067SKip Macy } 508b6d90eb7SKip Macy /* Allocate the BAR for doing MSI-X. If it succeeds, try to allocate 509b6d90eb7SKip Macy * enough messages for the queue sets. If that fails, try falling 510b6d90eb7SKip Macy * back to MSI. If that fails, then try falling back to the legacy 511b6d90eb7SKip Macy * interrupt pin model. 512b6d90eb7SKip Macy */ 513b6d90eb7SKip Macy #ifdef MSI_SUPPORTED 514693d746cSKip Macy 515b6d90eb7SKip Macy sc->msix_regs_rid = 0x20; 516b6d90eb7SKip Macy if ((msi_allowed >= 2) && 517b6d90eb7SKip Macy (sc->msix_regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 518b6d90eb7SKip Macy &sc->msix_regs_rid, RF_ACTIVE)) != NULL) { 519b6d90eb7SKip Macy 520d722cab4SKip Macy msi_needed = sc->msi_count = SGE_MSIX_COUNT; 521693d746cSKip Macy 522d722cab4SKip Macy if (((error = pci_alloc_msix(dev, &sc->msi_count)) != 0) || 523d722cab4SKip Macy (sc->msi_count != msi_needed)) { 524d722cab4SKip Macy device_printf(dev, "msix allocation failed - msi_count = %d" 525d722cab4SKip Macy " msi_needed=%d will try msi err=%d\n", sc->msi_count, 526d722cab4SKip Macy msi_needed, error); 527d722cab4SKip Macy sc->msi_count = 0; 528b6d90eb7SKip Macy pci_release_msi(dev); 529b6d90eb7SKip Macy bus_release_resource(dev, SYS_RES_MEMORY, 530b6d90eb7SKip Macy sc->msix_regs_rid, sc->msix_regs_res); 531b6d90eb7SKip Macy sc->msix_regs_res = NULL; 532b6d90eb7SKip Macy } else { 533b6d90eb7SKip Macy sc->flags |= USING_MSIX; 534f0a542f8SKip Macy sc->cxgb_intr = t3_intr_msix; 535b6d90eb7SKip Macy } 536b6d90eb7SKip Macy } 537b6d90eb7SKip Macy 538d722cab4SKip Macy if ((msi_allowed >= 1) && (sc->msi_count == 0)) { 539d722cab4SKip Macy sc->msi_count = 1; 540d722cab4SKip Macy if (pci_alloc_msi(dev, &sc->msi_count)) { 541693d746cSKip Macy device_printf(dev, "alloc msi failed - will try INTx\n"); 542d722cab4SKip Macy sc->msi_count = 0; 543b6d90eb7SKip Macy pci_release_msi(dev); 544b6d90eb7SKip Macy } else { 545b6d90eb7SKip Macy sc->flags |= USING_MSI; 546b6d90eb7SKip Macy sc->irq_rid = 1; 547f0a542f8SKip Macy sc->cxgb_intr = t3_intr_msi; 548b6d90eb7SKip Macy } 549b6d90eb7SKip Macy } 550b6d90eb7SKip Macy #endif 551d722cab4SKip Macy if (sc->msi_count == 0) { 552693d746cSKip Macy device_printf(dev, "using line interrupts\n"); 553b6d90eb7SKip Macy sc->irq_rid = 0; 554f0a542f8SKip Macy sc->cxgb_intr = t3b_intr; 555b6d90eb7SKip Macy } 556b6d90eb7SKip Macy 557a02573bcSKip Macy if ((sc->flags & USING_MSIX) && multiq) 558f705d735SKip Macy port_qsets = min((SGE_QSETS/(sc)->params.nports), mp_ncpus); 559b6d90eb7SKip Macy 560b6d90eb7SKip Macy /* Create a private taskqueue thread for handling driver events */ 561b6d90eb7SKip Macy #ifdef TASKQUEUE_CURRENT 562b6d90eb7SKip Macy sc->tq = taskqueue_create("cxgb_taskq", M_NOWAIT, 563b6d90eb7SKip Macy taskqueue_thread_enqueue, &sc->tq); 564b6d90eb7SKip Macy #else 565b6d90eb7SKip Macy sc->tq = taskqueue_create_fast("cxgb_taskq", M_NOWAIT, 566b6d90eb7SKip Macy taskqueue_thread_enqueue, &sc->tq); 567b6d90eb7SKip Macy #endif 568b6d90eb7SKip Macy if (sc->tq == NULL) { 569b6d90eb7SKip Macy device_printf(dev, "failed to allocate controller task queue\n"); 570b6d90eb7SKip Macy goto out; 571b6d90eb7SKip Macy } 572b6d90eb7SKip Macy 573b6d90eb7SKip Macy taskqueue_start_threads(&sc->tq, 1, PI_NET, "%s taskq", 574b6d90eb7SKip Macy device_get_nameunit(dev)); 575b6d90eb7SKip Macy TASK_INIT(&sc->ext_intr_task, 0, cxgb_ext_intr_handler, sc); 576bb38cd2fSKip Macy TASK_INIT(&sc->tick_task, 0, cxgb_tick_handler, sc); 577b6d90eb7SKip Macy 578b6d90eb7SKip Macy 579b6d90eb7SKip Macy /* Create a periodic callout for checking adapter status */ 580bb38cd2fSKip Macy callout_init(&sc->cxgb_tick_ch, TRUE); 581b6d90eb7SKip Macy 582f2d8ff04SGeorge V. Neville-Neil if (t3_check_fw_version(sc) < 0 || force_fw_update) { 583b6d90eb7SKip Macy /* 584b6d90eb7SKip Macy * Warn user that a firmware update will be attempted in init. 585b6d90eb7SKip Macy */ 586d722cab4SKip Macy device_printf(dev, "firmware needs to be updated to version %d.%d.%d\n", 587d722cab4SKip Macy FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO); 588b6d90eb7SKip Macy sc->flags &= ~FW_UPTODATE; 589b6d90eb7SKip Macy } else { 590b6d90eb7SKip Macy sc->flags |= FW_UPTODATE; 591b6d90eb7SKip Macy } 592b6d90eb7SKip Macy 593f2d8ff04SGeorge V. Neville-Neil if (t3_check_tpsram_version(sc) < 0) { 594ac3a6d9cSKip Macy /* 595ac3a6d9cSKip Macy * Warn user that a firmware update will be attempted in init. 596ac3a6d9cSKip Macy */ 597ac3a6d9cSKip Macy device_printf(dev, "SRAM needs to be updated to version %c-%d.%d.%d\n", 598ac3a6d9cSKip Macy t3rev2char(sc), TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); 599ac3a6d9cSKip Macy sc->flags &= ~TPS_UPTODATE; 600ac3a6d9cSKip Macy } else { 601ac3a6d9cSKip Macy sc->flags |= TPS_UPTODATE; 602ac3a6d9cSKip Macy } 603ac3a6d9cSKip Macy 604b6d90eb7SKip Macy /* 605b6d90eb7SKip Macy * Create a child device for each MAC. The ethernet attachment 606b6d90eb7SKip Macy * will be done in these children. 607b6d90eb7SKip Macy */ 608693d746cSKip Macy for (i = 0; i < (sc)->params.nports; i++) { 6097ac2e6c3SKip Macy struct port_info *pi; 6107ac2e6c3SKip Macy 611b6d90eb7SKip Macy if ((child = device_add_child(dev, "cxgb", -1)) == NULL) { 612b6d90eb7SKip Macy device_printf(dev, "failed to add child port\n"); 613b6d90eb7SKip Macy error = EINVAL; 614b6d90eb7SKip Macy goto out; 615b6d90eb7SKip Macy } 6167ac2e6c3SKip Macy pi = &sc->port[i]; 6177ac2e6c3SKip Macy pi->adapter = sc; 6187ac2e6c3SKip Macy pi->nqsets = port_qsets; 6197ac2e6c3SKip Macy pi->first_qset = i*port_qsets; 6207ac2e6c3SKip Macy pi->port_id = i; 6217ac2e6c3SKip Macy pi->tx_chan = i >= ai->nports0; 6227ac2e6c3SKip Macy pi->txpkt_intf = pi->tx_chan ? 2 * (i - ai->nports0) + 1 : 2 * i; 6237ac2e6c3SKip Macy sc->rxpkt_map[pi->txpkt_intf] = i; 6248090c9f5SKip Macy sc->port[i].tx_chan = i >= ai->nports0; 625ac3a6d9cSKip Macy sc->portdev[i] = child; 6267ac2e6c3SKip Macy device_set_softc(child, pi); 627b6d90eb7SKip Macy } 628b6d90eb7SKip Macy if ((error = bus_generic_attach(dev)) != 0) 629b6d90eb7SKip Macy goto out; 630b6d90eb7SKip Macy 631b6d90eb7SKip Macy /* initialize sge private state */ 632ef72318fSKip Macy t3_sge_init_adapter(sc); 633b6d90eb7SKip Macy 634b6d90eb7SKip Macy t3_led_ready(sc); 635b6d90eb7SKip Macy 636d722cab4SKip Macy cxgb_offload_init(); 637d722cab4SKip Macy if (is_offload(sc)) { 638d722cab4SKip Macy setbit(&sc->registered_device_map, OFFLOAD_DEVMAP_BIT); 639d722cab4SKip Macy cxgb_adapter_ofld(sc); 640d722cab4SKip Macy } 641b6d90eb7SKip Macy error = t3_get_fw_version(sc, &vers); 642b6d90eb7SKip Macy if (error) 643b6d90eb7SKip Macy goto out; 644b6d90eb7SKip Macy 645d722cab4SKip Macy snprintf(&sc->fw_version[0], sizeof(sc->fw_version), "%d.%d.%d", 646d722cab4SKip Macy G_FW_VERSION_MAJOR(vers), G_FW_VERSION_MINOR(vers), 647d722cab4SKip Macy G_FW_VERSION_MICRO(vers)); 648b6d90eb7SKip Macy 6495197f3abSGeorge V. Neville-Neil snprintf(buf, sizeof(buf), "%s\t E/C: %s S/N: %s", 6505197f3abSGeorge V. Neville-Neil ai->desc, 6515197f3abSGeorge V. Neville-Neil sc->params.vpd.ec, sc->params.vpd.sn); 6525197f3abSGeorge V. Neville-Neil device_set_desc_copy(dev, buf); 6535197f3abSGeorge V. Neville-Neil 6540bbdea77SGeorge V. Neville-Neil snprintf(&sc->port_types[0], sizeof(sc->port_types), "%x%x%x%x", 6550bbdea77SGeorge V. Neville-Neil sc->params.vpd.port_type[0], sc->params.vpd.port_type[1], 6560bbdea77SGeorge V. Neville-Neil sc->params.vpd.port_type[2], sc->params.vpd.port_type[3]); 6570bbdea77SGeorge V. Neville-Neil 6588e10660fSKip Macy device_printf(sc->dev, "Firmware Version %s\n", &sc->fw_version[0]); 659706cb31fSKip Macy callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc); 6608090c9f5SKip Macy t3_add_attach_sysctls(sc); 661b6d90eb7SKip Macy out: 662b6d90eb7SKip Macy if (error) 663b6d90eb7SKip Macy cxgb_free(sc); 664b6d90eb7SKip Macy 665b6d90eb7SKip Macy return (error); 666b6d90eb7SKip Macy } 667b6d90eb7SKip Macy 6683cf138bbSGeorge V. Neville-Neil /* 669c2009a4cSGeorge V. Neville-Neil * The cxgb_controller_detach routine is called with the device is 6703cf138bbSGeorge V. Neville-Neil * unloaded from the system. 6713cf138bbSGeorge V. Neville-Neil */ 6723cf138bbSGeorge V. Neville-Neil 673b6d90eb7SKip Macy static int 674b6d90eb7SKip Macy cxgb_controller_detach(device_t dev) 675b6d90eb7SKip Macy { 676b6d90eb7SKip Macy struct adapter *sc; 677b6d90eb7SKip Macy 678b6d90eb7SKip Macy sc = device_get_softc(dev); 679b6d90eb7SKip Macy 680b6d90eb7SKip Macy cxgb_free(sc); 681b6d90eb7SKip Macy 682b6d90eb7SKip Macy return (0); 683b6d90eb7SKip Macy } 684b6d90eb7SKip Macy 6853cf138bbSGeorge V. Neville-Neil /* 6863cf138bbSGeorge V. Neville-Neil * The cxgb_free() is called by the cxgb_controller_detach() routine 6873cf138bbSGeorge V. Neville-Neil * to tear down the structures that were built up in 6883cf138bbSGeorge V. Neville-Neil * cxgb_controller_attach(), and should be the final piece of work 689c2009a4cSGeorge V. Neville-Neil * done when fully unloading the driver. 6903cf138bbSGeorge V. Neville-Neil * 6913cf138bbSGeorge V. Neville-Neil * 6923cf138bbSGeorge V. Neville-Neil * 1. Shutting down the threads started by the cxgb_controller_attach() 6933cf138bbSGeorge V. Neville-Neil * routine. 6943cf138bbSGeorge V. Neville-Neil * 2. Stopping the lower level device and all callouts (cxgb_down_locked()). 6953cf138bbSGeorge V. Neville-Neil * 3. Detaching all of the port devices created during the 6963cf138bbSGeorge V. Neville-Neil * cxgb_controller_attach() routine. 6973cf138bbSGeorge V. Neville-Neil * 4. Removing the device children created via cxgb_controller_attach(). 6983cf138bbSGeorge V. Neville-Neil * 5. Releaseing PCI resources associated with the device. 6993cf138bbSGeorge V. Neville-Neil * 6. Turning off the offload support, iff it was turned on. 7003cf138bbSGeorge V. Neville-Neil * 7. Destroying the mutexes created in cxgb_controller_attach(). 7013cf138bbSGeorge V. Neville-Neil * 7023cf138bbSGeorge V. Neville-Neil */ 703b6d90eb7SKip Macy static void 704b6d90eb7SKip Macy cxgb_free(struct adapter *sc) 705b6d90eb7SKip Macy { 706b6d90eb7SKip Macy int i; 707b6d90eb7SKip Macy 7088e10660fSKip Macy ADAPTER_LOCK(sc); 7098e10660fSKip Macy sc->flags |= CXGB_SHUTDOWN; 7108e10660fSKip Macy ADAPTER_UNLOCK(sc); 7118e10660fSKip Macy 7123cf138bbSGeorge V. Neville-Neil cxgb_pcpu_shutdown_threads(sc); 7133cf138bbSGeorge V. Neville-Neil 7143cf138bbSGeorge V. Neville-Neil ADAPTER_LOCK(sc); 715bb38cd2fSKip Macy cxgb_down_locked(sc); 7163cf138bbSGeorge V. Neville-Neil ADAPTER_UNLOCK(sc); 7173cf138bbSGeorge V. Neville-Neil 7183cf138bbSGeorge V. Neville-Neil t3_sge_deinit_sw(sc); 7193cf138bbSGeorge V. Neville-Neil /* 7203cf138bbSGeorge V. Neville-Neil * Wait for last callout 7213cf138bbSGeorge V. Neville-Neil */ 7223cf138bbSGeorge V. Neville-Neil 7233cf138bbSGeorge V. Neville-Neil DELAY(hz*100); 7243cf138bbSGeorge V. Neville-Neil 7253cf138bbSGeorge V. Neville-Neil bus_generic_detach(sc->dev); 7263cf138bbSGeorge V. Neville-Neil 7273cf138bbSGeorge V. Neville-Neil for (i = 0; i < (sc)->params.nports; i++) { 728c2009a4cSGeorge V. Neville-Neil if (sc->portdev[i] && 729c2009a4cSGeorge V. Neville-Neil device_delete_child(sc->dev, sc->portdev[i]) != 0) 7303cf138bbSGeorge V. Neville-Neil device_printf(sc->dev, "failed to delete child port\n"); 7313cf138bbSGeorge V. Neville-Neil } 732d722cab4SKip Macy 733d722cab4SKip Macy #ifdef MSI_SUPPORTED 734d722cab4SKip Macy if (sc->flags & (USING_MSI | USING_MSIX)) { 735d722cab4SKip Macy device_printf(sc->dev, "releasing msi message(s)\n"); 736d722cab4SKip Macy pci_release_msi(sc->dev); 737d722cab4SKip Macy } else { 738d722cab4SKip Macy device_printf(sc->dev, "no msi message to release\n"); 739d722cab4SKip Macy } 740d722cab4SKip Macy #endif 741d722cab4SKip Macy if (sc->msix_regs_res != NULL) { 742d722cab4SKip Macy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->msix_regs_rid, 743d722cab4SKip Macy sc->msix_regs_res); 744d722cab4SKip Macy } 745d722cab4SKip Macy 7468e10660fSKip Macy if (sc->tq != NULL) { 7477ac2e6c3SKip Macy taskqueue_free(sc->tq); 7488e10660fSKip Macy sc->tq = NULL; 7498e10660fSKip Macy } 7508e10660fSKip Macy 751d722cab4SKip Macy if (is_offload(sc)) { 752d722cab4SKip Macy cxgb_adapter_unofld(sc); 753d722cab4SKip Macy if (isset(&sc->open_device_map, OFFLOAD_DEVMAP_BIT)) 754d722cab4SKip Macy offload_close(&sc->tdev); 7558090c9f5SKip Macy else 7568090c9f5SKip Macy printf("cxgb_free: DEVMAP_BIT not set\n"); 7578090c9f5SKip Macy } else 7588090c9f5SKip Macy printf("not offloading set\n"); 75946b0a854SKip Macy #ifdef notyet 7608e10660fSKip Macy if (sc->flags & CXGB_OFLD_INIT) 7618e10660fSKip Macy cxgb_offload_deactivate(sc); 76246b0a854SKip Macy #endif 763ac3a6d9cSKip Macy free(sc->filters, M_DEVBUF); 764b6d90eb7SKip Macy t3_sge_free(sc); 765b6d90eb7SKip Macy 766bb38cd2fSKip Macy cxgb_offload_exit(); 767bb38cd2fSKip Macy 7688e10660fSKip Macy if (sc->udbs_res != NULL) 7698e10660fSKip Macy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->udbs_rid, 7708e10660fSKip Macy sc->udbs_res); 7718e10660fSKip Macy 772b6d90eb7SKip Macy if (sc->regs_res != NULL) 773b6d90eb7SKip Macy bus_release_resource(sc->dev, SYS_RES_MEMORY, sc->regs_rid, 774b6d90eb7SKip Macy sc->regs_res); 775b6d90eb7SKip Macy 776bb38cd2fSKip Macy MTX_DESTROY(&sc->mdio_lock); 777bb38cd2fSKip Macy MTX_DESTROY(&sc->sge.reg_lock); 778bb38cd2fSKip Macy MTX_DESTROY(&sc->elmer_lock); 779bb38cd2fSKip Macy ADAPTER_LOCK_DEINIT(sc); 780b6d90eb7SKip Macy } 781b6d90eb7SKip Macy 782b6d90eb7SKip Macy /** 783b6d90eb7SKip Macy * setup_sge_qsets - configure SGE Tx/Rx/response queues 784b6d90eb7SKip Macy * @sc: the controller softc 785b6d90eb7SKip Macy * 786b6d90eb7SKip Macy * Determines how many sets of SGE queues to use and initializes them. 787b6d90eb7SKip Macy * We support multiple queue sets per port if we have MSI-X, otherwise 788b6d90eb7SKip Macy * just one queue set per port. 789b6d90eb7SKip Macy */ 790b6d90eb7SKip Macy static int 791b6d90eb7SKip Macy setup_sge_qsets(adapter_t *sc) 792b6d90eb7SKip Macy { 7935c5df3daSKip Macy int i, j, err, irq_idx = 0, qset_idx = 0; 794d722cab4SKip Macy u_int ntxq = SGE_TXQ_PER_SET; 795b6d90eb7SKip Macy 796b6d90eb7SKip Macy if ((err = t3_sge_alloc(sc)) != 0) { 797693d746cSKip Macy device_printf(sc->dev, "t3_sge_alloc returned %d\n", err); 798b6d90eb7SKip Macy return (err); 799b6d90eb7SKip Macy } 800b6d90eb7SKip Macy 801b6d90eb7SKip Macy if (sc->params.rev > 0 && !(sc->flags & USING_MSI)) 802b6d90eb7SKip Macy irq_idx = -1; 803b6d90eb7SKip Macy 8045c5df3daSKip Macy for (i = 0; i < (sc)->params.nports; i++) { 805b6d90eb7SKip Macy struct port_info *pi = &sc->port[i]; 806b6d90eb7SKip Macy 8077ac2e6c3SKip Macy for (j = 0; j < pi->nqsets; j++, qset_idx++) { 808693d746cSKip Macy err = t3_sge_alloc_qset(sc, qset_idx, (sc)->params.nports, 809b6d90eb7SKip Macy (sc->flags & USING_MSIX) ? qset_idx + 1 : irq_idx, 810b6d90eb7SKip Macy &sc->params.sge.qset[qset_idx], ntxq, pi); 811b6d90eb7SKip Macy if (err) { 812b6d90eb7SKip Macy t3_free_sge_resources(sc); 8137ac2e6c3SKip Macy device_printf(sc->dev, "t3_sge_alloc_qset failed with %d\n", 8147ac2e6c3SKip Macy err); 815b6d90eb7SKip Macy return (err); 816b6d90eb7SKip Macy } 817b6d90eb7SKip Macy } 818b6d90eb7SKip Macy } 819b6d90eb7SKip Macy 820b6d90eb7SKip Macy return (0); 821b6d90eb7SKip Macy } 822b6d90eb7SKip Macy 823ef72318fSKip Macy static void 824ef72318fSKip Macy cxgb_teardown_msix(adapter_t *sc) 825ef72318fSKip Macy { 826ef72318fSKip Macy int i, nqsets; 827ef72318fSKip Macy 828ef72318fSKip Macy for (nqsets = i = 0; i < (sc)->params.nports; i++) 829ef72318fSKip Macy nqsets += sc->port[i].nqsets; 830ef72318fSKip Macy 831ef72318fSKip Macy for (i = 0; i < nqsets; i++) { 832ef72318fSKip Macy if (sc->msix_intr_tag[i] != NULL) { 833ef72318fSKip Macy bus_teardown_intr(sc->dev, sc->msix_irq_res[i], 834ef72318fSKip Macy sc->msix_intr_tag[i]); 835ef72318fSKip Macy sc->msix_intr_tag[i] = NULL; 836ef72318fSKip Macy } 837ef72318fSKip Macy if (sc->msix_irq_res[i] != NULL) { 838ef72318fSKip Macy bus_release_resource(sc->dev, SYS_RES_IRQ, 839ef72318fSKip Macy sc->msix_irq_rid[i], sc->msix_irq_res[i]); 840ef72318fSKip Macy sc->msix_irq_res[i] = NULL; 841ef72318fSKip Macy } 842ef72318fSKip Macy } 843ef72318fSKip Macy } 844ef72318fSKip Macy 845b6d90eb7SKip Macy static int 846b6d90eb7SKip Macy cxgb_setup_msix(adapter_t *sc, int msix_count) 847b6d90eb7SKip Macy { 848b6d90eb7SKip Macy int i, j, k, nqsets, rid; 849b6d90eb7SKip Macy 850b6d90eb7SKip Macy /* The first message indicates link changes and error conditions */ 851b6d90eb7SKip Macy sc->irq_rid = 1; 852b6d90eb7SKip Macy if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 853b6d90eb7SKip Macy &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 854b6d90eb7SKip Macy device_printf(sc->dev, "Cannot allocate msix interrupt\n"); 855b6d90eb7SKip Macy return (EINVAL); 856b6d90eb7SKip Macy } 857693d746cSKip Macy 858b6d90eb7SKip Macy if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET, 859b6d90eb7SKip Macy #ifdef INTR_FILTERS 860b6d90eb7SKip Macy NULL, 861b6d90eb7SKip Macy #endif 862b6d90eb7SKip Macy cxgb_async_intr, sc, &sc->intr_tag)) { 863b6d90eb7SKip Macy device_printf(sc->dev, "Cannot set up interrupt\n"); 864b6d90eb7SKip Macy return (EINVAL); 865b6d90eb7SKip Macy } 866ef72318fSKip Macy for (i = k = 0; i < (sc)->params.nports; i++) { 867b6d90eb7SKip Macy nqsets = sc->port[i].nqsets; 868ef72318fSKip Macy for (j = 0; j < nqsets; j++, k++) { 869b6d90eb7SKip Macy struct sge_qset *qs = &sc->sge.qs[k]; 870b6d90eb7SKip Macy 871b6d90eb7SKip Macy rid = k + 2; 872b6d90eb7SKip Macy if (cxgb_debug) 873b6d90eb7SKip Macy printf("rid=%d ", rid); 874b6d90eb7SKip Macy if ((sc->msix_irq_res[k] = bus_alloc_resource_any( 875b6d90eb7SKip Macy sc->dev, SYS_RES_IRQ, &rid, 876b6d90eb7SKip Macy RF_SHAREABLE | RF_ACTIVE)) == NULL) { 877b6d90eb7SKip Macy device_printf(sc->dev, "Cannot allocate " 878b6d90eb7SKip Macy "interrupt for message %d\n", rid); 879b6d90eb7SKip Macy return (EINVAL); 880b6d90eb7SKip Macy } 881b6d90eb7SKip Macy sc->msix_irq_rid[k] = rid; 882ef72318fSKip Macy if (bus_setup_intr(sc->dev, sc->msix_irq_res[k], 883b6d90eb7SKip Macy INTR_MPSAFE|INTR_TYPE_NET, 884b6d90eb7SKip Macy #ifdef INTR_FILTERS 885b6d90eb7SKip Macy NULL, 886b6d90eb7SKip Macy #endif 887b6d90eb7SKip Macy t3_intr_msix, qs, &sc->msix_intr_tag[k])) { 888b6d90eb7SKip Macy device_printf(sc->dev, "Cannot set up " 889b6d90eb7SKip Macy "interrupt for message %d\n", rid); 890b6d90eb7SKip Macy return (EINVAL); 891a02573bcSKip Macy 892b6d90eb7SKip Macy } 893a02573bcSKip Macy #if 0 8948090c9f5SKip Macy #ifdef IFNET_MULTIQUEUE 895a02573bcSKip Macy if (multiq) { 8968090c9f5SKip Macy int vector = rman_get_start(sc->msix_irq_res[k]); 8978090c9f5SKip Macy if (bootverbose) 8988090c9f5SKip Macy device_printf(sc->dev, "binding vector=%d to cpu=%d\n", vector, k % mp_ncpus); 8998090c9f5SKip Macy intr_bind(vector, k % mp_ncpus); 9008090c9f5SKip Macy } 9018090c9f5SKip Macy #endif 902a02573bcSKip Macy #endif 903b6d90eb7SKip Macy } 904b6d90eb7SKip Macy } 905693d746cSKip Macy 906b6d90eb7SKip Macy return (0); 907b6d90eb7SKip Macy } 908b6d90eb7SKip Macy 909b6d90eb7SKip Macy static int 910b6d90eb7SKip Macy cxgb_port_probe(device_t dev) 911b6d90eb7SKip Macy { 912b6d90eb7SKip Macy struct port_info *p; 913b6d90eb7SKip Macy char buf[80]; 9148e10660fSKip Macy const char *desc; 915b6d90eb7SKip Macy 916b6d90eb7SKip Macy p = device_get_softc(dev); 9178e10660fSKip Macy desc = p->phy.desc; 9188e10660fSKip Macy snprintf(buf, sizeof(buf), "Port %d %s", p->port_id, desc); 919b6d90eb7SKip Macy device_set_desc_copy(dev, buf); 920b6d90eb7SKip Macy return (0); 921b6d90eb7SKip Macy } 922b6d90eb7SKip Macy 923b6d90eb7SKip Macy 924b6d90eb7SKip Macy static int 925b6d90eb7SKip Macy cxgb_makedev(struct port_info *pi) 926b6d90eb7SKip Macy { 927b6d90eb7SKip Macy 928ef72318fSKip Macy pi->port_cdev = make_dev(&cxgb_cdevsw, pi->ifp->if_dunit, 929ef72318fSKip Macy UID_ROOT, GID_WHEEL, 0600, if_name(pi->ifp)); 930b6d90eb7SKip Macy 931b6d90eb7SKip Macy if (pi->port_cdev == NULL) 932b6d90eb7SKip Macy return (ENOMEM); 933b6d90eb7SKip Macy 934b6d90eb7SKip Macy pi->port_cdev->si_drv1 = (void *)pi; 935b6d90eb7SKip Macy 936b6d90eb7SKip Macy return (0); 937b6d90eb7SKip Macy } 938b6d90eb7SKip Macy 939e97121daSKip Macy #ifndef LRO_SUPPORTED 940e97121daSKip Macy #ifdef IFCAP_LRO 941e97121daSKip Macy #undef IFCAP_LRO 942e97121daSKip Macy #endif 943e97121daSKip Macy #define IFCAP_LRO 0x0 944e97121daSKip Macy #endif 945b6d90eb7SKip Macy 946b6d90eb7SKip Macy #ifdef TSO_SUPPORTED 94725292debSKip Macy #define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO | IFCAP_JUMBO_MTU | IFCAP_LRO) 948b6d90eb7SKip Macy /* Don't enable TSO6 yet */ 94925292debSKip Macy #define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_VLAN_HWCSUM | IFCAP_TSO4 | IFCAP_JUMBO_MTU | IFCAP_LRO) 950b6d90eb7SKip Macy #else 951b6d90eb7SKip Macy #define CXGB_CAP (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU) 952b6d90eb7SKip Macy /* Don't enable TSO6 yet */ 953b6d90eb7SKip Macy #define CXGB_CAP_ENABLE (IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU | IFCAP_HWCSUM | IFCAP_JUMBO_MTU) 954b6d90eb7SKip Macy #define IFCAP_TSO4 0x0 9557aff6d8eSKip Macy #define IFCAP_TSO6 0x0 956b6d90eb7SKip Macy #define CSUM_TSO 0x0 957b6d90eb7SKip Macy #endif 958b6d90eb7SKip Macy 959b6d90eb7SKip Macy 960b6d90eb7SKip Macy static int 961b6d90eb7SKip Macy cxgb_port_attach(device_t dev) 962b6d90eb7SKip Macy { 963b6d90eb7SKip Macy struct port_info *p; 964b6d90eb7SKip Macy struct ifnet *ifp; 965ef72318fSKip Macy int err, media_flags; 9668e10660fSKip Macy struct adapter *sc; 9678e10660fSKip Macy 968b6d90eb7SKip Macy 969b6d90eb7SKip Macy p = device_get_softc(dev); 9708e10660fSKip Macy sc = p->adapter; 971bb38cd2fSKip Macy snprintf(p->lockbuf, PORT_NAME_LEN, "cxgb port lock %d:%d", 9726b68e276SKip Macy device_get_unit(device_get_parent(dev)), p->port_id); 973bb38cd2fSKip Macy PORT_LOCK_INIT(p, p->lockbuf); 974b6d90eb7SKip Macy 975b6d90eb7SKip Macy /* Allocate an ifnet object and set it up */ 976b6d90eb7SKip Macy ifp = p->ifp = if_alloc(IFT_ETHER); 977b6d90eb7SKip Macy if (ifp == NULL) { 978b6d90eb7SKip Macy device_printf(dev, "Cannot allocate ifnet\n"); 979b6d90eb7SKip Macy return (ENOMEM); 980b6d90eb7SKip Macy } 981b6d90eb7SKip Macy 982b6d90eb7SKip Macy /* 983b6d90eb7SKip Macy * Note that there is currently no watchdog timer. 984b6d90eb7SKip Macy */ 985b6d90eb7SKip Macy if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 986b6d90eb7SKip Macy ifp->if_init = cxgb_init; 987b6d90eb7SKip Macy ifp->if_softc = p; 988b6d90eb7SKip Macy ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 989b6d90eb7SKip Macy ifp->if_ioctl = cxgb_ioctl; 990b6d90eb7SKip Macy ifp->if_start = cxgb_start; 9918090c9f5SKip Macy 992a02573bcSKip Macy 993b6d90eb7SKip Macy ifp->if_timer = 0; /* Disable ifnet watchdog */ 994b6d90eb7SKip Macy ifp->if_watchdog = NULL; 995b6d90eb7SKip Macy 996a02573bcSKip Macy ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN; 997b6d90eb7SKip Macy IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); 998b6d90eb7SKip Macy IFQ_SET_READY(&ifp->if_snd); 999b6d90eb7SKip Macy 1000b6d90eb7SKip Macy ifp->if_hwassist = ifp->if_capabilities = ifp->if_capenable = 0; 1001b6d90eb7SKip Macy ifp->if_capabilities |= CXGB_CAP; 1002b6d90eb7SKip Macy ifp->if_capenable |= CXGB_CAP_ENABLE; 1003b6d90eb7SKip Macy ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP | CSUM_TSO); 1004ac3a6d9cSKip Macy /* 1005ac3a6d9cSKip Macy * disable TSO on 4-port - it isn't supported by the firmware yet 1006ac3a6d9cSKip Macy */ 1007ac3a6d9cSKip Macy if (p->adapter->params.nports > 2) { 1008ac3a6d9cSKip Macy ifp->if_capabilities &= ~(IFCAP_TSO4 | IFCAP_TSO6); 1009ac3a6d9cSKip Macy ifp->if_capenable &= ~(IFCAP_TSO4 | IFCAP_TSO6); 1010ac3a6d9cSKip Macy ifp->if_hwassist &= ~CSUM_TSO; 1011ac3a6d9cSKip Macy } 1012b6d90eb7SKip Macy 1013b6d90eb7SKip Macy ether_ifattach(ifp, p->hw_addr); 10143cf138bbSGeorge V. Neville-Neil 10155eba27feSKip Macy #ifdef IFNET_MULTIQUEUE 1016a02573bcSKip Macy ifp->if_transmit = cxgb_pcpu_transmit; 10175eba27feSKip Macy #endif 1018ac3a6d9cSKip Macy /* 1019ac3a6d9cSKip Macy * Only default to jumbo frames on 10GigE 1020ac3a6d9cSKip Macy */ 1021ac3a6d9cSKip Macy if (p->adapter->params.nports <= 2) 10224af83c8cSKip Macy ifp->if_mtu = ETHERMTU_JUMBO; 1023b6d90eb7SKip Macy if ((err = cxgb_makedev(p)) != 0) { 1024b6d90eb7SKip Macy printf("makedev failed %d\n", err); 1025b6d90eb7SKip Macy return (err); 1026b6d90eb7SKip Macy } 1027b6d90eb7SKip Macy ifmedia_init(&p->media, IFM_IMASK, cxgb_media_change, 1028b6d90eb7SKip Macy cxgb_media_status); 1029b6d90eb7SKip Macy 10308e10660fSKip Macy if (!strcmp(p->phy.desc, "10GBASE-CX4")) { 1031ef72318fSKip Macy media_flags = IFM_ETHER | IFM_10G_CX4 | IFM_FDX; 10328e10660fSKip Macy } else if (!strcmp(p->phy.desc, "10GBASE-SR")) { 1033ef72318fSKip Macy media_flags = IFM_ETHER | IFM_10G_SR | IFM_FDX; 103419905d6dSKip Macy } else if (!strcmp(p->phy.desc, "10GBASE-R")) { 1035837f41b0SGeorge V. Neville-Neil media_flags = cxgb_ifm_type(p->phy.modtype); 10368e10660fSKip Macy } else if (!strcmp(p->phy.desc, "10/100/1000BASE-T")) { 1037ef72318fSKip Macy ifmedia_add(&p->media, IFM_ETHER | IFM_10_T, 0, NULL); 1038ef72318fSKip Macy ifmedia_add(&p->media, IFM_ETHER | IFM_10_T | IFM_FDX, 1039ef72318fSKip Macy 0, NULL); 1040ef72318fSKip Macy ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX, 1041ef72318fSKip Macy 0, NULL); 1042ef72318fSKip Macy ifmedia_add(&p->media, IFM_ETHER | IFM_100_TX | IFM_FDX, 1043ef72318fSKip Macy 0, NULL); 1044ef72318fSKip Macy ifmedia_add(&p->media, IFM_ETHER | IFM_1000_T | IFM_FDX, 1045ef72318fSKip Macy 0, NULL); 1046ef72318fSKip Macy media_flags = 0; 104741509ecdSKip Macy } else if (!strcmp(p->phy.desc, "1000BASE-X")) { 104841509ecdSKip Macy /* 104941509ecdSKip Macy * XXX: This is not very accurate. Fix when common code 105041509ecdSKip Macy * returns more specific value - eg 1000BASE-SX, LX, etc. 1051837f41b0SGeorge V. Neville-Neil * 1052837f41b0SGeorge V. Neville-Neil * XXX: In the meantime, don't lie. Consider setting IFM_AUTO 1053837f41b0SGeorge V. Neville-Neil * instead of SX. 105441509ecdSKip Macy */ 105541509ecdSKip Macy media_flags = IFM_ETHER | IFM_1000_SX | IFM_FDX; 1056ef72318fSKip Macy } else { 10578e10660fSKip Macy printf("unsupported media type %s\n", p->phy.desc); 1058b6d90eb7SKip Macy return (ENXIO); 1059b6d90eb7SKip Macy } 1060ef72318fSKip Macy if (media_flags) { 1061837f41b0SGeorge V. Neville-Neil /* 1062837f41b0SGeorge V. Neville-Neil * Note the modtype on which we based our flags. If modtype 1063837f41b0SGeorge V. Neville-Neil * changes, we'll redo the ifmedia for this ifp. modtype may 1064837f41b0SGeorge V. Neville-Neil * change when transceivers are plugged in/out, and in other 1065837f41b0SGeorge V. Neville-Neil * situations. 1066837f41b0SGeorge V. Neville-Neil */ 1067837f41b0SGeorge V. Neville-Neil ifmedia_add(&p->media, media_flags, p->phy.modtype, NULL); 1068b6d90eb7SKip Macy ifmedia_set(&p->media, media_flags); 1069ef72318fSKip Macy } else { 1070ef72318fSKip Macy ifmedia_add(&p->media, IFM_ETHER | IFM_AUTO, 0, NULL); 1071ef72318fSKip Macy ifmedia_set(&p->media, IFM_ETHER | IFM_AUTO); 1072ef72318fSKip Macy } 1073ef72318fSKip Macy 107419905d6dSKip Macy /* Get the latest mac address, User can use a LAA */ 107519905d6dSKip Macy bcopy(IF_LLADDR(p->ifp), p->hw_addr, ETHER_ADDR_LEN); 1076ef72318fSKip Macy t3_sge_init_port(p); 1077f2d8ff04SGeorge V. Neville-Neil 10783cf138bbSGeorge V. Neville-Neil /* If it's MSI or INTx, allocate a single interrupt for everything */ 10793cf138bbSGeorge V. Neville-Neil if ((sc->flags & USING_MSIX) == 0) { 10803cf138bbSGeorge V. Neville-Neil if ((sc->irq_res = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, 10813cf138bbSGeorge V. Neville-Neil &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 10823cf138bbSGeorge V. Neville-Neil device_printf(sc->dev, "Cannot allocate interrupt rid=%d\n", 10833cf138bbSGeorge V. Neville-Neil sc->irq_rid); 10843cf138bbSGeorge V. Neville-Neil err = EINVAL; 10853cf138bbSGeorge V. Neville-Neil goto out; 10863cf138bbSGeorge V. Neville-Neil } 10873cf138bbSGeorge V. Neville-Neil device_printf(sc->dev, "allocated irq_res=%p\n", sc->irq_res); 10883cf138bbSGeorge V. Neville-Neil 10893cf138bbSGeorge V. Neville-Neil if (bus_setup_intr(sc->dev, sc->irq_res, INTR_MPSAFE|INTR_TYPE_NET, 10903cf138bbSGeorge V. Neville-Neil #ifdef INTR_FILTERS 10913cf138bbSGeorge V. Neville-Neil NULL, 10923cf138bbSGeorge V. Neville-Neil #endif 10933cf138bbSGeorge V. Neville-Neil sc->cxgb_intr, sc, &sc->intr_tag)) { 10943cf138bbSGeorge V. Neville-Neil device_printf(sc->dev, "Cannot set up interrupt\n"); 10953cf138bbSGeorge V. Neville-Neil err = EINVAL; 10963cf138bbSGeorge V. Neville-Neil goto irq_err; 10973cf138bbSGeorge V. Neville-Neil } 10983cf138bbSGeorge V. Neville-Neil } else { 10993cf138bbSGeorge V. Neville-Neil cxgb_setup_msix(sc, sc->msi_count); 11003cf138bbSGeorge V. Neville-Neil } 11013cf138bbSGeorge V. Neville-Neil 1102ef027c52SKip Macy #if defined(LINK_ATTACH) 11038e10660fSKip Macy cxgb_link_start(p); 11048e10660fSKip Macy t3_link_changed(sc, p->port_id); 1105ef027c52SKip Macy #endif 11063cf138bbSGeorge V. Neville-Neil out: 11073cf138bbSGeorge V. Neville-Neil return (err); 11083cf138bbSGeorge V. Neville-Neil irq_err: 11093cf138bbSGeorge V. Neville-Neil CH_ERR(sc, "request_irq failed, err %d\n", err); 11103cf138bbSGeorge V. Neville-Neil goto out; 1111b6d90eb7SKip Macy } 1112b6d90eb7SKip Macy 11133cf138bbSGeorge V. Neville-Neil /* 11143cf138bbSGeorge V. Neville-Neil * cxgb_port_detach() is called via the device_detach methods when 11153cf138bbSGeorge V. Neville-Neil * cxgb_free() calls the bus_generic_detach. It is responsible for 11163cf138bbSGeorge V. Neville-Neil * removing the device from the view of the kernel, i.e. from all 11173cf138bbSGeorge V. Neville-Neil * interfaces lists etc. This routine is only called when the driver is 11183cf138bbSGeorge V. Neville-Neil * being unloaded, not when the link goes down. 11193cf138bbSGeorge V. Neville-Neil * 11203cf138bbSGeorge V. Neville-Neil */ 1121b6d90eb7SKip Macy static int 1122b6d90eb7SKip Macy cxgb_port_detach(device_t dev) 1123b6d90eb7SKip Macy { 1124b6d90eb7SKip Macy struct port_info *p; 11253cf138bbSGeorge V. Neville-Neil struct adapter *sc; 1126b6d90eb7SKip Macy 1127b6d90eb7SKip Macy p = device_get_softc(dev); 11283cf138bbSGeorge V. Neville-Neil sc = p->adapter; 11293cf138bbSGeorge V. Neville-Neil 11303cf138bbSGeorge V. Neville-Neil if (p->port_cdev != NULL) 11313cf138bbSGeorge V. Neville-Neil destroy_dev(p->port_cdev); 11323cf138bbSGeorge V. Neville-Neil 11333cf138bbSGeorge V. Neville-Neil ether_ifdetach(p->ifp); 11343cf138bbSGeorge V. Neville-Neil printf("waiting for callout to stop ..."); 11353cf138bbSGeorge V. Neville-Neil printf("done\n"); 1136d722cab4SKip Macy 1137d722cab4SKip Macy PORT_LOCK(p); 1138ef72318fSKip Macy if (p->ifp->if_drv_flags & IFF_DRV_RUNNING) 1139d722cab4SKip Macy cxgb_stop_locked(p); 1140d722cab4SKip Macy PORT_UNLOCK(p); 1141d722cab4SKip Macy 11423cf138bbSGeorge V. Neville-Neil if (sc->intr_tag != NULL) { 11433cf138bbSGeorge V. Neville-Neil bus_teardown_intr(sc->dev, sc->irq_res, sc->intr_tag); 11443cf138bbSGeorge V. Neville-Neil sc->intr_tag = NULL; 11453cf138bbSGeorge V. Neville-Neil } 11463cf138bbSGeorge V. Neville-Neil if (sc->irq_res != NULL) { 11473cf138bbSGeorge V. Neville-Neil device_printf(sc->dev, "de-allocating interrupt irq_rid=%d irq_res=%p\n", 11483cf138bbSGeorge V. Neville-Neil sc->irq_rid, sc->irq_res); 11493cf138bbSGeorge V. Neville-Neil bus_release_resource(sc->dev, SYS_RES_IRQ, sc->irq_rid, 11503cf138bbSGeorge V. Neville-Neil sc->irq_res); 11513cf138bbSGeorge V. Neville-Neil sc->irq_res = NULL; 11523cf138bbSGeorge V. Neville-Neil } 11533cf138bbSGeorge V. Neville-Neil 11543cf138bbSGeorge V. Neville-Neil if (sc->flags & USING_MSIX) 11553cf138bbSGeorge V. Neville-Neil cxgb_teardown_msix(sc); 11563cf138bbSGeorge V. Neville-Neil 11573cf138bbSGeorge V. Neville-Neil callout_drain(&sc->cxgb_tick_ch); 11583cf138bbSGeorge V. Neville-Neil callout_drain(&sc->sge_timer_ch); 11593cf138bbSGeorge V. Neville-Neil 11603cf138bbSGeorge V. Neville-Neil if (sc->tq != NULL) { 11613cf138bbSGeorge V. Neville-Neil printf("draining slow intr\n"); 11623cf138bbSGeorge V. Neville-Neil 11633cf138bbSGeorge V. Neville-Neil taskqueue_drain(sc->tq, &sc->slow_intr_task); 11643cf138bbSGeorge V. Neville-Neil printf("draining ext intr\n"); 11653cf138bbSGeorge V. Neville-Neil taskqueue_drain(sc->tq, &sc->ext_intr_task); 11663cf138bbSGeorge V. Neville-Neil printf("draining tick task\n"); 11673cf138bbSGeorge V. Neville-Neil taskqueue_drain(sc->tq, &sc->tick_task); 11683cf138bbSGeorge V. Neville-Neil } 11693cf138bbSGeorge V. Neville-Neil 11707ac2e6c3SKip Macy /* 11717ac2e6c3SKip Macy * the lock may be acquired in ifdetach 11727ac2e6c3SKip Macy */ 11737ac2e6c3SKip Macy PORT_LOCK_DEINIT(p); 1174b6d90eb7SKip Macy if_free(p->ifp); 1175b6d90eb7SKip Macy 1176b6d90eb7SKip Macy return (0); 1177b6d90eb7SKip Macy } 1178b6d90eb7SKip Macy 1179b6d90eb7SKip Macy void 1180b6d90eb7SKip Macy t3_fatal_err(struct adapter *sc) 1181b6d90eb7SKip Macy { 1182b6d90eb7SKip Macy u_int fw_status[4]; 1183b6d90eb7SKip Macy 11845c5df3daSKip Macy if (sc->flags & FULL_INIT_DONE) { 11855c5df3daSKip Macy t3_sge_stop(sc); 11865c5df3daSKip Macy t3_write_reg(sc, A_XGM_TX_CTRL, 0); 11875c5df3daSKip Macy t3_write_reg(sc, A_XGM_RX_CTRL, 0); 11885c5df3daSKip Macy t3_write_reg(sc, XGM_REG(A_XGM_TX_CTRL, 1), 0); 11895c5df3daSKip Macy t3_write_reg(sc, XGM_REG(A_XGM_RX_CTRL, 1), 0); 11905c5df3daSKip Macy t3_intr_disable(sc); 11915c5df3daSKip Macy } 1192b6d90eb7SKip Macy device_printf(sc->dev,"encountered fatal error, operation suspended\n"); 1193b6d90eb7SKip Macy if (!t3_cim_ctl_blk_read(sc, 0xa0, 4, fw_status)) 1194b6d90eb7SKip Macy device_printf(sc->dev, "FW_ status: 0x%x, 0x%x, 0x%x, 0x%x\n", 1195b6d90eb7SKip Macy fw_status[0], fw_status[1], fw_status[2], fw_status[3]); 1196b6d90eb7SKip Macy } 1197b6d90eb7SKip Macy 1198b6d90eb7SKip Macy int 1199b6d90eb7SKip Macy t3_os_find_pci_capability(adapter_t *sc, int cap) 1200b6d90eb7SKip Macy { 1201b6d90eb7SKip Macy device_t dev; 1202b6d90eb7SKip Macy struct pci_devinfo *dinfo; 1203b6d90eb7SKip Macy pcicfgregs *cfg; 1204b6d90eb7SKip Macy uint32_t status; 1205b6d90eb7SKip Macy uint8_t ptr; 1206b6d90eb7SKip Macy 1207b6d90eb7SKip Macy dev = sc->dev; 1208b6d90eb7SKip Macy dinfo = device_get_ivars(dev); 1209b6d90eb7SKip Macy cfg = &dinfo->cfg; 1210b6d90eb7SKip Macy 1211b6d90eb7SKip Macy status = pci_read_config(dev, PCIR_STATUS, 2); 1212b6d90eb7SKip Macy if (!(status & PCIM_STATUS_CAPPRESENT)) 1213b6d90eb7SKip Macy return (0); 1214b6d90eb7SKip Macy 1215b6d90eb7SKip Macy switch (cfg->hdrtype & PCIM_HDRTYPE) { 1216b6d90eb7SKip Macy case 0: 1217b6d90eb7SKip Macy case 1: 1218b6d90eb7SKip Macy ptr = PCIR_CAP_PTR; 1219b6d90eb7SKip Macy break; 1220b6d90eb7SKip Macy case 2: 1221b6d90eb7SKip Macy ptr = PCIR_CAP_PTR_2; 1222b6d90eb7SKip Macy break; 1223b6d90eb7SKip Macy default: 1224b6d90eb7SKip Macy return (0); 1225b6d90eb7SKip Macy break; 1226b6d90eb7SKip Macy } 1227b6d90eb7SKip Macy ptr = pci_read_config(dev, ptr, 1); 1228b6d90eb7SKip Macy 1229b6d90eb7SKip Macy while (ptr != 0) { 1230b6d90eb7SKip Macy if (pci_read_config(dev, ptr + PCICAP_ID, 1) == cap) 1231b6d90eb7SKip Macy return (ptr); 1232b6d90eb7SKip Macy ptr = pci_read_config(dev, ptr + PCICAP_NEXTPTR, 1); 1233b6d90eb7SKip Macy } 1234b6d90eb7SKip Macy 1235b6d90eb7SKip Macy return (0); 1236b6d90eb7SKip Macy } 1237b6d90eb7SKip Macy 1238b6d90eb7SKip Macy int 1239b6d90eb7SKip Macy t3_os_pci_save_state(struct adapter *sc) 1240b6d90eb7SKip Macy { 1241b6d90eb7SKip Macy device_t dev; 1242b6d90eb7SKip Macy struct pci_devinfo *dinfo; 1243b6d90eb7SKip Macy 1244b6d90eb7SKip Macy dev = sc->dev; 1245b6d90eb7SKip Macy dinfo = device_get_ivars(dev); 1246b6d90eb7SKip Macy 1247b6d90eb7SKip Macy pci_cfg_save(dev, dinfo, 0); 1248b6d90eb7SKip Macy return (0); 1249b6d90eb7SKip Macy } 1250b6d90eb7SKip Macy 1251b6d90eb7SKip Macy int 1252b6d90eb7SKip Macy t3_os_pci_restore_state(struct adapter *sc) 1253b6d90eb7SKip Macy { 1254b6d90eb7SKip Macy device_t dev; 1255b6d90eb7SKip Macy struct pci_devinfo *dinfo; 1256b6d90eb7SKip Macy 1257b6d90eb7SKip Macy dev = sc->dev; 1258b6d90eb7SKip Macy dinfo = device_get_ivars(dev); 1259b6d90eb7SKip Macy 1260b6d90eb7SKip Macy pci_cfg_restore(dev, dinfo); 1261b6d90eb7SKip Macy return (0); 1262b6d90eb7SKip Macy } 1263b6d90eb7SKip Macy 1264b6d90eb7SKip Macy /** 1265b6d90eb7SKip Macy * t3_os_link_changed - handle link status changes 1266b6d90eb7SKip Macy * @adapter: the adapter associated with the link change 1267b6d90eb7SKip Macy * @port_id: the port index whose limk status has changed 126819905d6dSKip Macy * @link_status: the new status of the link 1269b6d90eb7SKip Macy * @speed: the new speed setting 1270b6d90eb7SKip Macy * @duplex: the new duplex setting 1271b6d90eb7SKip Macy * @fc: the new flow-control setting 1272b6d90eb7SKip Macy * 1273b6d90eb7SKip Macy * This is the OS-dependent handler for link status changes. The OS 1274b6d90eb7SKip Macy * neutral handler takes care of most of the processing for these events, 1275b6d90eb7SKip Macy * then calls this handler for any OS-specific processing. 1276b6d90eb7SKip Macy */ 1277b6d90eb7SKip Macy void 1278b6d90eb7SKip Macy t3_os_link_changed(adapter_t *adapter, int port_id, int link_status, int speed, 1279b6d90eb7SKip Macy int duplex, int fc) 1280b6d90eb7SKip Macy { 1281b6d90eb7SKip Macy struct port_info *pi = &adapter->port[port_id]; 1282b6d90eb7SKip Macy 1283d722cab4SKip Macy if (link_status) { 12840bbdea77SGeorge V. Neville-Neil pi->ifp->if_baudrate = IF_Mbps(speed); 1285f2d8ff04SGeorge V. Neville-Neil if_link_state_change(pi->ifp, LINK_STATE_UP); 12860bbdea77SGeorge V. Neville-Neil } else 12878e10660fSKip Macy if_link_state_change(pi->ifp, LINK_STATE_DOWN); 1288d722cab4SKip Macy } 1289b6d90eb7SKip Macy 12909b4de886SKip Macy /** 12919b4de886SKip Macy * t3_os_phymod_changed - handle PHY module changes 12929b4de886SKip Macy * @phy: the PHY reporting the module change 12939b4de886SKip Macy * @mod_type: new module type 12949b4de886SKip Macy * 12959b4de886SKip Macy * This is the OS-dependent handler for PHY module changes. It is 12969b4de886SKip Macy * invoked when a PHY module is removed or inserted for any OS-specific 12979b4de886SKip Macy * processing. 12989b4de886SKip Macy */ 12999b4de886SKip Macy void t3_os_phymod_changed(struct adapter *adap, int port_id) 13009b4de886SKip Macy { 13019b4de886SKip Macy static const char *mod_str[] = { 13029b4de886SKip Macy NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown" 13039b4de886SKip Macy }; 13049b4de886SKip Macy 13059b4de886SKip Macy struct port_info *pi = &adap->port[port_id]; 13069b4de886SKip Macy 13079b4de886SKip Macy if (pi->phy.modtype == phy_modtype_none) 13089b4de886SKip Macy device_printf(adap->dev, "PHY module unplugged\n"); 13099b4de886SKip Macy else { 13109b4de886SKip Macy KASSERT(pi->phy.modtype < ARRAY_SIZE(mod_str), 13119b4de886SKip Macy ("invalid PHY module type %d", pi->phy.modtype)); 13129b4de886SKip Macy device_printf(adap->dev, "%s PHY module inserted\n", 13139b4de886SKip Macy mod_str[pi->phy.modtype]); 13149b4de886SKip Macy } 13159b4de886SKip Macy } 13169b4de886SKip Macy 1317b6d90eb7SKip Macy /* 1318b6d90eb7SKip Macy * Interrupt-context handler for external (PHY) interrupts. 1319b6d90eb7SKip Macy */ 1320b6d90eb7SKip Macy void 1321b6d90eb7SKip Macy t3_os_ext_intr_handler(adapter_t *sc) 1322b6d90eb7SKip Macy { 1323b6d90eb7SKip Macy if (cxgb_debug) 1324b6d90eb7SKip Macy printf("t3_os_ext_intr_handler\n"); 1325b6d90eb7SKip Macy /* 1326b6d90eb7SKip Macy * Schedule a task to handle external interrupts as they may be slow 1327b6d90eb7SKip Macy * and we use a mutex to protect MDIO registers. We disable PHY 1328b6d90eb7SKip Macy * interrupts in the meantime and let the task reenable them when 1329b6d90eb7SKip Macy * it's done. 1330b6d90eb7SKip Macy */ 1331d722cab4SKip Macy ADAPTER_LOCK(sc); 1332b6d90eb7SKip Macy if (sc->slow_intr_mask) { 1333b6d90eb7SKip Macy sc->slow_intr_mask &= ~F_T3DBG; 1334b6d90eb7SKip Macy t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask); 1335b6d90eb7SKip Macy taskqueue_enqueue(sc->tq, &sc->ext_intr_task); 1336b6d90eb7SKip Macy } 1337d722cab4SKip Macy ADAPTER_UNLOCK(sc); 1338b6d90eb7SKip Macy } 1339b6d90eb7SKip Macy 1340b6d90eb7SKip Macy void 1341b6d90eb7SKip Macy t3_os_set_hw_addr(adapter_t *adapter, int port_idx, u8 hw_addr[]) 1342b6d90eb7SKip Macy { 1343b6d90eb7SKip Macy 1344b6d90eb7SKip Macy /* 1345b6d90eb7SKip Macy * The ifnet might not be allocated before this gets called, 1346b6d90eb7SKip Macy * as this is called early on in attach by t3_prep_adapter 1347b6d90eb7SKip Macy * save the address off in the port structure 1348b6d90eb7SKip Macy */ 1349b6d90eb7SKip Macy if (cxgb_debug) 1350b6d90eb7SKip Macy printf("set_hw_addr on idx %d addr %6D\n", port_idx, hw_addr, ":"); 1351b6d90eb7SKip Macy bcopy(hw_addr, adapter->port[port_idx].hw_addr, ETHER_ADDR_LEN); 1352b6d90eb7SKip Macy } 1353b6d90eb7SKip Macy 1354b6d90eb7SKip Macy /** 1355b6d90eb7SKip Macy * link_start - enable a port 1356b6d90eb7SKip Macy * @p: the port to enable 1357b6d90eb7SKip Macy * 1358b6d90eb7SKip Macy * Performs the MAC and PHY actions needed to enable a port. 1359b6d90eb7SKip Macy */ 1360b6d90eb7SKip Macy static void 1361b6d90eb7SKip Macy cxgb_link_start(struct port_info *p) 1362b6d90eb7SKip Macy { 1363b6d90eb7SKip Macy struct ifnet *ifp; 1364b6d90eb7SKip Macy struct t3_rx_mode rm; 1365b6d90eb7SKip Macy struct cmac *mac = &p->mac; 13664af83c8cSKip Macy int mtu, hwtagging; 1367b6d90eb7SKip Macy 1368b6d90eb7SKip Macy ifp = p->ifp; 1369b6d90eb7SKip Macy 13704af83c8cSKip Macy bcopy(IF_LLADDR(ifp), p->hw_addr, ETHER_ADDR_LEN); 13714af83c8cSKip Macy 13724af83c8cSKip Macy mtu = ifp->if_mtu; 13734af83c8cSKip Macy if (ifp->if_capenable & IFCAP_VLAN_MTU) 13744af83c8cSKip Macy mtu += ETHER_VLAN_ENCAP_LEN; 13754af83c8cSKip Macy 13764af83c8cSKip Macy hwtagging = (ifp->if_capenable & IFCAP_VLAN_HWTAGGING) != 0; 13774af83c8cSKip Macy 1378b6d90eb7SKip Macy t3_init_rx_mode(&rm, p); 13797ac2e6c3SKip Macy if (!mac->multiport) 1380b6d90eb7SKip Macy t3_mac_reset(mac); 13814af83c8cSKip Macy t3_mac_set_mtu(mac, mtu); 13824af83c8cSKip Macy t3_set_vlan_accel(p->adapter, 1 << p->tx_chan, hwtagging); 1383b6d90eb7SKip Macy t3_mac_set_address(mac, 0, p->hw_addr); 1384b6d90eb7SKip Macy t3_mac_set_rx_mode(mac, &rm); 1385b6d90eb7SKip Macy t3_link_start(&p->phy, mac, &p->link_config); 1386b6d90eb7SKip Macy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 1387b6d90eb7SKip Macy } 1388b6d90eb7SKip Macy 13898e10660fSKip Macy 13908e10660fSKip Macy static int 13918e10660fSKip Macy await_mgmt_replies(struct adapter *adap, unsigned long init_cnt, 13928e10660fSKip Macy unsigned long n) 13938e10660fSKip Macy { 13948e10660fSKip Macy int attempts = 5; 13958e10660fSKip Macy 13968e10660fSKip Macy while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) { 13978e10660fSKip Macy if (!--attempts) 13988e10660fSKip Macy return (ETIMEDOUT); 13998e10660fSKip Macy t3_os_sleep(10); 14008e10660fSKip Macy } 14018e10660fSKip Macy return 0; 14028e10660fSKip Macy } 14038e10660fSKip Macy 14048e10660fSKip Macy static int 14058e10660fSKip Macy init_tp_parity(struct adapter *adap) 14068e10660fSKip Macy { 14078e10660fSKip Macy int i; 14088e10660fSKip Macy struct mbuf *m; 14098e10660fSKip Macy struct cpl_set_tcb_field *greq; 14108e10660fSKip Macy unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts; 14118e10660fSKip Macy 14128e10660fSKip Macy t3_tp_set_offload_mode(adap, 1); 14138e10660fSKip Macy 14148e10660fSKip Macy for (i = 0; i < 16; i++) { 14158e10660fSKip Macy struct cpl_smt_write_req *req; 14168e10660fSKip Macy 14178e10660fSKip Macy m = m_gethdr(M_WAITOK, MT_DATA); 14188e10660fSKip Macy req = mtod(m, struct cpl_smt_write_req *); 14198e10660fSKip Macy m->m_len = m->m_pkthdr.len = sizeof(*req); 14208e10660fSKip Macy memset(req, 0, sizeof(*req)); 14218e10660fSKip Macy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 14228e10660fSKip Macy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i)); 14238e10660fSKip Macy req->iff = i; 14248e10660fSKip Macy t3_mgmt_tx(adap, m); 14258e10660fSKip Macy } 14268e10660fSKip Macy 14278e10660fSKip Macy for (i = 0; i < 2048; i++) { 14288e10660fSKip Macy struct cpl_l2t_write_req *req; 14298e10660fSKip Macy 14308e10660fSKip Macy m = m_gethdr(M_WAITOK, MT_DATA); 14318e10660fSKip Macy req = mtod(m, struct cpl_l2t_write_req *); 14328e10660fSKip Macy m->m_len = m->m_pkthdr.len = sizeof(*req); 14338e10660fSKip Macy memset(req, 0, sizeof(*req)); 14348e10660fSKip Macy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 14358e10660fSKip Macy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i)); 14368e10660fSKip Macy req->params = htonl(V_L2T_W_IDX(i)); 14378e10660fSKip Macy t3_mgmt_tx(adap, m); 14388e10660fSKip Macy } 14398e10660fSKip Macy 14408e10660fSKip Macy for (i = 0; i < 2048; i++) { 14418e10660fSKip Macy struct cpl_rte_write_req *req; 14428e10660fSKip Macy 14438e10660fSKip Macy m = m_gethdr(M_WAITOK, MT_DATA); 14448e10660fSKip Macy req = mtod(m, struct cpl_rte_write_req *); 14458e10660fSKip Macy m->m_len = m->m_pkthdr.len = sizeof(*req); 14468e10660fSKip Macy memset(req, 0, sizeof(*req)); 14478e10660fSKip Macy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 14488e10660fSKip Macy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i)); 14498e10660fSKip Macy req->l2t_idx = htonl(V_L2T_W_IDX(i)); 14508e10660fSKip Macy t3_mgmt_tx(adap, m); 14518e10660fSKip Macy } 14528e10660fSKip Macy 14538e10660fSKip Macy m = m_gethdr(M_WAITOK, MT_DATA); 14548e10660fSKip Macy greq = mtod(m, struct cpl_set_tcb_field *); 14558e10660fSKip Macy m->m_len = m->m_pkthdr.len = sizeof(*greq); 14568e10660fSKip Macy memset(greq, 0, sizeof(*greq)); 14578e10660fSKip Macy greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 14588e10660fSKip Macy OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0)); 14598e10660fSKip Macy greq->mask = htobe64(1); 14608e10660fSKip Macy t3_mgmt_tx(adap, m); 14618e10660fSKip Macy 14628e10660fSKip Macy i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1); 14638e10660fSKip Macy t3_tp_set_offload_mode(adap, 0); 14648e10660fSKip Macy return (i); 14658e10660fSKip Macy } 14668e10660fSKip Macy 1467b6d90eb7SKip Macy /** 1468b6d90eb7SKip Macy * setup_rss - configure Receive Side Steering (per-queue connection demux) 1469b6d90eb7SKip Macy * @adap: the adapter 1470b6d90eb7SKip Macy * 1471b6d90eb7SKip Macy * Sets up RSS to distribute packets to multiple receive queues. We 1472b6d90eb7SKip Macy * configure the RSS CPU lookup table to distribute to the number of HW 1473b6d90eb7SKip Macy * receive queues, and the response queue lookup table to narrow that 1474b6d90eb7SKip Macy * down to the response queues actually configured for each port. 1475b6d90eb7SKip Macy * We always configure the RSS mapping for two ports since the mapping 1476b6d90eb7SKip Macy * table has plenty of entries. 1477b6d90eb7SKip Macy */ 1478b6d90eb7SKip Macy static void 1479b6d90eb7SKip Macy setup_rss(adapter_t *adap) 1480b6d90eb7SKip Macy { 1481b6d90eb7SKip Macy int i; 1482ac3a6d9cSKip Macy u_int nq[2]; 1483b6d90eb7SKip Macy uint8_t cpus[SGE_QSETS + 1]; 1484b6d90eb7SKip Macy uint16_t rspq_map[RSS_TABLE_SIZE]; 14855c5df3daSKip Macy 1486b6d90eb7SKip Macy for (i = 0; i < SGE_QSETS; ++i) 1487b6d90eb7SKip Macy cpus[i] = i; 1488b6d90eb7SKip Macy cpus[SGE_QSETS] = 0xff; 1489b6d90eb7SKip Macy 14907ac2e6c3SKip Macy nq[0] = nq[1] = 0; 14917ac2e6c3SKip Macy for_each_port(adap, i) { 14927ac2e6c3SKip Macy const struct port_info *pi = adap2pinfo(adap, i); 14937ac2e6c3SKip Macy 14947ac2e6c3SKip Macy nq[pi->tx_chan] += pi->nqsets; 14957ac2e6c3SKip Macy } 1496b6d90eb7SKip Macy for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) { 14978e10660fSKip Macy rspq_map[i] = nq[0] ? i % nq[0] : 0; 14988e10660fSKip Macy rspq_map[i + RSS_TABLE_SIZE / 2] = nq[1] ? i % nq[1] + nq[0] : 0; 1499b6d90eb7SKip Macy } 1500ac3a6d9cSKip Macy /* Calculate the reverse RSS map table */ 1501ac3a6d9cSKip Macy for (i = 0; i < RSS_TABLE_SIZE; ++i) 1502ac3a6d9cSKip Macy if (adap->rrss_map[rspq_map[i]] == 0xff) 1503ac3a6d9cSKip Macy adap->rrss_map[rspq_map[i]] = i; 1504b6d90eb7SKip Macy 1505b6d90eb7SKip Macy t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN | 1506ac3a6d9cSKip Macy F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN | F_OFDMAPEN | 15078e10660fSKip Macy F_RRCPLMAPEN | V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, 15088e10660fSKip Macy cpus, rspq_map); 1509ac3a6d9cSKip Macy 1510b6d90eb7SKip Macy } 1511b6d90eb7SKip Macy 1512d722cab4SKip Macy /* 1513d722cab4SKip Macy * Sends an mbuf to an offload queue driver 1514d722cab4SKip Macy * after dealing with any active network taps. 1515d722cab4SKip Macy */ 1516d722cab4SKip Macy static inline int 15173e96c7e7SKip Macy offload_tx(struct t3cdev *tdev, struct mbuf *m) 1518d722cab4SKip Macy { 1519d722cab4SKip Macy int ret; 1520d722cab4SKip Macy 1521d722cab4SKip Macy ret = t3_offload_tx(tdev, m); 1522ef72318fSKip Macy return (ret); 1523d722cab4SKip Macy } 1524d722cab4SKip Macy 1525d722cab4SKip Macy static int 1526d722cab4SKip Macy write_smt_entry(struct adapter *adapter, int idx) 1527d722cab4SKip Macy { 1528d722cab4SKip Macy struct port_info *pi = &adapter->port[idx]; 1529d722cab4SKip Macy struct cpl_smt_write_req *req; 1530d722cab4SKip Macy struct mbuf *m; 1531d722cab4SKip Macy 1532d722cab4SKip Macy if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL) 1533d722cab4SKip Macy return (ENOMEM); 1534d722cab4SKip Macy 1535d722cab4SKip Macy req = mtod(m, struct cpl_smt_write_req *); 15368090c9f5SKip Macy m->m_pkthdr.len = m->m_len = sizeof(struct cpl_smt_write_req); 15378090c9f5SKip Macy 1538d722cab4SKip Macy req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); 1539d722cab4SKip Macy OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx)); 1540d722cab4SKip Macy req->mtu_idx = NMTUS - 1; /* should be 0 but there's a T3 bug */ 1541d722cab4SKip Macy req->iff = idx; 1542d722cab4SKip Macy memset(req->src_mac1, 0, sizeof(req->src_mac1)); 1543d722cab4SKip Macy memcpy(req->src_mac0, pi->hw_addr, ETHER_ADDR_LEN); 1544d722cab4SKip Macy 1545d722cab4SKip Macy m_set_priority(m, 1); 1546d722cab4SKip Macy 1547d722cab4SKip Macy offload_tx(&adapter->tdev, m); 1548d722cab4SKip Macy 1549d722cab4SKip Macy return (0); 1550d722cab4SKip Macy } 1551d722cab4SKip Macy 1552d722cab4SKip Macy static int 1553d722cab4SKip Macy init_smt(struct adapter *adapter) 1554d722cab4SKip Macy { 1555d722cab4SKip Macy int i; 1556d722cab4SKip Macy 1557d722cab4SKip Macy for_each_port(adapter, i) 1558d722cab4SKip Macy write_smt_entry(adapter, i); 1559d722cab4SKip Macy return 0; 1560d722cab4SKip Macy } 1561d722cab4SKip Macy 1562d722cab4SKip Macy static void 1563d722cab4SKip Macy init_port_mtus(adapter_t *adapter) 1564d722cab4SKip Macy { 1565d722cab4SKip Macy unsigned int mtus = adapter->port[0].ifp->if_mtu; 1566d722cab4SKip Macy 1567d722cab4SKip Macy if (adapter->port[1].ifp) 1568d722cab4SKip Macy mtus |= adapter->port[1].ifp->if_mtu << 16; 1569d722cab4SKip Macy t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus); 1570d722cab4SKip Macy } 1571d722cab4SKip Macy 1572b6d90eb7SKip Macy static void 1573b6d90eb7SKip Macy send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo, 1574b6d90eb7SKip Macy int hi, int port) 1575b6d90eb7SKip Macy { 1576b6d90eb7SKip Macy struct mbuf *m; 1577b6d90eb7SKip Macy struct mngt_pktsched_wr *req; 1578b6d90eb7SKip Macy 1579ac3a6d9cSKip Macy m = m_gethdr(M_DONTWAIT, MT_DATA); 158020fe52b8SKip Macy if (m) { 1581d722cab4SKip Macy req = mtod(m, struct mngt_pktsched_wr *); 1582b6d90eb7SKip Macy req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT)); 1583b6d90eb7SKip Macy req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET; 1584b6d90eb7SKip Macy req->sched = sched; 1585b6d90eb7SKip Macy req->idx = qidx; 1586b6d90eb7SKip Macy req->min = lo; 1587b6d90eb7SKip Macy req->max = hi; 1588b6d90eb7SKip Macy req->binding = port; 1589b6d90eb7SKip Macy m->m_len = m->m_pkthdr.len = sizeof(*req); 1590b6d90eb7SKip Macy t3_mgmt_tx(adap, m); 1591b6d90eb7SKip Macy } 159220fe52b8SKip Macy } 1593b6d90eb7SKip Macy 1594b6d90eb7SKip Macy static void 1595b6d90eb7SKip Macy bind_qsets(adapter_t *sc) 1596b6d90eb7SKip Macy { 1597b6d90eb7SKip Macy int i, j; 1598b6d90eb7SKip Macy 15998090c9f5SKip Macy cxgb_pcpu_startup_threads(sc); 1600b6d90eb7SKip Macy for (i = 0; i < (sc)->params.nports; ++i) { 1601b6d90eb7SKip Macy const struct port_info *pi = adap2pinfo(sc, i); 1602b6d90eb7SKip Macy 16035c5df3daSKip Macy for (j = 0; j < pi->nqsets; ++j) { 1604b6d90eb7SKip Macy send_pktsched_cmd(sc, 1, pi->first_qset + j, -1, 16055c5df3daSKip Macy -1, pi->tx_chan); 16065c5df3daSKip Macy 16075c5df3daSKip Macy } 1608b6d90eb7SKip Macy } 1609b6d90eb7SKip Macy } 1610b6d90eb7SKip Macy 1611ac3a6d9cSKip Macy static void 1612ac3a6d9cSKip Macy update_tpeeprom(struct adapter *adap) 1613ac3a6d9cSKip Macy { 16142de1fa86SKip Macy #ifdef FIRMWARE_LATEST 1615ac3a6d9cSKip Macy const struct firmware *tpeeprom; 16162de1fa86SKip Macy #else 16172de1fa86SKip Macy struct firmware *tpeeprom; 16182de1fa86SKip Macy #endif 16192de1fa86SKip Macy 1620ac3a6d9cSKip Macy uint32_t version; 1621ac3a6d9cSKip Macy unsigned int major, minor; 1622ac3a6d9cSKip Macy int ret, len; 1623f2d8ff04SGeorge V. Neville-Neil char rev, name[32]; 1624ac3a6d9cSKip Macy 1625ac3a6d9cSKip Macy t3_seeprom_read(adap, TP_SRAM_OFFSET, &version); 1626ac3a6d9cSKip Macy 1627ac3a6d9cSKip Macy major = G_TP_VERSION_MAJOR(version); 1628ac3a6d9cSKip Macy minor = G_TP_VERSION_MINOR(version); 1629ac3a6d9cSKip Macy if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) 1630ac3a6d9cSKip Macy return; 1631ac3a6d9cSKip Macy 1632ac3a6d9cSKip Macy rev = t3rev2char(adap); 1633f2d8ff04SGeorge V. Neville-Neil snprintf(name, sizeof(name), TPEEPROM_NAME, rev); 1634ac3a6d9cSKip Macy 1635f2d8ff04SGeorge V. Neville-Neil tpeeprom = firmware_get(name); 1636ac3a6d9cSKip Macy if (tpeeprom == NULL) { 16370c1ff9c6SGeorge V. Neville-Neil device_printf(adap->dev, 16380c1ff9c6SGeorge V. Neville-Neil "could not load TP EEPROM: unable to load %s\n", 16390c1ff9c6SGeorge V. Neville-Neil name); 1640ac3a6d9cSKip Macy return; 1641ac3a6d9cSKip Macy } 1642ac3a6d9cSKip Macy 1643ac3a6d9cSKip Macy len = tpeeprom->datasize - 4; 1644ac3a6d9cSKip Macy 1645ac3a6d9cSKip Macy ret = t3_check_tpsram(adap, tpeeprom->data, tpeeprom->datasize); 1646ac3a6d9cSKip Macy if (ret) 1647ac3a6d9cSKip Macy goto release_tpeeprom; 1648ac3a6d9cSKip Macy 1649ac3a6d9cSKip Macy if (len != TP_SRAM_LEN) { 16500c1ff9c6SGeorge V. Neville-Neil device_printf(adap->dev, 16510c1ff9c6SGeorge V. Neville-Neil "%s length is wrong len=%d expected=%d\n", name, 16520c1ff9c6SGeorge V. Neville-Neil len, TP_SRAM_LEN); 1653ac3a6d9cSKip Macy return; 1654ac3a6d9cSKip Macy } 1655ac3a6d9cSKip Macy 1656ac3a6d9cSKip Macy ret = set_eeprom(&adap->port[0], tpeeprom->data, tpeeprom->datasize, 1657ac3a6d9cSKip Macy TP_SRAM_OFFSET); 1658ac3a6d9cSKip Macy 1659ac3a6d9cSKip Macy if (!ret) { 1660ac3a6d9cSKip Macy device_printf(adap->dev, 1661ac3a6d9cSKip Macy "Protocol SRAM image updated in EEPROM to %d.%d.%d\n", 1662ac3a6d9cSKip Macy TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO); 1663ac3a6d9cSKip Macy } else 16640c1ff9c6SGeorge V. Neville-Neil device_printf(adap->dev, 16650c1ff9c6SGeorge V. Neville-Neil "Protocol SRAM image update in EEPROM failed\n"); 1666ac3a6d9cSKip Macy 1667ac3a6d9cSKip Macy release_tpeeprom: 1668ac3a6d9cSKip Macy firmware_put(tpeeprom, FIRMWARE_UNLOAD); 1669ac3a6d9cSKip Macy 1670ac3a6d9cSKip Macy return; 1671ac3a6d9cSKip Macy } 1672ac3a6d9cSKip Macy 1673ac3a6d9cSKip Macy static int 1674ac3a6d9cSKip Macy update_tpsram(struct adapter *adap) 1675ac3a6d9cSKip Macy { 16762de1fa86SKip Macy #ifdef FIRMWARE_LATEST 1677ac3a6d9cSKip Macy const struct firmware *tpsram; 16782de1fa86SKip Macy #else 16792de1fa86SKip Macy struct firmware *tpsram; 16802de1fa86SKip Macy #endif 1681ac3a6d9cSKip Macy int ret; 1682f2d8ff04SGeorge V. Neville-Neil char rev, name[32]; 1683ac3a6d9cSKip Macy 1684ac3a6d9cSKip Macy rev = t3rev2char(adap); 1685f2d8ff04SGeorge V. Neville-Neil snprintf(name, sizeof(name), TPSRAM_NAME, rev); 1686ac3a6d9cSKip Macy 1687ac3a6d9cSKip Macy update_tpeeprom(adap); 1688ac3a6d9cSKip Macy 1689f2d8ff04SGeorge V. Neville-Neil tpsram = firmware_get(name); 1690ac3a6d9cSKip Macy if (tpsram == NULL){ 169164a37133SKip Macy device_printf(adap->dev, "could not load TP SRAM\n"); 1692ac3a6d9cSKip Macy return (EINVAL); 1693ac3a6d9cSKip Macy } else 169464a37133SKip Macy device_printf(adap->dev, "updating TP SRAM\n"); 1695ac3a6d9cSKip Macy 1696ac3a6d9cSKip Macy ret = t3_check_tpsram(adap, tpsram->data, tpsram->datasize); 1697ac3a6d9cSKip Macy if (ret) 1698ac3a6d9cSKip Macy goto release_tpsram; 1699ac3a6d9cSKip Macy 1700ac3a6d9cSKip Macy ret = t3_set_proto_sram(adap, tpsram->data); 1701ac3a6d9cSKip Macy if (ret) 1702ac3a6d9cSKip Macy device_printf(adap->dev, "loading protocol SRAM failed\n"); 1703ac3a6d9cSKip Macy 1704ac3a6d9cSKip Macy release_tpsram: 1705ac3a6d9cSKip Macy firmware_put(tpsram, FIRMWARE_UNLOAD); 1706ac3a6d9cSKip Macy 1707ac3a6d9cSKip Macy return ret; 1708ac3a6d9cSKip Macy } 1709ac3a6d9cSKip Macy 1710d722cab4SKip Macy /** 1711d722cab4SKip Macy * cxgb_up - enable the adapter 1712d722cab4SKip Macy * @adap: adapter being enabled 1713d722cab4SKip Macy * 1714d722cab4SKip Macy * Called when the first port is enabled, this function performs the 1715d722cab4SKip Macy * actions necessary to make an adapter operational, such as completing 1716d722cab4SKip Macy * the initialization of HW modules, and enabling interrupts. 1717d722cab4SKip Macy */ 1718d722cab4SKip Macy static int 1719d722cab4SKip Macy cxgb_up(struct adapter *sc) 1720d722cab4SKip Macy { 1721d722cab4SKip Macy int err = 0; 1722d722cab4SKip Macy 1723d722cab4SKip Macy if ((sc->flags & FULL_INIT_DONE) == 0) { 1724d722cab4SKip Macy 1725d722cab4SKip Macy if ((sc->flags & FW_UPTODATE) == 0) 1726ac3a6d9cSKip Macy if ((err = upgrade_fw(sc))) 1727d722cab4SKip Macy goto out; 1728ac3a6d9cSKip Macy if ((sc->flags & TPS_UPTODATE) == 0) 1729ac3a6d9cSKip Macy if ((err = update_tpsram(sc))) 1730ac3a6d9cSKip Macy goto out; 1731d722cab4SKip Macy err = t3_init_hw(sc, 0); 1732d722cab4SKip Macy if (err) 1733d722cab4SKip Macy goto out; 1734d722cab4SKip Macy 17358e10660fSKip Macy t3_set_reg_field(sc, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT); 1736d722cab4SKip Macy t3_write_reg(sc, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12)); 1737d722cab4SKip Macy 1738d722cab4SKip Macy err = setup_sge_qsets(sc); 1739d722cab4SKip Macy if (err) 1740d722cab4SKip Macy goto out; 1741d722cab4SKip Macy 1742d722cab4SKip Macy setup_rss(sc); 17438090c9f5SKip Macy t3_add_configured_sysctls(sc); 1744d722cab4SKip Macy sc->flags |= FULL_INIT_DONE; 1745d722cab4SKip Macy } 1746d722cab4SKip Macy 1747d722cab4SKip Macy t3_intr_clear(sc); 1748d722cab4SKip Macy 1749d722cab4SKip Macy t3_sge_start(sc); 1750d722cab4SKip Macy t3_intr_enable(sc); 1751d722cab4SKip Macy 17528e10660fSKip Macy if (sc->params.rev >= T3_REV_C && !(sc->flags & TP_PARITY_INIT) && 17538e10660fSKip Macy is_offload(sc) && init_tp_parity(sc) == 0) 17548e10660fSKip Macy sc->flags |= TP_PARITY_INIT; 17558e10660fSKip Macy 17568e10660fSKip Macy if (sc->flags & TP_PARITY_INIT) { 17578e10660fSKip Macy t3_write_reg(sc, A_TP_INT_CAUSE, 17588e10660fSKip Macy F_CMCACHEPERR | F_ARPLUTPERR); 17598e10660fSKip Macy t3_write_reg(sc, A_TP_INT_ENABLE, 0x7fbfffff); 17608e10660fSKip Macy } 17618e10660fSKip Macy 17628e10660fSKip Macy 17635c5df3daSKip Macy if (!(sc->flags & QUEUES_BOUND)) { 1764d722cab4SKip Macy bind_qsets(sc); 1765d722cab4SKip Macy sc->flags |= QUEUES_BOUND; 1766ac3a6d9cSKip Macy } 1767d722cab4SKip Macy out: 1768d722cab4SKip Macy return (err); 1769d722cab4SKip Macy } 1770d722cab4SKip Macy 1771d722cab4SKip Macy 1772d722cab4SKip Macy /* 1773c2009a4cSGeorge V. Neville-Neil * Bring down the interface but do not free any resources. 1774d722cab4SKip Macy */ 1775d722cab4SKip Macy static void 1776bb38cd2fSKip Macy cxgb_down_locked(struct adapter *sc) 1777d722cab4SKip Macy { 1778d722cab4SKip Macy 1779d722cab4SKip Macy t3_sge_stop(sc); 1780d722cab4SKip Macy t3_intr_disable(sc); 1781d722cab4SKip Macy 17828090c9f5SKip Macy callout_stop(&sc->cxgb_tick_ch); 17838090c9f5SKip Macy callout_stop(&sc->sge_timer_ch); 1784d722cab4SKip Macy } 1785d722cab4SKip Macy 1786d722cab4SKip Macy static int 1787d722cab4SKip Macy offload_open(struct port_info *pi) 1788d722cab4SKip Macy { 1789d722cab4SKip Macy struct adapter *adapter = pi->adapter; 17908090c9f5SKip Macy struct t3cdev *tdev = &adapter->tdev; 1791af9b081cSKip Macy 1792d722cab4SKip Macy int adap_up = adapter->open_device_map & PORT_MASK; 1793d722cab4SKip Macy int err = 0; 1794d722cab4SKip Macy 1795d722cab4SKip Macy if (atomic_cmpset_int(&adapter->open_device_map, 17968090c9f5SKip Macy (adapter->open_device_map & ~(1<<OFFLOAD_DEVMAP_BIT)), 17978090c9f5SKip Macy (adapter->open_device_map | (1<<OFFLOAD_DEVMAP_BIT))) == 0) 1798d722cab4SKip Macy return (0); 1799d722cab4SKip Macy 18008090c9f5SKip Macy if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT)) 1801af9b081cSKip Macy printf("offload_open: DEVMAP_BIT did not get set 0x%x\n", 1802af9b081cSKip Macy adapter->open_device_map); 1803d722cab4SKip Macy ADAPTER_LOCK(pi->adapter); 1804d722cab4SKip Macy if (!adap_up) 1805d722cab4SKip Macy err = cxgb_up(adapter); 1806d722cab4SKip Macy ADAPTER_UNLOCK(pi->adapter); 1807ac3a6d9cSKip Macy if (err) 1808d722cab4SKip Macy return (err); 1809d722cab4SKip Macy 1810d722cab4SKip Macy t3_tp_set_offload_mode(adapter, 1); 18118090c9f5SKip Macy tdev->lldev = pi->ifp; 1812d722cab4SKip Macy 1813d722cab4SKip Macy init_port_mtus(adapter); 1814d722cab4SKip Macy t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd, 1815d722cab4SKip Macy adapter->params.b_wnd, 1816d722cab4SKip Macy adapter->params.rev == 0 ? 1817d722cab4SKip Macy adapter->port[0].ifp->if_mtu : 0xffff); 1818d722cab4SKip Macy init_smt(adapter); 1819ed0fb18dSKip Macy /* Call back all registered clients */ 1820ed0fb18dSKip Macy cxgb_add_clients(tdev); 1821ed0fb18dSKip Macy 1822d722cab4SKip Macy /* restore them in case the offload module has changed them */ 1823d722cab4SKip Macy if (err) { 1824d722cab4SKip Macy t3_tp_set_offload_mode(adapter, 0); 1825d722cab4SKip Macy clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT); 1826d722cab4SKip Macy cxgb_set_dummy_ops(tdev); 1827d722cab4SKip Macy } 1828d722cab4SKip Macy return (err); 1829d722cab4SKip Macy } 18308090c9f5SKip Macy 1831d722cab4SKip Macy static int 18328090c9f5SKip Macy offload_close(struct t3cdev *tdev) 1833d722cab4SKip Macy { 1834d722cab4SKip Macy struct adapter *adapter = tdev2adap(tdev); 1835d722cab4SKip Macy 18368e10660fSKip Macy if (!isset(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT)) 1837ef72318fSKip Macy return (0); 1838d722cab4SKip Macy 1839ed0fb18dSKip Macy /* Call back all registered clients */ 1840ed0fb18dSKip Macy cxgb_remove_clients(tdev); 1841ed0fb18dSKip Macy 1842d722cab4SKip Macy tdev->lldev = NULL; 1843d722cab4SKip Macy cxgb_set_dummy_ops(tdev); 1844d722cab4SKip Macy t3_tp_set_offload_mode(adapter, 0); 1845d722cab4SKip Macy clrbit(&adapter->open_device_map, OFFLOAD_DEVMAP_BIT); 1846d722cab4SKip Macy 18478090c9f5SKip Macy ADAPTER_LOCK(adapter); 1848d722cab4SKip Macy if (!adapter->open_device_map) 18498090c9f5SKip Macy cxgb_down_locked(adapter); 18503cf138bbSGeorge V. Neville-Neil 18518090c9f5SKip Macy ADAPTER_UNLOCK(adapter); 18523cf138bbSGeorge V. Neville-Neil 1853ef72318fSKip Macy return (0); 1854d722cab4SKip Macy } 18558090c9f5SKip Macy 1856d722cab4SKip Macy 1857b6d90eb7SKip Macy static void 1858b6d90eb7SKip Macy cxgb_init(void *arg) 1859b6d90eb7SKip Macy { 1860b6d90eb7SKip Macy struct port_info *p = arg; 1861b6d90eb7SKip Macy 1862b6d90eb7SKip Macy PORT_LOCK(p); 1863b6d90eb7SKip Macy cxgb_init_locked(p); 1864b6d90eb7SKip Macy PORT_UNLOCK(p); 1865b6d90eb7SKip Macy } 1866b6d90eb7SKip Macy 1867b6d90eb7SKip Macy static void 1868b6d90eb7SKip Macy cxgb_init_locked(struct port_info *p) 1869b6d90eb7SKip Macy { 1870b6d90eb7SKip Macy struct ifnet *ifp; 1871b6d90eb7SKip Macy adapter_t *sc = p->adapter; 1872d722cab4SKip Macy int err; 1873b6d90eb7SKip Macy 1874bb38cd2fSKip Macy PORT_LOCK_ASSERT_OWNED(p); 1875b6d90eb7SKip Macy ifp = p->ifp; 1876d722cab4SKip Macy 1877d722cab4SKip Macy ADAPTER_LOCK(p->adapter); 1878ac3a6d9cSKip Macy if ((sc->open_device_map == 0) && (err = cxgb_up(sc))) { 1879d722cab4SKip Macy ADAPTER_UNLOCK(p->adapter); 1880d722cab4SKip Macy cxgb_stop_locked(p); 1881b6d90eb7SKip Macy return; 1882b6d90eb7SKip Macy } 1883bb38cd2fSKip Macy if (p->adapter->open_device_map == 0) { 1884b6d90eb7SKip Macy t3_intr_clear(sc); 1885bb38cd2fSKip Macy } 18866b68e276SKip Macy setbit(&p->adapter->open_device_map, p->port_id); 1887b6d90eb7SKip Macy ADAPTER_UNLOCK(p->adapter); 1888ef72318fSKip Macy 1889d722cab4SKip Macy if (is_offload(sc) && !ofld_disable) { 1890d722cab4SKip Macy err = offload_open(p); 1891d722cab4SKip Macy if (err) 1892d722cab4SKip Macy log(LOG_WARNING, 1893d722cab4SKip Macy "Could not initialize offload capabilities\n"); 1894d722cab4SKip Macy } 18950bbdea77SGeorge V. Neville-Neil 18960bbdea77SGeorge V. Neville-Neil device_printf(sc->dev, "enabling interrupts on port=%d\n", p->port_id); 18970bbdea77SGeorge V. Neville-Neil t3_port_intr_enable(sc, p->port_id); 18980bbdea77SGeorge V. Neville-Neil 1899ef027c52SKip Macy #if !defined(LINK_ATTACH) 1900ef027c52SKip Macy cxgb_link_start(p); 1901ef027c52SKip Macy t3_link_changed(sc, p->port_id); 1902ef027c52SKip Macy #endif 1903837f41b0SGeorge V. Neville-Neil ifp->if_baudrate = IF_Mbps(p->link_config.speed); 1904ef72318fSKip Macy 19056b6e256aSGeorge V. Neville-Neil callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc); 19069330dbc3SKip Macy t3_sge_reset_adapter(sc); 1907b6d90eb7SKip Macy 1908c2009a4cSGeorge V. Neville-Neil sc->flags &= ~CXGB_SHUTDOWN; 1909b6d90eb7SKip Macy ifp->if_drv_flags |= IFF_DRV_RUNNING; 1910b6d90eb7SKip Macy ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1911b6d90eb7SKip Macy } 1912b6d90eb7SKip Macy 1913b6d90eb7SKip Macy static void 1914b6d90eb7SKip Macy cxgb_set_rxmode(struct port_info *p) 1915b6d90eb7SKip Macy { 1916b6d90eb7SKip Macy struct t3_rx_mode rm; 1917b6d90eb7SKip Macy struct cmac *mac = &p->mac; 1918b6d90eb7SKip Macy 1919b6d90eb7SKip Macy t3_init_rx_mode(&rm, p); 19208e10660fSKip Macy mtx_lock(&p->adapter->mdio_lock); 1921b6d90eb7SKip Macy t3_mac_set_rx_mode(mac, &rm); 19228e10660fSKip Macy mtx_unlock(&p->adapter->mdio_lock); 1923b6d90eb7SKip Macy } 1924b6d90eb7SKip Macy 1925b6d90eb7SKip Macy static void 192619905d6dSKip Macy cxgb_stop_locked(struct port_info *pi) 1927b6d90eb7SKip Macy { 1928b6d90eb7SKip Macy struct ifnet *ifp; 1929c2009a4cSGeorge V. Neville-Neil adapter_t *sc = pi->adapter; 1930b6d90eb7SKip Macy 193119905d6dSKip Macy PORT_LOCK_ASSERT_OWNED(pi); 193219905d6dSKip Macy ADAPTER_LOCK_ASSERT_NOTOWNED(pi->adapter); 193377f07749SKip Macy 1934c2009a4cSGeorge V. Neville-Neil sc->flags |= CXGB_SHUTDOWN; 1935c2009a4cSGeorge V. Neville-Neil 193619905d6dSKip Macy ifp = pi->ifp; 193719905d6dSKip Macy t3_port_intr_disable(pi->adapter, pi->port_id); 1938d722cab4SKip Macy ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 1939b6d90eb7SKip Macy 194019905d6dSKip Macy /* disable pause frames */ 194119905d6dSKip Macy t3_set_reg_field(pi->adapter, A_XGM_TX_CFG + pi->mac.offset, 194219905d6dSKip Macy F_TXPAUSEEN, 0); 1943bb38cd2fSKip Macy 194419905d6dSKip Macy /* Reset RX FIFO HWM */ 194519905d6dSKip Macy t3_set_reg_field(pi->adapter, A_XGM_RXFIFO_CFG + pi->mac.offset, 194619905d6dSKip Macy V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM), 0); 194719905d6dSKip Macy 194819905d6dSKip Macy 194919905d6dSKip Macy ADAPTER_LOCK(pi->adapter); 195019905d6dSKip Macy clrbit(&pi->adapter->open_device_map, pi->port_id); 195119905d6dSKip Macy 19523cf138bbSGeorge V. Neville-Neil if (pi->adapter->open_device_map == 0) 195319905d6dSKip Macy cxgb_down_locked(pi->adapter); 19543cf138bbSGeorge V. Neville-Neil 195519905d6dSKip Macy ADAPTER_UNLOCK(pi->adapter); 195619905d6dSKip Macy 1957ef027c52SKip Macy #if !defined(LINK_ATTACH) 195819905d6dSKip Macy DELAY(100); 195919905d6dSKip Macy 196019905d6dSKip Macy /* Wait for TXFIFO empty */ 196119905d6dSKip Macy t3_wait_op_done(pi->adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 196219905d6dSKip Macy F_TXFIFO_EMPTY, 1, 20, 5); 196319905d6dSKip Macy 196419905d6dSKip Macy DELAY(100); 196519905d6dSKip Macy t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); 196619905d6dSKip Macy 196719905d6dSKip Macy pi->phy.ops->power_down(&pi->phy, 1); 1968ef027c52SKip Macy #endif 1969bb38cd2fSKip Macy 1970b6d90eb7SKip Macy } 1971b6d90eb7SKip Macy 1972b6d90eb7SKip Macy static int 1973ef72318fSKip Macy cxgb_set_mtu(struct port_info *p, int mtu) 1974ef72318fSKip Macy { 1975ef72318fSKip Macy struct ifnet *ifp = p->ifp; 1976ef72318fSKip Macy int error = 0; 1977ef72318fSKip Macy 19784af83c8cSKip Macy if ((mtu < ETHERMIN) || (mtu > ETHERMTU_JUMBO)) 1979ef72318fSKip Macy error = EINVAL; 1980ef72318fSKip Macy else if (ifp->if_mtu != mtu) { 1981ef72318fSKip Macy PORT_LOCK(p); 1982ef72318fSKip Macy ifp->if_mtu = mtu; 1983ef72318fSKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1984ef72318fSKip Macy cxgb_stop_locked(p); 1985ef72318fSKip Macy cxgb_init_locked(p); 1986ef72318fSKip Macy } 1987ef72318fSKip Macy PORT_UNLOCK(p); 1988ef72318fSKip Macy } 1989ef72318fSKip Macy return (error); 1990ef72318fSKip Macy } 1991ef72318fSKip Macy 1992e97121daSKip Macy #ifdef LRO_SUPPORTED 199325292debSKip Macy /* 199425292debSKip Macy * Mark lro enabled or disabled in all qsets for this port 199525292debSKip Macy */ 199625292debSKip Macy static int 199725292debSKip Macy cxgb_set_lro(struct port_info *p, int enabled) 199825292debSKip Macy { 199925292debSKip Macy int i; 200025292debSKip Macy struct adapter *adp = p->adapter; 200125292debSKip Macy struct sge_qset *q; 200225292debSKip Macy 200325292debSKip Macy PORT_LOCK_ASSERT_OWNED(p); 200425292debSKip Macy for (i = 0; i < p->nqsets; i++) { 200525292debSKip Macy q = &adp->sge.qs[p->first_qset + i]; 200625292debSKip Macy q->lro.enabled = (enabled != 0); 200725292debSKip Macy } 200825292debSKip Macy return (0); 200925292debSKip Macy } 2010e97121daSKip Macy #endif 201125292debSKip Macy 2012ef72318fSKip Macy static int 2013b6d90eb7SKip Macy cxgb_ioctl(struct ifnet *ifp, unsigned long command, caddr_t data) 2014b6d90eb7SKip Macy { 2015b6d90eb7SKip Macy struct port_info *p = ifp->if_softc; 201634627f93SBjoern A. Zeeb #ifdef INET 2017b6d90eb7SKip Macy struct ifaddr *ifa = (struct ifaddr *)data; 201834627f93SBjoern A. Zeeb #endif 2019b6d90eb7SKip Macy struct ifreq *ifr = (struct ifreq *)data; 20204af83c8cSKip Macy int flags, error = 0, reinit = 0; 2021b6d90eb7SKip Macy uint32_t mask; 2022b6d90eb7SKip Macy 202351580731SKip Macy /* 202451580731SKip Macy * XXX need to check that we aren't in the middle of an unload 202551580731SKip Macy */ 2026b6d90eb7SKip Macy switch (command) { 2027b6d90eb7SKip Macy case SIOCSIFMTU: 2028ef72318fSKip Macy error = cxgb_set_mtu(p, ifr->ifr_mtu); 2029b6d90eb7SKip Macy break; 2030b6d90eb7SKip Macy case SIOCSIFADDR: 203134627f93SBjoern A. Zeeb #ifdef INET 2032b6d90eb7SKip Macy if (ifa->ifa_addr->sa_family == AF_INET) { 2033b6d90eb7SKip Macy ifp->if_flags |= IFF_UP; 20348e10660fSKip Macy if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 20358e10660fSKip Macy PORT_LOCK(p); 2036ef72318fSKip Macy cxgb_init_locked(p); 20374f6a96aeSKip Macy PORT_UNLOCK(p); 20388e10660fSKip Macy } 20398e10660fSKip Macy arp_ifinit(ifp, ifa); 2040b6d90eb7SKip Macy } else 204134627f93SBjoern A. Zeeb #endif 2042b6d90eb7SKip Macy error = ether_ioctl(ifp, command, data); 2043b6d90eb7SKip Macy break; 2044b6d90eb7SKip Macy case SIOCSIFFLAGS: 2045693d746cSKip Macy PORT_LOCK(p); 2046ef72318fSKip Macy if (ifp->if_flags & IFF_UP) { 2047b6d90eb7SKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 2048b6d90eb7SKip Macy flags = p->if_flags; 2049b6d90eb7SKip Macy if (((ifp->if_flags ^ flags) & IFF_PROMISC) || 2050b6d90eb7SKip Macy ((ifp->if_flags ^ flags) & IFF_ALLMULTI)) 2051b6d90eb7SKip Macy cxgb_set_rxmode(p); 2052b6d90eb7SKip Macy } else 2053b6d90eb7SKip Macy cxgb_init_locked(p); 2054b6d90eb7SKip Macy p->if_flags = ifp->if_flags; 2055bb38cd2fSKip Macy } else if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2056693d746cSKip Macy cxgb_stop_locked(p); 2057bb38cd2fSKip Macy 2058ef72318fSKip Macy PORT_UNLOCK(p); 2059b6d90eb7SKip Macy break; 20608e10660fSKip Macy case SIOCADDMULTI: 20618e10660fSKip Macy case SIOCDELMULTI: 20628e10660fSKip Macy if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 20638e10660fSKip Macy cxgb_set_rxmode(p); 20648e10660fSKip Macy } 20658e10660fSKip Macy break; 2066b6d90eb7SKip Macy case SIOCSIFMEDIA: 2067b6d90eb7SKip Macy case SIOCGIFMEDIA: 2068837f41b0SGeorge V. Neville-Neil PORT_LOCK(p); 2069b6d90eb7SKip Macy error = ifmedia_ioctl(ifp, ifr, &p->media, command); 2070837f41b0SGeorge V. Neville-Neil PORT_UNLOCK(p); 2071b6d90eb7SKip Macy break; 2072b6d90eb7SKip Macy case SIOCSIFCAP: 2073b6d90eb7SKip Macy PORT_LOCK(p); 2074b6d90eb7SKip Macy mask = ifr->ifr_reqcap ^ ifp->if_capenable; 2075b6d90eb7SKip Macy if (mask & IFCAP_TXCSUM) { 2076b6d90eb7SKip Macy if (IFCAP_TXCSUM & ifp->if_capenable) { 2077b6d90eb7SKip Macy ifp->if_capenable &= ~(IFCAP_TXCSUM|IFCAP_TSO4); 2078b6d90eb7SKip Macy ifp->if_hwassist &= ~(CSUM_TCP | CSUM_UDP 20794af83c8cSKip Macy | CSUM_IP | CSUM_TSO); 2080b6d90eb7SKip Macy } else { 2081b6d90eb7SKip Macy ifp->if_capenable |= IFCAP_TXCSUM; 20824af83c8cSKip Macy ifp->if_hwassist |= (CSUM_TCP | CSUM_UDP 20834af83c8cSKip Macy | CSUM_IP); 2084b6d90eb7SKip Macy } 2085b6d90eb7SKip Macy } 20864af83c8cSKip Macy if (mask & IFCAP_RXCSUM) { 20874af83c8cSKip Macy ifp->if_capenable ^= IFCAP_RXCSUM; 2088b6d90eb7SKip Macy } 2089b6d90eb7SKip Macy if (mask & IFCAP_TSO4) { 2090b6d90eb7SKip Macy if (IFCAP_TSO4 & ifp->if_capenable) { 2091b6d90eb7SKip Macy ifp->if_capenable &= ~IFCAP_TSO4; 2092b6d90eb7SKip Macy ifp->if_hwassist &= ~CSUM_TSO; 2093b6d90eb7SKip Macy } else if (IFCAP_TXCSUM & ifp->if_capenable) { 2094b6d90eb7SKip Macy ifp->if_capenable |= IFCAP_TSO4; 2095b6d90eb7SKip Macy ifp->if_hwassist |= CSUM_TSO; 2096b6d90eb7SKip Macy } else { 2097b6d90eb7SKip Macy if (cxgb_debug) 2098b6d90eb7SKip Macy printf("cxgb requires tx checksum offload" 2099b6d90eb7SKip Macy " be enabled to use TSO\n"); 2100b6d90eb7SKip Macy error = EINVAL; 2101b6d90eb7SKip Macy } 2102b6d90eb7SKip Macy } 2103e97121daSKip Macy #ifdef LRO_SUPPORTED 210425292debSKip Macy if (mask & IFCAP_LRO) { 210525292debSKip Macy ifp->if_capenable ^= IFCAP_LRO; 210625292debSKip Macy 210725292debSKip Macy /* Safe to do this even if cxgb_up not called yet */ 210825292debSKip Macy cxgb_set_lro(p, ifp->if_capenable & IFCAP_LRO); 210925292debSKip Macy } 2110e97121daSKip Macy #endif 21114af83c8cSKip Macy if (mask & IFCAP_VLAN_HWTAGGING) { 21124af83c8cSKip Macy ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 21134af83c8cSKip Macy reinit = ifp->if_drv_flags & IFF_DRV_RUNNING; 21144af83c8cSKip Macy } 21154af83c8cSKip Macy if (mask & IFCAP_VLAN_MTU) { 21164af83c8cSKip Macy ifp->if_capenable ^= IFCAP_VLAN_MTU; 21174af83c8cSKip Macy reinit = ifp->if_drv_flags & IFF_DRV_RUNNING; 21184af83c8cSKip Macy } 21194af83c8cSKip Macy if (mask & IFCAP_VLAN_HWCSUM) { 21204af83c8cSKip Macy ifp->if_capenable ^= IFCAP_VLAN_HWCSUM; 21214af83c8cSKip Macy } 21224af83c8cSKip Macy if (reinit) { 21234af83c8cSKip Macy cxgb_stop_locked(p); 21244af83c8cSKip Macy cxgb_init_locked(p); 21254af83c8cSKip Macy } 2126b6d90eb7SKip Macy PORT_UNLOCK(p); 21274af83c8cSKip Macy 21284af83c8cSKip Macy #ifdef VLAN_CAPABILITIES 21294af83c8cSKip Macy VLAN_CAPABILITIES(ifp); 21304af83c8cSKip Macy #endif 2131b6d90eb7SKip Macy break; 2132b6d90eb7SKip Macy default: 2133b6d90eb7SKip Macy error = ether_ioctl(ifp, command, data); 2134b6d90eb7SKip Macy break; 2135b6d90eb7SKip Macy } 2136b6d90eb7SKip Macy return (error); 2137b6d90eb7SKip Macy } 2138b6d90eb7SKip Macy 2139b6d90eb7SKip Macy static int 2140b6d90eb7SKip Macy cxgb_media_change(struct ifnet *ifp) 2141b6d90eb7SKip Macy { 2142b6d90eb7SKip Macy if_printf(ifp, "media change not supported\n"); 2143b6d90eb7SKip Macy return (ENXIO); 2144b6d90eb7SKip Macy } 2145b6d90eb7SKip Macy 2146837f41b0SGeorge V. Neville-Neil /* 2147837f41b0SGeorge V. Neville-Neil * Translates from phy->modtype to IFM_TYPE. 2148837f41b0SGeorge V. Neville-Neil */ 2149837f41b0SGeorge V. Neville-Neil static int 2150837f41b0SGeorge V. Neville-Neil cxgb_ifm_type(int phymod) 2151837f41b0SGeorge V. Neville-Neil { 2152837f41b0SGeorge V. Neville-Neil int rc = IFM_ETHER | IFM_FDX; 2153837f41b0SGeorge V. Neville-Neil 2154837f41b0SGeorge V. Neville-Neil switch (phymod) { 2155837f41b0SGeorge V. Neville-Neil case phy_modtype_sr: 2156837f41b0SGeorge V. Neville-Neil rc |= IFM_10G_SR; 2157837f41b0SGeorge V. Neville-Neil break; 2158837f41b0SGeorge V. Neville-Neil case phy_modtype_lr: 2159837f41b0SGeorge V. Neville-Neil rc |= IFM_10G_LR; 2160837f41b0SGeorge V. Neville-Neil break; 2161837f41b0SGeorge V. Neville-Neil case phy_modtype_lrm: 2162837f41b0SGeorge V. Neville-Neil #ifdef IFM_10G_LRM 2163837f41b0SGeorge V. Neville-Neil rc |= IFM_10G_LRM; 2164837f41b0SGeorge V. Neville-Neil #endif 2165837f41b0SGeorge V. Neville-Neil break; 2166837f41b0SGeorge V. Neville-Neil case phy_modtype_twinax: 2167837f41b0SGeorge V. Neville-Neil #ifdef IFM_10G_TWINAX 2168837f41b0SGeorge V. Neville-Neil rc |= IFM_10G_TWINAX; 2169837f41b0SGeorge V. Neville-Neil #endif 2170837f41b0SGeorge V. Neville-Neil break; 2171837f41b0SGeorge V. Neville-Neil case phy_modtype_twinax_long: 2172837f41b0SGeorge V. Neville-Neil #ifdef IFM_10G_TWINAX_LONG 2173837f41b0SGeorge V. Neville-Neil rc |= IFM_10G_TWINAX_LONG; 2174837f41b0SGeorge V. Neville-Neil #endif 2175837f41b0SGeorge V. Neville-Neil break; 2176837f41b0SGeorge V. Neville-Neil case phy_modtype_none: 2177837f41b0SGeorge V. Neville-Neil rc = IFM_ETHER | IFM_NONE; 2178837f41b0SGeorge V. Neville-Neil break; 2179837f41b0SGeorge V. Neville-Neil case phy_modtype_unknown: 2180837f41b0SGeorge V. Neville-Neil break; 2181837f41b0SGeorge V. Neville-Neil } 2182837f41b0SGeorge V. Neville-Neil 2183837f41b0SGeorge V. Neville-Neil return (rc); 2184837f41b0SGeorge V. Neville-Neil } 2185837f41b0SGeorge V. Neville-Neil 2186b6d90eb7SKip Macy static void 2187b6d90eb7SKip Macy cxgb_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 2188b6d90eb7SKip Macy { 2189b6d90eb7SKip Macy struct port_info *p = ifp->if_softc; 2190837f41b0SGeorge V. Neville-Neil struct ifmedia_entry *cur = p->media.ifm_cur; 2191837f41b0SGeorge V. Neville-Neil int m; 2192837f41b0SGeorge V. Neville-Neil 2193837f41b0SGeorge V. Neville-Neil if (cur->ifm_data != p->phy.modtype) { 2194837f41b0SGeorge V. Neville-Neil /* p->media about to be rebuilt, must hold lock */ 2195837f41b0SGeorge V. Neville-Neil PORT_LOCK_ASSERT_OWNED(p); 2196837f41b0SGeorge V. Neville-Neil 2197837f41b0SGeorge V. Neville-Neil m = cxgb_ifm_type(p->phy.modtype); 2198837f41b0SGeorge V. Neville-Neil ifmedia_removeall(&p->media); 2199837f41b0SGeorge V. Neville-Neil ifmedia_add(&p->media, m, p->phy.modtype, NULL); 2200837f41b0SGeorge V. Neville-Neil ifmedia_set(&p->media, m); 2201837f41b0SGeorge V. Neville-Neil cur = p->media.ifm_cur; /* ifmedia_set modified ifm_cur */ 2202837f41b0SGeorge V. Neville-Neil ifmr->ifm_current = m; 2203837f41b0SGeorge V. Neville-Neil } 2204b6d90eb7SKip Macy 2205b6d90eb7SKip Macy ifmr->ifm_status = IFM_AVALID; 2206b6d90eb7SKip Macy ifmr->ifm_active = IFM_ETHER; 2207b6d90eb7SKip Macy 2208b6d90eb7SKip Macy if (!p->link_config.link_ok) 2209b6d90eb7SKip Macy return; 2210b6d90eb7SKip Macy 2211b6d90eb7SKip Macy ifmr->ifm_status |= IFM_ACTIVE; 2212b6d90eb7SKip Macy 2213ef72318fSKip Macy switch (p->link_config.speed) { 2214ef72318fSKip Macy case 10: 2215ef72318fSKip Macy ifmr->ifm_active |= IFM_10_T; 2216ef72318fSKip Macy break; 2217ef72318fSKip Macy case 100: 2218ef72318fSKip Macy ifmr->ifm_active |= IFM_100_TX; 2219ef72318fSKip Macy break; 2220ef72318fSKip Macy case 1000: 2221ef72318fSKip Macy ifmr->ifm_active |= IFM_1000_T; 2222ef72318fSKip Macy break; 2223837f41b0SGeorge V. Neville-Neil case 10000: 2224837f41b0SGeorge V. Neville-Neil ifmr->ifm_active |= IFM_SUBTYPE(cur->ifm_media); 2225837f41b0SGeorge V. Neville-Neil break; 2226ef72318fSKip Macy } 2227ef72318fSKip Macy 2228b6d90eb7SKip Macy if (p->link_config.duplex) 2229b6d90eb7SKip Macy ifmr->ifm_active |= IFM_FDX; 2230b6d90eb7SKip Macy else 2231b6d90eb7SKip Macy ifmr->ifm_active |= IFM_HDX; 2232b6d90eb7SKip Macy } 2233b6d90eb7SKip Macy 2234b6d90eb7SKip Macy static void 2235b6d90eb7SKip Macy cxgb_async_intr(void *data) 2236b6d90eb7SKip Macy { 2237693d746cSKip Macy adapter_t *sc = data; 2238693d746cSKip Macy 2239b6d90eb7SKip Macy if (cxgb_debug) 2240693d746cSKip Macy device_printf(sc->dev, "cxgb_async_intr\n"); 2241bb38cd2fSKip Macy /* 2242bb38cd2fSKip Macy * May need to sleep - defer to taskqueue 2243bb38cd2fSKip Macy */ 2244bb38cd2fSKip Macy taskqueue_enqueue(sc->tq, &sc->slow_intr_task); 2245b6d90eb7SKip Macy } 2246b6d90eb7SKip Macy 2247b6d90eb7SKip Macy static void 2248b6d90eb7SKip Macy cxgb_ext_intr_handler(void *arg, int count) 2249b6d90eb7SKip Macy { 2250b6d90eb7SKip Macy adapter_t *sc = (adapter_t *)arg; 2251b6d90eb7SKip Macy 2252b6d90eb7SKip Macy if (cxgb_debug) 2253b6d90eb7SKip Macy printf("cxgb_ext_intr_handler\n"); 2254b6d90eb7SKip Macy 2255b6d90eb7SKip Macy t3_phy_intr_handler(sc); 2256b6d90eb7SKip Macy 2257b6d90eb7SKip Macy /* Now reenable external interrupts */ 2258d722cab4SKip Macy ADAPTER_LOCK(sc); 2259b6d90eb7SKip Macy if (sc->slow_intr_mask) { 2260b6d90eb7SKip Macy sc->slow_intr_mask |= F_T3DBG; 2261b6d90eb7SKip Macy t3_write_reg(sc, A_PL_INT_CAUSE0, F_T3DBG); 2262b6d90eb7SKip Macy t3_write_reg(sc, A_PL_INT_ENABLE0, sc->slow_intr_mask); 2263b6d90eb7SKip Macy } 2264d722cab4SKip Macy ADAPTER_UNLOCK(sc); 2265b6d90eb7SKip Macy } 2266b6d90eb7SKip Macy 2267b6d90eb7SKip Macy static void 2268b6d90eb7SKip Macy check_link_status(adapter_t *sc) 2269b6d90eb7SKip Macy { 2270b6d90eb7SKip Macy int i; 2271b6d90eb7SKip Macy 22720bbdea77SGeorge V. Neville-Neil /* For synchronized access to open_device_map */ 22730bbdea77SGeorge V. Neville-Neil ADAPTER_LOCK_ASSERT_OWNED(sc); 22740bbdea77SGeorge V. Neville-Neil 2275b6d90eb7SKip Macy for (i = 0; i < (sc)->params.nports; ++i) { 2276b6d90eb7SKip Macy struct port_info *p = &sc->port[i]; 22770bbdea77SGeorge V. Neville-Neil struct link_config *lc = &p->link_config; 2278b6d90eb7SKip Macy 22790bbdea77SGeorge V. Neville-Neil if (!isset(&sc->open_device_map, p->port_id)) { 22800bbdea77SGeorge V. Neville-Neil /* 22810bbdea77SGeorge V. Neville-Neil * port is down, report link down too. Note 22820bbdea77SGeorge V. Neville-Neil * that we do this for IRQ based PHYs too. 22830bbdea77SGeorge V. Neville-Neil */ 22840bbdea77SGeorge V. Neville-Neil lc->link_ok = 0; 22850bbdea77SGeorge V. Neville-Neil t3_os_link_changed(sc, i, lc->link_ok, lc->speed, 22860bbdea77SGeorge V. Neville-Neil lc->duplex, lc->fc); 22870bbdea77SGeorge V. Neville-Neil } else if (p->link_fault || !(p->phy.caps & SUPPORTED_IRQ)) 2288b6d90eb7SKip Macy t3_link_changed(sc, i); 2289b6d90eb7SKip Macy } 2290b6d90eb7SKip Macy } 2291b6d90eb7SKip Macy 2292577e9bbeSKip Macy static void 2293577e9bbeSKip Macy check_t3b2_mac(struct adapter *adapter) 2294577e9bbeSKip Macy { 2295577e9bbeSKip Macy int i; 2296577e9bbeSKip Macy 22978e10660fSKip Macy if(adapter->flags & CXGB_SHUTDOWN) 22988e10660fSKip Macy return; 22998e10660fSKip Macy 2300577e9bbeSKip Macy for_each_port(adapter, i) { 2301577e9bbeSKip Macy struct port_info *p = &adapter->port[i]; 2302577e9bbeSKip Macy struct ifnet *ifp = p->ifp; 2303577e9bbeSKip Macy int status; 2304577e9bbeSKip Macy 23058e10660fSKip Macy if(adapter->flags & CXGB_SHUTDOWN) 23068e10660fSKip Macy return; 23078e10660fSKip Macy 2308577e9bbeSKip Macy if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 2309577e9bbeSKip Macy continue; 2310577e9bbeSKip Macy 2311577e9bbeSKip Macy status = 0; 2312577e9bbeSKip Macy PORT_LOCK(p); 2313577e9bbeSKip Macy if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) 2314577e9bbeSKip Macy status = t3b2_mac_watchdog_task(&p->mac); 2315577e9bbeSKip Macy if (status == 1) 2316577e9bbeSKip Macy p->mac.stats.num_toggled++; 2317577e9bbeSKip Macy else if (status == 2) { 2318577e9bbeSKip Macy struct cmac *mac = &p->mac; 23194af83c8cSKip Macy int mtu = ifp->if_mtu; 2320577e9bbeSKip Macy 23214af83c8cSKip Macy if (ifp->if_capenable & IFCAP_VLAN_MTU) 23224af83c8cSKip Macy mtu += ETHER_VLAN_ENCAP_LEN; 23234af83c8cSKip Macy t3_mac_set_mtu(mac, mtu); 2324577e9bbeSKip Macy t3_mac_set_address(mac, 0, p->hw_addr); 2325577e9bbeSKip Macy cxgb_set_rxmode(p); 2326577e9bbeSKip Macy t3_link_start(&p->phy, mac, &p->link_config); 2327577e9bbeSKip Macy t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX); 23286b68e276SKip Macy t3_port_intr_enable(adapter, p->port_id); 2329577e9bbeSKip Macy p->mac.stats.num_resets++; 2330577e9bbeSKip Macy } 2331577e9bbeSKip Macy PORT_UNLOCK(p); 2332577e9bbeSKip Macy } 2333577e9bbeSKip Macy } 2334577e9bbeSKip Macy 2335577e9bbeSKip Macy static void 2336577e9bbeSKip Macy cxgb_tick(void *arg) 2337577e9bbeSKip Macy { 2338577e9bbeSKip Macy adapter_t *sc = (adapter_t *)arg; 23398090c9f5SKip Macy 23408e10660fSKip Macy if(sc->flags & CXGB_SHUTDOWN) 23418090c9f5SKip Macy return; 2342577e9bbeSKip Macy 2343bb38cd2fSKip Macy taskqueue_enqueue(sc->tq, &sc->tick_task); 2344706cb31fSKip Macy callout_reset(&sc->cxgb_tick_ch, CXGB_TICKS(sc), cxgb_tick, sc); 2345bb38cd2fSKip Macy } 2346bb38cd2fSKip Macy 2347bb38cd2fSKip Macy static void 2348bb38cd2fSKip Macy cxgb_tick_handler(void *arg, int count) 2349bb38cd2fSKip Macy { 2350bb38cd2fSKip Macy adapter_t *sc = (adapter_t *)arg; 2351bb38cd2fSKip Macy const struct adapter_params *p = &sc->params; 2352706cb31fSKip Macy int i; 2353f2d8ff04SGeorge V. Neville-Neil uint32_t cause, reset; 2354bb38cd2fSKip Macy 23550bbdea77SGeorge V. Neville-Neil if(sc->flags & CXGB_SHUTDOWN || !(sc->flags & FULL_INIT_DONE)) 23568e10660fSKip Macy return; 23578e10660fSKip Macy 2358bb38cd2fSKip Macy ADAPTER_LOCK(sc); 23590bbdea77SGeorge V. Neville-Neil 2360bb38cd2fSKip Macy check_link_status(sc); 2361577e9bbeSKip Macy 2362f35c2d65SKip Macy sc->check_task_cnt++; 2363f35c2d65SKip Macy 2364f35c2d65SKip Macy /* 2365f35c2d65SKip Macy * adapter lock can currently only be acquired after the 2366f35c2d65SKip Macy * port lock 2367f35c2d65SKip Macy */ 2368f35c2d65SKip Macy ADAPTER_UNLOCK(sc); 2369f35c2d65SKip Macy 2370f35c2d65SKip Macy if (p->rev == T3_REV_B2 && p->nports < 4 && sc->open_device_map) 2371f35c2d65SKip Macy check_t3b2_mac(sc); 2372f35c2d65SKip Macy 2373f2d8ff04SGeorge V. Neville-Neil cause = t3_read_reg(sc, A_SG_INT_CAUSE); 2374f2d8ff04SGeorge V. Neville-Neil reset = 0; 2375f2d8ff04SGeorge V. Neville-Neil if (cause & F_FLEMPTY) { 2376f2d8ff04SGeorge V. Neville-Neil struct sge_qset *qs = &sc->sge.qs[0]; 2377f2d8ff04SGeorge V. Neville-Neil 2378f2d8ff04SGeorge V. Neville-Neil i = 0; 2379f2d8ff04SGeorge V. Neville-Neil reset |= F_FLEMPTY; 2380f2d8ff04SGeorge V. Neville-Neil 2381f2d8ff04SGeorge V. Neville-Neil cause = (t3_read_reg(sc, A_SG_RSPQ_FL_STATUS) >> 2382f2d8ff04SGeorge V. Neville-Neil S_FL0EMPTY) & 0xffff; 2383f2d8ff04SGeorge V. Neville-Neil while (cause) { 2384f2d8ff04SGeorge V. Neville-Neil qs->fl[i].empty += (cause & 1); 2385f2d8ff04SGeorge V. Neville-Neil if (i) 2386f2d8ff04SGeorge V. Neville-Neil qs++; 2387f2d8ff04SGeorge V. Neville-Neil i ^= 1; 2388f2d8ff04SGeorge V. Neville-Neil cause >>= 1; 2389f2d8ff04SGeorge V. Neville-Neil } 2390f2d8ff04SGeorge V. Neville-Neil } 2391f2d8ff04SGeorge V. Neville-Neil t3_write_reg(sc, A_SG_INT_CAUSE, reset); 2392f2d8ff04SGeorge V. Neville-Neil 2393ceac50ebSKip Macy for (i = 0; i < sc->params.nports; i++) { 2394ceac50ebSKip Macy struct port_info *pi = &sc->port[i]; 2395ceac50ebSKip Macy struct ifnet *ifp = pi->ifp; 2396f2d8ff04SGeorge V. Neville-Neil struct cmac *mac = &pi->mac; 2397f2d8ff04SGeorge V. Neville-Neil struct mac_stats *mstats = &mac->stats; 2398f35c2d65SKip Macy PORT_LOCK(pi); 2399f2d8ff04SGeorge V. Neville-Neil t3_mac_update_stats(mac); 2400f35c2d65SKip Macy PORT_UNLOCK(pi); 2401f35c2d65SKip Macy 2402ceac50ebSKip Macy ifp->if_opackets = 2403ceac50ebSKip Macy mstats->tx_frames_64 + 2404ceac50ebSKip Macy mstats->tx_frames_65_127 + 2405ceac50ebSKip Macy mstats->tx_frames_128_255 + 2406ceac50ebSKip Macy mstats->tx_frames_256_511 + 2407ceac50ebSKip Macy mstats->tx_frames_512_1023 + 2408ceac50ebSKip Macy mstats->tx_frames_1024_1518 + 2409ceac50ebSKip Macy mstats->tx_frames_1519_max; 2410ceac50ebSKip Macy 2411ceac50ebSKip Macy ifp->if_ipackets = 2412ceac50ebSKip Macy mstats->rx_frames_64 + 2413ceac50ebSKip Macy mstats->rx_frames_65_127 + 2414ceac50ebSKip Macy mstats->rx_frames_128_255 + 2415ceac50ebSKip Macy mstats->rx_frames_256_511 + 2416ceac50ebSKip Macy mstats->rx_frames_512_1023 + 2417ceac50ebSKip Macy mstats->rx_frames_1024_1518 + 2418ceac50ebSKip Macy mstats->rx_frames_1519_max; 2419ceac50ebSKip Macy 2420ceac50ebSKip Macy ifp->if_obytes = mstats->tx_octets; 2421ceac50ebSKip Macy ifp->if_ibytes = mstats->rx_octets; 2422ceac50ebSKip Macy ifp->if_omcasts = mstats->tx_mcast_frames; 2423ceac50ebSKip Macy ifp->if_imcasts = mstats->rx_mcast_frames; 2424ceac50ebSKip Macy 2425ceac50ebSKip Macy ifp->if_collisions = 2426ceac50ebSKip Macy mstats->tx_total_collisions; 2427ceac50ebSKip Macy 2428ceac50ebSKip Macy ifp->if_iqdrops = mstats->rx_cong_drops; 2429ceac50ebSKip Macy 2430ceac50ebSKip Macy ifp->if_oerrors = 2431ceac50ebSKip Macy mstats->tx_excess_collisions + 2432ceac50ebSKip Macy mstats->tx_underrun + 2433ceac50ebSKip Macy mstats->tx_len_errs + 2434ceac50ebSKip Macy mstats->tx_mac_internal_errs + 2435ceac50ebSKip Macy mstats->tx_excess_deferral + 2436ceac50ebSKip Macy mstats->tx_fcs_errs; 2437ceac50ebSKip Macy ifp->if_ierrors = 2438ceac50ebSKip Macy mstats->rx_jabber + 2439ceac50ebSKip Macy mstats->rx_data_errs + 2440ceac50ebSKip Macy mstats->rx_sequence_errs + 2441ceac50ebSKip Macy mstats->rx_runt + 2442ceac50ebSKip Macy mstats->rx_too_long + 2443ceac50ebSKip Macy mstats->rx_mac_internal_errs + 2444ceac50ebSKip Macy mstats->rx_short + 2445ceac50ebSKip Macy mstats->rx_fcs_errs; 2446f2d8ff04SGeorge V. Neville-Neil 2447f2d8ff04SGeorge V. Neville-Neil if (mac->multiport) 2448f2d8ff04SGeorge V. Neville-Neil continue; 2449f2d8ff04SGeorge V. Neville-Neil 2450f2d8ff04SGeorge V. Neville-Neil /* Count rx fifo overflows, once per second */ 2451f2d8ff04SGeorge V. Neville-Neil cause = t3_read_reg(sc, A_XGM_INT_CAUSE + mac->offset); 2452f2d8ff04SGeorge V. Neville-Neil reset = 0; 2453f2d8ff04SGeorge V. Neville-Neil if (cause & F_RXFIFO_OVERFLOW) { 2454f2d8ff04SGeorge V. Neville-Neil mac->stats.rx_fifo_ovfl++; 2455f2d8ff04SGeorge V. Neville-Neil reset |= F_RXFIFO_OVERFLOW; 2456f2d8ff04SGeorge V. Neville-Neil } 2457f2d8ff04SGeorge V. Neville-Neil t3_write_reg(sc, A_XGM_INT_CAUSE + mac->offset, reset); 2458ceac50ebSKip Macy } 2459577e9bbeSKip Macy } 2460577e9bbeSKip Macy 24617ac2e6c3SKip Macy static void 24627ac2e6c3SKip Macy touch_bars(device_t dev) 24637ac2e6c3SKip Macy { 24647ac2e6c3SKip Macy /* 24657ac2e6c3SKip Macy * Don't enable yet 24667ac2e6c3SKip Macy */ 24677ac2e6c3SKip Macy #if !defined(__LP64__) && 0 24687ac2e6c3SKip Macy u32 v; 24697ac2e6c3SKip Macy 24707ac2e6c3SKip Macy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, &v); 24717ac2e6c3SKip Macy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_1, v); 24727ac2e6c3SKip Macy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_3, &v); 24737ac2e6c3SKip Macy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_3, v); 24747ac2e6c3SKip Macy pci_read_config_dword(pdev, PCI_BASE_ADDRESS_5, &v); 24757ac2e6c3SKip Macy pci_write_config_dword(pdev, PCI_BASE_ADDRESS_5, v); 24767ac2e6c3SKip Macy #endif 24777ac2e6c3SKip Macy } 24787ac2e6c3SKip Macy 2479ac3a6d9cSKip Macy static int 2480ac3a6d9cSKip Macy set_eeprom(struct port_info *pi, const uint8_t *data, int len, int offset) 2481ac3a6d9cSKip Macy { 2482ac3a6d9cSKip Macy uint8_t *buf; 2483ac3a6d9cSKip Macy int err = 0; 2484ac3a6d9cSKip Macy u32 aligned_offset, aligned_len, *p; 2485ac3a6d9cSKip Macy struct adapter *adapter = pi->adapter; 2486ac3a6d9cSKip Macy 2487ac3a6d9cSKip Macy 2488ac3a6d9cSKip Macy aligned_offset = offset & ~3; 2489ac3a6d9cSKip Macy aligned_len = (len + (offset & 3) + 3) & ~3; 2490ac3a6d9cSKip Macy 2491ac3a6d9cSKip Macy if (aligned_offset != offset || aligned_len != len) { 2492ac3a6d9cSKip Macy buf = malloc(aligned_len, M_DEVBUF, M_WAITOK|M_ZERO); 2493ac3a6d9cSKip Macy if (!buf) 2494ac3a6d9cSKip Macy return (ENOMEM); 2495ac3a6d9cSKip Macy err = t3_seeprom_read(adapter, aligned_offset, (u32 *)buf); 2496ac3a6d9cSKip Macy if (!err && aligned_len > 4) 2497ac3a6d9cSKip Macy err = t3_seeprom_read(adapter, 2498ac3a6d9cSKip Macy aligned_offset + aligned_len - 4, 2499ac3a6d9cSKip Macy (u32 *)&buf[aligned_len - 4]); 2500ac3a6d9cSKip Macy if (err) 2501ac3a6d9cSKip Macy goto out; 2502ac3a6d9cSKip Macy memcpy(buf + (offset & 3), data, len); 2503ac3a6d9cSKip Macy } else 2504ac3a6d9cSKip Macy buf = (uint8_t *)(uintptr_t)data; 2505ac3a6d9cSKip Macy 2506ac3a6d9cSKip Macy err = t3_seeprom_wp(adapter, 0); 2507ac3a6d9cSKip Macy if (err) 2508ac3a6d9cSKip Macy goto out; 2509ac3a6d9cSKip Macy 2510ac3a6d9cSKip Macy for (p = (u32 *)buf; !err && aligned_len; aligned_len -= 4, p++) { 2511ac3a6d9cSKip Macy err = t3_seeprom_write(adapter, aligned_offset, *p); 2512ac3a6d9cSKip Macy aligned_offset += 4; 2513ac3a6d9cSKip Macy } 2514ac3a6d9cSKip Macy 2515ac3a6d9cSKip Macy if (!err) 2516ac3a6d9cSKip Macy err = t3_seeprom_wp(adapter, 1); 2517ac3a6d9cSKip Macy out: 2518ac3a6d9cSKip Macy if (buf != data) 2519ac3a6d9cSKip Macy free(buf, M_DEVBUF); 2520ac3a6d9cSKip Macy return err; 2521ac3a6d9cSKip Macy } 2522ac3a6d9cSKip Macy 2523ac3a6d9cSKip Macy 2524b6d90eb7SKip Macy static int 2525b6d90eb7SKip Macy in_range(int val, int lo, int hi) 2526b6d90eb7SKip Macy { 2527b6d90eb7SKip Macy return val < 0 || (val <= hi && val >= lo); 2528b6d90eb7SKip Macy } 2529b6d90eb7SKip Macy 2530b6d90eb7SKip Macy static int 253100b4e54aSWarner Losh cxgb_extension_open(struct cdev *dev, int flags, int fmp, struct thread *td) 2532ef72318fSKip Macy { 2533ef72318fSKip Macy return (0); 2534ef72318fSKip Macy } 2535ef72318fSKip Macy 2536ef72318fSKip Macy static int 253700b4e54aSWarner Losh cxgb_extension_close(struct cdev *dev, int flags, int fmt, struct thread *td) 2538ef72318fSKip Macy { 2539ef72318fSKip Macy return (0); 2540ef72318fSKip Macy } 2541ef72318fSKip Macy 2542ef72318fSKip Macy static int 2543b6d90eb7SKip Macy cxgb_extension_ioctl(struct cdev *dev, unsigned long cmd, caddr_t data, 2544b6d90eb7SKip Macy int fflag, struct thread *td) 2545b6d90eb7SKip Macy { 2546b6d90eb7SKip Macy int mmd, error = 0; 2547b6d90eb7SKip Macy struct port_info *pi = dev->si_drv1; 2548b6d90eb7SKip Macy adapter_t *sc = pi->adapter; 2549b6d90eb7SKip Macy 2550b6d90eb7SKip Macy #ifdef PRIV_SUPPORTED 2551b6d90eb7SKip Macy if (priv_check(td, PRIV_DRIVER)) { 2552b6d90eb7SKip Macy if (cxgb_debug) 2553b6d90eb7SKip Macy printf("user does not have access to privileged ioctls\n"); 2554b6d90eb7SKip Macy return (EPERM); 2555b6d90eb7SKip Macy } 2556b6d90eb7SKip Macy #else 2557b6d90eb7SKip Macy if (suser(td)) { 2558b6d90eb7SKip Macy if (cxgb_debug) 2559b6d90eb7SKip Macy printf("user does not have access to privileged ioctls\n"); 2560b6d90eb7SKip Macy return (EPERM); 2561b6d90eb7SKip Macy } 2562b6d90eb7SKip Macy #endif 2563b6d90eb7SKip Macy 2564b6d90eb7SKip Macy switch (cmd) { 25651ffd6e58SKip Macy case CHELSIO_GET_MIIREG: { 2566b6d90eb7SKip Macy uint32_t val; 2567b6d90eb7SKip Macy struct cphy *phy = &pi->phy; 25681ffd6e58SKip Macy struct ch_mii_data *mid = (struct ch_mii_data *)data; 2569b6d90eb7SKip Macy 2570b6d90eb7SKip Macy if (!phy->mdio_read) 2571b6d90eb7SKip Macy return (EOPNOTSUPP); 2572b6d90eb7SKip Macy if (is_10G(sc)) { 2573b6d90eb7SKip Macy mmd = mid->phy_id >> 8; 2574b6d90eb7SKip Macy if (!mmd) 2575b6d90eb7SKip Macy mmd = MDIO_DEV_PCS; 25760c1ff9c6SGeorge V. Neville-Neil else if (mmd > MDIO_DEV_VEND2) 2577ac3a6d9cSKip Macy return (EINVAL); 2578b6d90eb7SKip Macy 2579b6d90eb7SKip Macy error = phy->mdio_read(sc, mid->phy_id & 0x1f, mmd, 2580b6d90eb7SKip Macy mid->reg_num, &val); 2581b6d90eb7SKip Macy } else 2582b6d90eb7SKip Macy error = phy->mdio_read(sc, mid->phy_id & 0x1f, 0, 2583b6d90eb7SKip Macy mid->reg_num & 0x1f, &val); 2584b6d90eb7SKip Macy if (error == 0) 2585b6d90eb7SKip Macy mid->val_out = val; 2586b6d90eb7SKip Macy break; 2587b6d90eb7SKip Macy } 25881ffd6e58SKip Macy case CHELSIO_SET_MIIREG: { 2589b6d90eb7SKip Macy struct cphy *phy = &pi->phy; 25901ffd6e58SKip Macy struct ch_mii_data *mid = (struct ch_mii_data *)data; 2591b6d90eb7SKip Macy 2592b6d90eb7SKip Macy if (!phy->mdio_write) 2593b6d90eb7SKip Macy return (EOPNOTSUPP); 2594b6d90eb7SKip Macy if (is_10G(sc)) { 2595b6d90eb7SKip Macy mmd = mid->phy_id >> 8; 2596b6d90eb7SKip Macy if (!mmd) 2597b6d90eb7SKip Macy mmd = MDIO_DEV_PCS; 25980c1ff9c6SGeorge V. Neville-Neil else if (mmd > MDIO_DEV_VEND2) 2599b6d90eb7SKip Macy return (EINVAL); 2600b6d90eb7SKip Macy 2601b6d90eb7SKip Macy error = phy->mdio_write(sc, mid->phy_id & 0x1f, 2602b6d90eb7SKip Macy mmd, mid->reg_num, mid->val_in); 2603b6d90eb7SKip Macy } else 2604b6d90eb7SKip Macy error = phy->mdio_write(sc, mid->phy_id & 0x1f, 0, 2605b6d90eb7SKip Macy mid->reg_num & 0x1f, 2606b6d90eb7SKip Macy mid->val_in); 2607b6d90eb7SKip Macy break; 2608b6d90eb7SKip Macy } 2609b6d90eb7SKip Macy case CHELSIO_SETREG: { 2610b6d90eb7SKip Macy struct ch_reg *edata = (struct ch_reg *)data; 2611b6d90eb7SKip Macy if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 2612b6d90eb7SKip Macy return (EFAULT); 2613b6d90eb7SKip Macy t3_write_reg(sc, edata->addr, edata->val); 2614b6d90eb7SKip Macy break; 2615b6d90eb7SKip Macy } 2616b6d90eb7SKip Macy case CHELSIO_GETREG: { 2617b6d90eb7SKip Macy struct ch_reg *edata = (struct ch_reg *)data; 2618b6d90eb7SKip Macy if ((edata->addr & 0x3) != 0 || edata->addr >= sc->mmio_len) 2619b6d90eb7SKip Macy return (EFAULT); 2620b6d90eb7SKip Macy edata->val = t3_read_reg(sc, edata->addr); 2621b6d90eb7SKip Macy break; 2622b6d90eb7SKip Macy } 2623b6d90eb7SKip Macy case CHELSIO_GET_SGE_CONTEXT: { 2624b6d90eb7SKip Macy struct ch_cntxt *ecntxt = (struct ch_cntxt *)data; 26258e10660fSKip Macy mtx_lock_spin(&sc->sge.reg_lock); 2626b6d90eb7SKip Macy switch (ecntxt->cntxt_type) { 2627b6d90eb7SKip Macy case CNTXT_TYPE_EGRESS: 26281ffd6e58SKip Macy error = -t3_sge_read_ecntxt(sc, ecntxt->cntxt_id, 2629b6d90eb7SKip Macy ecntxt->data); 2630b6d90eb7SKip Macy break; 2631b6d90eb7SKip Macy case CNTXT_TYPE_FL: 26321ffd6e58SKip Macy error = -t3_sge_read_fl(sc, ecntxt->cntxt_id, 2633b6d90eb7SKip Macy ecntxt->data); 2634b6d90eb7SKip Macy break; 2635b6d90eb7SKip Macy case CNTXT_TYPE_RSP: 26361ffd6e58SKip Macy error = -t3_sge_read_rspq(sc, ecntxt->cntxt_id, 2637b6d90eb7SKip Macy ecntxt->data); 2638b6d90eb7SKip Macy break; 2639b6d90eb7SKip Macy case CNTXT_TYPE_CQ: 26401ffd6e58SKip Macy error = -t3_sge_read_cq(sc, ecntxt->cntxt_id, 2641b6d90eb7SKip Macy ecntxt->data); 2642b6d90eb7SKip Macy break; 2643b6d90eb7SKip Macy default: 2644b6d90eb7SKip Macy error = EINVAL; 2645b6d90eb7SKip Macy break; 2646b6d90eb7SKip Macy } 26478e10660fSKip Macy mtx_unlock_spin(&sc->sge.reg_lock); 2648b6d90eb7SKip Macy break; 2649b6d90eb7SKip Macy } 2650b6d90eb7SKip Macy case CHELSIO_GET_SGE_DESC: { 2651b6d90eb7SKip Macy struct ch_desc *edesc = (struct ch_desc *)data; 2652b6d90eb7SKip Macy int ret; 2653b6d90eb7SKip Macy if (edesc->queue_num >= SGE_QSETS * 6) 2654b6d90eb7SKip Macy return (EINVAL); 2655b6d90eb7SKip Macy ret = t3_get_desc(&sc->sge.qs[edesc->queue_num / 6], 2656b6d90eb7SKip Macy edesc->queue_num % 6, edesc->idx, edesc->data); 2657b6d90eb7SKip Macy if (ret < 0) 2658b6d90eb7SKip Macy return (EINVAL); 2659b6d90eb7SKip Macy edesc->size = ret; 2660b6d90eb7SKip Macy break; 2661b6d90eb7SKip Macy } 2662b6d90eb7SKip Macy case CHELSIO_GET_QSET_PARAMS: { 2663b6d90eb7SKip Macy struct qset_params *q; 2664b6d90eb7SKip Macy struct ch_qset_params *t = (struct ch_qset_params *)data; 26651ffd6e58SKip Macy int q1 = pi->first_qset; 26661ffd6e58SKip Macy int nqsets = pi->nqsets; 26671ffd6e58SKip Macy int i; 2668b6d90eb7SKip Macy 26691ffd6e58SKip Macy if (t->qset_idx >= nqsets) 26701ffd6e58SKip Macy return EINVAL; 2671b6d90eb7SKip Macy 26721ffd6e58SKip Macy i = q1 + t->qset_idx; 26731ffd6e58SKip Macy q = &sc->params.sge.qset[i]; 2674b6d90eb7SKip Macy t->rspq_size = q->rspq_size; 2675b6d90eb7SKip Macy t->txq_size[0] = q->txq_size[0]; 2676b6d90eb7SKip Macy t->txq_size[1] = q->txq_size[1]; 2677b6d90eb7SKip Macy t->txq_size[2] = q->txq_size[2]; 2678b6d90eb7SKip Macy t->fl_size[0] = q->fl_size; 2679b6d90eb7SKip Macy t->fl_size[1] = q->jumbo_size; 2680b6d90eb7SKip Macy t->polling = q->polling; 26811ffd6e58SKip Macy t->lro = q->lro; 26824af83c8cSKip Macy t->intr_lat = q->coalesce_usecs; 2683b6d90eb7SKip Macy t->cong_thres = q->cong_thres; 26841ffd6e58SKip Macy t->qnum = i; 2685b6d90eb7SKip Macy 26861ffd6e58SKip Macy if (sc->flags & USING_MSIX) 26871ffd6e58SKip Macy t->vector = rman_get_start(sc->msix_irq_res[i]); 26881ffd6e58SKip Macy else 26891ffd6e58SKip Macy t->vector = rman_get_start(sc->irq_res); 26901ffd6e58SKip Macy 2691b6d90eb7SKip Macy break; 2692b6d90eb7SKip Macy } 2693b6d90eb7SKip Macy case CHELSIO_GET_QSET_NUM: { 2694b6d90eb7SKip Macy struct ch_reg *edata = (struct ch_reg *)data; 2695b6d90eb7SKip Macy edata->val = pi->nqsets; 2696b6d90eb7SKip Macy break; 2697b6d90eb7SKip Macy } 26981ffd6e58SKip Macy case CHELSIO_LOAD_FW: { 26991ffd6e58SKip Macy uint8_t *fw_data; 27001ffd6e58SKip Macy uint32_t vers; 27011ffd6e58SKip Macy struct ch_mem_range *t = (struct ch_mem_range *)data; 27021ffd6e58SKip Macy 27031ffd6e58SKip Macy /* 27041ffd6e58SKip Macy * You're allowed to load a firmware only before FULL_INIT_DONE 27051ffd6e58SKip Macy * 27061ffd6e58SKip Macy * FW_UPTODATE is also set so the rest of the initialization 27071ffd6e58SKip Macy * will not overwrite what was loaded here. This gives you the 27081ffd6e58SKip Macy * flexibility to load any firmware (and maybe shoot yourself in 27091ffd6e58SKip Macy * the foot). 27101ffd6e58SKip Macy */ 27111ffd6e58SKip Macy 27121ffd6e58SKip Macy ADAPTER_LOCK(sc); 27131ffd6e58SKip Macy if (sc->open_device_map || sc->flags & FULL_INIT_DONE) { 27141ffd6e58SKip Macy ADAPTER_UNLOCK(sc); 27151ffd6e58SKip Macy return (EBUSY); 27161ffd6e58SKip Macy } 27171ffd6e58SKip Macy 27181ffd6e58SKip Macy fw_data = malloc(t->len, M_DEVBUF, M_NOWAIT); 27191ffd6e58SKip Macy if (!fw_data) 27201ffd6e58SKip Macy error = ENOMEM; 27211ffd6e58SKip Macy else 27221ffd6e58SKip Macy error = copyin(t->buf, fw_data, t->len); 27231ffd6e58SKip Macy 27241ffd6e58SKip Macy if (!error) 27251ffd6e58SKip Macy error = -t3_load_fw(sc, fw_data, t->len); 27261ffd6e58SKip Macy 27271ffd6e58SKip Macy if (t3_get_fw_version(sc, &vers) == 0) { 27281ffd6e58SKip Macy snprintf(&sc->fw_version[0], sizeof(sc->fw_version), 27291ffd6e58SKip Macy "%d.%d.%d", G_FW_VERSION_MAJOR(vers), 27301ffd6e58SKip Macy G_FW_VERSION_MINOR(vers), G_FW_VERSION_MICRO(vers)); 27311ffd6e58SKip Macy } 27321ffd6e58SKip Macy 27331ffd6e58SKip Macy if (!error) 27341ffd6e58SKip Macy sc->flags |= FW_UPTODATE; 27351ffd6e58SKip Macy 27361ffd6e58SKip Macy free(fw_data, M_DEVBUF); 27371ffd6e58SKip Macy ADAPTER_UNLOCK(sc); 2738b6d90eb7SKip Macy break; 27391ffd6e58SKip Macy } 27401ffd6e58SKip Macy case CHELSIO_LOAD_BOOT: { 27411ffd6e58SKip Macy uint8_t *boot_data; 27421ffd6e58SKip Macy struct ch_mem_range *t = (struct ch_mem_range *)data; 27431ffd6e58SKip Macy 27441ffd6e58SKip Macy boot_data = malloc(t->len, M_DEVBUF, M_NOWAIT); 27451ffd6e58SKip Macy if (!boot_data) 27461ffd6e58SKip Macy return ENOMEM; 27471ffd6e58SKip Macy 27481ffd6e58SKip Macy error = copyin(t->buf, boot_data, t->len); 27491ffd6e58SKip Macy if (!error) 27501ffd6e58SKip Macy error = -t3_load_boot(sc, boot_data, t->len); 27511ffd6e58SKip Macy 27521ffd6e58SKip Macy free(boot_data, M_DEVBUF); 27531ffd6e58SKip Macy break; 27541ffd6e58SKip Macy } 27551ffd6e58SKip Macy case CHELSIO_GET_PM: { 27561ffd6e58SKip Macy struct ch_pm *m = (struct ch_pm *)data; 27571ffd6e58SKip Macy struct tp_params *p = &sc->params.tp; 27581ffd6e58SKip Macy 27591ffd6e58SKip Macy if (!is_offload(sc)) 27601ffd6e58SKip Macy return (EOPNOTSUPP); 27611ffd6e58SKip Macy 27621ffd6e58SKip Macy m->tx_pg_sz = p->tx_pg_size; 27631ffd6e58SKip Macy m->tx_num_pg = p->tx_num_pgs; 27641ffd6e58SKip Macy m->rx_pg_sz = p->rx_pg_size; 27651ffd6e58SKip Macy m->rx_num_pg = p->rx_num_pgs; 27661ffd6e58SKip Macy m->pm_total = p->pmtx_size + p->chan_rx_size * p->nchan; 27671ffd6e58SKip Macy 27681ffd6e58SKip Macy break; 27691ffd6e58SKip Macy } 27701ffd6e58SKip Macy case CHELSIO_SET_PM: { 27711ffd6e58SKip Macy struct ch_pm *m = (struct ch_pm *)data; 27721ffd6e58SKip Macy struct tp_params *p = &sc->params.tp; 27731ffd6e58SKip Macy 27741ffd6e58SKip Macy if (!is_offload(sc)) 27751ffd6e58SKip Macy return (EOPNOTSUPP); 27761ffd6e58SKip Macy if (sc->flags & FULL_INIT_DONE) 27771ffd6e58SKip Macy return (EBUSY); 27781ffd6e58SKip Macy 27791ffd6e58SKip Macy if (!m->rx_pg_sz || (m->rx_pg_sz & (m->rx_pg_sz - 1)) || 27801ffd6e58SKip Macy !m->tx_pg_sz || (m->tx_pg_sz & (m->tx_pg_sz - 1))) 27811ffd6e58SKip Macy return (EINVAL); /* not power of 2 */ 27821ffd6e58SKip Macy if (!(m->rx_pg_sz & 0x14000)) 27831ffd6e58SKip Macy return (EINVAL); /* not 16KB or 64KB */ 27841ffd6e58SKip Macy if (!(m->tx_pg_sz & 0x1554000)) 27851ffd6e58SKip Macy return (EINVAL); 27861ffd6e58SKip Macy if (m->tx_num_pg == -1) 27871ffd6e58SKip Macy m->tx_num_pg = p->tx_num_pgs; 27881ffd6e58SKip Macy if (m->rx_num_pg == -1) 27891ffd6e58SKip Macy m->rx_num_pg = p->rx_num_pgs; 27901ffd6e58SKip Macy if (m->tx_num_pg % 24 || m->rx_num_pg % 24) 27911ffd6e58SKip Macy return (EINVAL); 27921ffd6e58SKip Macy if (m->rx_num_pg * m->rx_pg_sz > p->chan_rx_size || 27931ffd6e58SKip Macy m->tx_num_pg * m->tx_pg_sz > p->chan_tx_size) 27941ffd6e58SKip Macy return (EINVAL); 27951ffd6e58SKip Macy 27961ffd6e58SKip Macy p->rx_pg_size = m->rx_pg_sz; 27971ffd6e58SKip Macy p->tx_pg_size = m->tx_pg_sz; 27981ffd6e58SKip Macy p->rx_num_pgs = m->rx_num_pg; 27991ffd6e58SKip Macy p->tx_num_pgs = m->tx_num_pg; 28001ffd6e58SKip Macy break; 28011ffd6e58SKip Macy } 2802d722cab4SKip Macy case CHELSIO_SETMTUTAB: { 2803d722cab4SKip Macy struct ch_mtus *m = (struct ch_mtus *)data; 2804d722cab4SKip Macy int i; 2805d722cab4SKip Macy 2806d722cab4SKip Macy if (!is_offload(sc)) 2807d722cab4SKip Macy return (EOPNOTSUPP); 2808d722cab4SKip Macy if (offload_running(sc)) 2809d722cab4SKip Macy return (EBUSY); 2810d722cab4SKip Macy if (m->nmtus != NMTUS) 2811d722cab4SKip Macy return (EINVAL); 2812d722cab4SKip Macy if (m->mtus[0] < 81) /* accommodate SACK */ 2813d722cab4SKip Macy return (EINVAL); 2814d722cab4SKip Macy 2815d722cab4SKip Macy /* 2816d722cab4SKip Macy * MTUs must be in ascending order 2817d722cab4SKip Macy */ 2818d722cab4SKip Macy for (i = 1; i < NMTUS; ++i) 2819d722cab4SKip Macy if (m->mtus[i] < m->mtus[i - 1]) 2820d722cab4SKip Macy return (EINVAL); 2821d722cab4SKip Macy 28221ffd6e58SKip Macy memcpy(sc->params.mtus, m->mtus, sizeof(sc->params.mtus)); 2823d722cab4SKip Macy break; 2824d722cab4SKip Macy } 2825d722cab4SKip Macy case CHELSIO_GETMTUTAB: { 2826d722cab4SKip Macy struct ch_mtus *m = (struct ch_mtus *)data; 2827d722cab4SKip Macy 2828d722cab4SKip Macy if (!is_offload(sc)) 2829d722cab4SKip Macy return (EOPNOTSUPP); 2830d722cab4SKip Macy 2831d722cab4SKip Macy memcpy(m->mtus, sc->params.mtus, sizeof(m->mtus)); 2832d722cab4SKip Macy m->nmtus = NMTUS; 2833d722cab4SKip Macy break; 2834d722cab4SKip Macy } 2835b6d90eb7SKip Macy case CHELSIO_GET_MEM: { 2836b6d90eb7SKip Macy struct ch_mem_range *t = (struct ch_mem_range *)data; 2837b6d90eb7SKip Macy struct mc7 *mem; 2838b6d90eb7SKip Macy uint8_t *useraddr; 2839b6d90eb7SKip Macy u64 buf[32]; 2840b6d90eb7SKip Macy 28411ffd6e58SKip Macy /* 28421ffd6e58SKip Macy * Use these to avoid modifying len/addr in the the return 28431ffd6e58SKip Macy * struct 28441ffd6e58SKip Macy */ 28451ffd6e58SKip Macy uint32_t len = t->len, addr = t->addr; 28461ffd6e58SKip Macy 2847b6d90eb7SKip Macy if (!is_offload(sc)) 2848b6d90eb7SKip Macy return (EOPNOTSUPP); 2849b6d90eb7SKip Macy if (!(sc->flags & FULL_INIT_DONE)) 2850b6d90eb7SKip Macy return (EIO); /* need the memory controllers */ 28511ffd6e58SKip Macy if ((addr & 0x7) || (len & 0x7)) 2852b6d90eb7SKip Macy return (EINVAL); 2853b6d90eb7SKip Macy if (t->mem_id == MEM_CM) 2854b6d90eb7SKip Macy mem = &sc->cm; 2855b6d90eb7SKip Macy else if (t->mem_id == MEM_PMRX) 2856b6d90eb7SKip Macy mem = &sc->pmrx; 2857b6d90eb7SKip Macy else if (t->mem_id == MEM_PMTX) 2858b6d90eb7SKip Macy mem = &sc->pmtx; 2859b6d90eb7SKip Macy else 2860b6d90eb7SKip Macy return (EINVAL); 2861b6d90eb7SKip Macy 2862b6d90eb7SKip Macy /* 2863b6d90eb7SKip Macy * Version scheme: 2864b6d90eb7SKip Macy * bits 0..9: chip version 2865b6d90eb7SKip Macy * bits 10..15: chip revision 2866b6d90eb7SKip Macy */ 2867b6d90eb7SKip Macy t->version = 3 | (sc->params.rev << 10); 2868b6d90eb7SKip Macy 2869b6d90eb7SKip Macy /* 2870b6d90eb7SKip Macy * Read 256 bytes at a time as len can be large and we don't 2871b6d90eb7SKip Macy * want to use huge intermediate buffers. 2872b6d90eb7SKip Macy */ 28738090c9f5SKip Macy useraddr = (uint8_t *)t->buf; 28741ffd6e58SKip Macy while (len) { 28751ffd6e58SKip Macy unsigned int chunk = min(len, sizeof(buf)); 2876b6d90eb7SKip Macy 28771ffd6e58SKip Macy error = t3_mc7_bd_read(mem, addr / 8, chunk / 8, buf); 2878b6d90eb7SKip Macy if (error) 2879b6d90eb7SKip Macy return (-error); 2880b6d90eb7SKip Macy if (copyout(buf, useraddr, chunk)) 2881b6d90eb7SKip Macy return (EFAULT); 2882b6d90eb7SKip Macy useraddr += chunk; 28831ffd6e58SKip Macy addr += chunk; 28841ffd6e58SKip Macy len -= chunk; 2885b6d90eb7SKip Macy } 2886b6d90eb7SKip Macy break; 2887b6d90eb7SKip Macy } 2888d722cab4SKip Macy case CHELSIO_READ_TCAM_WORD: { 2889d722cab4SKip Macy struct ch_tcam_word *t = (struct ch_tcam_word *)data; 2890d722cab4SKip Macy 2891d722cab4SKip Macy if (!is_offload(sc)) 2892d722cab4SKip Macy return (EOPNOTSUPP); 2893ac3a6d9cSKip Macy if (!(sc->flags & FULL_INIT_DONE)) 2894ac3a6d9cSKip Macy return (EIO); /* need MC5 */ 2895d722cab4SKip Macy return -t3_read_mc5_range(&sc->mc5, t->addr, 1, t->buf); 2896d722cab4SKip Macy break; 2897d722cab4SKip Macy } 2898b6d90eb7SKip Macy case CHELSIO_SET_TRACE_FILTER: { 2899b6d90eb7SKip Macy struct ch_trace *t = (struct ch_trace *)data; 2900b6d90eb7SKip Macy const struct trace_params *tp; 2901b6d90eb7SKip Macy 2902b6d90eb7SKip Macy tp = (const struct trace_params *)&t->sip; 2903b6d90eb7SKip Macy if (t->config_tx) 2904b6d90eb7SKip Macy t3_config_trace_filter(sc, tp, 0, t->invert_match, 2905b6d90eb7SKip Macy t->trace_tx); 2906b6d90eb7SKip Macy if (t->config_rx) 2907b6d90eb7SKip Macy t3_config_trace_filter(sc, tp, 1, t->invert_match, 2908b6d90eb7SKip Macy t->trace_rx); 2909b6d90eb7SKip Macy break; 2910b6d90eb7SKip Macy } 2911b6d90eb7SKip Macy case CHELSIO_SET_PKTSCHED: { 2912b6d90eb7SKip Macy struct ch_pktsched_params *p = (struct ch_pktsched_params *)data; 2913b6d90eb7SKip Macy if (sc->open_device_map == 0) 2914b6d90eb7SKip Macy return (EAGAIN); 2915b6d90eb7SKip Macy send_pktsched_cmd(sc, p->sched, p->idx, p->min, p->max, 2916b6d90eb7SKip Macy p->binding); 2917b6d90eb7SKip Macy break; 2918b6d90eb7SKip Macy } 2919b6d90eb7SKip Macy case CHELSIO_IFCONF_GETREGS: { 29201ffd6e58SKip Macy struct ch_ifconf_regs *regs = (struct ch_ifconf_regs *)data; 2921b6d90eb7SKip Macy int reglen = cxgb_get_regs_len(); 29221ffd6e58SKip Macy uint8_t *buf = malloc(reglen, M_DEVBUF, M_NOWAIT); 2923b6d90eb7SKip Macy if (buf == NULL) { 2924b6d90eb7SKip Macy return (ENOMEM); 2925b6d90eb7SKip Macy } 29261ffd6e58SKip Macy if (regs->len > reglen) 29271ffd6e58SKip Macy regs->len = reglen; 29281ffd6e58SKip Macy else if (regs->len < reglen) 2929f2d8ff04SGeorge V. Neville-Neil error = ENOBUFS; 29301ffd6e58SKip Macy 29311ffd6e58SKip Macy if (!error) { 2932b6d90eb7SKip Macy cxgb_get_regs(sc, regs, buf); 2933b6d90eb7SKip Macy error = copyout(buf, regs->data, reglen); 29341ffd6e58SKip Macy } 2935b6d90eb7SKip Macy free(buf, M_DEVBUF); 2936b6d90eb7SKip Macy 2937b6d90eb7SKip Macy break; 2938b6d90eb7SKip Macy } 2939d722cab4SKip Macy case CHELSIO_SET_HW_SCHED: { 2940d722cab4SKip Macy struct ch_hw_sched *t = (struct ch_hw_sched *)data; 2941d722cab4SKip Macy unsigned int ticks_per_usec = core_ticks_per_usec(sc); 2942d722cab4SKip Macy 2943d722cab4SKip Macy if ((sc->flags & FULL_INIT_DONE) == 0) 2944d722cab4SKip Macy return (EAGAIN); /* need TP to be initialized */ 2945d722cab4SKip Macy if (t->sched >= NTX_SCHED || !in_range(t->mode, 0, 1) || 2946d722cab4SKip Macy !in_range(t->channel, 0, 1) || 2947d722cab4SKip Macy !in_range(t->kbps, 0, 10000000) || 2948d722cab4SKip Macy !in_range(t->class_ipg, 0, 10000 * 65535 / ticks_per_usec) || 2949d722cab4SKip Macy !in_range(t->flow_ipg, 0, 2950d722cab4SKip Macy dack_ticks_to_usec(sc, 0x7ff))) 2951d722cab4SKip Macy return (EINVAL); 2952d722cab4SKip Macy 2953d722cab4SKip Macy if (t->kbps >= 0) { 2954d722cab4SKip Macy error = t3_config_sched(sc, t->kbps, t->sched); 2955d722cab4SKip Macy if (error < 0) 2956d722cab4SKip Macy return (-error); 2957d722cab4SKip Macy } 2958d722cab4SKip Macy if (t->class_ipg >= 0) 2959d722cab4SKip Macy t3_set_sched_ipg(sc, t->sched, t->class_ipg); 2960d722cab4SKip Macy if (t->flow_ipg >= 0) { 2961d722cab4SKip Macy t->flow_ipg *= 1000; /* us -> ns */ 2962d722cab4SKip Macy t3_set_pace_tbl(sc, &t->flow_ipg, t->sched, 1); 2963d722cab4SKip Macy } 2964d722cab4SKip Macy if (t->mode >= 0) { 2965d722cab4SKip Macy int bit = 1 << (S_TX_MOD_TIMER_MODE + t->sched); 2966d722cab4SKip Macy 2967d722cab4SKip Macy t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP, 2968d722cab4SKip Macy bit, t->mode ? bit : 0); 2969d722cab4SKip Macy } 2970d722cab4SKip Macy if (t->channel >= 0) 2971d722cab4SKip Macy t3_set_reg_field(sc, A_TP_TX_MOD_QUEUE_REQ_MAP, 2972d722cab4SKip Macy 1 << t->sched, t->channel << t->sched); 2973d722cab4SKip Macy break; 2974d722cab4SKip Macy } 29751ffd6e58SKip Macy case CHELSIO_GET_EEPROM: { 29761ffd6e58SKip Macy int i; 29771ffd6e58SKip Macy struct ch_eeprom *e = (struct ch_eeprom *)data; 29781ffd6e58SKip Macy uint8_t *buf = malloc(EEPROMSIZE, M_DEVBUF, M_NOWAIT); 29791ffd6e58SKip Macy 29801ffd6e58SKip Macy if (buf == NULL) { 29811ffd6e58SKip Macy return (ENOMEM); 29821ffd6e58SKip Macy } 29831ffd6e58SKip Macy e->magic = EEPROM_MAGIC; 29841ffd6e58SKip Macy for (i = e->offset & ~3; !error && i < e->offset + e->len; i += 4) 29851ffd6e58SKip Macy error = -t3_seeprom_read(sc, i, (uint32_t *)&buf[i]); 29861ffd6e58SKip Macy 29871ffd6e58SKip Macy if (!error) 29881ffd6e58SKip Macy error = copyout(buf + e->offset, e->data, e->len); 29891ffd6e58SKip Macy 29901ffd6e58SKip Macy free(buf, M_DEVBUF); 29911ffd6e58SKip Macy break; 29921ffd6e58SKip Macy } 29931ffd6e58SKip Macy case CHELSIO_CLEAR_STATS: { 29941ffd6e58SKip Macy if (!(sc->flags & FULL_INIT_DONE)) 29951ffd6e58SKip Macy return EAGAIN; 29961ffd6e58SKip Macy 29971ffd6e58SKip Macy PORT_LOCK(pi); 29981ffd6e58SKip Macy t3_mac_update_stats(&pi->mac); 29991ffd6e58SKip Macy memset(&pi->mac.stats, 0, sizeof(pi->mac.stats)); 30001ffd6e58SKip Macy PORT_UNLOCK(pi); 30011ffd6e58SKip Macy break; 30021ffd6e58SKip Macy } 3003f2d8ff04SGeorge V. Neville-Neil case CHELSIO_GET_UP_LA: { 3004f2d8ff04SGeorge V. Neville-Neil struct ch_up_la *la = (struct ch_up_la *)data; 3005f2d8ff04SGeorge V. Neville-Neil uint8_t *buf = malloc(LA_BUFSIZE, M_DEVBUF, M_NOWAIT); 3006f2d8ff04SGeorge V. Neville-Neil if (buf == NULL) { 3007f2d8ff04SGeorge V. Neville-Neil return (ENOMEM); 3008f2d8ff04SGeorge V. Neville-Neil } 3009f2d8ff04SGeorge V. Neville-Neil if (la->bufsize < LA_BUFSIZE) 3010f2d8ff04SGeorge V. Neville-Neil error = ENOBUFS; 3011f2d8ff04SGeorge V. Neville-Neil 3012f2d8ff04SGeorge V. Neville-Neil if (!error) 3013f2d8ff04SGeorge V. Neville-Neil error = -t3_get_up_la(sc, &la->stopped, &la->idx, 3014f2d8ff04SGeorge V. Neville-Neil &la->bufsize, buf); 3015f2d8ff04SGeorge V. Neville-Neil if (!error) 3016f2d8ff04SGeorge V. Neville-Neil error = copyout(buf, la->data, la->bufsize); 3017f2d8ff04SGeorge V. Neville-Neil 3018f2d8ff04SGeorge V. Neville-Neil free(buf, M_DEVBUF); 3019f2d8ff04SGeorge V. Neville-Neil break; 3020f2d8ff04SGeorge V. Neville-Neil } 3021f2d8ff04SGeorge V. Neville-Neil case CHELSIO_GET_UP_IOQS: { 3022f2d8ff04SGeorge V. Neville-Neil struct ch_up_ioqs *ioqs = (struct ch_up_ioqs *)data; 3023f2d8ff04SGeorge V. Neville-Neil uint8_t *buf = malloc(IOQS_BUFSIZE, M_DEVBUF, M_NOWAIT); 3024f2d8ff04SGeorge V. Neville-Neil uint32_t *v; 3025f2d8ff04SGeorge V. Neville-Neil 3026f2d8ff04SGeorge V. Neville-Neil if (buf == NULL) { 3027f2d8ff04SGeorge V. Neville-Neil return (ENOMEM); 3028f2d8ff04SGeorge V. Neville-Neil } 3029f2d8ff04SGeorge V. Neville-Neil if (ioqs->bufsize < IOQS_BUFSIZE) 3030f2d8ff04SGeorge V. Neville-Neil error = ENOBUFS; 3031f2d8ff04SGeorge V. Neville-Neil 3032f2d8ff04SGeorge V. Neville-Neil if (!error) 3033f2d8ff04SGeorge V. Neville-Neil error = -t3_get_up_ioqs(sc, &ioqs->bufsize, buf); 3034f2d8ff04SGeorge V. Neville-Neil 3035f2d8ff04SGeorge V. Neville-Neil if (!error) { 3036f2d8ff04SGeorge V. Neville-Neil v = (uint32_t *)buf; 3037f2d8ff04SGeorge V. Neville-Neil 3038f2d8ff04SGeorge V. Neville-Neil ioqs->bufsize -= 4 * sizeof(uint32_t); 3039f2d8ff04SGeorge V. Neville-Neil ioqs->ioq_rx_enable = *v++; 3040f2d8ff04SGeorge V. Neville-Neil ioqs->ioq_tx_enable = *v++; 3041f2d8ff04SGeorge V. Neville-Neil ioqs->ioq_rx_status = *v++; 3042f2d8ff04SGeorge V. Neville-Neil ioqs->ioq_tx_status = *v++; 3043f2d8ff04SGeorge V. Neville-Neil 3044f2d8ff04SGeorge V. Neville-Neil error = copyout(v, ioqs->data, ioqs->bufsize); 3045f2d8ff04SGeorge V. Neville-Neil } 3046f2d8ff04SGeorge V. Neville-Neil 3047f2d8ff04SGeorge V. Neville-Neil free(buf, M_DEVBUF); 3048f2d8ff04SGeorge V. Neville-Neil break; 3049f2d8ff04SGeorge V. Neville-Neil } 3050b6d90eb7SKip Macy default: 3051b6d90eb7SKip Macy return (EOPNOTSUPP); 3052b6d90eb7SKip Macy break; 3053b6d90eb7SKip Macy } 3054b6d90eb7SKip Macy 3055b6d90eb7SKip Macy return (error); 3056b6d90eb7SKip Macy } 3057b6d90eb7SKip Macy 3058b6d90eb7SKip Macy static __inline void 3059b6d90eb7SKip Macy reg_block_dump(struct adapter *ap, uint8_t *buf, unsigned int start, 3060b6d90eb7SKip Macy unsigned int end) 3061b6d90eb7SKip Macy { 30621ffd6e58SKip Macy uint32_t *p = (uint32_t *)(buf + start); 3063b6d90eb7SKip Macy 3064b6d90eb7SKip Macy for ( ; start <= end; start += sizeof(uint32_t)) 3065b6d90eb7SKip Macy *p++ = t3_read_reg(ap, start); 3066b6d90eb7SKip Macy } 3067b6d90eb7SKip Macy 3068b6d90eb7SKip Macy #define T3_REGMAP_SIZE (3 * 1024) 3069b6d90eb7SKip Macy static int 3070b6d90eb7SKip Macy cxgb_get_regs_len(void) 3071b6d90eb7SKip Macy { 3072b6d90eb7SKip Macy return T3_REGMAP_SIZE; 3073b6d90eb7SKip Macy } 3074b6d90eb7SKip Macy 3075b6d90eb7SKip Macy static void 30761ffd6e58SKip Macy cxgb_get_regs(adapter_t *sc, struct ch_ifconf_regs *regs, uint8_t *buf) 3077b6d90eb7SKip Macy { 3078b6d90eb7SKip Macy 3079b6d90eb7SKip Macy /* 3080b6d90eb7SKip Macy * Version scheme: 3081b6d90eb7SKip Macy * bits 0..9: chip version 3082b6d90eb7SKip Macy * bits 10..15: chip revision 3083b6d90eb7SKip Macy * bit 31: set for PCIe cards 3084b6d90eb7SKip Macy */ 3085b6d90eb7SKip Macy regs->version = 3 | (sc->params.rev << 10) | (is_pcie(sc) << 31); 3086b6d90eb7SKip Macy 3087b6d90eb7SKip Macy /* 3088b6d90eb7SKip Macy * We skip the MAC statistics registers because they are clear-on-read. 3089b6d90eb7SKip Macy * Also reading multi-register stats would need to synchronize with the 3090b6d90eb7SKip Macy * periodic mac stats accumulation. Hard to justify the complexity. 3091b6d90eb7SKip Macy */ 30921ffd6e58SKip Macy memset(buf, 0, cxgb_get_regs_len()); 3093b6d90eb7SKip Macy reg_block_dump(sc, buf, 0, A_SG_RSPQ_CREDIT_RETURN); 3094b6d90eb7SKip Macy reg_block_dump(sc, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT); 3095b6d90eb7SKip Macy reg_block_dump(sc, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE); 3096b6d90eb7SKip Macy reg_block_dump(sc, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA); 3097b6d90eb7SKip Macy reg_block_dump(sc, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3); 3098b6d90eb7SKip Macy reg_block_dump(sc, buf, A_XGM_SERDES_STATUS0, 3099b6d90eb7SKip Macy XGM_REG(A_XGM_SERDES_STAT3, 1)); 3100b6d90eb7SKip Macy reg_block_dump(sc, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1), 3101b6d90eb7SKip Macy XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1)); 3102b6d90eb7SKip Macy } 3103404825a7SKip Macy 3104404825a7SKip Macy 3105404825a7SKip Macy MODULE_DEPEND(if_cxgb, cxgb_t3fw, 1, 1, 1); 3106