1d39a76e7Sxw /* 2d39a76e7Sxw * CDDL HEADER START 3d39a76e7Sxw * 4d39a76e7Sxw * The contents of this file are subject to the terms of the 5d39a76e7Sxw * Common Development and Distribution License (the "License"). 6d39a76e7Sxw * You may not use this file except in compliance with the License. 7d39a76e7Sxw * 8d39a76e7Sxw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9d39a76e7Sxw * or http://www.opensolaris.org/os/licensing. 10d39a76e7Sxw * See the License for the specific language governing permissions 11d39a76e7Sxw * and limitations under the License. 12d39a76e7Sxw * 13d39a76e7Sxw * When distributing Covered Code, include this CDDL HEADER in each 14d39a76e7Sxw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15d39a76e7Sxw * If applicable, add the following below this CDDL HEADER, with the 16d39a76e7Sxw * fields enclosed by brackets "[]" replaced with your own identifying 17d39a76e7Sxw * information: Portions Copyright [yyyy] [name of copyright owner] 18d39a76e7Sxw * 19d39a76e7Sxw * CDDL HEADER END 20d39a76e7Sxw */ 21d39a76e7Sxw 22d39a76e7Sxw /* 2319397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24d39a76e7Sxw * Use is subject to license terms. 25d39a76e7Sxw */ 26d39a76e7Sxw 27d39a76e7Sxw /* 28d39a76e7Sxw * This file is part of the Chelsio T1 Ethernet driver. 29d39a76e7Sxw * 30d39a76e7Sxw * Copyright (C) 2003-2005 Chelsio Communications. All rights reserved. 31d39a76e7Sxw */ 32d39a76e7Sxw 33d39a76e7Sxw /* 34d39a76e7Sxw * Solaris Multithreaded STREAMS DLPI Chelsio PCI Ethernet Driver 35d39a76e7Sxw */ 36d39a76e7Sxw 37d39a76e7Sxw /* #define CH_DEBUG 1 */ 38d39a76e7Sxw #ifdef CH_DEBUG 39d39a76e7Sxw #define DEBUG_ENTER(a) debug_enter(a) 40d39a76e7Sxw #define PRINT(a) printf a 41d39a76e7Sxw #else 42d39a76e7Sxw #define DEBUG_ENTER(a) 43d39a76e7Sxw #define PRINT(a) 44d39a76e7Sxw #endif 45d39a76e7Sxw 46d39a76e7Sxw #include <sys/types.h> 47d39a76e7Sxw #include <sys/conf.h> 48d39a76e7Sxw #include <sys/debug.h> 49d39a76e7Sxw #include <sys/stropts.h> 50d39a76e7Sxw #include <sys/stream.h> 51d39a76e7Sxw #include <sys/strlog.h> 52d39a76e7Sxw #include <sys/kmem.h> 53d39a76e7Sxw #include <sys/stat.h> 54d39a76e7Sxw #include <sys/kstat.h> 55d39a76e7Sxw #include <sys/modctl.h> 56d39a76e7Sxw #include <sys/errno.h> 57d39a76e7Sxw #include <sys/cmn_err.h> 58d39a76e7Sxw #include <sys/ddi.h> 59d39a76e7Sxw #include <sys/sunddi.h> 60d39a76e7Sxw #include <sys/dlpi.h> 61d39a76e7Sxw #include <sys/ethernet.h> 62d39a76e7Sxw #include <sys/strsun.h> 63d39a76e7Sxw #include <sys/strsubr.h> 64d39a76e7Sxw #include <inet/common.h> 65d39a76e7Sxw #include <inet/nd.h> 66d39a76e7Sxw #include <inet/ip.h> 67d39a76e7Sxw #include <inet/tcp.h> 68d39a76e7Sxw #include <sys/pattr.h> 69d39a76e7Sxw #include <sys/gld.h> 70d39a76e7Sxw #include "ostypes.h" 71d39a76e7Sxw #include "common.h" 72d39a76e7Sxw #include "oschtoe.h" 73d39a76e7Sxw #include "sge.h" 7419397407SSherry Moore #include "regs.h" 75d39a76e7Sxw #include "ch.h" /* Chelsio Driver specific parameters */ 76d39a76e7Sxw #include "version.h" 77d39a76e7Sxw 78d39a76e7Sxw /* 79d39a76e7Sxw * Function prototypes. 80d39a76e7Sxw */ 81d39a76e7Sxw static int ch_attach(dev_info_t *, ddi_attach_cmd_t); 82d39a76e7Sxw static int ch_detach(dev_info_t *, ddi_detach_cmd_t); 8319397407SSherry Moore static int ch_quiesce(dev_info_t *); 84d39a76e7Sxw static void ch_free_dma_handles(ch_t *chp); 85d39a76e7Sxw static void ch_set_name(ch_t *chp, int unit); 86d39a76e7Sxw static void ch_free_name(ch_t *chp); 87d39a76e7Sxw static void ch_get_prop(ch_t *chp); 88d39a76e7Sxw 89d39a76e7Sxw #if defined(__sparc) 90d39a76e7Sxw static void ch_free_dvma_handles(ch_t *chp); 91d39a76e7Sxw #endif 92d39a76e7Sxw 93d39a76e7Sxw /* GLD interfaces */ 94d39a76e7Sxw static int ch_reset(gld_mac_info_t *); 95d39a76e7Sxw static int ch_start(gld_mac_info_t *); 96d39a76e7Sxw static int ch_stop(gld_mac_info_t *); 97d39a76e7Sxw static int ch_set_mac_address(gld_mac_info_t *, uint8_t *); 98d39a76e7Sxw static int ch_set_multicast(gld_mac_info_t *, uint8_t *, int); 99d39a76e7Sxw static int ch_ioctl(gld_mac_info_t *, queue_t *, mblk_t *); 100d39a76e7Sxw static int ch_set_promiscuous(gld_mac_info_t *, int); 101d39a76e7Sxw static int ch_get_stats(gld_mac_info_t *, struct gld_stats *); 102d39a76e7Sxw static int ch_send(gld_mac_info_t *, mblk_t *); 103d39a76e7Sxw static uint_t ch_intr(gld_mac_info_t *); 104d39a76e7Sxw 105d39a76e7Sxw /* 106d39a76e7Sxw * Data access requirements. 107d39a76e7Sxw */ 108d39a76e7Sxw static struct ddi_device_acc_attr le_attr = { 109d39a76e7Sxw DDI_DEVICE_ATTR_V0, 110d39a76e7Sxw DDI_STRUCTURE_LE_ACC, 111d39a76e7Sxw DDI_STRICTORDER_ACC 112d39a76e7Sxw }; 113d39a76e7Sxw 114d39a76e7Sxw /* 115d39a76e7Sxw * No swap mapping device attributes 116d39a76e7Sxw */ 117d39a76e7Sxw static struct ddi_device_acc_attr null_attr = { 118d39a76e7Sxw DDI_DEVICE_ATTR_V0, 119d39a76e7Sxw DDI_NEVERSWAP_ACC, 120d39a76e7Sxw DDI_STRICTORDER_ACC 121d39a76e7Sxw }; 122d39a76e7Sxw 123d39a76e7Sxw /* 124d39a76e7Sxw * STREAMS driver identification struture module_info(9s) 125d39a76e7Sxw * 126d39a76e7Sxw * driver limit values 127d39a76e7Sxw */ 128d39a76e7Sxw 129d39a76e7Sxw static struct module_info ch_minfo = { 130d39a76e7Sxw CHIDNUM, /* mi_idnum */ 131d39a76e7Sxw CHNAME, /* mi_idname */ 132d39a76e7Sxw CHMINPSZ, /* mi_minpsz */ 133d39a76e7Sxw CHMAXPSZ, /* mi_maxpsz */ 134d39a76e7Sxw CHHIWAT, /* mi_hiwat */ 135d39a76e7Sxw CHLOWAT /* mi_lowat */ 136d39a76e7Sxw }; 137d39a76e7Sxw 138d39a76e7Sxw /* 139d39a76e7Sxw * STREAMS queue processiong procedures qinit(9s) 140d39a76e7Sxw * 141d39a76e7Sxw * read queue procedures 142d39a76e7Sxw */ 143d39a76e7Sxw 144d39a76e7Sxw static struct qinit ch_rinit = { 145d39a76e7Sxw (int (*)()) NULL, /* qi_putp */ 146d39a76e7Sxw gld_rsrv, /* qi_srvp */ 147d39a76e7Sxw gld_open, /* qi_qopen */ 148d39a76e7Sxw gld_close, /* qi_qclose */ 149d39a76e7Sxw (int (*)()) NULL, /* qi_qadmin */ 150d39a76e7Sxw &ch_minfo, /* qi_minfo */ 151d39a76e7Sxw NULL /* qi_mstat */ 152d39a76e7Sxw }; 153d39a76e7Sxw 154d39a76e7Sxw /* 155d39a76e7Sxw * STREAMS queue processiong procedures qinit(9s) 156d39a76e7Sxw * 157d39a76e7Sxw * write queue procedures 158d39a76e7Sxw */ 159d39a76e7Sxw 160d39a76e7Sxw static struct qinit ch_winit = { 161d39a76e7Sxw gld_wput, /* qi_putp */ 162d39a76e7Sxw gld_wsrv, /* qi_srvp */ 163d39a76e7Sxw (int (*)()) NULL, /* qi_qopen */ 164d39a76e7Sxw (int (*)()) NULL, /* qi_qclose */ 165d39a76e7Sxw (int (*)()) NULL, /* qi_qadmin */ 166d39a76e7Sxw &ch_minfo, /* qi_minfo */ 167d39a76e7Sxw NULL /* qi_mstat */ 168d39a76e7Sxw }; 169d39a76e7Sxw 170d39a76e7Sxw /* 171d39a76e7Sxw * STREAMS entity declaration structure - streamtab(9s) 172d39a76e7Sxw */ 173d39a76e7Sxw static struct streamtab chinfo = { 174d39a76e7Sxw &ch_rinit, /* read queue information */ 175d39a76e7Sxw &ch_winit, /* write queue information */ 176d39a76e7Sxw NULL, /* st_muxrinit */ 177d39a76e7Sxw NULL /* st_muxwrinit */ 178d39a76e7Sxw }; 179d39a76e7Sxw 180d39a76e7Sxw /* 181d39a76e7Sxw * Device driver ops vector - cb_ops(9s) 182d39a76e7Sxw * 183d39a76e7Sxw * charater/block entry points structure. 184d39a76e7Sxw * chinfo identifies driver as a STREAMS driver. 185d39a76e7Sxw */ 186d39a76e7Sxw 187d39a76e7Sxw static struct cb_ops cb_ch_ops = { 188d39a76e7Sxw nulldev, /* cb_open */ 189d39a76e7Sxw nulldev, /* cb_close */ 190d39a76e7Sxw nodev, /* cb_strategy */ 191d39a76e7Sxw nodev, /* cb_print */ 192d39a76e7Sxw nodev, /* cb_dump */ 193d39a76e7Sxw nodev, /* cb_read */ 194d39a76e7Sxw nodev, /* cb_write */ 195d39a76e7Sxw nodev, /* cb_ioctl */ 196d39a76e7Sxw nodev, /* cb_devmap */ 197d39a76e7Sxw nodev, /* cb_mmap */ 198d39a76e7Sxw nodev, /* cb_segmap */ 199d39a76e7Sxw nochpoll, /* cb_chpoll */ 200d39a76e7Sxw ddi_prop_op, /* report driver property information - prop_op(9e) */ 201d39a76e7Sxw &chinfo, /* cb_stream */ 202d39a76e7Sxw #if defined(__sparc) 203d39a76e7Sxw D_MP | D_64BIT, 204d39a76e7Sxw #else 205d39a76e7Sxw D_MP, /* cb_flag (supports multi-threading) */ 206d39a76e7Sxw #endif 207d39a76e7Sxw CB_REV, /* cb_rev */ 208d39a76e7Sxw nodev, /* cb_aread */ 209d39a76e7Sxw nodev /* cb_awrite */ 210d39a76e7Sxw }; 211d39a76e7Sxw 212d39a76e7Sxw /* 213d39a76e7Sxw * dev_ops(9S) structure 214d39a76e7Sxw * 215d39a76e7Sxw * Device Operations table, for autoconfiguration 216d39a76e7Sxw */ 217d39a76e7Sxw 218d39a76e7Sxw static struct dev_ops ch_ops = { 219d39a76e7Sxw DEVO_REV, /* Driver build version */ 220d39a76e7Sxw 0, /* Initial driver reference count */ 221d39a76e7Sxw gld_getinfo, /* funcp: get driver information - getinfo(9e) */ 222d39a76e7Sxw nulldev, /* funcp: entry point obsolute - identify(9e) */ 223d39a76e7Sxw nulldev, /* funp: probe for device - probe(9e) */ 224d39a76e7Sxw ch_attach, /* funp: attach driver to dev_info - attach(9e) */ 225d39a76e7Sxw ch_detach, /* funp: detach driver to unload - detach(9e) */ 226d39a76e7Sxw nodev, /* funp: reset device (not supported) - dev_ops(9s) */ 227d39a76e7Sxw &cb_ch_ops, /* ptr to cb_ops structure */ 228d39a76e7Sxw NULL, /* ptr to nexus bus operations structure (leaf) */ 22919397407SSherry Moore NULL, /* funp: change device power level - power(9e) */ 23019397407SSherry Moore ch_quiesce, /* devo_quiesce */ 231d39a76e7Sxw }; 232d39a76e7Sxw 233d39a76e7Sxw /* 234d39a76e7Sxw * modldrv(9s) structure 235d39a76e7Sxw * 236d39a76e7Sxw * Definition for module specific device driver linkage structures (modctl.h) 237d39a76e7Sxw */ 238d39a76e7Sxw 239d39a76e7Sxw static struct modldrv modldrv = { 240d39a76e7Sxw &mod_driverops, /* driver module */ 241d39a76e7Sxw VERSION, 242d39a76e7Sxw &ch_ops, /* driver ops */ 243d39a76e7Sxw }; 244d39a76e7Sxw 245d39a76e7Sxw /* 246d39a76e7Sxw * modlinkage(9s) structure 247d39a76e7Sxw * 248d39a76e7Sxw * module linkage base structure (modctl.h) 249d39a76e7Sxw */ 250d39a76e7Sxw 251d39a76e7Sxw static struct modlinkage modlinkage = { 252d39a76e7Sxw MODREV_1, /* revision # of system */ 253d39a76e7Sxw &modldrv, /* NULL terminated list of linkage strucures */ 254d39a76e7Sxw NULL 255d39a76e7Sxw }; 256d39a76e7Sxw 257d39a76e7Sxw /* ===================== start of STREAMS driver code ================== */ 258d39a76e7Sxw 259d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD 260d39a76e7Sxw /* 261d39a76e7Sxw * global pointer to toe per-driver control structure. 262d39a76e7Sxw */ 263d39a76e7Sxw #define MAX_CARDS 4 264d39a76e7Sxw ch_t *gchp[MAX_CARDS]; 265d39a76e7Sxw #endif 266d39a76e7Sxw 267d39a76e7Sxw kmutex_t in_use_l; 268d39a76e7Sxw uint32_t buffers_in_use[SZ_INUSE]; 269d39a76e7Sxw uint32_t in_use_index; 270d39a76e7Sxw 271d39a76e7Sxw /* 272d39a76e7Sxw * Ethernet broadcast address definition. 273d39a76e7Sxw */ 274d39a76e7Sxw static struct ether_addr etherbroadcastaddr = { 275d39a76e7Sxw 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 276d39a76e7Sxw }; 277d39a76e7Sxw 278d39a76e7Sxw /* 279d39a76e7Sxw * Module initialization functions. 280d39a76e7Sxw * 281d39a76e7Sxw * Routine Called by 282d39a76e7Sxw * _init(9E) modload(9F) 283d39a76e7Sxw * _info(9E) modinfo(9F) 284d39a76e7Sxw * _fini(9E) modunload(9F) 285d39a76e7Sxw */ 286d39a76e7Sxw 287d39a76e7Sxw /* 288d39a76e7Sxw * _init(9E): 289d39a76e7Sxw * 290d39a76e7Sxw * Initial, one-time, resource allocation and data initialization. 291d39a76e7Sxw */ 292d39a76e7Sxw 293d39a76e7Sxw int 294d39a76e7Sxw _init(void) 295d39a76e7Sxw { 296d39a76e7Sxw int status; 297d39a76e7Sxw 298d39a76e7Sxw status = mod_install(&modlinkage); 299d39a76e7Sxw 300d39a76e7Sxw mutex_init(&in_use_l, NULL, MUTEX_DRIVER, NULL); 301d39a76e7Sxw 302d39a76e7Sxw return (status); 303d39a76e7Sxw } 304d39a76e7Sxw 305d39a76e7Sxw /* 306d39a76e7Sxw * _fini(9E): It is here that any device information that was allocated 307d39a76e7Sxw * during the _init(9E) routine should be released and the module removed 308d39a76e7Sxw * from the system. In the case of per-instance information, that information 309d39a76e7Sxw * should be released in the _detach(9E) routine. 310d39a76e7Sxw */ 311d39a76e7Sxw 312d39a76e7Sxw int 313d39a76e7Sxw _fini(void) 314d39a76e7Sxw { 315d39a76e7Sxw int status; 316d39a76e7Sxw int i; 317d39a76e7Sxw uint32_t t = 0; 318d39a76e7Sxw 319d39a76e7Sxw for (i = 0; i < SZ_INUSE; i++) 320d39a76e7Sxw t += buffers_in_use[i]; 321d39a76e7Sxw 322*11abda1eSToomas Soome if (t != 0) 323d39a76e7Sxw return (DDI_FAILURE); 324d39a76e7Sxw 325d39a76e7Sxw status = mod_remove(&modlinkage); 326d39a76e7Sxw 327d39a76e7Sxw if (status == DDI_SUCCESS) 328d39a76e7Sxw mutex_destroy(&in_use_l); 329d39a76e7Sxw 330d39a76e7Sxw return (status); 331d39a76e7Sxw } 332d39a76e7Sxw 333d39a76e7Sxw int 334d39a76e7Sxw _info(struct modinfo *modinfop) 335d39a76e7Sxw { 336d39a76e7Sxw int status; 337d39a76e7Sxw 338d39a76e7Sxw 339d39a76e7Sxw status = mod_info(&modlinkage, modinfop); 340d39a76e7Sxw 341d39a76e7Sxw return (status); 342d39a76e7Sxw } 343d39a76e7Sxw 344d39a76e7Sxw /* 345d39a76e7Sxw * Attach(9E) - This is called on the open to the device. It creates 346d39a76e7Sxw * an instance of the driver. In this routine we create the minor 347d39a76e7Sxw * device node. The routine also initializes all per-unit 348d39a76e7Sxw * mutex's and conditional variables. 349d39a76e7Sxw * 350d39a76e7Sxw * If we were resuming a suspended instance of a device due to power 351d39a76e7Sxw * management, then that would be handled here as well. For more on 352d39a76e7Sxw * that subject see the man page for pm(9E) 353d39a76e7Sxw * 354d39a76e7Sxw * Interface exists: make available by filling in network interface 355d39a76e7Sxw * record. System will initialize the interface when it is ready 356d39a76e7Sxw * to accept packets. 357d39a76e7Sxw */ 358d39a76e7Sxw int chdebug = 0; 359d39a76e7Sxw int ch_abort_debug = 0; 360d39a76e7Sxw 361d39a76e7Sxw static int 362d39a76e7Sxw ch_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 363d39a76e7Sxw { 364d39a76e7Sxw ch_t *chp; 365d39a76e7Sxw int rv; 366d39a76e7Sxw int unit; 367d39a76e7Sxw #ifdef CH_DEBUG 368d39a76e7Sxw int Version; 369d39a76e7Sxw int VendorID; 370d39a76e7Sxw int DeviceID; 371d39a76e7Sxw int SubDeviceID; 372d39a76e7Sxw int Command; 373d39a76e7Sxw #endif 374d39a76e7Sxw gld_mac_info_t *macinfo; /* GLD stuff follows */ 375d39a76e7Sxw char *driver; 376d39a76e7Sxw 377d39a76e7Sxw if (ch_abort_debug) 378d39a76e7Sxw debug_enter("ch_attach"); 379d39a76e7Sxw 380d39a76e7Sxw if (chdebug) 381d39a76e7Sxw return (DDI_FAILURE); 382d39a76e7Sxw 383d39a76e7Sxw 384d39a76e7Sxw if (cmd == DDI_ATTACH) { 385d39a76e7Sxw 386d39a76e7Sxw unit = ddi_get_instance(dip); 387d39a76e7Sxw 388d39a76e7Sxw driver = (char *)ddi_driver_name(dip); 389d39a76e7Sxw 390d39a76e7Sxw PRINT(("driver %s unit: %d\n", driver, unit)); 391d39a76e7Sxw 392d39a76e7Sxw macinfo = gld_mac_alloc(dip); 393d39a76e7Sxw if (macinfo == NULL) { 394d39a76e7Sxw PRINT(("macinfo allocation failed\n")); 395d39a76e7Sxw DEBUG_ENTER("ch_attach"); 396d39a76e7Sxw return (DDI_FAILURE); 397d39a76e7Sxw } 398d39a76e7Sxw 399d39a76e7Sxw chp = (ch_t *)kmem_zalloc(sizeof (ch_t), KM_SLEEP); 400d39a76e7Sxw 401d39a76e7Sxw if (chp == NULL) { 402d39a76e7Sxw PRINT(("zalloc of chp failed\n")); 403d39a76e7Sxw DEBUG_ENTER("ch_attach"); 404d39a76e7Sxw 405d39a76e7Sxw gld_mac_free(macinfo); 406d39a76e7Sxw 407d39a76e7Sxw return (DDI_FAILURE); 408d39a76e7Sxw } 409d39a76e7Sxw 410d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD 411d39a76e7Sxw /* Solaris TOE support */ 412d39a76e7Sxw gchp[unit] = chp; 413d39a76e7Sxw #endif 414d39a76e7Sxw 415d39a76e7Sxw PRINT(("attach macinfo: %p chp: %p\n", macinfo, chp)); 416d39a76e7Sxw 417d39a76e7Sxw chp->ch_dip = dip; 418d39a76e7Sxw chp->ch_macp = macinfo; 419d39a76e7Sxw chp->ch_unit = unit; 420d39a76e7Sxw ch_set_name(chp, unit); 421d39a76e7Sxw 422d39a76e7Sxw /* 423d39a76e7Sxw * map in PCI register spaces 424d39a76e7Sxw * 425d39a76e7Sxw * PCI register set 0 - PCI configuration space 426d39a76e7Sxw * PCI register set 1 - T101 card register space #1 427d39a76e7Sxw */ 428d39a76e7Sxw 429d39a76e7Sxw /* map in T101 PCI configuration space */ 430d39a76e7Sxw rv = pci_config_setup( 43119397407SSherry Moore dip, /* ptr to dev's dev_info struct */ 43219397407SSherry Moore &chp->ch_hpci); /* ptr to data access handle */ 433d39a76e7Sxw 434d39a76e7Sxw if (rv != DDI_SUCCESS) { 435d39a76e7Sxw PRINT(("PCI config setup failed\n")); 436d39a76e7Sxw DEBUG_ENTER("ch_attach"); 437d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD 438d39a76e7Sxw gchp[unit] = NULL; 439d39a76e7Sxw #endif 440d39a76e7Sxw cmn_err(CE_WARN, "%s: ddi_config_setup PCI error %d\n", 44119397407SSherry Moore chp->ch_name, rv); 442d39a76e7Sxw 443d39a76e7Sxw ch_free_name(chp); 444d39a76e7Sxw kmem_free(chp, sizeof (ch_t)); 445d39a76e7Sxw gld_mac_free(macinfo); 446d39a76e7Sxw 447d39a76e7Sxw return (DDI_FAILURE); 448d39a76e7Sxw } 449d39a76e7Sxw 450d39a76e7Sxw ch_get_prop(chp); 451d39a76e7Sxw 452d39a76e7Sxw macinfo->gldm_devinfo = dip; 453d39a76e7Sxw macinfo->gldm_private = (caddr_t)chp; 454d39a76e7Sxw macinfo->gldm_reset = ch_reset; 455d39a76e7Sxw macinfo->gldm_start = ch_start; 456d39a76e7Sxw macinfo->gldm_stop = ch_stop; 457d39a76e7Sxw macinfo->gldm_set_mac_addr = ch_set_mac_address; 458d39a76e7Sxw macinfo->gldm_send = ch_send; 459d39a76e7Sxw macinfo->gldm_set_promiscuous = ch_set_promiscuous; 460d39a76e7Sxw macinfo->gldm_get_stats = ch_get_stats; 461d39a76e7Sxw macinfo->gldm_ioctl = ch_ioctl; 462d39a76e7Sxw macinfo->gldm_set_multicast = ch_set_multicast; 463d39a76e7Sxw macinfo->gldm_intr = ch_intr; 464d39a76e7Sxw macinfo->gldm_mctl = NULL; 465d39a76e7Sxw 466d39a76e7Sxw macinfo->gldm_ident = driver; 467d39a76e7Sxw macinfo->gldm_type = DL_ETHER; 468d39a76e7Sxw macinfo->gldm_minpkt = 0; 469d39a76e7Sxw macinfo->gldm_maxpkt = chp->ch_mtu; 470d39a76e7Sxw macinfo->gldm_addrlen = ETHERADDRL; 471d39a76e7Sxw macinfo->gldm_saplen = -2; 472d39a76e7Sxw macinfo->gldm_ppa = unit; 473d39a76e7Sxw macinfo->gldm_broadcast_addr = 47419397407SSherry Moore etherbroadcastaddr.ether_addr_octet; 475d39a76e7Sxw 476d39a76e7Sxw 477d39a76e7Sxw /* 478d39a76e7Sxw * do a power reset of card 479d39a76e7Sxw * 480d39a76e7Sxw * 1. set PwrState to D3hot (3) 481d39a76e7Sxw * 2. clear PwrState flags 482d39a76e7Sxw */ 483d39a76e7Sxw pci_config_put32(chp->ch_hpci, 0x44, 3); 484d39a76e7Sxw pci_config_put32(chp->ch_hpci, 0x44, 0); 485d39a76e7Sxw 486d39a76e7Sxw /* delay .5 sec */ 487d39a76e7Sxw DELAY(500000); 488d39a76e7Sxw 489d39a76e7Sxw #ifdef CH_DEBUG 490d39a76e7Sxw VendorID = pci_config_get16(chp->ch_hpci, 0); 491d39a76e7Sxw DeviceID = pci_config_get16(chp->ch_hpci, 2); 492d39a76e7Sxw SubDeviceID = pci_config_get16(chp->ch_hpci, 0x2e); 493d39a76e7Sxw Command = pci_config_get16(chp->ch_hpci, 4); 494d39a76e7Sxw 495d39a76e7Sxw PRINT(("IDs: %x,%x,%x\n", VendorID, DeviceID, SubDeviceID)); 496d39a76e7Sxw PRINT(("Command: %x\n", Command)); 497d39a76e7Sxw #endif 498d39a76e7Sxw /* map in T101 register space (BAR0) */ 499d39a76e7Sxw rv = ddi_regs_map_setup( 50019397407SSherry Moore dip, /* ptr to dev's dev_info struct */ 50119397407SSherry Moore BAR0, /* register address space */ 50219397407SSherry Moore &chp->ch_bar0, /* address of offset */ 50319397407SSherry Moore 0, /* offset into register address space */ 50419397407SSherry Moore 0, /* length mapped (everything) */ 50519397407SSherry Moore &le_attr, /* ptr to device attr structure */ 50619397407SSherry Moore &chp->ch_hbar0); /* ptr to data access handle */ 507d39a76e7Sxw 508d39a76e7Sxw if (rv != DDI_SUCCESS) { 509d39a76e7Sxw PRINT(("map registers failed\n")); 510d39a76e7Sxw DEBUG_ENTER("ch_attach"); 511d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD 512d39a76e7Sxw gchp[unit] = NULL; 513d39a76e7Sxw #endif 514d39a76e7Sxw cmn_err(CE_WARN, 51519397407SSherry Moore "%s: ddi_regs_map_setup BAR0 error %d\n", 51619397407SSherry Moore chp->ch_name, rv); 517d39a76e7Sxw 518d39a76e7Sxw pci_config_teardown(&chp->ch_hpci); 519d39a76e7Sxw ch_free_name(chp); 520d39a76e7Sxw kmem_free(chp, sizeof (ch_t)); 521d39a76e7Sxw gld_mac_free(macinfo); 522d39a76e7Sxw 523d39a76e7Sxw return (DDI_FAILURE); 524d39a76e7Sxw } 525d39a76e7Sxw 526d39a76e7Sxw #ifdef CH_DEBUG 527d39a76e7Sxw Version = ddi_get32(chp->ch_hbar0, 52819397407SSherry Moore (uint32_t *)(chp->ch_bar0+0x6c)); 529d39a76e7Sxw #endif 530d39a76e7Sxw 531d39a76e7Sxw (void) ddi_dev_regsize(dip, 1, &chp->ch_bar0sz); 532d39a76e7Sxw 533d39a76e7Sxw PRINT(("PCI BAR0 space addr: %p\n", chp->ch_bar0)); 534d39a76e7Sxw PRINT(("PCI BAR0 space size: %x\n", chp->ch_bar0sz)); 535d39a76e7Sxw PRINT(("PE Version: %x\n", Version)); 536d39a76e7Sxw 537d39a76e7Sxw /* 538d39a76e7Sxw * Add interrupt to system. 539d39a76e7Sxw */ 540d39a76e7Sxw rv = ddi_get_iblock_cookie( 54119397407SSherry Moore dip, /* ptr to dev's dev_info struct */ 54219397407SSherry Moore 0, /* interrupt # (0) */ 54319397407SSherry Moore &chp->ch_icookp); /* ptr to interrupt block cookie */ 544d39a76e7Sxw 545d39a76e7Sxw if (rv != DDI_SUCCESS) { 546d39a76e7Sxw PRINT(("iblock cookie failed\n")); 547d39a76e7Sxw DEBUG_ENTER("ch_attach"); 548d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD 549d39a76e7Sxw gchp[unit] = NULL; 550d39a76e7Sxw #endif 551d39a76e7Sxw cmn_err(CE_WARN, 55219397407SSherry Moore "%s: ddi_get_iblock_cookie error %d\n", 55319397407SSherry Moore chp->ch_name, rv); 554d39a76e7Sxw 555d39a76e7Sxw ddi_regs_map_free(&chp->ch_hbar0); 556d39a76e7Sxw pci_config_teardown(&chp->ch_hpci); 557d39a76e7Sxw ch_free_name(chp); 558d39a76e7Sxw kmem_free(chp, sizeof (ch_t)); 559d39a76e7Sxw gld_mac_free(macinfo); 560d39a76e7Sxw 561d39a76e7Sxw return (DDI_FAILURE); 562d39a76e7Sxw } 563d39a76e7Sxw 564d39a76e7Sxw /* 565d39a76e7Sxw * add interrupt handler before card setup. 566d39a76e7Sxw */ 567d39a76e7Sxw rv = ddi_add_intr( 56819397407SSherry Moore dip, /* ptr to dev's dev_info struct */ 56919397407SSherry Moore 0, /* interrupt # (0) */ 57019397407SSherry Moore 0, /* iblock cookie ptr (NULL) */ 57119397407SSherry Moore 0, /* idevice cookie ptr (NULL) */ 57219397407SSherry Moore gld_intr, /* function ptr to interrupt handler */ 57319397407SSherry Moore (caddr_t)macinfo); /* handler argument */ 574d39a76e7Sxw 575d39a76e7Sxw if (rv != DDI_SUCCESS) { 576d39a76e7Sxw PRINT(("add_intr failed\n")); 577d39a76e7Sxw DEBUG_ENTER("ch_attach"); 578d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD 579d39a76e7Sxw gchp[unit] = NULL; 580d39a76e7Sxw #endif 581d39a76e7Sxw cmn_err(CE_WARN, "%s: ddi_add_intr error %d\n", 58219397407SSherry Moore chp->ch_name, rv); 583d39a76e7Sxw 584d39a76e7Sxw ddi_regs_map_free(&chp->ch_hbar0); 585d39a76e7Sxw pci_config_teardown(&chp->ch_hpci); 586d39a76e7Sxw ch_free_name(chp); 587d39a76e7Sxw kmem_free(chp, sizeof (ch_t)); 588d39a76e7Sxw gld_mac_free(macinfo); 589d39a76e7Sxw 590d39a76e7Sxw return (DDI_FAILURE); 591d39a76e7Sxw } 592d39a76e7Sxw 593d39a76e7Sxw /* initalize all the remaining per-card locks */ 594d39a76e7Sxw mutex_init(&chp->ch_lock, NULL, MUTEX_DRIVER, 59519397407SSherry Moore (void *)chp->ch_icookp); 596d39a76e7Sxw mutex_init(&chp->ch_intr, NULL, MUTEX_DRIVER, 59719397407SSherry Moore (void *)chp->ch_icookp); 598d39a76e7Sxw mutex_init(&chp->ch_mc_lck, NULL, MUTEX_DRIVER, NULL); 599d39a76e7Sxw mutex_init(&chp->ch_dh_lck, NULL, MUTEX_DRIVER, NULL); 600d39a76e7Sxw mutex_init(&chp->mac_lock, NULL, MUTEX_DRIVER, NULL); 601d39a76e7Sxw 602d39a76e7Sxw /* ------- initialize Chelsio card ------- */ 603d39a76e7Sxw 604d39a76e7Sxw if (pe_attach(chp)) { 605d39a76e7Sxw PRINT(("card initialization failed\n")); 606d39a76e7Sxw DEBUG_ENTER("ch_attach"); 607d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD 608d39a76e7Sxw gchp[unit] = NULL; 609d39a76e7Sxw #endif 610d39a76e7Sxw cmn_err(CE_WARN, "%s: pe_attach failed\n", 61119397407SSherry Moore chp->ch_name); 612d39a76e7Sxw 613d39a76e7Sxw mutex_destroy(&chp->ch_lock); 614d39a76e7Sxw mutex_destroy(&chp->ch_intr); 615d39a76e7Sxw mutex_destroy(&chp->ch_mc_lck); 616d39a76e7Sxw mutex_destroy(&chp->ch_dh_lck); 617d39a76e7Sxw mutex_destroy(&chp->mac_lock); 618d39a76e7Sxw ddi_remove_intr(dip, 0, chp->ch_icookp); 619d39a76e7Sxw ddi_regs_map_free(&chp->ch_hbar0); 620d39a76e7Sxw pci_config_teardown(&chp->ch_hpci); 621d39a76e7Sxw ch_free_name(chp); 622d39a76e7Sxw kmem_free(chp, sizeof (ch_t)); 623d39a76e7Sxw gld_mac_free(macinfo); 624d39a76e7Sxw 625d39a76e7Sxw return (DDI_FAILURE); 626d39a76e7Sxw } 627d39a76e7Sxw 628d39a76e7Sxw /* ------- done with Chelsio card ------- */ 629d39a76e7Sxw 630d39a76e7Sxw /* now can set mac address */ 631d39a76e7Sxw macinfo->gldm_vendor_addr = pe_get_mac(chp); 632d39a76e7Sxw 633d39a76e7Sxw macinfo->gldm_cookie = chp->ch_icookp; 634d39a76e7Sxw 635d39a76e7Sxw /* 636d39a76e7Sxw * We only active checksum offload for T2 architectures. 637d39a76e7Sxw */ 638d39a76e7Sxw if (is_T2(chp)) { 639d39a76e7Sxw if (chp->ch_config.cksum_enabled) 640d39a76e7Sxw macinfo->gldm_capabilities |= 641d39a76e7Sxw GLD_CAP_CKSUM_FULL_V4; 642d39a76e7Sxw } else 643d39a76e7Sxw chp->ch_config.cksum_enabled = 0; 644d39a76e7Sxw 645d39a76e7Sxw rv = gld_register( 64619397407SSherry Moore dip, /* ptr to dev's dev_info struct */ 64719397407SSherry Moore (char *)ddi_driver_name(dip), /* driver name */ 64819397407SSherry Moore macinfo); /* ptr to gld macinfo buffer */ 649d39a76e7Sxw 650d39a76e7Sxw /* 651d39a76e7Sxw * The Jumbo frames capability is not yet available 652d39a76e7Sxw * in Solaris 10 so registration will fail. MTU > 1500 is 653d39a76e7Sxw * supported in Update 1. 654d39a76e7Sxw */ 655d39a76e7Sxw if (rv != DDI_SUCCESS) { 656d39a76e7Sxw cmn_err(CE_NOTE, "MTU > 1500 not supported by GLD.\n"); 657d39a76e7Sxw cmn_err(CE_NOTE, "Setting MTU to 1500. \n"); 658d39a76e7Sxw macinfo->gldm_maxpkt = chp->ch_mtu = 1500; 659d39a76e7Sxw rv = gld_register( 66019397407SSherry Moore dip, /* ptr to dev's dev_info struct */ 66119397407SSherry Moore (char *)ddi_driver_name(dip), /* driver name */ 66219397407SSherry Moore macinfo); /* ptr to gld macinfo buffer */ 663d39a76e7Sxw } 664d39a76e7Sxw 665d39a76e7Sxw 666d39a76e7Sxw if (rv != DDI_SUCCESS) { 667d39a76e7Sxw PRINT(("gld_register failed\n")); 668d39a76e7Sxw DEBUG_ENTER("ch_attach"); 669d39a76e7Sxw 670d39a76e7Sxw cmn_err(CE_WARN, "%s: gld_register error %d\n", 67119397407SSherry Moore chp->ch_name, rv); 672d39a76e7Sxw 673d39a76e7Sxw pe_detach(chp); 674d39a76e7Sxw 675d39a76e7Sxw mutex_destroy(&chp->ch_lock); 676d39a76e7Sxw mutex_destroy(&chp->ch_intr); 677d39a76e7Sxw mutex_destroy(&chp->ch_mc_lck); 678d39a76e7Sxw mutex_destroy(&chp->ch_dh_lck); 679d39a76e7Sxw mutex_destroy(&chp->mac_lock); 680d39a76e7Sxw ddi_remove_intr(dip, 0, chp->ch_icookp); 681d39a76e7Sxw ddi_regs_map_free(&chp->ch_hbar0); 682d39a76e7Sxw pci_config_teardown(&chp->ch_hpci); 683d39a76e7Sxw ch_free_name(chp); 684d39a76e7Sxw kmem_free(chp, sizeof (ch_t)); 685d39a76e7Sxw gld_mac_free(macinfo); 686d39a76e7Sxw 687d39a76e7Sxw return (DDI_FAILURE); 688d39a76e7Sxw } 689d39a76e7Sxw 690d39a76e7Sxw /* 691d39a76e7Sxw * print a banner at boot time (verbose mode), announcing 692d39a76e7Sxw * the device pointed to by dip 693d39a76e7Sxw */ 694d39a76e7Sxw ddi_report_dev(dip); 695d39a76e7Sxw 696d39a76e7Sxw if (ch_abort_debug) 697d39a76e7Sxw debug_enter("ch_attach"); 698d39a76e7Sxw 699d39a76e7Sxw return (DDI_SUCCESS); 700d39a76e7Sxw 701d39a76e7Sxw } else if (cmd == DDI_RESUME) { 702d39a76e7Sxw PRINT(("attach resume\n")); 703d39a76e7Sxw DEBUG_ENTER("ch_attach"); 704d39a76e7Sxw if ((chp = (ch_t *)ddi_get_driver_private(dip)) == NULL) 705d39a76e7Sxw return (DDI_FAILURE); 706d39a76e7Sxw 707d39a76e7Sxw mutex_enter(&chp->ch_lock); 708d39a76e7Sxw chp->ch_flags &= ~PESUSPENDED; 709d39a76e7Sxw mutex_exit(&chp->ch_lock); 710d39a76e7Sxw return (DDI_SUCCESS); 711d39a76e7Sxw } else { 712d39a76e7Sxw PRINT(("attach: bad command\n")); 713d39a76e7Sxw DEBUG_ENTER("ch_attach"); 714d39a76e7Sxw 715d39a76e7Sxw return (DDI_FAILURE); 716d39a76e7Sxw } 717d39a76e7Sxw } 718d39a76e7Sxw 71919397407SSherry Moore /* 72019397407SSherry Moore * quiesce(9E) entry point. 72119397407SSherry Moore * 72219397407SSherry Moore * This function is called when the system is single-threaded at high 72319397407SSherry Moore * PIL with preemption disabled. Therefore, this function must not be 72419397407SSherry Moore * blocked. 72519397407SSherry Moore * 72619397407SSherry Moore * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 72719397407SSherry Moore * DDI_FAILURE indicates an error condition and should almost never happen. 72819397407SSherry Moore */ 72919397407SSherry Moore static int 73019397407SSherry Moore ch_quiesce(dev_info_t *dip) 73119397407SSherry Moore { 73219397407SSherry Moore ch_t *chp; 73319397407SSherry Moore gld_mac_info_t *macinfo = 73419397407SSherry Moore (gld_mac_info_t *)ddi_get_driver_private(dip); 73519397407SSherry Moore 73619397407SSherry Moore chp = (ch_t *)macinfo->gldm_private; 73719397407SSherry Moore chdebug = 0; 73819397407SSherry Moore ch_abort_debug = 0; 73919397407SSherry Moore 74019397407SSherry Moore #ifdef CONFIG_CHELSIO_T1_OFFLOAD 74119397407SSherry Moore gchp[chp->ch_unit] = NULL; 74219397407SSherry Moore #endif 74319397407SSherry Moore 74419397407SSherry Moore /* Set driver state for this card to IDLE */ 74519397407SSherry Moore chp->ch_state = PEIDLE; 74619397407SSherry Moore 74719397407SSherry Moore /* 74819397407SSherry Moore * Do a power reset of card 74919397407SSherry Moore * 1. set PwrState to D3hot (3) 75019397407SSherry Moore * 2. clear PwrState flags 75119397407SSherry Moore */ 75219397407SSherry Moore pci_config_put32(chp->ch_hpci, 0x44, 3); 75319397407SSherry Moore pci_config_put32(chp->ch_hpci, 0x44, 0); 75419397407SSherry Moore 75519397407SSherry Moore /* Wait 0.5 sec */ 75619397407SSherry Moore drv_usecwait(500000); 75719397407SSherry Moore 75819397407SSherry Moore /* 75919397407SSherry Moore * Now stop the chip 76019397407SSherry Moore */ 76119397407SSherry Moore chp->ch_refcnt = 0; 76219397407SSherry Moore chp->ch_state = PESTOP; 76319397407SSherry Moore 76419397407SSherry Moore /* Disables all interrupts */ 76519397407SSherry Moore t1_interrupts_disable(chp); 76619397407SSherry Moore 76719397407SSherry Moore /* Disables SGE queues */ 76819397407SSherry Moore t1_write_reg_4(chp->sge->obj, A_SG_CONTROL, 0x0); 76919397407SSherry Moore t1_write_reg_4(chp->sge->obj, A_SG_INT_CAUSE, 0x0); 77019397407SSherry Moore 77119397407SSherry Moore return (DDI_SUCCESS); 77219397407SSherry Moore } 77319397407SSherry Moore 774d39a76e7Sxw static int 775d39a76e7Sxw ch_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 776d39a76e7Sxw { 777d39a76e7Sxw gld_mac_info_t *macinfo; 778d39a76e7Sxw ch_t *chp; 779d39a76e7Sxw 780d39a76e7Sxw if (cmd == DDI_DETACH) { 781d39a76e7Sxw macinfo = (gld_mac_info_t *)ddi_get_driver_private(dip); 782d39a76e7Sxw chp = (ch_t *)macinfo->gldm_private; 783d39a76e7Sxw 784d39a76e7Sxw /* 785d39a76e7Sxw * fail detach if there are outstanding mblks still 786d39a76e7Sxw * in use somewhere. 787d39a76e7Sxw */ 788d39a76e7Sxw DEBUG_ENTER("ch_detach"); 789d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD 790d39a76e7Sxw mutex_enter(&chp->ch_lock); 791d39a76e7Sxw if (chp->ch_refcnt > 0) { 792d39a76e7Sxw mutex_exit(&chp->ch_lock); 793d39a76e7Sxw return (DDI_FAILURE); 794d39a76e7Sxw } 795d39a76e7Sxw mutex_exit(&chp->ch_lock); 796d39a76e7Sxw gchp[chp->ch_unit] = NULL; 797d39a76e7Sxw #endif 798d39a76e7Sxw /* 799d39a76e7Sxw * set driver state for this card to IDLE. We're 800d39a76e7Sxw * shutting down. 801d39a76e7Sxw */ 802d39a76e7Sxw mutex_enter(&chp->ch_lock); 803d39a76e7Sxw chp->ch_state = PEIDLE; 804d39a76e7Sxw mutex_exit(&chp->ch_lock); 805d39a76e7Sxw 806d39a76e7Sxw /* 807d39a76e7Sxw * do a power reset of card 808d39a76e7Sxw * 809d39a76e7Sxw * 1. set PwrState to D3hot (3) 810d39a76e7Sxw * 2. clear PwrState flags 811d39a76e7Sxw */ 812d39a76e7Sxw pci_config_put32(chp->ch_hpci, 0x44, 3); 813d39a76e7Sxw pci_config_put32(chp->ch_hpci, 0x44, 0); 814d39a76e7Sxw 815d39a76e7Sxw /* delay .5 sec */ 816d39a76e7Sxw DELAY(500000); 817d39a76e7Sxw 818d39a76e7Sxw /* free register resources */ 819d39a76e7Sxw (void) gld_unregister(macinfo); 820d39a76e7Sxw 821d39a76e7Sxw /* make sure no interrupts while shutting down card */ 822d39a76e7Sxw ddi_remove_intr(dip, 0, chp->ch_icookp); 823d39a76e7Sxw 824d39a76e7Sxw /* 825d39a76e7Sxw * reset device and recover resources 826d39a76e7Sxw */ 827d39a76e7Sxw pe_detach(chp); 828d39a76e7Sxw 829d39a76e7Sxw ddi_regs_map_free(&chp->ch_hbar0); 830d39a76e7Sxw pci_config_teardown(&chp->ch_hpci); 831d39a76e7Sxw mutex_destroy(&chp->ch_lock); 832d39a76e7Sxw mutex_destroy(&chp->ch_intr); 833d39a76e7Sxw mutex_destroy(&chp->ch_mc_lck); 834d39a76e7Sxw mutex_destroy(&chp->ch_dh_lck); 835d39a76e7Sxw mutex_destroy(&chp->mac_lock); 836d39a76e7Sxw ch_free_dma_handles(chp); 837d39a76e7Sxw #if defined(__sparc) 838d39a76e7Sxw ch_free_dvma_handles(chp); 839d39a76e7Sxw #endif 840d39a76e7Sxw ch_free_name(chp); 841d39a76e7Sxw kmem_free(chp, sizeof (ch_t)); 842d39a76e7Sxw gld_mac_free(macinfo); 843d39a76e7Sxw 844d39a76e7Sxw DEBUG_ENTER("ch_detach end"); 845d39a76e7Sxw 846d39a76e7Sxw return (DDI_SUCCESS); 847d39a76e7Sxw 848d39a76e7Sxw } else if ((cmd == DDI_SUSPEND) || (cmd == DDI_PM_SUSPEND)) { 849d39a76e7Sxw DEBUG_ENTER("suspend"); 850d39a76e7Sxw if ((chp = (ch_t *)ddi_get_driver_private(dip)) == NULL) 851d39a76e7Sxw return (DDI_FAILURE); 852d39a76e7Sxw mutex_enter(&chp->ch_lock); 853d39a76e7Sxw chp->ch_flags |= PESUSPENDED; 854d39a76e7Sxw mutex_exit(&chp->ch_lock); 855d39a76e7Sxw #ifdef TODO 856d39a76e7Sxw /* Un-initialize (STOP) T101 */ 857d39a76e7Sxw #endif 858d39a76e7Sxw return (DDI_SUCCESS); 859d39a76e7Sxw } else 860d39a76e7Sxw return (DDI_FAILURE); 861d39a76e7Sxw } 862d39a76e7Sxw 863d39a76e7Sxw /* 864d39a76e7Sxw * ch_alloc_dma_mem 865d39a76e7Sxw * 866d39a76e7Sxw * allocates DMA handle 867d39a76e7Sxw * allocates kernel memory 868d39a76e7Sxw * allocates DMA access handle 869d39a76e7Sxw * 870d39a76e7Sxw * chp - per-board descriptor 871d39a76e7Sxw * type - byteswap mapping? 872d39a76e7Sxw * flags - type of mapping 873d39a76e7Sxw * size - # bytes mapped 874d39a76e7Sxw * paddr - physical address 875d39a76e7Sxw * dh - ddi dma handle 876d39a76e7Sxw * ah - ddi access handle 877d39a76e7Sxw */ 878d39a76e7Sxw 879d39a76e7Sxw void * 880d39a76e7Sxw ch_alloc_dma_mem(ch_t *chp, int type, int flags, int size, uint64_t *paddr, 881d39a76e7Sxw ulong_t *dh, ulong_t *ah) 882d39a76e7Sxw { 883d39a76e7Sxw ddi_dma_attr_t ch_dma_attr; 884d39a76e7Sxw ddi_dma_cookie_t cookie; 885d39a76e7Sxw ddi_dma_handle_t ch_dh; 886d39a76e7Sxw ddi_acc_handle_t ch_ah; 887d39a76e7Sxw ddi_device_acc_attr_t *dev_attrp; 888d39a76e7Sxw caddr_t ch_vaddr; 889d39a76e7Sxw size_t rlen; 890d39a76e7Sxw uint_t count; 891d39a76e7Sxw uint_t mapping; 892d39a76e7Sxw uint_t align; 893d39a76e7Sxw uint_t rv; 894d39a76e7Sxw uint_t direction; 895d39a76e7Sxw 896d39a76e7Sxw mapping = (flags&DMA_STREAM)?DDI_DMA_STREAMING:DDI_DMA_CONSISTENT; 897d39a76e7Sxw if (flags & DMA_4KALN) 898d39a76e7Sxw align = 0x4000; 899d39a76e7Sxw else if (flags & DMA_SMALN) 900d39a76e7Sxw align = chp->ch_sm_buf_aln; 901d39a76e7Sxw else if (flags & DMA_BGALN) 902d39a76e7Sxw align = chp->ch_bg_buf_aln; 903d39a76e7Sxw else { 904d39a76e7Sxw cmn_err(CE_WARN, "ch_alloc_dma_mem(%s): bad alignment flag\n", 905d39a76e7Sxw chp->ch_name); 906d39a76e7Sxw return (0); 907d39a76e7Sxw } 908d39a76e7Sxw direction = (flags&DMA_OUT)?DDI_DMA_WRITE:DDI_DMA_READ; 909d39a76e7Sxw 910d39a76e7Sxw /* 911d39a76e7Sxw * dynamically create a dma attribute structure 912d39a76e7Sxw */ 913d39a76e7Sxw ch_dma_attr.dma_attr_version = DMA_ATTR_V0; 914d39a76e7Sxw ch_dma_attr.dma_attr_addr_lo = 0; 915d39a76e7Sxw ch_dma_attr.dma_attr_addr_hi = 0xffffffffffffffff; 916d39a76e7Sxw ch_dma_attr.dma_attr_count_max = 0x00ffffff; 917d39a76e7Sxw ch_dma_attr.dma_attr_align = align; 918d39a76e7Sxw ch_dma_attr.dma_attr_burstsizes = 0xfff; 919d39a76e7Sxw ch_dma_attr.dma_attr_minxfer = 1; 920d39a76e7Sxw ch_dma_attr.dma_attr_maxxfer = 0x00ffffff; 921d39a76e7Sxw ch_dma_attr.dma_attr_seg = 0xffffffff; 922d39a76e7Sxw ch_dma_attr.dma_attr_sgllen = 1; 923d39a76e7Sxw ch_dma_attr.dma_attr_granular = 1; 924d39a76e7Sxw ch_dma_attr.dma_attr_flags = 0; 925d39a76e7Sxw 926d39a76e7Sxw rv = ddi_dma_alloc_handle( 927d39a76e7Sxw chp->ch_dip, /* device dev_info structure */ 928d39a76e7Sxw &ch_dma_attr, /* DMA attributes */ 929d39a76e7Sxw DDI_DMA_SLEEP, /* Wait if no memory */ 930d39a76e7Sxw NULL, /* no argument to callback */ 931d39a76e7Sxw &ch_dh); /* DMA handle */ 932d39a76e7Sxw if (rv != DDI_SUCCESS) { 933d39a76e7Sxw 934d39a76e7Sxw cmn_err(CE_WARN, 93519397407SSherry Moore "%s: ch_alloc_dma_mem: ddi_dma_alloc_handle error %d\n", 93619397407SSherry Moore chp->ch_name, rv); 937d39a76e7Sxw 938d39a76e7Sxw return (0); 939d39a76e7Sxw } 940d39a76e7Sxw 941d39a76e7Sxw /* set byte order for data xfer */ 942d39a76e7Sxw if (type) 943d39a76e7Sxw dev_attrp = &null_attr; 944d39a76e7Sxw else 945d39a76e7Sxw dev_attrp = &le_attr; 946d39a76e7Sxw 947d39a76e7Sxw rv = ddi_dma_mem_alloc( 948d39a76e7Sxw ch_dh, /* dma handle */ 949d39a76e7Sxw size, /* size desired allocate */ 950d39a76e7Sxw dev_attrp, /* access attributes */ 951d39a76e7Sxw mapping, 952d39a76e7Sxw DDI_DMA_SLEEP, /* wait for resources */ 953d39a76e7Sxw NULL, /* no argument */ 954d39a76e7Sxw &ch_vaddr, /* allocated memory */ 955d39a76e7Sxw &rlen, /* real size allocated */ 956d39a76e7Sxw &ch_ah); /* data access handle */ 957d39a76e7Sxw if (rv != DDI_SUCCESS) { 958d39a76e7Sxw ddi_dma_free_handle(&ch_dh); 959d39a76e7Sxw 960d39a76e7Sxw cmn_err(CE_WARN, 96119397407SSherry Moore "%s: ch_alloc_dma_mem: ddi_dma_mem_alloc error %d\n", 96219397407SSherry Moore chp->ch_name, rv); 963d39a76e7Sxw 964d39a76e7Sxw return (0); 965d39a76e7Sxw } 966d39a76e7Sxw 967d39a76e7Sxw rv = ddi_dma_addr_bind_handle( 968d39a76e7Sxw ch_dh, /* dma handle */ 969d39a76e7Sxw (struct as *)0, /* kernel address space */ 970d39a76e7Sxw ch_vaddr, /* virtual address */ 971d39a76e7Sxw rlen, /* length of object */ 972d39a76e7Sxw direction|mapping, 973d39a76e7Sxw DDI_DMA_SLEEP, /* Wait for resources */ 974d39a76e7Sxw NULL, /* no argument */ 975d39a76e7Sxw &cookie, /* dma cookie */ 976d39a76e7Sxw &count); 977d39a76e7Sxw if (rv != DDI_DMA_MAPPED) { 978d39a76e7Sxw ddi_dma_mem_free(&ch_ah); 979d39a76e7Sxw ddi_dma_free_handle(&ch_dh); 980d39a76e7Sxw 981d39a76e7Sxw cmn_err(CE_WARN, 982d39a76e7Sxw "%s: ch_alloc_dma_mem: ddi_dma_addr_bind_handle error %d\n", 98319397407SSherry Moore chp->ch_name, rv); 984d39a76e7Sxw 985d39a76e7Sxw return (0); 986d39a76e7Sxw } 987d39a76e7Sxw 988d39a76e7Sxw if (count != 1) { 989d39a76e7Sxw cmn_err(CE_WARN, 990d39a76e7Sxw "%s: ch_alloc_dma_mem: ch_alloc_dma_mem cookie count %d\n", 99119397407SSherry Moore chp->ch_name, count); 992d39a76e7Sxw PRINT(("ch_alloc_dma_mem cookie count %d\n", count)); 993d39a76e7Sxw 994d39a76e7Sxw ddi_dma_mem_free(&ch_ah); 995d39a76e7Sxw ddi_dma_free_handle(&ch_dh); 996d39a76e7Sxw 997d39a76e7Sxw return (0); 998d39a76e7Sxw } 999d39a76e7Sxw 1000d39a76e7Sxw *paddr = cookie.dmac_laddress; 1001d39a76e7Sxw 1002d39a76e7Sxw *(ddi_dma_handle_t *)dh = ch_dh; 1003d39a76e7Sxw *(ddi_acc_handle_t *)ah = ch_ah; 1004d39a76e7Sxw 1005d39a76e7Sxw return ((void *)ch_vaddr); 1006d39a76e7Sxw } 1007d39a76e7Sxw 1008d39a76e7Sxw /* 1009d39a76e7Sxw * ch_free_dma_mem 1010d39a76e7Sxw * 1011d39a76e7Sxw * frees resources allocated by ch_alloc_dma_mem() 1012d39a76e7Sxw * 1013d39a76e7Sxw * frees DMA handle 1014d39a76e7Sxw * frees kernel memory 1015d39a76e7Sxw * frees DMA access handle 1016d39a76e7Sxw */ 1017d39a76e7Sxw 1018d39a76e7Sxw void 1019d39a76e7Sxw ch_free_dma_mem(ulong_t dh, ulong_t ah) 1020d39a76e7Sxw { 1021d39a76e7Sxw ddi_dma_handle_t ch_dh = (ddi_dma_handle_t)dh; 1022d39a76e7Sxw ddi_acc_handle_t ch_ah = (ddi_acc_handle_t)ah; 1023d39a76e7Sxw 1024d39a76e7Sxw (void) ddi_dma_unbind_handle(ch_dh); 1025d39a76e7Sxw ddi_dma_mem_free(&ch_ah); 1026d39a76e7Sxw ddi_dma_free_handle(&ch_dh); 1027d39a76e7Sxw } 1028d39a76e7Sxw 1029d39a76e7Sxw /* 1030d39a76e7Sxw * create a dma handle and return a dma handle entry. 1031d39a76e7Sxw */ 1032d39a76e7Sxw free_dh_t * 1033d39a76e7Sxw ch_get_dma_handle(ch_t *chp) 1034d39a76e7Sxw { 1035d39a76e7Sxw ddi_dma_handle_t ch_dh; 1036d39a76e7Sxw ddi_dma_attr_t ch_dma_attr; 1037d39a76e7Sxw free_dh_t *dhe; 1038d39a76e7Sxw int rv; 1039d39a76e7Sxw 1040d39a76e7Sxw dhe = (free_dh_t *)kmem_zalloc(sizeof (*dhe), KM_SLEEP); 1041d39a76e7Sxw 1042d39a76e7Sxw ch_dma_attr.dma_attr_version = DMA_ATTR_V0; 1043d39a76e7Sxw ch_dma_attr.dma_attr_addr_lo = 0; 1044d39a76e7Sxw ch_dma_attr.dma_attr_addr_hi = 0xffffffffffffffff; 1045d39a76e7Sxw ch_dma_attr.dma_attr_count_max = 0x00ffffff; 1046d39a76e7Sxw ch_dma_attr.dma_attr_align = 1; 1047d39a76e7Sxw ch_dma_attr.dma_attr_burstsizes = 0xfff; 1048d39a76e7Sxw ch_dma_attr.dma_attr_minxfer = 1; 1049d39a76e7Sxw ch_dma_attr.dma_attr_maxxfer = 0x00ffffff; 1050d39a76e7Sxw ch_dma_attr.dma_attr_seg = 0xffffffff; 1051d39a76e7Sxw ch_dma_attr.dma_attr_sgllen = 5; 1052d39a76e7Sxw ch_dma_attr.dma_attr_granular = 1; 1053d39a76e7Sxw ch_dma_attr.dma_attr_flags = 0; 1054d39a76e7Sxw 1055d39a76e7Sxw rv = ddi_dma_alloc_handle( 1056d39a76e7Sxw chp->ch_dip, /* device dev_info */ 1057d39a76e7Sxw &ch_dma_attr, /* DMA attributes */ 1058d39a76e7Sxw DDI_DMA_SLEEP, /* Wait if no memory */ 1059d39a76e7Sxw NULL, /* no argument */ 1060d39a76e7Sxw &ch_dh); /* DMA handle */ 1061d39a76e7Sxw if (rv != DDI_SUCCESS) { 1062d39a76e7Sxw 1063d39a76e7Sxw cmn_err(CE_WARN, 1064d39a76e7Sxw "%s: ch_get_dma_handle: ddi_dma_alloc_handle error %d\n", 106519397407SSherry Moore chp->ch_name, rv); 1066d39a76e7Sxw 1067d39a76e7Sxw kmem_free(dhe, sizeof (*dhe)); 1068d39a76e7Sxw 1069d39a76e7Sxw return ((free_dh_t *)0); 1070d39a76e7Sxw } 1071d39a76e7Sxw 1072d39a76e7Sxw dhe->dhe_dh = (ulong_t)ch_dh; 1073d39a76e7Sxw 1074d39a76e7Sxw return (dhe); 1075d39a76e7Sxw } 1076d39a76e7Sxw 1077d39a76e7Sxw /* 1078d39a76e7Sxw * free the linked list of dma descriptor entries. 1079d39a76e7Sxw */ 1080d39a76e7Sxw static void 1081d39a76e7Sxw ch_free_dma_handles(ch_t *chp) 1082d39a76e7Sxw { 1083d39a76e7Sxw free_dh_t *dhe, *the; 1084d39a76e7Sxw 1085d39a76e7Sxw dhe = chp->ch_dh; 1086d39a76e7Sxw while (dhe) { 1087d39a76e7Sxw ddi_dma_free_handle((ddi_dma_handle_t *)&dhe->dhe_dh); 1088d39a76e7Sxw the = dhe; 1089d39a76e7Sxw dhe = dhe->dhe_next; 1090d39a76e7Sxw kmem_free(the, sizeof (*the)); 1091d39a76e7Sxw } 1092d39a76e7Sxw chp->ch_dh = NULL; 1093d39a76e7Sxw } 1094d39a76e7Sxw 1095d39a76e7Sxw /* 1096d39a76e7Sxw * ch_bind_dma_handle() 1097d39a76e7Sxw * 1098d39a76e7Sxw * returns # of entries used off of cmdQ_ce_t array to hold physical addrs. 1099d39a76e7Sxw * 1100d39a76e7Sxw * chp - per-board descriptor 1101d39a76e7Sxw * size - # bytes mapped 1102d39a76e7Sxw * vaddr - virtual address 1103d39a76e7Sxw * cmp - array of cmdQ_ce_t entries 1104d39a76e7Sxw * cnt - # free entries in cmp array 1105d39a76e7Sxw */ 1106d39a76e7Sxw 1107d39a76e7Sxw uint32_t 1108d39a76e7Sxw ch_bind_dma_handle(ch_t *chp, int size, caddr_t vaddr, cmdQ_ce_t *cmp, 1109d39a76e7Sxw uint32_t cnt) 1110d39a76e7Sxw { 1111d39a76e7Sxw ddi_dma_cookie_t cookie; 1112d39a76e7Sxw ddi_dma_handle_t ch_dh; 1113d39a76e7Sxw uint_t count; 1114d39a76e7Sxw uint32_t n = 1; 1115d39a76e7Sxw free_dh_t *dhe; 1116d39a76e7Sxw uint_t rv; 1117d39a76e7Sxw 1118d39a76e7Sxw mutex_enter(&chp->ch_dh_lck); 1119d39a76e7Sxw if ((dhe = chp->ch_dh) != NULL) { 1120d39a76e7Sxw chp->ch_dh = dhe->dhe_next; 1121d39a76e7Sxw } 1122d39a76e7Sxw mutex_exit(&chp->ch_dh_lck); 1123d39a76e7Sxw 1124d39a76e7Sxw if (dhe == NULL) { 1125d39a76e7Sxw return (0); 1126d39a76e7Sxw } 1127d39a76e7Sxw 1128d39a76e7Sxw ch_dh = (ddi_dma_handle_t)dhe->dhe_dh; 1129d39a76e7Sxw 1130d39a76e7Sxw rv = ddi_dma_addr_bind_handle( 1131d39a76e7Sxw ch_dh, /* dma handle */ 1132d39a76e7Sxw (struct as *)0, /* kernel address space */ 1133d39a76e7Sxw vaddr, /* virtual address */ 1134d39a76e7Sxw size, /* length of object */ 1135d39a76e7Sxw DDI_DMA_WRITE|DDI_DMA_STREAMING, 1136d39a76e7Sxw DDI_DMA_SLEEP, /* Wait for resources */ 1137d39a76e7Sxw NULL, /* no argument */ 1138d39a76e7Sxw &cookie, /* dma cookie */ 1139d39a76e7Sxw &count); 1140d39a76e7Sxw if (rv != DDI_DMA_MAPPED) { 1141d39a76e7Sxw 1142d39a76e7Sxw /* return dma header descriptor back to free list */ 1143d39a76e7Sxw mutex_enter(&chp->ch_dh_lck); 1144d39a76e7Sxw dhe->dhe_next = chp->ch_dh; 1145d39a76e7Sxw chp->ch_dh = dhe; 1146d39a76e7Sxw mutex_exit(&chp->ch_dh_lck); 1147d39a76e7Sxw 1148d39a76e7Sxw cmn_err(CE_WARN, 1149d39a76e7Sxw "%s: ch_bind_dma_handle: ddi_dma_addr_bind_handle err %d\n", 115019397407SSherry Moore chp->ch_name, rv); 1151d39a76e7Sxw 1152d39a76e7Sxw return (0); 1153d39a76e7Sxw } 1154d39a76e7Sxw 1155d39a76e7Sxw /* 1156d39a76e7Sxw * abort if we've run out of space 1157d39a76e7Sxw */ 1158d39a76e7Sxw if (count > cnt) { 1159d39a76e7Sxw /* return dma header descriptor back to free list */ 1160d39a76e7Sxw mutex_enter(&chp->ch_dh_lck); 1161d39a76e7Sxw dhe->dhe_next = chp->ch_dh; 1162d39a76e7Sxw chp->ch_dh = dhe; 1163d39a76e7Sxw mutex_exit(&chp->ch_dh_lck); 1164d39a76e7Sxw 1165d39a76e7Sxw return (0); 1166d39a76e7Sxw } 1167d39a76e7Sxw 1168d39a76e7Sxw cmp->ce_pa = cookie.dmac_laddress; 1169d39a76e7Sxw cmp->ce_dh = NULL; 1170d39a76e7Sxw cmp->ce_len = cookie.dmac_size; 1171d39a76e7Sxw cmp->ce_mp = NULL; 1172d39a76e7Sxw cmp->ce_flg = DH_DMA; 1173d39a76e7Sxw 1174d39a76e7Sxw while (--count) { 1175d39a76e7Sxw cmp++; 1176d39a76e7Sxw n++; 1177d39a76e7Sxw ddi_dma_nextcookie(ch_dh, &cookie); 1178d39a76e7Sxw cmp->ce_pa = cookie.dmac_laddress; 1179d39a76e7Sxw cmp->ce_dh = NULL; 1180d39a76e7Sxw cmp->ce_len = cookie.dmac_size; 1181d39a76e7Sxw cmp->ce_mp = NULL; 1182d39a76e7Sxw cmp->ce_flg = DH_DMA; 1183d39a76e7Sxw } 1184d39a76e7Sxw 1185d39a76e7Sxw cmp->ce_dh = dhe; 1186d39a76e7Sxw 1187d39a76e7Sxw return (n); 1188d39a76e7Sxw } 1189d39a76e7Sxw 1190d39a76e7Sxw /* 1191d39a76e7Sxw * ch_unbind_dma_handle() 1192d39a76e7Sxw * 1193d39a76e7Sxw * frees resources alloacted by ch_bind_dma_handle(). 1194d39a76e7Sxw * 1195d39a76e7Sxw * frees DMA handle 1196d39a76e7Sxw */ 1197d39a76e7Sxw 1198d39a76e7Sxw void 1199d39a76e7Sxw ch_unbind_dma_handle(ch_t *chp, free_dh_t *dhe) 1200d39a76e7Sxw { 1201d39a76e7Sxw ddi_dma_handle_t ch_dh = (ddi_dma_handle_t)dhe->dhe_dh; 1202d39a76e7Sxw 1203d39a76e7Sxw if (ddi_dma_unbind_handle(ch_dh)) 1204d39a76e7Sxw cmn_err(CE_WARN, "%s: ddi_dma_unbind_handle failed", 120519397407SSherry Moore chp->ch_name); 1206d39a76e7Sxw 1207d39a76e7Sxw mutex_enter(&chp->ch_dh_lck); 1208d39a76e7Sxw dhe->dhe_next = chp->ch_dh; 1209d39a76e7Sxw chp->ch_dh = dhe; 1210d39a76e7Sxw mutex_exit(&chp->ch_dh_lck); 1211d39a76e7Sxw } 1212d39a76e7Sxw 1213d39a76e7Sxw #if defined(__sparc) 1214d39a76e7Sxw /* 1215d39a76e7Sxw * DVMA stuff. Solaris only. 1216d39a76e7Sxw */ 1217d39a76e7Sxw 1218d39a76e7Sxw /* 1219d39a76e7Sxw * create a dvma handle and return a dma handle entry. 1220d39a76e7Sxw * DVMA is on sparc only! 1221d39a76e7Sxw */ 1222d39a76e7Sxw 1223d39a76e7Sxw free_dh_t * 1224d39a76e7Sxw ch_get_dvma_handle(ch_t *chp) 1225d39a76e7Sxw { 1226d39a76e7Sxw ddi_dma_handle_t ch_dh; 1227d39a76e7Sxw ddi_dma_lim_t ch_dvma_attr; 1228d39a76e7Sxw free_dh_t *dhe; 1229d39a76e7Sxw int rv; 1230d39a76e7Sxw 1231d39a76e7Sxw dhe = (free_dh_t *)kmem_zalloc(sizeof (*dhe), KM_SLEEP); 1232d39a76e7Sxw 1233d39a76e7Sxw ch_dvma_attr.dlim_addr_lo = 0; 1234d39a76e7Sxw ch_dvma_attr.dlim_addr_hi = 0xffffffff; 1235d39a76e7Sxw ch_dvma_attr.dlim_cntr_max = 0xffffffff; 1236d39a76e7Sxw ch_dvma_attr.dlim_burstsizes = 0xfff; 1237d39a76e7Sxw ch_dvma_attr.dlim_minxfer = 1; 1238d39a76e7Sxw ch_dvma_attr.dlim_dmaspeed = 0; 1239d39a76e7Sxw 1240d39a76e7Sxw rv = dvma_reserve( 124119397407SSherry Moore chp->ch_dip, /* device dev_info */ 124219397407SSherry Moore &ch_dvma_attr, /* DVMA attributes */ 124319397407SSherry Moore 3, /* number of pages */ 124419397407SSherry Moore &ch_dh); /* DVMA handle */ 1245d39a76e7Sxw 1246d39a76e7Sxw if (rv != DDI_SUCCESS) { 1247d39a76e7Sxw 1248d39a76e7Sxw cmn_err(CE_WARN, 1249d39a76e7Sxw "%s: ch_get_dvma_handle: dvma_reserve() error %d\n", 125019397407SSherry Moore chp->ch_name, rv); 1251d39a76e7Sxw 1252d39a76e7Sxw kmem_free(dhe, sizeof (*dhe)); 1253d39a76e7Sxw 1254d39a76e7Sxw return ((free_dh_t *)0); 1255d39a76e7Sxw } 1256d39a76e7Sxw 1257d39a76e7Sxw dhe->dhe_dh = (ulong_t)ch_dh; 1258d39a76e7Sxw 1259d39a76e7Sxw return (dhe); 1260d39a76e7Sxw } 1261d39a76e7Sxw 1262d39a76e7Sxw /* 1263d39a76e7Sxw * free the linked list of dvma descriptor entries. 1264d39a76e7Sxw * DVMA is only on sparc! 1265d39a76e7Sxw */ 1266d39a76e7Sxw 1267d39a76e7Sxw static void 1268d39a76e7Sxw ch_free_dvma_handles(ch_t *chp) 1269d39a76e7Sxw { 1270d39a76e7Sxw free_dh_t *dhe, *the; 1271d39a76e7Sxw 1272d39a76e7Sxw dhe = chp->ch_vdh; 1273d39a76e7Sxw while (dhe) { 1274d39a76e7Sxw dvma_release((ddi_dma_handle_t)dhe->dhe_dh); 1275d39a76e7Sxw the = dhe; 1276d39a76e7Sxw dhe = dhe->dhe_next; 1277d39a76e7Sxw kmem_free(the, sizeof (*the)); 1278d39a76e7Sxw } 1279d39a76e7Sxw chp->ch_vdh = NULL; 1280d39a76e7Sxw } 1281d39a76e7Sxw 1282d39a76e7Sxw /* 1283d39a76e7Sxw * ch_bind_dvma_handle() 1284d39a76e7Sxw * 1285d39a76e7Sxw * returns # of entries used off of cmdQ_ce_t array to hold physical addrs. 1286d39a76e7Sxw * DVMA in sparc only 1287d39a76e7Sxw * 1288d39a76e7Sxw * chp - per-board descriptor 1289d39a76e7Sxw * size - # bytes mapped 1290d39a76e7Sxw * vaddr - virtual address 1291d39a76e7Sxw * cmp - array of cmdQ_ce_t entries 1292d39a76e7Sxw * cnt - # free entries in cmp array 1293d39a76e7Sxw */ 1294d39a76e7Sxw 1295d39a76e7Sxw uint32_t 1296d39a76e7Sxw ch_bind_dvma_handle(ch_t *chp, int size, caddr_t vaddr, cmdQ_ce_t *cmp, 1297d39a76e7Sxw uint32_t cnt) 1298d39a76e7Sxw { 1299d39a76e7Sxw ddi_dma_cookie_t cookie; 1300d39a76e7Sxw ddi_dma_handle_t ch_dh; 1301d39a76e7Sxw uint32_t n = 1; 1302d39a76e7Sxw free_dh_t *dhe; 1303d39a76e7Sxw 1304d39a76e7Sxw mutex_enter(&chp->ch_dh_lck); 1305d39a76e7Sxw if ((dhe = chp->ch_vdh) != NULL) { 1306d39a76e7Sxw chp->ch_vdh = dhe->dhe_next; 1307d39a76e7Sxw } 1308d39a76e7Sxw mutex_exit(&chp->ch_dh_lck); 1309d39a76e7Sxw 1310d39a76e7Sxw if (dhe == NULL) { 1311d39a76e7Sxw return (0); 1312d39a76e7Sxw } 1313d39a76e7Sxw 1314d39a76e7Sxw ch_dh = (ddi_dma_handle_t)dhe->dhe_dh; 1315d39a76e7Sxw n = cnt; 1316d39a76e7Sxw 1317d39a76e7Sxw dvma_kaddr_load( 131819397407SSherry Moore ch_dh, /* dvma handle */ 131919397407SSherry Moore vaddr, /* virtual address */ 132019397407SSherry Moore size, /* length of object */ 132119397407SSherry Moore 0, /* start at index 0 */ 132219397407SSherry Moore &cookie); 1323d39a76e7Sxw 1324d39a76e7Sxw dvma_sync(ch_dh, 0, DDI_DMA_SYNC_FORDEV); 1325d39a76e7Sxw 1326d39a76e7Sxw cookie.dmac_notused = 0; 1327d39a76e7Sxw n = 1; 1328d39a76e7Sxw 1329d39a76e7Sxw cmp->ce_pa = cookie.dmac_laddress; 1330d39a76e7Sxw cmp->ce_dh = dhe; 1331d39a76e7Sxw cmp->ce_len = cookie.dmac_size; 1332d39a76e7Sxw cmp->ce_mp = NULL; 1333d39a76e7Sxw cmp->ce_flg = DH_DVMA; /* indicate a dvma descriptor */ 1334d39a76e7Sxw 1335d39a76e7Sxw return (n); 1336d39a76e7Sxw } 1337d39a76e7Sxw 1338d39a76e7Sxw /* 1339d39a76e7Sxw * ch_unbind_dvma_handle() 1340d39a76e7Sxw * 1341d39a76e7Sxw * frees resources alloacted by ch_bind_dvma_handle(). 1342d39a76e7Sxw * 1343d39a76e7Sxw * frees DMA handle 1344d39a76e7Sxw */ 1345d39a76e7Sxw 1346d39a76e7Sxw void 1347d39a76e7Sxw ch_unbind_dvma_handle(ch_t *chp, free_dh_t *dhe) 1348d39a76e7Sxw { 1349d39a76e7Sxw ddi_dma_handle_t ch_dh = (ddi_dma_handle_t)dhe->dhe_dh; 1350d39a76e7Sxw 1351d39a76e7Sxw dvma_unload(ch_dh, 0, -1); 1352d39a76e7Sxw 1353d39a76e7Sxw mutex_enter(&chp->ch_dh_lck); 1354d39a76e7Sxw dhe->dhe_next = chp->ch_vdh; 1355d39a76e7Sxw chp->ch_vdh = dhe; 1356d39a76e7Sxw mutex_exit(&chp->ch_dh_lck); 1357d39a76e7Sxw } 1358d39a76e7Sxw 1359d39a76e7Sxw #endif /* defined(__sparc) */ 1360d39a76e7Sxw 1361d39a76e7Sxw /* 1362d39a76e7Sxw * send received packet up stream. 1363d39a76e7Sxw * 1364d39a76e7Sxw * if driver has been stopped, then we drop the message. 1365d39a76e7Sxw */ 1366d39a76e7Sxw void 1367d39a76e7Sxw ch_send_up(ch_t *chp, mblk_t *mp, uint32_t cksum, int flg) 1368d39a76e7Sxw { 1369d39a76e7Sxw /* 1370d39a76e7Sxw * probably do not need a lock here. When we set PESTOP in 1371d39a76e7Sxw * ch_stop() a packet could have just passed here and gone 1372d39a76e7Sxw * upstream. The next one will be dropped. 1373d39a76e7Sxw */ 1374d39a76e7Sxw if (chp->ch_state == PERUNNING) { 1375d39a76e7Sxw /* 1376d39a76e7Sxw * note that flg will not be set unless enable_checksum_offload 1377d39a76e7Sxw * set in /etc/system (see sge.c). 1378d39a76e7Sxw */ 1379d39a76e7Sxw if (flg) 1380d39a76e7Sxw (void) hcksum_assoc(mp, NULL, NULL, 0, 0, 0, cksum, 138119397407SSherry Moore HCK_FULLCKSUM, 0); 1382d39a76e7Sxw gld_recv(chp->ch_macp, mp); 1383d39a76e7Sxw } else { 1384d39a76e7Sxw freemsg(mp); 1385d39a76e7Sxw } 1386d39a76e7Sxw } 1387d39a76e7Sxw 1388d39a76e7Sxw /* 1389d39a76e7Sxw * unblock gld driver. 1390d39a76e7Sxw */ 1391d39a76e7Sxw void 1392d39a76e7Sxw ch_gld_ok(ch_t *chp) 1393d39a76e7Sxw { 1394d39a76e7Sxw gld_sched(chp->ch_macp); 1395d39a76e7Sxw } 1396d39a76e7Sxw 1397d39a76e7Sxw 1398d39a76e7Sxw /* 1399d39a76e7Sxw * reset the card. 1400d39a76e7Sxw * 1401d39a76e7Sxw * Note: we only do this after the card has been initialized. 1402d39a76e7Sxw */ 1403d39a76e7Sxw static int 1404d39a76e7Sxw ch_reset(gld_mac_info_t *mp) 1405d39a76e7Sxw { 1406d39a76e7Sxw ch_t *chp; 1407d39a76e7Sxw 1408d39a76e7Sxw if (mp == NULL) { 1409d39a76e7Sxw return (GLD_FAILURE); 1410d39a76e7Sxw } 1411d39a76e7Sxw 1412d39a76e7Sxw chp = (ch_t *)mp->gldm_private; 1413d39a76e7Sxw 1414d39a76e7Sxw if (chp == NULL) { 1415d39a76e7Sxw return (GLD_FAILURE); 1416d39a76e7Sxw } 1417d39a76e7Sxw 1418d39a76e7Sxw #ifdef NOTYET 1419d39a76e7Sxw /* 1420d39a76e7Sxw * do a reset of card 1421d39a76e7Sxw * 1422d39a76e7Sxw * 1. set PwrState to D3hot (3) 1423d39a76e7Sxw * 2. clear PwrState flags 1424d39a76e7Sxw */ 1425d39a76e7Sxw /* 1426d39a76e7Sxw * When we did this, the card didn't start. First guess is that 1427d39a76e7Sxw * the initialization is not quite correct. For now, we don't 1428d39a76e7Sxw * reset things. 1429d39a76e7Sxw */ 1430d39a76e7Sxw if (chp->ch_hpci) { 1431d39a76e7Sxw pci_config_put32(chp->ch_hpci, 0x44, 3); 1432d39a76e7Sxw pci_config_put32(chp->ch_hpci, 0x44, 0); 1433d39a76e7Sxw 1434d39a76e7Sxw /* delay .5 sec */ 1435d39a76e7Sxw DELAY(500000); 1436d39a76e7Sxw } 1437d39a76e7Sxw #endif 1438d39a76e7Sxw 1439d39a76e7Sxw return (GLD_SUCCESS); 1440d39a76e7Sxw } 1441d39a76e7Sxw 1442d39a76e7Sxw static int 1443d39a76e7Sxw ch_start(gld_mac_info_t *macinfo) 1444d39a76e7Sxw { 1445d39a76e7Sxw ch_t *chp = (ch_t *)macinfo->gldm_private; 1446d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD 1447d39a76e7Sxw /* only initialize card on first attempt */ 1448d39a76e7Sxw mutex_enter(&chp->ch_lock); 1449d39a76e7Sxw chp->ch_refcnt++; 1450d39a76e7Sxw if (chp->ch_refcnt == 1) { 1451d39a76e7Sxw chp->ch_state = PERUNNING; 1452d39a76e7Sxw mutex_exit(&chp->ch_lock); 1453d39a76e7Sxw pe_init((void *)chp); 1454d39a76e7Sxw } else 1455d39a76e7Sxw mutex_exit(&chp->ch_lock); 1456d39a76e7Sxw #else 1457d39a76e7Sxw pe_init((void *)chp); 1458d39a76e7Sxw 1459d39a76e7Sxw /* go to running state, we're being started */ 1460d39a76e7Sxw mutex_enter(&chp->ch_lock); 1461d39a76e7Sxw chp->ch_state = PERUNNING; 1462d39a76e7Sxw mutex_exit(&chp->ch_lock); 1463d39a76e7Sxw #endif 1464d39a76e7Sxw 1465d39a76e7Sxw return (GLD_SUCCESS); 1466d39a76e7Sxw } 1467d39a76e7Sxw 1468d39a76e7Sxw static int 1469d39a76e7Sxw ch_stop(gld_mac_info_t *mp) 1470d39a76e7Sxw { 1471d39a76e7Sxw ch_t *chp = (ch_t *)mp->gldm_private; 1472d39a76e7Sxw 1473d39a76e7Sxw /* 1474d39a76e7Sxw * can only stop the chip if it's been initialized 1475d39a76e7Sxw */ 1476d39a76e7Sxw mutex_enter(&chp->ch_lock); 1477d39a76e7Sxw if (chp->ch_state == PEIDLE) { 1478d39a76e7Sxw mutex_exit(&chp->ch_lock); 1479d39a76e7Sxw return (GLD_FAILURE); 1480d39a76e7Sxw } 1481d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD 1482d39a76e7Sxw chp->ch_refcnt--; 1483d39a76e7Sxw if (chp->ch_refcnt == 0) { 1484d39a76e7Sxw chp->ch_state = PESTOP; 1485d39a76e7Sxw mutex_exit(&chp->ch_lock); 1486d39a76e7Sxw pe_stop(chp); 1487d39a76e7Sxw } else 1488d39a76e7Sxw mutex_exit(&chp->ch_lock); 1489d39a76e7Sxw #else 1490d39a76e7Sxw chp->ch_state = PESTOP; 1491d39a76e7Sxw mutex_exit(&chp->ch_lock); 1492d39a76e7Sxw pe_stop(chp); 1493d39a76e7Sxw #endif 1494d39a76e7Sxw return (GLD_SUCCESS); 1495d39a76e7Sxw } 1496d39a76e7Sxw 1497d39a76e7Sxw static int 1498d39a76e7Sxw ch_set_mac_address(gld_mac_info_t *mp, uint8_t *mac) 1499d39a76e7Sxw { 1500d39a76e7Sxw ch_t *chp; 1501d39a76e7Sxw 1502d39a76e7Sxw if (mp) { 1503d39a76e7Sxw chp = (ch_t *)mp->gldm_private; 1504d39a76e7Sxw } else { 1505d39a76e7Sxw return (GLD_FAILURE); 1506d39a76e7Sxw } 1507d39a76e7Sxw 1508d39a76e7Sxw pe_set_mac(chp, mac); 1509d39a76e7Sxw 1510d39a76e7Sxw return (GLD_SUCCESS); 1511d39a76e7Sxw } 1512d39a76e7Sxw 1513d39a76e7Sxw static int 1514d39a76e7Sxw ch_set_multicast(gld_mac_info_t *mp, uint8_t *ep, int flg) 1515d39a76e7Sxw { 1516d39a76e7Sxw ch_t *chp = (ch_t *)mp->gldm_private; 1517d39a76e7Sxw 1518d39a76e7Sxw return (pe_set_mc(chp, ep, flg)); 1519d39a76e7Sxw } 1520d39a76e7Sxw 1521d39a76e7Sxw static int 1522d39a76e7Sxw ch_ioctl(gld_mac_info_t *macinfo, queue_t *q, mblk_t *mp) 1523d39a76e7Sxw { 1524d39a76e7Sxw struct iocblk *iocp; 1525d39a76e7Sxw 1526d39a76e7Sxw switch (mp->b_datap->db_type) { 1527d39a76e7Sxw case M_IOCTL: 1528d39a76e7Sxw /* pe_ioctl() does qreply() */ 1529d39a76e7Sxw pe_ioctl((ch_t *)(macinfo->gldm_private), q, mp); 1530d39a76e7Sxw break; 1531d39a76e7Sxw 1532d39a76e7Sxw default: 1533d39a76e7Sxw /* 1534d39a76e7Sxw * cmn_err(CE_NOTE, "ch_ioctl not M_IOCTL\n"); 1535d39a76e7Sxw * debug_enter("bad ch_ioctl"); 1536d39a76e7Sxw */ 1537d39a76e7Sxw 1538d39a76e7Sxw iocp = (struct iocblk *)mp->b_rptr; 1539d39a76e7Sxw 1540d39a76e7Sxw if (mp->b_cont) 1541d39a76e7Sxw freemsg(mp->b_cont); 1542d39a76e7Sxw mp->b_cont = NULL; 1543d39a76e7Sxw 1544d39a76e7Sxw mp->b_datap->db_type = M_IOCNAK; 1545d39a76e7Sxw iocp->ioc_error = EINVAL; 1546d39a76e7Sxw qreply(q, mp); 1547d39a76e7Sxw break; 1548d39a76e7Sxw } 1549d39a76e7Sxw 1550d39a76e7Sxw return (GLD_SUCCESS); 1551d39a76e7Sxw } 1552d39a76e7Sxw 1553d39a76e7Sxw static int 1554d39a76e7Sxw ch_set_promiscuous(gld_mac_info_t *mp, int flag) 1555d39a76e7Sxw { 1556d39a76e7Sxw ch_t *chp = (ch_t *)mp->gldm_private; 1557d39a76e7Sxw 1558d39a76e7Sxw switch (flag) { 1559d39a76e7Sxw case GLD_MAC_PROMISC_MULTI: 1560d39a76e7Sxw pe_set_promiscuous(chp, 2); 1561d39a76e7Sxw break; 1562d39a76e7Sxw 1563d39a76e7Sxw case GLD_MAC_PROMISC_NONE: 1564d39a76e7Sxw pe_set_promiscuous(chp, 0); 1565d39a76e7Sxw break; 1566d39a76e7Sxw 1567d39a76e7Sxw case GLD_MAC_PROMISC_PHYS: 1568d39a76e7Sxw default: 1569d39a76e7Sxw pe_set_promiscuous(chp, 1); 1570d39a76e7Sxw break; 1571d39a76e7Sxw } 1572d39a76e7Sxw 1573d39a76e7Sxw return (GLD_SUCCESS); 1574d39a76e7Sxw } 1575d39a76e7Sxw 1576d39a76e7Sxw static int 1577d39a76e7Sxw ch_get_stats(gld_mac_info_t *mp, struct gld_stats *gs) 1578d39a76e7Sxw { 1579d39a76e7Sxw ch_t *chp = (ch_t *)mp->gldm_private; 1580d39a76e7Sxw uint64_t speed; 1581d39a76e7Sxw uint32_t intrcnt; 1582d39a76e7Sxw uint32_t norcvbuf; 1583d39a76e7Sxw uint32_t oerrors; 1584d39a76e7Sxw uint32_t ierrors; 1585d39a76e7Sxw uint32_t underrun; 1586d39a76e7Sxw uint32_t overrun; 1587d39a76e7Sxw uint32_t framing; 1588d39a76e7Sxw uint32_t crc; 1589d39a76e7Sxw uint32_t carrier; 1590d39a76e7Sxw uint32_t collisions; 1591d39a76e7Sxw uint32_t xcollisions; 1592d39a76e7Sxw uint32_t late; 1593d39a76e7Sxw uint32_t defer; 1594d39a76e7Sxw uint32_t xerrs; 1595d39a76e7Sxw uint32_t rerrs; 1596d39a76e7Sxw uint32_t toolong; 1597d39a76e7Sxw uint32_t runt; 1598d39a76e7Sxw ulong_t multixmt; 1599d39a76e7Sxw ulong_t multircv; 1600d39a76e7Sxw ulong_t brdcstxmt; 1601d39a76e7Sxw ulong_t brdcstrcv; 1602d39a76e7Sxw 1603d39a76e7Sxw /* 1604d39a76e7Sxw * race looks benign here. 1605d39a76e7Sxw */ 1606d39a76e7Sxw if (chp->ch_state != PERUNNING) { 1607d39a76e7Sxw return (GLD_FAILURE); 1608d39a76e7Sxw } 1609d39a76e7Sxw 1610d39a76e7Sxw (void) pe_get_stats(chp, 161119397407SSherry Moore &speed, 161219397407SSherry Moore &intrcnt, 161319397407SSherry Moore &norcvbuf, 161419397407SSherry Moore &oerrors, 161519397407SSherry Moore &ierrors, 161619397407SSherry Moore &underrun, 161719397407SSherry Moore &overrun, 161819397407SSherry Moore &framing, 161919397407SSherry Moore &crc, 162019397407SSherry Moore &carrier, 162119397407SSherry Moore &collisions, 162219397407SSherry Moore &xcollisions, 162319397407SSherry Moore &late, 162419397407SSherry Moore &defer, 162519397407SSherry Moore &xerrs, 162619397407SSherry Moore &rerrs, 162719397407SSherry Moore &toolong, 162819397407SSherry Moore &runt, 162919397407SSherry Moore &multixmt, 163019397407SSherry Moore &multircv, 163119397407SSherry Moore &brdcstxmt, 163219397407SSherry Moore &brdcstrcv); 1633d39a76e7Sxw 1634d39a76e7Sxw gs->glds_speed = speed; 1635d39a76e7Sxw gs->glds_media = GLDM_UNKNOWN; 1636d39a76e7Sxw gs->glds_intr = intrcnt; 1637d39a76e7Sxw gs->glds_norcvbuf = norcvbuf; 1638d39a76e7Sxw gs->glds_errxmt = oerrors; 1639d39a76e7Sxw gs->glds_errrcv = ierrors; 1640d39a76e7Sxw gs->glds_missed = ierrors; /* ??? */ 1641d39a76e7Sxw gs->glds_underflow = underrun; 1642d39a76e7Sxw gs->glds_overflow = overrun; 1643d39a76e7Sxw gs->glds_frame = framing; 1644d39a76e7Sxw gs->glds_crc = crc; 1645d39a76e7Sxw gs->glds_duplex = GLD_DUPLEX_FULL; 1646d39a76e7Sxw gs->glds_nocarrier = carrier; 1647d39a76e7Sxw gs->glds_collisions = collisions; 1648d39a76e7Sxw gs->glds_excoll = xcollisions; 1649d39a76e7Sxw gs->glds_xmtlatecoll = late; 1650d39a76e7Sxw gs->glds_defer = defer; 1651d39a76e7Sxw gs->glds_dot3_first_coll = 0; /* Not available */ 1652d39a76e7Sxw gs->glds_dot3_multi_coll = 0; /* Not available */ 1653d39a76e7Sxw gs->glds_dot3_sqe_error = 0; /* Not available */ 1654d39a76e7Sxw gs->glds_dot3_mac_xmt_error = xerrs; 1655d39a76e7Sxw gs->glds_dot3_mac_rcv_error = rerrs; 1656d39a76e7Sxw gs->glds_dot3_frame_too_long = toolong; 1657d39a76e7Sxw gs->glds_short = runt; 1658d39a76e7Sxw 1659d39a76e7Sxw gs->glds_noxmtbuf = 0; /* not documented */ 1660d39a76e7Sxw gs->glds_xmtretry = 0; /* not documented */ 1661d39a76e7Sxw gs->glds_multixmt = multixmt; /* not documented */ 1662d39a76e7Sxw gs->glds_multircv = multircv; /* not documented */ 1663d39a76e7Sxw gs->glds_brdcstxmt = brdcstxmt; /* not documented */ 1664d39a76e7Sxw gs->glds_brdcstrcv = brdcstrcv; /* not documented */ 1665d39a76e7Sxw 1666d39a76e7Sxw return (GLD_SUCCESS); 1667d39a76e7Sxw } 1668d39a76e7Sxw 1669d39a76e7Sxw 1670d39a76e7Sxw static int 1671d39a76e7Sxw ch_send(gld_mac_info_t *macinfo, mblk_t *mp) 1672d39a76e7Sxw { 1673d39a76e7Sxw ch_t *chp = (ch_t *)macinfo->gldm_private; 1674d39a76e7Sxw uint32_t flg; 1675d39a76e7Sxw uint32_t msg_flg; 1676d39a76e7Sxw 1677d39a76e7Sxw #ifdef TX_CKSUM_FIX 1678d39a76e7Sxw mblk_t *nmp; 1679d39a76e7Sxw int frags; 1680d39a76e7Sxw size_t msg_len; 1681d39a76e7Sxw struct ether_header *ehdr; 1682d39a76e7Sxw ipha_t *ihdr; 1683d39a76e7Sxw int tflg = 0; 1684d39a76e7Sxw #endif /* TX_CKSUM_FIX */ 1685d39a76e7Sxw 1686d39a76e7Sxw /* 1687d39a76e7Sxw * race looks benign here. 1688d39a76e7Sxw */ 1689d39a76e7Sxw if (chp->ch_state != PERUNNING) { 1690d39a76e7Sxw return (GLD_FAILURE); 1691d39a76e7Sxw } 1692d39a76e7Sxw 1693d39a76e7Sxw msg_flg = 0; 1694d39a76e7Sxw if (chp->ch_config.cksum_enabled) { 1695d39a76e7Sxw if (is_T2(chp)) { 1696d39a76e7Sxw hcksum_retrieve(mp, NULL, NULL, NULL, NULL, NULL, 169719397407SSherry Moore NULL, &msg_flg); 1698d39a76e7Sxw flg = (msg_flg & HCK_FULLCKSUM)? 169919397407SSherry Moore CH_NO_CPL: CH_NO_HWCKSUM|CH_NO_CPL; 1700d39a76e7Sxw } else 1701d39a76e7Sxw flg = CH_NO_CPL; 1702d39a76e7Sxw } else 1703d39a76e7Sxw flg = CH_NO_HWCKSUM | CH_NO_CPL; 1704d39a76e7Sxw 1705d39a76e7Sxw #ifdef TX_CKSUM_FIX 1706d39a76e7Sxw /* 1707d39a76e7Sxw * Check if the message spans more than one mblk or 1708d39a76e7Sxw * if it does and the ip header is not in the first 1709d39a76e7Sxw * fragment then pull up the message. This case is 1710d39a76e7Sxw * expected to be rare. 1711d39a76e7Sxw */ 1712d39a76e7Sxw frags = 0; 1713d39a76e7Sxw msg_len = 0; 1714d39a76e7Sxw nmp = mp; 1715d39a76e7Sxw do { 1716d39a76e7Sxw frags++; 1717d39a76e7Sxw msg_len += MBLKL(nmp); 1718d39a76e7Sxw nmp = nmp->b_cont; 1719d39a76e7Sxw } while (nmp); 1720d39a76e7Sxw #define MAX_ALL_HDRLEN SZ_CPL_TX_PKT + sizeof (struct ether_header) + \ 1721d39a76e7Sxw TCP_MAX_COMBINED_HEADER_LENGTH 1722d39a76e7Sxw /* 1723d39a76e7Sxw * If the first mblk has enough space at the beginning of 1724d39a76e7Sxw * the data buffer to hold a CPL header, then, we'll expancd 1725d39a76e7Sxw * the front of the buffer so a pullup will leave space for 1726d39a76e7Sxw * pe_start() to add the CPL header in line. We need to remember 1727d39a76e7Sxw * that we've done this so we can undo it after the pullup. 1728d39a76e7Sxw * 1729d39a76e7Sxw * Note that if we decide to do an allocb to hold the CPL header, 1730d39a76e7Sxw * we need to catch the case where we've added an empty mblk for 1731d39a76e7Sxw * the header but never did a pullup. This would result in the 1732d39a76e7Sxw * tests for etherheader, etc. being done on the initial, empty, 1733d39a76e7Sxw * mblk instead of the one with data. See PR3646 for further 1734d39a76e7Sxw * details. (note this PR is closed since it is no longer relevant). 1735d39a76e7Sxw * 1736d39a76e7Sxw * Another point is that if we do add an allocb to add space for 1737d39a76e7Sxw * a CPL header, after a pullup, the initial pointer, mp, in GLD will 1738d39a76e7Sxw * no longer point to a valid mblk. When we get the mblk (by allocb), 1739d39a76e7Sxw * we need to switch the mblk structure values between it and the 1740d39a76e7Sxw * mp structure values referenced by GLD. This handles the case where 1741d39a76e7Sxw * we've run out of cmdQ entries and report GLD_NORESOURCES back to 1742d39a76e7Sxw * GLD. The pointer to the mblk data will have been modified to hold 1743d39a76e7Sxw * an empty 8 bytes for the CPL header, For now, we let the pe_start() 1744d39a76e7Sxw * routine prepend an 8 byte mblk. 1745d39a76e7Sxw */ 1746d39a76e7Sxw if (MBLKHEAD(mp) >= SZ_CPL_TX_PKT) { 1747d39a76e7Sxw mp->b_rptr -= SZ_CPL_TX_PKT; 1748d39a76e7Sxw tflg = 1; 1749d39a76e7Sxw } 1750d39a76e7Sxw if (frags > 3) { 1751d39a76e7Sxw chp->sge->intr_cnt.tx_msg_pullups++; 1752d39a76e7Sxw if (pullupmsg(mp, -1) == 0) { 1753d39a76e7Sxw freemsg(mp); 1754d39a76e7Sxw return (GLD_SUCCESS); 1755d39a76e7Sxw } 1756d39a76e7Sxw } else if ((msg_len > MAX_ALL_HDRLEN) && 175719397407SSherry Moore (MBLKL(mp) < MAX_ALL_HDRLEN)) { 1758d39a76e7Sxw chp->sge->intr_cnt.tx_hdr_pullups++; 1759d39a76e7Sxw if (pullupmsg(mp, MAX_ALL_HDRLEN) == 0) { 1760d39a76e7Sxw freemsg(mp); 1761d39a76e7Sxw return (GLD_SUCCESS); 1762d39a76e7Sxw } 1763d39a76e7Sxw } 1764d39a76e7Sxw if (tflg) 1765d39a76e7Sxw mp->b_rptr += SZ_CPL_TX_PKT; 1766d39a76e7Sxw 1767d39a76e7Sxw ehdr = (struct ether_header *)mp->b_rptr; 1768d39a76e7Sxw if (ehdr->ether_type == htons(ETHERTYPE_IP)) { 1769d39a76e7Sxw ihdr = (ipha_t *)&mp->b_rptr[sizeof (struct ether_header)]; 1770d39a76e7Sxw if ((ihdr->ipha_fragment_offset_and_flags & IPH_MF)) { 1771d39a76e7Sxw if (ihdr->ipha_protocol == IPPROTO_UDP) { 1772d39a76e7Sxw flg |= CH_UDP_MF; 1773d39a76e7Sxw chp->sge->intr_cnt.tx_udp_ip_frag++; 1774d39a76e7Sxw } else if (ihdr->ipha_protocol == IPPROTO_TCP) { 1775d39a76e7Sxw flg |= CH_TCP_MF; 1776d39a76e7Sxw chp->sge->intr_cnt.tx_tcp_ip_frag++; 1777d39a76e7Sxw } 1778d39a76e7Sxw } else if (ihdr->ipha_protocol == IPPROTO_UDP) 1779d39a76e7Sxw flg |= CH_UDP; 1780d39a76e7Sxw } 1781d39a76e7Sxw #endif /* TX_CKSUM_FIX */ 1782d39a76e7Sxw 1783d39a76e7Sxw /* 1784d39a76e7Sxw * return 0 - data send successfully 1785d39a76e7Sxw * return 1 - no resources, reschedule 1786d39a76e7Sxw */ 1787d39a76e7Sxw if (pe_start(chp, mp, flg)) 1788d39a76e7Sxw return (GLD_NORESOURCES); 1789d39a76e7Sxw else 1790d39a76e7Sxw return (GLD_SUCCESS); 1791d39a76e7Sxw } 1792d39a76e7Sxw 1793d39a76e7Sxw static uint_t 1794d39a76e7Sxw ch_intr(gld_mac_info_t *mp) 1795d39a76e7Sxw { 1796d39a76e7Sxw return (pe_intr((ch_t *)mp->gldm_private)); 1797d39a76e7Sxw } 1798d39a76e7Sxw 1799d39a76e7Sxw /* 1800d39a76e7Sxw * generate name of driver with unit# postpended. 1801d39a76e7Sxw */ 1802d39a76e7Sxw void 1803d39a76e7Sxw ch_set_name(ch_t *chp, int unit) 1804d39a76e7Sxw { 1805d39a76e7Sxw chp->ch_name = (char *)kmem_alloc(sizeof ("chxge00"), KM_SLEEP); 1806d39a76e7Sxw if (unit > 9) { 1807d39a76e7Sxw bcopy("chxge00", (void *)chp->ch_name, sizeof ("chxge00")); 1808d39a76e7Sxw chp->ch_name[5] += unit/10; 1809d39a76e7Sxw chp->ch_name[6] += unit%10; 1810d39a76e7Sxw } else { 1811d39a76e7Sxw bcopy("chxge0", (void *)chp->ch_name, sizeof ("chxge0")); 1812d39a76e7Sxw chp->ch_name[5] += unit; 1813d39a76e7Sxw } 1814d39a76e7Sxw } 1815d39a76e7Sxw 1816d39a76e7Sxw void 1817d39a76e7Sxw ch_free_name(ch_t *chp) 1818d39a76e7Sxw { 1819d39a76e7Sxw if (chp->ch_name) 1820d39a76e7Sxw kmem_free(chp->ch_name, sizeof ("chxge00")); 1821d39a76e7Sxw chp->ch_name = NULL; 1822d39a76e7Sxw } 1823d39a76e7Sxw 1824d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD 1825d39a76e7Sxw /* 1826d39a76e7Sxw * register toe offload. 1827d39a76e7Sxw */ 1828d39a76e7Sxw void * 1829d39a76e7Sxw ch_register(void *instp, void *toe_rcv, void *toe_free, void *toe_tunnel, 1830d39a76e7Sxw kmutex_t *toe_tx_mx, kcondvar_t *toe_of_cv, int unit) 1831d39a76e7Sxw { 1832d39a76e7Sxw ch_t *chp = gchp[unit]; 1833d39a76e7Sxw if (chp != NULL) { 1834d39a76e7Sxw mutex_enter(&chp->ch_lock); 1835d39a76e7Sxw 1836d39a76e7Sxw chp->toe_rcv = (void (*)(void *, mblk_t *))toe_rcv; 1837d39a76e7Sxw chp->ch_toeinst = instp; 1838d39a76e7Sxw chp->toe_free = (void (*)(void *, tbuf_t *))toe_free; 1839d39a76e7Sxw chp->toe_tunnel = (int (*)(void *, mblk_t *))toe_tunnel; 1840d39a76e7Sxw chp->ch_tx_overflow_mutex = toe_tx_mx; 1841d39a76e7Sxw chp->ch_tx_overflow_cv = toe_of_cv; 1842d39a76e7Sxw chp->open_device_map |= TOEDEV_DEVMAP_BIT; 1843d39a76e7Sxw 1844d39a76e7Sxw /* start up adapter if first user */ 1845d39a76e7Sxw chp->ch_refcnt++; 1846d39a76e7Sxw if (chp->ch_refcnt == 1) { 1847d39a76e7Sxw chp->ch_state = PERUNNING; 1848d39a76e7Sxw mutex_exit(&chp->ch_lock); 1849d39a76e7Sxw pe_init((void *)chp); 1850d39a76e7Sxw } else 1851d39a76e7Sxw mutex_exit(&chp->ch_lock); 1852d39a76e7Sxw } 1853d39a76e7Sxw return ((void *)gchp[unit]); 1854d39a76e7Sxw } 1855d39a76e7Sxw 1856d39a76e7Sxw /* 1857d39a76e7Sxw * unregister toe offload. 1858d39a76e7Sxw * XXX Need to fix races here. 1859d39a76e7Sxw * 1. turn off SGE interrupts. 1860d39a76e7Sxw * 2. do update 1861d39a76e7Sxw * 3. re-enable SGE interrupts 1862d39a76e7Sxw * 4. SGE doorbell to make sure things get restarted. 1863d39a76e7Sxw */ 1864d39a76e7Sxw void 1865d39a76e7Sxw ch_unregister(void) 1866d39a76e7Sxw { 1867d39a76e7Sxw int i; 1868d39a76e7Sxw ch_t *chp; 1869d39a76e7Sxw 1870d39a76e7Sxw for (i = 0; i < MAX_CARDS; i++) { 1871d39a76e7Sxw chp = gchp[i]; 1872d39a76e7Sxw if (chp == NULL) 1873d39a76e7Sxw continue; 1874d39a76e7Sxw 1875d39a76e7Sxw mutex_enter(&chp->ch_lock); 1876d39a76e7Sxw 1877d39a76e7Sxw chp->ch_refcnt--; 1878d39a76e7Sxw if (chp->ch_refcnt == 0) { 1879d39a76e7Sxw chp->ch_state = PESTOP; 1880d39a76e7Sxw mutex_exit(&chp->ch_lock); 1881d39a76e7Sxw pe_stop(chp); 1882d39a76e7Sxw } else 1883d39a76e7Sxw mutex_exit(&chp->ch_lock); 1884d39a76e7Sxw 1885d39a76e7Sxw chp->open_device_map &= ~TOEDEV_DEVMAP_BIT; 1886d39a76e7Sxw chp->toe_rcv = NULL; 1887d39a76e7Sxw chp->ch_toeinst = NULL; 1888d39a76e7Sxw chp->toe_free = NULL; 1889d39a76e7Sxw chp->toe_tunnel = NULL; 1890d39a76e7Sxw chp->ch_tx_overflow_mutex = NULL; 1891d39a76e7Sxw chp->ch_tx_overflow_cv = NULL; 1892d39a76e7Sxw } 1893d39a76e7Sxw } 1894d39a76e7Sxw #endif /* CONFIG_CHELSIO_T1_OFFLOAD */ 1895d39a76e7Sxw 1896d39a76e7Sxw /* 1897d39a76e7Sxw * get properties from chxge.conf 1898d39a76e7Sxw */ 1899d39a76e7Sxw static void 1900d39a76e7Sxw ch_get_prop(ch_t *chp) 1901d39a76e7Sxw { 1902d39a76e7Sxw int val; 1903d39a76e7Sxw int tval = 0; 1904d39a76e7Sxw extern int enable_latency_timer; 1905d39a76e7Sxw extern uint32_t sge_cmdq0_cnt; 1906d39a76e7Sxw extern uint32_t sge_cmdq1_cnt; 1907d39a76e7Sxw extern uint32_t sge_flq0_cnt; 1908d39a76e7Sxw extern uint32_t sge_flq1_cnt; 1909d39a76e7Sxw extern uint32_t sge_respq_cnt; 1910d39a76e7Sxw extern uint32_t sge_cmdq0_cnt_orig; 1911d39a76e7Sxw extern uint32_t sge_cmdq1_cnt_orig; 1912d39a76e7Sxw extern uint32_t sge_flq0_cnt_orig; 1913d39a76e7Sxw extern uint32_t sge_flq1_cnt_orig; 1914d39a76e7Sxw extern uint32_t sge_respq_cnt_orig; 1915d39a76e7Sxw dev_info_t *pdip; 1916d39a76e7Sxw uint32_t vendor_id, device_id, revision_id; 1917d39a76e7Sxw uint32_t *prop_val = NULL; 1918*11abda1eSToomas Soome uint32_t prop_len = 0; 1919d39a76e7Sxw 1920d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 192119397407SSherry Moore "enable_dvma", -1); 1922d39a76e7Sxw if (val == -1) 1923d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 192419397407SSherry Moore "enable-dvma", -1); 1925d39a76e7Sxw if (val != -1) { 1926d39a76e7Sxw if (val != 0) 1927d39a76e7Sxw chp->ch_config.enable_dvma = 1; 1928d39a76e7Sxw } 1929d39a76e7Sxw 1930d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 193119397407SSherry Moore "amd_bug_workaround", -1); 1932d39a76e7Sxw if (val == -1) 1933d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 193419397407SSherry Moore "amd-bug-workaround", -1); 1935d39a76e7Sxw 1936d39a76e7Sxw if (val != -1) { 1937d39a76e7Sxw if (val == 0) { 1938d39a76e7Sxw chp->ch_config.burstsize_set = 0; 1939d39a76e7Sxw chp->ch_config.transaction_cnt_set = 0; 1940d39a76e7Sxw goto fail_exit; 1941d39a76e7Sxw } 1942d39a76e7Sxw } 1943d39a76e7Sxw /* 1944d39a76e7Sxw * Step up to the parent node, That's the node above us 1945d39a76e7Sxw * in the device tree. And will typically be the PCI host 1946d39a76e7Sxw * Controller. 1947d39a76e7Sxw */ 1948d39a76e7Sxw pdip = ddi_get_parent(chp->ch_dip); 1949d39a76e7Sxw 1950d39a76e7Sxw /* 1951d39a76e7Sxw * Now get the 'Vendor id' properties 1952d39a76e7Sxw */ 1953d39a76e7Sxw if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, pdip, 0, "vendor-id", 1954d39a76e7Sxw (int **)&prop_val, &prop_len) != DDI_PROP_SUCCESS) { 1955d39a76e7Sxw chp->ch_config.burstsize_set = 0; 1956d39a76e7Sxw chp->ch_config.transaction_cnt_set = 0; 1957d39a76e7Sxw goto fail_exit; 1958d39a76e7Sxw } 1959d39a76e7Sxw vendor_id = *(uint32_t *)prop_val; 1960d39a76e7Sxw ddi_prop_free(prop_val); 1961d39a76e7Sxw 1962d39a76e7Sxw /* 1963d39a76e7Sxw * Now get the 'Device id' properties 1964d39a76e7Sxw */ 1965d39a76e7Sxw if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, pdip, 0, "device-id", 1966d39a76e7Sxw (int **)&prop_val, &prop_len) != DDI_PROP_SUCCESS) { 1967d39a76e7Sxw chp->ch_config.burstsize_set = 0; 1968d39a76e7Sxw chp->ch_config.transaction_cnt_set = 0; 1969d39a76e7Sxw goto fail_exit; 1970d39a76e7Sxw } 1971d39a76e7Sxw device_id = *(uint32_t *)prop_val; 1972d39a76e7Sxw ddi_prop_free(prop_val); 1973d39a76e7Sxw 1974d39a76e7Sxw /* 1975d39a76e7Sxw * Now get the 'Revision id' properties 1976d39a76e7Sxw */ 1977d39a76e7Sxw if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, pdip, 0, "revision-id", 1978d39a76e7Sxw (int **)&prop_val, &prop_len) != DDI_PROP_SUCCESS) { 1979d39a76e7Sxw chp->ch_config.burstsize_set = 0; 1980d39a76e7Sxw chp->ch_config.transaction_cnt_set = 0; 1981d39a76e7Sxw goto fail_exit; 1982d39a76e7Sxw } 1983d39a76e7Sxw revision_id = *(uint32_t *)prop_val; 1984d39a76e7Sxw ddi_prop_free(prop_val); 1985d39a76e7Sxw 1986d39a76e7Sxw /* 1987d39a76e7Sxw * set default values based on node above us. 1988d39a76e7Sxw */ 1989d39a76e7Sxw if ((vendor_id == AMD_VENDOR_ID) && (device_id == AMD_BRIDGE) && 1990d39a76e7Sxw (revision_id <= AMD_BRIDGE_REV)) { 1991d39a76e7Sxw uint32_t v; 1992d39a76e7Sxw uint32_t burst; 1993d39a76e7Sxw uint32_t cnt; 1994d39a76e7Sxw 1995d39a76e7Sxw /* if 133 Mhz not enabled, then do nothing - we're not PCIx */ 1996d39a76e7Sxw v = pci_config_get32(chp->ch_hpci, 0x64); 1997*11abda1eSToomas Soome if ((v & 0x20000) == 0) { 1998d39a76e7Sxw chp->ch_config.burstsize_set = 0; 1999d39a76e7Sxw chp->ch_config.transaction_cnt_set = 0; 2000d39a76e7Sxw goto fail_exit; 2001d39a76e7Sxw } 2002d39a76e7Sxw 2003d39a76e7Sxw /* check burst size and transaction count */ 2004d39a76e7Sxw v = pci_config_get32(chp->ch_hpci, 0x60); 2005d39a76e7Sxw burst = (v >> 18) & 3; 2006d39a76e7Sxw cnt = (v >> 20) & 7; 2007d39a76e7Sxw 2008d39a76e7Sxw switch (burst) { 2009d39a76e7Sxw case 0: /* 512 */ 2010d39a76e7Sxw /* 512 burst size legal with split cnts 1,2,3 */ 2011d39a76e7Sxw if (cnt <= 2) { 2012d39a76e7Sxw chp->ch_config.burstsize_set = 0; 2013d39a76e7Sxw chp->ch_config.transaction_cnt_set = 0; 2014d39a76e7Sxw goto fail_exit; 2015d39a76e7Sxw } 2016d39a76e7Sxw break; 2017d39a76e7Sxw case 1: /* 1024 */ 2018d39a76e7Sxw /* 1024 burst size legal with split cnts 1,2 */ 2019d39a76e7Sxw if (cnt <= 1) { 2020d39a76e7Sxw chp->ch_config.burstsize_set = 0; 2021d39a76e7Sxw chp->ch_config.transaction_cnt_set = 0; 2022d39a76e7Sxw goto fail_exit; 2023d39a76e7Sxw } 2024d39a76e7Sxw break; 2025d39a76e7Sxw case 2: /* 2048 */ 2026d39a76e7Sxw /* 2048 burst size legal with split cnts 1 */ 2027d39a76e7Sxw if (cnt == 0) { 2028d39a76e7Sxw chp->ch_config.burstsize_set = 0; 2029d39a76e7Sxw chp->ch_config.transaction_cnt_set = 0; 2030d39a76e7Sxw goto fail_exit; 2031d39a76e7Sxw } 2032d39a76e7Sxw break; 2033d39a76e7Sxw case 3: /* 4096 */ 2034d39a76e7Sxw break; 2035d39a76e7Sxw } 2036d39a76e7Sxw } else { 2037d39a76e7Sxw goto fail_exit; 2038d39a76e7Sxw } 2039d39a76e7Sxw 2040d39a76e7Sxw /* 2041d39a76e7Sxw * if illegal burst size seen, then default to 1024 burst size 2042d39a76e7Sxw */ 2043d39a76e7Sxw chp->ch_config.burstsize = 1; 2044d39a76e7Sxw chp->ch_config.burstsize_set = 1; 2045d39a76e7Sxw /* 2046d39a76e7Sxw * if illegal transaction cnt seen, then default to 2 2047d39a76e7Sxw */ 2048d39a76e7Sxw chp->ch_config.transaction_cnt = 1; 2049d39a76e7Sxw chp->ch_config.transaction_cnt_set = 1; 2050d39a76e7Sxw 2051d39a76e7Sxw 2052d39a76e7Sxw fail_exit: 2053d39a76e7Sxw 2054d39a76e7Sxw /* 2055d39a76e7Sxw * alter the burstsize parameter via an entry 2056d39a76e7Sxw * in chxge.conf 2057d39a76e7Sxw */ 2058d39a76e7Sxw 2059d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 206019397407SSherry Moore "pci_burstsize", -1); 2061d39a76e7Sxw if (val == -1) 2062d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 206319397407SSherry Moore "pci-burstsize", -1); 2064d39a76e7Sxw 2065d39a76e7Sxw if (val != -1) { 2066d39a76e7Sxw 2067d39a76e7Sxw switch (val) { 2068d39a76e7Sxw case 0: /* use default */ 2069d39a76e7Sxw chp->ch_config.burstsize_set = 0; 2070d39a76e7Sxw break; 2071d39a76e7Sxw 2072d39a76e7Sxw case 1024: 2073d39a76e7Sxw chp->ch_config.burstsize_set = 1; 2074d39a76e7Sxw chp->ch_config.burstsize = 1; 2075d39a76e7Sxw break; 2076d39a76e7Sxw 2077d39a76e7Sxw case 2048: 2078d39a76e7Sxw chp->ch_config.burstsize_set = 1; 2079d39a76e7Sxw chp->ch_config.burstsize = 2; 2080d39a76e7Sxw break; 2081d39a76e7Sxw 2082d39a76e7Sxw case 4096: 2083d39a76e7Sxw cmn_err(CE_WARN, "%s not supported %d\n", 2084d39a76e7Sxw chp->ch_name, val); 2085d39a76e7Sxw break; 2086d39a76e7Sxw 2087d39a76e7Sxw default: 2088d39a76e7Sxw cmn_err(CE_WARN, "%s illegal burst size %d\n", 2089d39a76e7Sxw chp->ch_name, val); 2090d39a76e7Sxw break; 2091d39a76e7Sxw } 2092d39a76e7Sxw } 2093d39a76e7Sxw 2094d39a76e7Sxw /* 2095d39a76e7Sxw * set transaction count 2096d39a76e7Sxw */ 2097d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 209819397407SSherry Moore "pci_split_transaction_cnt", -1); 2099d39a76e7Sxw if (val == -1) 2100d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 210119397407SSherry Moore "pci-split-transaction-cnt", -1); 2102d39a76e7Sxw 2103d39a76e7Sxw if (val != -1) { 2104d39a76e7Sxw switch (val) { 2105d39a76e7Sxw case 0: /* use default */ 2106d39a76e7Sxw chp->ch_config.transaction_cnt_set = 0; 2107d39a76e7Sxw break; 2108d39a76e7Sxw 2109d39a76e7Sxw case 1: 2110d39a76e7Sxw chp->ch_config.transaction_cnt_set = 1; 2111d39a76e7Sxw chp->ch_config.transaction_cnt = 0; 2112d39a76e7Sxw break; 2113d39a76e7Sxw 2114d39a76e7Sxw case 2: 2115d39a76e7Sxw chp->ch_config.transaction_cnt_set = 1; 2116d39a76e7Sxw chp->ch_config.transaction_cnt = 1; 2117d39a76e7Sxw break; 2118d39a76e7Sxw 2119d39a76e7Sxw case 3: 2120d39a76e7Sxw chp->ch_config.transaction_cnt_set = 1; 2121d39a76e7Sxw chp->ch_config.transaction_cnt = 2; 2122d39a76e7Sxw break; 2123d39a76e7Sxw 2124d39a76e7Sxw case 4: 2125d39a76e7Sxw chp->ch_config.transaction_cnt_set = 1; 2126d39a76e7Sxw chp->ch_config.transaction_cnt = 3; 2127d39a76e7Sxw break; 2128d39a76e7Sxw 2129d39a76e7Sxw case 8: 2130d39a76e7Sxw chp->ch_config.transaction_cnt_set = 1; 2131d39a76e7Sxw chp->ch_config.transaction_cnt = 4; 2132d39a76e7Sxw break; 2133d39a76e7Sxw 2134d39a76e7Sxw case 12: 2135d39a76e7Sxw chp->ch_config.transaction_cnt_set = 1; 2136d39a76e7Sxw chp->ch_config.transaction_cnt = 5; 2137d39a76e7Sxw break; 2138d39a76e7Sxw 2139d39a76e7Sxw case 16: 2140d39a76e7Sxw chp->ch_config.transaction_cnt_set = 1; 2141d39a76e7Sxw chp->ch_config.transaction_cnt = 6; 2142d39a76e7Sxw break; 2143d39a76e7Sxw 2144d39a76e7Sxw case 32: 2145d39a76e7Sxw chp->ch_config.transaction_cnt_set = 1; 2146d39a76e7Sxw chp->ch_config.transaction_cnt = 7; 2147d39a76e7Sxw break; 2148d39a76e7Sxw 2149d39a76e7Sxw default: 2150d39a76e7Sxw cmn_err(CE_WARN, "%s illegal transaction cnt %d\n", 2151d39a76e7Sxw chp->ch_name, val); 2152d39a76e7Sxw break; 2153d39a76e7Sxw } 2154d39a76e7Sxw } 2155d39a76e7Sxw 2156d39a76e7Sxw /* 2157d39a76e7Sxw * set relaxed ordering bit? 2158d39a76e7Sxw */ 2159d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 216019397407SSherry Moore "pci_relaxed_ordering_on", -1); 2161d39a76e7Sxw if (val == -1) 2162d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 216319397407SSherry Moore "pci-relaxed-ordering-on", -1); 2164d39a76e7Sxw 2165d39a76e7Sxw /* 2166d39a76e7Sxw * default is to use system default value. 2167d39a76e7Sxw */ 2168d39a76e7Sxw chp->ch_config.relaxed_ordering = 0; 2169d39a76e7Sxw 2170d39a76e7Sxw if (val != -1) { 2171d39a76e7Sxw if (val) 2172d39a76e7Sxw chp->ch_config.relaxed_ordering = 1; 2173d39a76e7Sxw } 2174d39a76e7Sxw 2175d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 217619397407SSherry Moore "enable_latency_timer", -1); 2177d39a76e7Sxw if (val == -1) 2178d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 217919397407SSherry Moore "enable-latency-timer", -1); 2180d39a76e7Sxw if (val != -1) 2181d39a76e7Sxw enable_latency_timer = (val == 0)? 0: 1; 2182d39a76e7Sxw 2183d39a76e7Sxw /* 2184d39a76e7Sxw * default maximum Jumbo Frame size. 2185d39a76e7Sxw */ 2186d39a76e7Sxw chp->ch_maximum_mtu = 9198; /* tunable via chxge.conf */ 2187d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 218819397407SSherry Moore "maximum_mtu", -1); 2189d39a76e7Sxw if (val == -1) { 2190d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 219119397407SSherry Moore "maximum-mtu", -1); 2192d39a76e7Sxw } 2193d39a76e7Sxw if (val != -1) { 2194d39a76e7Sxw if (val > 9582) { 2195d39a76e7Sxw cmn_err(CE_WARN, 2196d39a76e7Sxw "maximum_mtu value %d > 9582. Value set to 9582", 2197d39a76e7Sxw val); 2198d39a76e7Sxw val = 9582; 2199d39a76e7Sxw } else if (val < 1500) { 2200d39a76e7Sxw cmn_err(CE_WARN, 2201d39a76e7Sxw "maximum_mtu value %d < 1500. Value set to 1500", 2202d39a76e7Sxw val); 2203d39a76e7Sxw val = 1500; 2204d39a76e7Sxw } 2205d39a76e7Sxw 2206d39a76e7Sxw if (val) 2207d39a76e7Sxw chp->ch_maximum_mtu = val; 2208d39a76e7Sxw } 2209d39a76e7Sxw 2210d39a76e7Sxw /* 2211d39a76e7Sxw * default value for this instance mtu 2212d39a76e7Sxw */ 2213d39a76e7Sxw chp->ch_mtu = ETHERMTU; 2214d39a76e7Sxw 2215d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 221619397407SSherry Moore "accept_jumbo", -1); 2217d39a76e7Sxw if (val == -1) { 2218d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 221919397407SSherry Moore "accept-jumbo", -1); 2220d39a76e7Sxw } 2221d39a76e7Sxw if (val != -1) { 2222d39a76e7Sxw if (val) 2223d39a76e7Sxw chp->ch_mtu = chp->ch_maximum_mtu; 2224d39a76e7Sxw } 2225d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD 2226d39a76e7Sxw chp->ch_sm_buf_sz = 0x800; 2227d39a76e7Sxw chp->ch_sm_buf_aln = 0x800; 2228d39a76e7Sxw chp->ch_bg_buf_sz = 0x4000; 2229d39a76e7Sxw chp->ch_bg_buf_aln = 0x4000; 2230d39a76e7Sxw #else 2231d39a76e7Sxw chp->ch_sm_buf_sz = 0x200; 2232d39a76e7Sxw chp->ch_sm_buf_aln = 0x200; 2233d39a76e7Sxw chp->ch_bg_buf_sz = 0x800; 2234d39a76e7Sxw chp->ch_bg_buf_aln = 0x800; 2235d39a76e7Sxw if ((chp->ch_mtu > 0x800) && (chp->ch_mtu <= 0x1000)) { 2236d39a76e7Sxw chp->ch_sm_buf_sz = 0x400; 2237d39a76e7Sxw chp->ch_sm_buf_aln = 0x400; 2238d39a76e7Sxw chp->ch_bg_buf_sz = 0x1000; 2239d39a76e7Sxw chp->ch_bg_buf_aln = 0x1000; 2240d39a76e7Sxw } else if ((chp->ch_mtu > 0x1000) && (chp->ch_mtu <= 0x2000)) { 2241d39a76e7Sxw chp->ch_sm_buf_sz = 0x400; 2242d39a76e7Sxw chp->ch_sm_buf_aln = 0x400; 2243d39a76e7Sxw chp->ch_bg_buf_sz = 0x2000; 2244d39a76e7Sxw chp->ch_bg_buf_aln = 0x2000; 2245d39a76e7Sxw } else if (chp->ch_mtu > 0x2000) { 2246d39a76e7Sxw chp->ch_sm_buf_sz = 0x400; 2247d39a76e7Sxw chp->ch_sm_buf_aln = 0x400; 2248d39a76e7Sxw chp->ch_bg_buf_sz = 0x3000; 2249d39a76e7Sxw chp->ch_bg_buf_aln = 0x4000; 2250d39a76e7Sxw } 2251d39a76e7Sxw #endif 2252d39a76e7Sxw chp->ch_config.cksum_enabled = 1; 2253d39a76e7Sxw 2254d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 225519397407SSherry Moore "enable_checksum_offload", -1); 2256d39a76e7Sxw if (val == -1) 2257d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 225819397407SSherry Moore "enable-checksum-offload", -1); 2259d39a76e7Sxw if (val != -1) { 2260*11abda1eSToomas Soome if (val == 0) 2261d39a76e7Sxw chp->ch_config.cksum_enabled = 0; 2262d39a76e7Sxw } 2263d39a76e7Sxw 2264d39a76e7Sxw /* 2265d39a76e7Sxw * Provides a tuning capability for the command queue 0 size. 2266d39a76e7Sxw */ 2267d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 226819397407SSherry Moore "sge_cmdq0_cnt", -1); 2269d39a76e7Sxw if (val == -1) 2270d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 227119397407SSherry Moore "sge-cmdq0-cnt", -1); 2272d39a76e7Sxw if (val != -1) { 2273d39a76e7Sxw if (val > 10) 2274d39a76e7Sxw sge_cmdq0_cnt = val; 2275d39a76e7Sxw } 2276d39a76e7Sxw 2277d39a76e7Sxw if (sge_cmdq0_cnt > 65535) { 2278d39a76e7Sxw cmn_err(CE_WARN, 2279d39a76e7Sxw "%s: sge-cmdQ0-cnt > 65535 - resetting value to default", 228019397407SSherry Moore chp->ch_name); 2281d39a76e7Sxw sge_cmdq0_cnt = sge_cmdq0_cnt_orig; 2282d39a76e7Sxw } 2283d39a76e7Sxw tval += sge_cmdq0_cnt; 2284d39a76e7Sxw 2285d39a76e7Sxw /* 2286d39a76e7Sxw * Provides a tuning capability for the command queue 1 size. 2287d39a76e7Sxw */ 2288d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 228919397407SSherry Moore "sge_cmdq1_cnt", -1); 2290d39a76e7Sxw if (val == -1) 2291d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 229219397407SSherry Moore "sge-cmdq1-cnt", -1); 2293d39a76e7Sxw if (val != -1) { 2294d39a76e7Sxw if (val > 10) 2295d39a76e7Sxw sge_cmdq1_cnt = val; 2296d39a76e7Sxw } 2297d39a76e7Sxw 2298d39a76e7Sxw if (sge_cmdq1_cnt > 65535) { 2299d39a76e7Sxw cmn_err(CE_WARN, 2300d39a76e7Sxw "%s: sge-cmdQ0-cnt > 65535 - resetting value to default", 230119397407SSherry Moore chp->ch_name); 2302d39a76e7Sxw sge_cmdq1_cnt = sge_cmdq1_cnt_orig; 2303d39a76e7Sxw } 2304d39a76e7Sxw 2305d39a76e7Sxw /* 2306d39a76e7Sxw * Provides a tuning capability for the free list 0 size. 2307d39a76e7Sxw */ 2308d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 230919397407SSherry Moore "sge_flq0_cnt", -1); 2310d39a76e7Sxw if (val == -1) 2311d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 231219397407SSherry Moore "sge-flq0-cnt", -1); 2313d39a76e7Sxw if (val != -1) { 2314d39a76e7Sxw if (val > 512) 2315d39a76e7Sxw sge_flq0_cnt = val; 2316d39a76e7Sxw } 2317d39a76e7Sxw 2318d39a76e7Sxw if (sge_flq0_cnt > 65535) { 2319d39a76e7Sxw cmn_err(CE_WARN, 2320d39a76e7Sxw "%s: sge-flq0-cnt > 65535 - resetting value to default", 232119397407SSherry Moore chp->ch_name); 2322d39a76e7Sxw sge_flq0_cnt = sge_flq0_cnt_orig; 2323d39a76e7Sxw } 2324d39a76e7Sxw 2325d39a76e7Sxw tval += sge_flq0_cnt; 2326d39a76e7Sxw 2327d39a76e7Sxw /* 2328d39a76e7Sxw * Provides a tuning capability for the free list 1 size. 2329d39a76e7Sxw */ 2330d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 233119397407SSherry Moore "sge_flq1_cnt", -1); 2332d39a76e7Sxw if (val == -1) 2333d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 233419397407SSherry Moore "sge-flq1-cnt", -1); 2335d39a76e7Sxw if (val != -1) { 2336d39a76e7Sxw if (val > 512) 2337d39a76e7Sxw sge_flq1_cnt = val; 2338d39a76e7Sxw } 2339d39a76e7Sxw 2340d39a76e7Sxw if (sge_flq1_cnt > 65535) { 2341d39a76e7Sxw cmn_err(CE_WARN, 2342d39a76e7Sxw "%s: sge-flq1-cnt > 65535 - resetting value to default", 234319397407SSherry Moore chp->ch_name); 2344d39a76e7Sxw sge_flq1_cnt = sge_flq1_cnt_orig; 2345d39a76e7Sxw } 2346d39a76e7Sxw 2347d39a76e7Sxw tval += sge_flq1_cnt; 2348d39a76e7Sxw 2349d39a76e7Sxw /* 2350d39a76e7Sxw * Provides a tuning capability for the responce queue size. 2351d39a76e7Sxw */ 2352d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 235319397407SSherry Moore "sge_respq_cnt", -1); 2354d39a76e7Sxw if (val == -1) 2355d39a76e7Sxw val = ddi_getprop(DDI_DEV_T_ANY, chp->ch_dip, DDI_PROP_DONTPASS, 235619397407SSherry Moore "sge-respq-cnt", -1); 2357d39a76e7Sxw if (val != -1) { 2358d39a76e7Sxw if (val > 30) 2359d39a76e7Sxw sge_respq_cnt = val; 2360d39a76e7Sxw } 2361d39a76e7Sxw 2362d39a76e7Sxw if (sge_respq_cnt > 65535) { 2363d39a76e7Sxw cmn_err(CE_WARN, 2364d39a76e7Sxw "%s: sge-respq-cnt > 65535 - resetting value to default", 236519397407SSherry Moore chp->ch_name); 2366d39a76e7Sxw sge_respq_cnt = sge_respq_cnt_orig; 2367d39a76e7Sxw } 2368d39a76e7Sxw 2369d39a76e7Sxw if (tval > sge_respq_cnt) { 2370d39a76e7Sxw if (tval <= 65535) { 2371d39a76e7Sxw cmn_err(CE_WARN, 2372d39a76e7Sxw "%s: sge-respq-cnt < %d - setting value to %d (cmdQ+flq0+flq1)", 2373d39a76e7Sxw chp->ch_name, tval, tval); 2374d39a76e7Sxw 2375d39a76e7Sxw sge_respq_cnt = tval; 2376d39a76e7Sxw } else { 2377d39a76e7Sxw cmn_err(CE_WARN, 2378d39a76e7Sxw "%s: Q sizes invalid - resetting to default values", 2379d39a76e7Sxw chp->ch_name); 2380d39a76e7Sxw 2381d39a76e7Sxw sge_cmdq0_cnt = sge_cmdq0_cnt_orig; 2382d39a76e7Sxw sge_cmdq1_cnt = sge_cmdq1_cnt_orig; 2383d39a76e7Sxw sge_flq0_cnt = sge_flq0_cnt_orig; 2384d39a76e7Sxw sge_flq1_cnt = sge_flq1_cnt_orig; 2385d39a76e7Sxw sge_respq_cnt = sge_respq_cnt_orig; 2386d39a76e7Sxw } 2387d39a76e7Sxw } 2388d39a76e7Sxw } 2389