1cde2885fSGarrett D'Amore /* 2cde2885fSGarrett D'Amore * CDDL HEADER START 3cde2885fSGarrett D'Amore * 4cde2885fSGarrett D'Amore * The contents of this file are subject to the terms of the 5cde2885fSGarrett D'Amore * Common Development and Distribution License (the "License"). 6cde2885fSGarrett D'Amore * You may not use this file except in compliance with the License. 7cde2885fSGarrett D'Amore * 8cde2885fSGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9cde2885fSGarrett D'Amore * or http://www.opensolaris.org/os/licensing. 10cde2885fSGarrett D'Amore * See the License for the specific language governing permissions 11cde2885fSGarrett D'Amore * and limitations under the License. 12cde2885fSGarrett D'Amore * 13cde2885fSGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each 14cde2885fSGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15cde2885fSGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the 16cde2885fSGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying 17cde2885fSGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner] 18cde2885fSGarrett D'Amore * 19cde2885fSGarrett D'Amore * CDDL HEADER END 20cde2885fSGarrett D'Amore */ 21cde2885fSGarrett D'Amore 22cde2885fSGarrett D'Amore /* 23ace3c3ffSVenugopal Iyer * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24*2c6a6ad1SIlya Yanok * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 25cde2885fSGarrett D'Amore */ 26cde2885fSGarrett D'Amore 27cde2885fSGarrett D'Amore /* 28cde2885fSGarrett D'Amore * rtls -- REALTEK 8139-serials PCI Fast Ethernet Driver, Depends on the 29cde2885fSGarrett D'Amore * Generic LAN Driver utility functions in /kernel/misc/mac 30cde2885fSGarrett D'Amore * 31cde2885fSGarrett D'Amore * This product is covered by one or more of the following patents: 32cde2885fSGarrett D'Amore * US5,307,459, US5,434,872, US5,732,094, US6,570,884, US6,115,776, and 33cde2885fSGarrett D'Amore * US6,327,625. 34cde2885fSGarrett D'Amore * 35cde2885fSGarrett D'Amore * Currently supports: 36cde2885fSGarrett D'Amore * RTL8139 37cde2885fSGarrett D'Amore */ 38cde2885fSGarrett D'Amore 39cde2885fSGarrett D'Amore #include <sys/types.h> 40cde2885fSGarrett D'Amore #include <sys/debug.h> 41cde2885fSGarrett D'Amore #include <sys/errno.h> 42cde2885fSGarrett D'Amore 43cde2885fSGarrett D'Amore #include <sys/stropts.h> 44cde2885fSGarrett D'Amore #include <sys/stream.h> 45cde2885fSGarrett D'Amore #include <sys/kmem.h> 46cde2885fSGarrett D'Amore #include <sys/conf.h> 47cde2885fSGarrett D'Amore #include <sys/ddi.h> 48cde2885fSGarrett D'Amore #include <sys/devops.h> 49cde2885fSGarrett D'Amore #include <sys/ksynch.h> 50cde2885fSGarrett D'Amore #include <sys/stat.h> 51cde2885fSGarrett D'Amore #include <sys/conf.h> 52cde2885fSGarrett D'Amore #include <sys/modctl.h> 53cde2885fSGarrett D'Amore #include <sys/dlpi.h> 54cde2885fSGarrett D'Amore #include <sys/ethernet.h> 55cde2885fSGarrett D'Amore #include <sys/vlan.h> 56cde2885fSGarrett D'Amore #include <sys/strsun.h> 57cde2885fSGarrett D'Amore #include <sys/pci.h> 58cde2885fSGarrett D'Amore #include <sys/sunddi.h> 59bbb1277bSGarrett D'Amore #include <sys/mii.h> 60bbb1277bSGarrett D'Amore #include <sys/miiregs.h> 61cde2885fSGarrett D'Amore #include <sys/mac_provider.h> 62cde2885fSGarrett D'Amore #include <sys/mac_ether.h> 63cde2885fSGarrett D'Amore 64cde2885fSGarrett D'Amore #include "rtls.h" 65cde2885fSGarrett D'Amore 66cde2885fSGarrett D'Amore /* 67cde2885fSGarrett D'Amore * Declarations and Module Linkage 68cde2885fSGarrett D'Amore */ 69cde2885fSGarrett D'Amore 70cde2885fSGarrett D'Amore /* 71cde2885fSGarrett D'Amore * This is the string displayed by modinfo, etc. 72cde2885fSGarrett D'Amore */ 73cde2885fSGarrett D'Amore static char rtls_ident[] = "RealTek 8139 Ethernet driver"; 74cde2885fSGarrett D'Amore 75cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG 76cde2885fSGarrett D'Amore int rtls_debug = 0; 77cde2885fSGarrett D'Amore #endif 78cde2885fSGarrett D'Amore 79cde2885fSGarrett D'Amore /* 80cde2885fSGarrett D'Amore * Required system entry points 81cde2885fSGarrett D'Amore */ 82cde2885fSGarrett D'Amore static int rtls_attach(dev_info_t *, ddi_attach_cmd_t); 83cde2885fSGarrett D'Amore static int rtls_detach(dev_info_t *, ddi_detach_cmd_t); 84cde2885fSGarrett D'Amore static int rtls_quiesce(dev_info_t *); 85cde2885fSGarrett D'Amore 86cde2885fSGarrett D'Amore /* 87cde2885fSGarrett D'Amore * Required driver entry points for MAC 88cde2885fSGarrett D'Amore */ 89cde2885fSGarrett D'Amore static int rtls_m_start(void *); 90cde2885fSGarrett D'Amore static void rtls_m_stop(void *); 91cde2885fSGarrett D'Amore static int rtls_m_unicst(void *, const uint8_t *); 92cde2885fSGarrett D'Amore static int rtls_m_multicst(void *, boolean_t, const uint8_t *); 93cde2885fSGarrett D'Amore static int rtls_m_promisc(void *, boolean_t); 94cde2885fSGarrett D'Amore static mblk_t *rtls_m_tx(void *, mblk_t *); 95ace3c3ffSVenugopal Iyer static int rtls_m_getprop(void *, const char *, mac_prop_id_t, uint_t, 96ace3c3ffSVenugopal Iyer void *); 97ace3c3ffSVenugopal Iyer static int rtls_m_setprop(void *, const char *, mac_prop_id_t, uint_t, 98ace3c3ffSVenugopal Iyer const void *); 99ace3c3ffSVenugopal Iyer static void rtls_m_propinfo(void *, const char *, mac_prop_id_t, 100ace3c3ffSVenugopal Iyer mac_prop_info_handle_t); 101cde2885fSGarrett D'Amore static int rtls_m_stat(void *, uint_t, uint64_t *); 102cde2885fSGarrett D'Amore 103cde2885fSGarrett D'Amore static uint_t rtls_intr(caddr_t); 104cde2885fSGarrett D'Amore 105cde2885fSGarrett D'Amore /* 106bbb1277bSGarrett D'Amore * MII entry points 107bbb1277bSGarrett D'Amore */ 108bbb1277bSGarrett D'Amore static uint16_t rtls_mii_read(void *, uint8_t, uint8_t); 109bbb1277bSGarrett D'Amore static void rtls_mii_write(void *, uint8_t, uint8_t, uint16_t); 110bbb1277bSGarrett D'Amore static void rtls_mii_notify(void *, link_state_t); 111bbb1277bSGarrett D'Amore 112bbb1277bSGarrett D'Amore /* 113cde2885fSGarrett D'Amore * Internal functions used by the above entry points 114cde2885fSGarrett D'Amore */ 115cde2885fSGarrett D'Amore static int rtls_chip_reset(rtls_t *, boolean_t); 116cde2885fSGarrett D'Amore static void rtls_chip_init(rtls_t *); 117cde2885fSGarrett D'Amore static void rtls_chip_stop(rtls_t *rtlsp); 118cde2885fSGarrett D'Amore static void rtls_chip_start(rtls_t *rtlsp); 119cde2885fSGarrett D'Amore static void rtls_chip_restart(rtls_t *rtlsp); 120cde2885fSGarrett D'Amore static void rtls_get_mac_addr(rtls_t *, uint8_t *); 121cde2885fSGarrett D'Amore static void rtls_set_mac_addr(rtls_t *, const uint8_t *); 122cde2885fSGarrett D'Amore static uint_t rtls_hash_index(const uint8_t *); 123cde2885fSGarrett D'Amore static boolean_t rtls_send(rtls_t *, mblk_t *); 124cde2885fSGarrett D'Amore static void rtls_receive(rtls_t *); 125cde2885fSGarrett D'Amore 126cde2885fSGarrett D'Amore /* 127cde2885fSGarrett D'Amore * Buffer Management Routines 128cde2885fSGarrett D'Amore */ 129cde2885fSGarrett D'Amore static int rtls_alloc_bufs(rtls_t *); 130cde2885fSGarrett D'Amore static void rtls_free_bufs(rtls_t *); 131cde2885fSGarrett D'Amore static int rtls_alloc_dma_mem(rtls_t *, size_t, ddi_device_acc_attr_t *, 132cde2885fSGarrett D'Amore uint_t, dma_area_t *); 133cde2885fSGarrett D'Amore static void rtls_free_dma_mem(dma_area_t *); 134cde2885fSGarrett D'Amore 135cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG 136cde2885fSGarrett D'Amore static void rtls_reg_print(rtls_t *); /* debug routine */ 137cde2885fSGarrett D'Amore #endif 138cde2885fSGarrett D'Amore 139cde2885fSGarrett D'Amore #define RTLS_DRIVER_NAME "rtls" 140cde2885fSGarrett D'Amore 141cde2885fSGarrett D'Amore /* 142cde2885fSGarrett D'Amore * Used for buffers allocated by ddi_dma_mem_alloc() 143cde2885fSGarrett D'Amore */ 144cde2885fSGarrett D'Amore static ddi_dma_attr_t dma_attr = { 145cde2885fSGarrett D'Amore DMA_ATTR_V0, /* dma_attr version */ 146cde2885fSGarrett D'Amore 0, /* dma_attr_addr_lo */ 147cde2885fSGarrett D'Amore (uint_t)0xFFFFFFFF, /* dma_attr_addr_hi */ 148cde2885fSGarrett D'Amore 0x7FFFFFFF, /* dma_attr_count_max */ 149cde2885fSGarrett D'Amore 4, /* dma_attr_align */ 150cde2885fSGarrett D'Amore 0x3F, /* dma_attr_burstsizes */ 151cde2885fSGarrett D'Amore 1, /* dma_attr_minxfer */ 152cde2885fSGarrett D'Amore (uint_t)0xFFFFFFFF, /* dma_attr_maxxfer */ 153cde2885fSGarrett D'Amore (uint_t)0xFFFFFFFF, /* dma_attr_seg */ 154cde2885fSGarrett D'Amore 1, /* dma_attr_sgllen */ 155cde2885fSGarrett D'Amore 1, /* dma_attr_granular */ 156cde2885fSGarrett D'Amore 0, /* dma_attr_flags */ 157cde2885fSGarrett D'Amore }; 158cde2885fSGarrett D'Amore 159cde2885fSGarrett D'Amore /* 160cde2885fSGarrett D'Amore * PIO access attributes for registers 161cde2885fSGarrett D'Amore */ 162cde2885fSGarrett D'Amore static ddi_device_acc_attr_t rtls_reg_accattr = { 163cde2885fSGarrett D'Amore DDI_DEVICE_ATTR_V0, 164cde2885fSGarrett D'Amore DDI_STRUCTURE_LE_ACC, 165cde2885fSGarrett D'Amore DDI_STRICTORDER_ACC 166cde2885fSGarrett D'Amore }; 167cde2885fSGarrett D'Amore 168cde2885fSGarrett D'Amore /* 169cde2885fSGarrett D'Amore * DMA access attributes for data 170cde2885fSGarrett D'Amore */ 171cde2885fSGarrett D'Amore static ddi_device_acc_attr_t rtls_buf_accattr = { 172cde2885fSGarrett D'Amore DDI_DEVICE_ATTR_V0, 173cde2885fSGarrett D'Amore DDI_NEVERSWAP_ACC, 174cde2885fSGarrett D'Amore DDI_STRICTORDER_ACC 175cde2885fSGarrett D'Amore }; 176cde2885fSGarrett D'Amore 177cde2885fSGarrett D'Amore uchar_t rtls_broadcastaddr[] = { 178cde2885fSGarrett D'Amore 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 179cde2885fSGarrett D'Amore }; 180cde2885fSGarrett D'Amore 181cde2885fSGarrett D'Amore static mac_callbacks_t rtls_m_callbacks = { 182ace3c3ffSVenugopal Iyer MC_PROPERTIES, 183cde2885fSGarrett D'Amore rtls_m_stat, 184cde2885fSGarrett D'Amore rtls_m_start, 185cde2885fSGarrett D'Amore rtls_m_stop, 186cde2885fSGarrett D'Amore rtls_m_promisc, 187cde2885fSGarrett D'Amore rtls_m_multicst, 188cde2885fSGarrett D'Amore rtls_m_unicst, 189ace3c3ffSVenugopal Iyer rtls_m_tx, 190ace3c3ffSVenugopal Iyer NULL, 191ace3c3ffSVenugopal Iyer NULL, /* mc_ioctl */ 192ace3c3ffSVenugopal Iyer NULL, /* mc_getcapab */ 193ace3c3ffSVenugopal Iyer NULL, /* mc_open */ 194ace3c3ffSVenugopal Iyer NULL, /* mc_close */ 195ace3c3ffSVenugopal Iyer rtls_m_setprop, 196ace3c3ffSVenugopal Iyer rtls_m_getprop, 197ace3c3ffSVenugopal Iyer rtls_m_propinfo 198bbb1277bSGarrett D'Amore }; 199bbb1277bSGarrett D'Amore 200bbb1277bSGarrett D'Amore static mii_ops_t rtls_mii_ops = { 201bbb1277bSGarrett D'Amore MII_OPS_VERSION, 202bbb1277bSGarrett D'Amore rtls_mii_read, 203bbb1277bSGarrett D'Amore rtls_mii_write, 204bbb1277bSGarrett D'Amore rtls_mii_notify, /* notify */ 205bbb1277bSGarrett D'Amore NULL, /* reset */ 206cde2885fSGarrett D'Amore }; 207cde2885fSGarrett D'Amore 208cde2885fSGarrett D'Amore DDI_DEFINE_STREAM_OPS(rtls_dev_ops, nulldev, nulldev, rtls_attach, rtls_detach, 209cde2885fSGarrett D'Amore nodev, NULL, D_MP, NULL, rtls_quiesce); 210cde2885fSGarrett D'Amore 211cde2885fSGarrett D'Amore /* 212cde2885fSGarrett D'Amore * Standard module linkage initialization for a MAC driver 213cde2885fSGarrett D'Amore */ 214cde2885fSGarrett D'Amore static struct modldrv rtls_modldrv = { 215cde2885fSGarrett D'Amore &mod_driverops, /* type of module. This one is a driver */ 216cde2885fSGarrett D'Amore rtls_ident, /* short description */ 217cde2885fSGarrett D'Amore &rtls_dev_ops /* driver specific ops */ 218cde2885fSGarrett D'Amore }; 219cde2885fSGarrett D'Amore 220cde2885fSGarrett D'Amore static struct modlinkage modlinkage = { 221cde2885fSGarrett D'Amore MODREV_1, { (void *)&rtls_modldrv, NULL } 222cde2885fSGarrett D'Amore }; 223cde2885fSGarrett D'Amore 224cde2885fSGarrett D'Amore /* 225cde2885fSGarrett D'Amore * ========== RealTek chip register access Routines ========== 226cde2885fSGarrett D'Amore */ 227cde2885fSGarrett D'Amore static uint8_t rtls_reg_get8(rtls_t *rtlsp, uint32_t reg); 228cde2885fSGarrett D'Amore #pragma inline(rtls_reg_get8) 229cde2885fSGarrett D'Amore static uint8_t 230cde2885fSGarrett D'Amore rtls_reg_get8(rtls_t *rtlsp, uint32_t reg) 231cde2885fSGarrett D'Amore { 232cde2885fSGarrett D'Amore uint8_t *addr; 233cde2885fSGarrett D'Amore 234cde2885fSGarrett D'Amore addr = REG8(rtlsp->io_reg, reg); 235cde2885fSGarrett D'Amore return (ddi_get8(rtlsp->io_handle, addr)); 236cde2885fSGarrett D'Amore } 237cde2885fSGarrett D'Amore 238cde2885fSGarrett D'Amore static uint16_t rtls_reg_get16(rtls_t *rtlsp, uint32_t reg); 239cde2885fSGarrett D'Amore #pragma inline(rtls_reg_get16) 240cde2885fSGarrett D'Amore static uint16_t 241cde2885fSGarrett D'Amore rtls_reg_get16(rtls_t *rtlsp, uint32_t reg) 242cde2885fSGarrett D'Amore { 243cde2885fSGarrett D'Amore uint16_t *addr; 244cde2885fSGarrett D'Amore 245cde2885fSGarrett D'Amore addr = REG16(rtlsp->io_reg, reg); 246cde2885fSGarrett D'Amore return (ddi_get16(rtlsp->io_handle, addr)); 247cde2885fSGarrett D'Amore } 248cde2885fSGarrett D'Amore 249cde2885fSGarrett D'Amore static uint32_t rtls_reg_get32(rtls_t *rtlsp, uint32_t reg); 250cde2885fSGarrett D'Amore #pragma inline(rtls_reg_get32) 251cde2885fSGarrett D'Amore static uint32_t 252cde2885fSGarrett D'Amore rtls_reg_get32(rtls_t *rtlsp, uint32_t reg) 253cde2885fSGarrett D'Amore { 254cde2885fSGarrett D'Amore uint32_t *addr; 255cde2885fSGarrett D'Amore 256cde2885fSGarrett D'Amore addr = REG32(rtlsp->io_reg, reg); 257cde2885fSGarrett D'Amore return (ddi_get32(rtlsp->io_handle, addr)); 258cde2885fSGarrett D'Amore } 259cde2885fSGarrett D'Amore 260cde2885fSGarrett D'Amore static void rtls_reg_set8(rtls_t *rtlsp, uint32_t reg, uint8_t value); 261cde2885fSGarrett D'Amore #pragma inline(rtls_reg_set8) 262cde2885fSGarrett D'Amore static void 263cde2885fSGarrett D'Amore rtls_reg_set8(rtls_t *rtlsp, uint32_t reg, uint8_t value) 264cde2885fSGarrett D'Amore { 265cde2885fSGarrett D'Amore uint8_t *addr; 266cde2885fSGarrett D'Amore 267cde2885fSGarrett D'Amore addr = REG8(rtlsp->io_reg, reg); 268cde2885fSGarrett D'Amore ddi_put8(rtlsp->io_handle, addr, value); 269cde2885fSGarrett D'Amore } 270cde2885fSGarrett D'Amore 271cde2885fSGarrett D'Amore static void rtls_reg_set16(rtls_t *rtlsp, uint32_t reg, uint16_t value); 272cde2885fSGarrett D'Amore #pragma inline(rtls_reg_set16) 273cde2885fSGarrett D'Amore static void 274cde2885fSGarrett D'Amore rtls_reg_set16(rtls_t *rtlsp, uint32_t reg, uint16_t value) 275cde2885fSGarrett D'Amore { 276cde2885fSGarrett D'Amore uint16_t *addr; 277cde2885fSGarrett D'Amore 278cde2885fSGarrett D'Amore addr = REG16(rtlsp->io_reg, reg); 279cde2885fSGarrett D'Amore ddi_put16(rtlsp->io_handle, addr, value); 280cde2885fSGarrett D'Amore } 281cde2885fSGarrett D'Amore 282cde2885fSGarrett D'Amore static void rtls_reg_set32(rtls_t *rtlsp, uint32_t reg, uint32_t value); 283cde2885fSGarrett D'Amore #pragma inline(rtls_reg_set32) 284cde2885fSGarrett D'Amore static void 285cde2885fSGarrett D'Amore rtls_reg_set32(rtls_t *rtlsp, uint32_t reg, uint32_t value) 286cde2885fSGarrett D'Amore { 287cde2885fSGarrett D'Amore uint32_t *addr; 288cde2885fSGarrett D'Amore 289cde2885fSGarrett D'Amore addr = REG32(rtlsp->io_reg, reg); 290cde2885fSGarrett D'Amore ddi_put32(rtlsp->io_handle, addr, value); 291cde2885fSGarrett D'Amore } 292cde2885fSGarrett D'Amore 293cde2885fSGarrett D'Amore /* 294cde2885fSGarrett D'Amore * ========== Module Loading Entry Points ========== 295cde2885fSGarrett D'Amore */ 296cde2885fSGarrett D'Amore int 297cde2885fSGarrett D'Amore _init(void) 298cde2885fSGarrett D'Amore { 299cde2885fSGarrett D'Amore int rv; 300cde2885fSGarrett D'Amore 301cde2885fSGarrett D'Amore mac_init_ops(&rtls_dev_ops, RTLS_DRIVER_NAME); 302cde2885fSGarrett D'Amore if ((rv = mod_install(&modlinkage)) != DDI_SUCCESS) { 303cde2885fSGarrett D'Amore mac_fini_ops(&rtls_dev_ops); 304cde2885fSGarrett D'Amore } 305cde2885fSGarrett D'Amore return (rv); 306cde2885fSGarrett D'Amore } 307cde2885fSGarrett D'Amore 308cde2885fSGarrett D'Amore int 309cde2885fSGarrett D'Amore _fini(void) 310cde2885fSGarrett D'Amore { 311cde2885fSGarrett D'Amore int rv; 312cde2885fSGarrett D'Amore 313cde2885fSGarrett D'Amore if ((rv = mod_remove(&modlinkage)) == DDI_SUCCESS) { 314cde2885fSGarrett D'Amore mac_fini_ops(&rtls_dev_ops); 315cde2885fSGarrett D'Amore } 316cde2885fSGarrett D'Amore return (rv); 317cde2885fSGarrett D'Amore } 318cde2885fSGarrett D'Amore 319cde2885fSGarrett D'Amore int 320cde2885fSGarrett D'Amore _info(struct modinfo *modinfop) 321cde2885fSGarrett D'Amore { 322cde2885fSGarrett D'Amore return (mod_info(&modlinkage, modinfop)); 323cde2885fSGarrett D'Amore } 324cde2885fSGarrett D'Amore 325cde2885fSGarrett D'Amore 326cde2885fSGarrett D'Amore /* 327cde2885fSGarrett D'Amore * ========== DDI Entry Points ========== 328cde2885fSGarrett D'Amore */ 329cde2885fSGarrett D'Amore 330cde2885fSGarrett D'Amore /* 331cde2885fSGarrett D'Amore * attach(9E) -- Attach a device to the system 332cde2885fSGarrett D'Amore * 333cde2885fSGarrett D'Amore * Called once for each board successfully probed. 334cde2885fSGarrett D'Amore */ 335cde2885fSGarrett D'Amore static int 336cde2885fSGarrett D'Amore rtls_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 337cde2885fSGarrett D'Amore { 338cde2885fSGarrett D'Amore rtls_t *rtlsp; /* Our private device info */ 339cde2885fSGarrett D'Amore ddi_acc_handle_t pci_handle; 340cde2885fSGarrett D'Amore uint16_t pci_commond; 341cde2885fSGarrett D'Amore uint16_t vendorid; 342cde2885fSGarrett D'Amore uint16_t deviceid; 343cde2885fSGarrett D'Amore uint32_t device; 344cde2885fSGarrett D'Amore mac_register_t *macp; 345cde2885fSGarrett D'Amore int err; 346cde2885fSGarrett D'Amore 347cde2885fSGarrett D'Amore switch (cmd) { 348cde2885fSGarrett D'Amore case DDI_ATTACH: 349cde2885fSGarrett D'Amore break; 350cde2885fSGarrett D'Amore case DDI_RESUME: 351cde2885fSGarrett D'Amore if ((rtlsp = ddi_get_driver_private(devinfo)) == NULL) { 352cde2885fSGarrett D'Amore return (DDI_FAILURE); 353cde2885fSGarrett D'Amore } 354cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_io_lock); 355cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_rx_lock); 356cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_tx_lock); 357cde2885fSGarrett D'Amore /* 358cde2885fSGarrett D'Amore * Turn on Master Enable (DMA) and IO Enable bits. 359cde2885fSGarrett D'Amore * Enable PCI Memory Space accesses 360cde2885fSGarrett D'Amore * Disable Memory Write/Invalidate 361cde2885fSGarrett D'Amore */ 362cde2885fSGarrett D'Amore if (pci_config_setup(devinfo, &pci_handle) != DDI_SUCCESS) { 363cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_tx_lock); 364cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_rx_lock); 365cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_io_lock); 366cde2885fSGarrett D'Amore return (DDI_FAILURE); 367cde2885fSGarrett D'Amore } 368cde2885fSGarrett D'Amore pci_commond = pci_config_get16(pci_handle, PCI_CONF_COMM); 369cde2885fSGarrett D'Amore pci_commond &= ~PCI_COMM_MEMWR_INVAL; 370cde2885fSGarrett D'Amore pci_commond |= PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_IO; 371cde2885fSGarrett D'Amore pci_config_put32(pci_handle, PCI_CONF_COMM, pci_commond); 372cde2885fSGarrett D'Amore pci_config_teardown(&pci_handle); 373cde2885fSGarrett D'Amore 374cde2885fSGarrett D'Amore rtls_chip_restart(rtlsp); 375cde2885fSGarrett D'Amore rtlsp->chip_error = B_FALSE; 376cde2885fSGarrett D'Amore rtlsp->tx_retry = 0; 377cde2885fSGarrett D'Amore rtlsp->rtls_suspended = B_FALSE; 378cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_tx_lock); 379cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_rx_lock); 380cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_io_lock); 381cde2885fSGarrett D'Amore 382bbb1277bSGarrett D'Amore mii_resume(rtlsp->mii); 383bbb1277bSGarrett D'Amore 384cde2885fSGarrett D'Amore mac_tx_update(rtlsp->mh); 385cde2885fSGarrett D'Amore return (DDI_SUCCESS); 386cde2885fSGarrett D'Amore default: 387cde2885fSGarrett D'Amore return (DDI_FAILURE); 388cde2885fSGarrett D'Amore } 389cde2885fSGarrett D'Amore 390cde2885fSGarrett D'Amore /* 391cde2885fSGarrett D'Amore * we don't support high level interrupts in the driver 392cde2885fSGarrett D'Amore */ 393cde2885fSGarrett D'Amore if (ddi_intr_hilevel(devinfo, 0) != 0) { 394bbb1277bSGarrett D'Amore cmn_err(CE_WARN, "unsupported high level interrupt"); 395cde2885fSGarrett D'Amore return (DDI_FAILURE); 396cde2885fSGarrett D'Amore } 397cde2885fSGarrett D'Amore 398cde2885fSGarrett D'Amore /* 399cde2885fSGarrett D'Amore * Get handle to access pci configuration space 400cde2885fSGarrett D'Amore */ 401cde2885fSGarrett D'Amore if (pci_config_setup(devinfo, &pci_handle) != DDI_SUCCESS) { 402bbb1277bSGarrett D'Amore cmn_err(CE_WARN, "pci_config_setup fail."); 403cde2885fSGarrett D'Amore return (DDI_FAILURE); 404cde2885fSGarrett D'Amore } 405cde2885fSGarrett D'Amore 406cde2885fSGarrett D'Amore /* 407cde2885fSGarrett D'Amore * Make sure we support this particular vendor/device 408cde2885fSGarrett D'Amore */ 409cde2885fSGarrett D'Amore vendorid = pci_config_get16(pci_handle, PCI_CONF_VENID); 410cde2885fSGarrett D'Amore deviceid = pci_config_get16(pci_handle, PCI_CONF_DEVID); 411cde2885fSGarrett D'Amore device = vendorid; 412cde2885fSGarrett D'Amore device = (device << 16) | deviceid; /* combine two id together */ 413cde2885fSGarrett D'Amore 414cde2885fSGarrett D'Amore /* 415cde2885fSGarrett D'Amore * See if we support this device 416cde2885fSGarrett D'Amore * We do not return for wrong device id. It's user risk. 417cde2885fSGarrett D'Amore */ 418cde2885fSGarrett D'Amore switch (device) { 419cde2885fSGarrett D'Amore default: 420cde2885fSGarrett D'Amore cmn_err(CE_WARN, 421bbb1277bSGarrett D'Amore "RTLS doesn't support this device: " 422cde2885fSGarrett D'Amore "vendorID = 0x%x, deviceID = 0x%x", 423cde2885fSGarrett D'Amore vendorid, deviceid); 424cde2885fSGarrett D'Amore break; 425cde2885fSGarrett D'Amore case RTLS_SUPPORT_DEVICE_1: 426cde2885fSGarrett D'Amore case RTLS_SUPPORT_DEVICE_2: 427cde2885fSGarrett D'Amore case RTLS_SUPPORT_DEVICE_3: 428bbb1277bSGarrett D'Amore case RTLS_SUPPORT_DEVICE_4: 429cde2885fSGarrett D'Amore break; 430cde2885fSGarrett D'Amore } 431cde2885fSGarrett D'Amore 432cde2885fSGarrett D'Amore /* 433cde2885fSGarrett D'Amore * Turn on Master Enable (DMA) and IO Enable bits. 434cde2885fSGarrett D'Amore * Enable PCI Memory Space accesses 435cde2885fSGarrett D'Amore * Disable Memory Write/Invalidate 436cde2885fSGarrett D'Amore */ 437cde2885fSGarrett D'Amore pci_commond = pci_config_get16(pci_handle, PCI_CONF_COMM); 438cde2885fSGarrett D'Amore pci_commond &= ~PCI_COMM_MEMWR_INVAL; 439cde2885fSGarrett D'Amore pci_commond |= PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_IO; 440cde2885fSGarrett D'Amore pci_config_put32(pci_handle, PCI_CONF_COMM, pci_commond); 441cde2885fSGarrett D'Amore 442cde2885fSGarrett D'Amore /* 443cde2885fSGarrett D'Amore * Free handle to access pci configuration space 444cde2885fSGarrett D'Amore */ 445cde2885fSGarrett D'Amore pci_config_teardown(&pci_handle); 446cde2885fSGarrett D'Amore 447cde2885fSGarrett D'Amore rtlsp = kmem_zalloc(sizeof (rtls_t), KM_SLEEP); 448cde2885fSGarrett D'Amore 449cde2885fSGarrett D'Amore ddi_set_driver_private(devinfo, rtlsp); 450cde2885fSGarrett D'Amore rtlsp->devinfo = devinfo; 451cde2885fSGarrett D'Amore rtlsp->instance = ddi_get_instance(devinfo); 452cde2885fSGarrett D'Amore 453cde2885fSGarrett D'Amore /* 454cde2885fSGarrett D'Amore * Map operating register 455cde2885fSGarrett D'Amore */ 456cde2885fSGarrett D'Amore err = ddi_regs_map_setup(devinfo, 1, &rtlsp->io_reg, 457cde2885fSGarrett D'Amore (offset_t)0, 0, &rtls_reg_accattr, &rtlsp->io_handle); 458cde2885fSGarrett D'Amore if (err != DDI_SUCCESS) { 459cde2885fSGarrett D'Amore kmem_free((caddr_t)rtlsp, sizeof (rtls_t)); 460bbb1277bSGarrett D'Amore cmn_err(CE_WARN, "ddi_regs_map_setup fail."); 461cde2885fSGarrett D'Amore return (DDI_FAILURE); 462cde2885fSGarrett D'Amore } 463cde2885fSGarrett D'Amore 464cde2885fSGarrett D'Amore /* 465cde2885fSGarrett D'Amore * Allocate the TX and RX descriptors/buffers 466cde2885fSGarrett D'Amore */ 467cde2885fSGarrett D'Amore if (rtls_alloc_bufs(rtlsp) == DDI_FAILURE) { 468bbb1277bSGarrett D'Amore cmn_err(CE_WARN, "DMA buffer allocation fail."); 469cde2885fSGarrett D'Amore goto fail; 470cde2885fSGarrett D'Amore } 471cde2885fSGarrett D'Amore 472cde2885fSGarrett D'Amore /* 473cde2885fSGarrett D'Amore * Reset the chip 474cde2885fSGarrett D'Amore */ 475cde2885fSGarrett D'Amore err = rtls_chip_reset(rtlsp, B_FALSE); 476cde2885fSGarrett D'Amore if (err != DDI_SUCCESS) 477cde2885fSGarrett D'Amore goto fail; 478cde2885fSGarrett D'Amore 479cde2885fSGarrett D'Amore /* 480cde2885fSGarrett D'Amore * Init rtls_t structure 481cde2885fSGarrett D'Amore */ 482cde2885fSGarrett D'Amore rtls_get_mac_addr(rtlsp, rtlsp->netaddr); 483cde2885fSGarrett D'Amore 484cde2885fSGarrett D'Amore /* 485cde2885fSGarrett D'Amore * Add the interrupt handler 486cde2885fSGarrett D'Amore * 487cde2885fSGarrett D'Amore * This will prevent receiving interrupts before device is ready, as 488cde2885fSGarrett D'Amore * we are initializing device after setting the interrupts. So we 489cde2885fSGarrett D'Amore * will not get our interrupt handler invoked by OS while our device 490cde2885fSGarrett D'Amore * is still coming up or timer routines will not start till we are 491cde2885fSGarrett D'Amore * all set to process... 492cde2885fSGarrett D'Amore */ 493cde2885fSGarrett D'Amore 494cde2885fSGarrett D'Amore if (ddi_add_intr(devinfo, 0, &rtlsp->iblk, NULL, rtls_intr, 495cde2885fSGarrett D'Amore (caddr_t)rtlsp) != DDI_SUCCESS) { 496bbb1277bSGarrett D'Amore cmn_err(CE_WARN, "ddi_add_intr fail."); 497cde2885fSGarrett D'Amore goto late_fail; 498cde2885fSGarrett D'Amore } 499cde2885fSGarrett D'Amore 500bbb1277bSGarrett D'Amore if ((rtlsp->mii = mii_alloc(rtlsp, devinfo, &rtls_mii_ops)) == NULL) { 501bbb1277bSGarrett D'Amore ddi_remove_intr(devinfo, 0, rtlsp->iblk); 502bbb1277bSGarrett D'Amore goto late_fail; 503bbb1277bSGarrett D'Amore } 504bbb1277bSGarrett D'Amore /* 505bbb1277bSGarrett D'Amore * Note: Some models of 8139 can support pause, but we have 506bbb1277bSGarrett D'Amore * not implemented support for it at this time. This might be 507bbb1277bSGarrett D'Amore * an interesting feature to add later. 508bbb1277bSGarrett D'Amore */ 509bbb1277bSGarrett D'Amore mii_set_pauseable(rtlsp->mii, B_FALSE, B_FALSE); 510bbb1277bSGarrett D'Amore 511cde2885fSGarrett D'Amore if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 512bbb1277bSGarrett D'Amore cmn_err(CE_WARN, "mac_alloc fail."); 513cde2885fSGarrett D'Amore ddi_remove_intr(devinfo, 0, rtlsp->iblk); 514cde2885fSGarrett D'Amore goto late_fail; 515cde2885fSGarrett D'Amore } 516cde2885fSGarrett D'Amore 517cde2885fSGarrett D'Amore /* 518cde2885fSGarrett D'Amore * Init mutex 519cde2885fSGarrett D'Amore */ 520cde2885fSGarrett D'Amore mutex_init(&rtlsp->rtls_io_lock, NULL, MUTEX_DRIVER, rtlsp->iblk); 521cde2885fSGarrett D'Amore mutex_init(&rtlsp->rtls_tx_lock, NULL, MUTEX_DRIVER, rtlsp->iblk); 522cde2885fSGarrett D'Amore mutex_init(&rtlsp->rtls_rx_lock, NULL, MUTEX_DRIVER, rtlsp->iblk); 523cde2885fSGarrett D'Amore 524cde2885fSGarrett D'Amore /* 525cde2885fSGarrett D'Amore * Initialize pointers to device specific functions which will be 526cde2885fSGarrett D'Amore * used by the generic layer. 527cde2885fSGarrett D'Amore */ 528cde2885fSGarrett D'Amore macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 529cde2885fSGarrett D'Amore macp->m_driver = rtlsp; 530cde2885fSGarrett D'Amore macp->m_dip = devinfo; 531cde2885fSGarrett D'Amore macp->m_src_addr = rtlsp->netaddr; 532cde2885fSGarrett D'Amore macp->m_callbacks = &rtls_m_callbacks; 533cde2885fSGarrett D'Amore macp->m_min_sdu = 0; 534cde2885fSGarrett D'Amore macp->m_max_sdu = ETHERMTU; 535cde2885fSGarrett D'Amore macp->m_margin = VLAN_TAGSZ; 536cde2885fSGarrett D'Amore 537cde2885fSGarrett D'Amore if (mac_register(macp, &rtlsp->mh) != 0) { 538cde2885fSGarrett D'Amore ddi_remove_intr(devinfo, 0, rtlsp->iblk); 539cde2885fSGarrett D'Amore mutex_destroy(&rtlsp->rtls_io_lock); 540cde2885fSGarrett D'Amore mutex_destroy(&rtlsp->rtls_tx_lock); 541cde2885fSGarrett D'Amore mutex_destroy(&rtlsp->rtls_rx_lock); 542cde2885fSGarrett D'Amore goto late_fail; 543cde2885fSGarrett D'Amore } 544cde2885fSGarrett D'Amore 545cde2885fSGarrett D'Amore mac_free(macp); 546cde2885fSGarrett D'Amore 547cde2885fSGarrett D'Amore return (DDI_SUCCESS); 548cde2885fSGarrett D'Amore 549cde2885fSGarrett D'Amore late_fail: 550cde2885fSGarrett D'Amore if (macp) 551cde2885fSGarrett D'Amore mac_free(macp); 552bbb1277bSGarrett D'Amore if (rtlsp->mii) 553bbb1277bSGarrett D'Amore mii_free(rtlsp->mii); 554cde2885fSGarrett D'Amore 555cde2885fSGarrett D'Amore fail: 556cde2885fSGarrett D'Amore ddi_regs_map_free(&rtlsp->io_handle); 557cde2885fSGarrett D'Amore rtls_free_bufs(rtlsp); 558cde2885fSGarrett D'Amore kmem_free(rtlsp, sizeof (rtls_t)); 559cde2885fSGarrett D'Amore 560cde2885fSGarrett D'Amore return (DDI_FAILURE); 561cde2885fSGarrett D'Amore } 562cde2885fSGarrett D'Amore 563cde2885fSGarrett D'Amore /* 564cde2885fSGarrett D'Amore * detach(9E) -- Detach a device from the system 565cde2885fSGarrett D'Amore */ 566cde2885fSGarrett D'Amore static int 567cde2885fSGarrett D'Amore rtls_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 568cde2885fSGarrett D'Amore { 569cde2885fSGarrett D'Amore rtls_t *rtlsp; /* our private device info */ 570cde2885fSGarrett D'Amore 571cde2885fSGarrett D'Amore /* 572cde2885fSGarrett D'Amore * Get the driver private structure 573cde2885fSGarrett D'Amore */ 574cde2885fSGarrett D'Amore if ((rtlsp = ddi_get_driver_private(devinfo)) == NULL) { 575cde2885fSGarrett D'Amore return (DDI_FAILURE); 576cde2885fSGarrett D'Amore } 577cde2885fSGarrett D'Amore 578cde2885fSGarrett D'Amore switch (cmd) { 579cde2885fSGarrett D'Amore case DDI_DETACH: 580cde2885fSGarrett D'Amore break; 581cde2885fSGarrett D'Amore 582cde2885fSGarrett D'Amore case DDI_SUSPEND: 583bbb1277bSGarrett D'Amore mii_suspend(rtlsp->mii); 584bbb1277bSGarrett D'Amore 585cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_io_lock); 586cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_rx_lock); 587cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_tx_lock); 588cde2885fSGarrett D'Amore 589cde2885fSGarrett D'Amore rtlsp->rtls_suspended = B_TRUE; 590cde2885fSGarrett D'Amore rtls_chip_stop(rtlsp); 591cde2885fSGarrett D'Amore 592cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_tx_lock); 593cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_rx_lock); 594cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_io_lock); 595cde2885fSGarrett D'Amore return (DDI_SUCCESS); 596cde2885fSGarrett D'Amore 597cde2885fSGarrett D'Amore default: 598cde2885fSGarrett D'Amore return (DDI_FAILURE); 599cde2885fSGarrett D'Amore } 600cde2885fSGarrett D'Amore 601cde2885fSGarrett D'Amore if (mac_unregister(rtlsp->mh) != 0) { 602cde2885fSGarrett D'Amore /* device busy */ 603cde2885fSGarrett D'Amore return (DDI_FAILURE); 604cde2885fSGarrett D'Amore } 605cde2885fSGarrett D'Amore 606cde2885fSGarrett D'Amore ddi_remove_intr(devinfo, 0, rtlsp->iblk); 607cde2885fSGarrett D'Amore 608bbb1277bSGarrett D'Amore mii_free(rtlsp->mii); 609cde2885fSGarrett D'Amore 610cde2885fSGarrett D'Amore mutex_destroy(&rtlsp->rtls_io_lock); 611cde2885fSGarrett D'Amore mutex_destroy(&rtlsp->rtls_tx_lock); 612cde2885fSGarrett D'Amore mutex_destroy(&rtlsp->rtls_rx_lock); 613cde2885fSGarrett D'Amore 614cde2885fSGarrett D'Amore ddi_regs_map_free(&rtlsp->io_handle); 615cde2885fSGarrett D'Amore rtls_free_bufs(rtlsp); 616cde2885fSGarrett D'Amore kmem_free(rtlsp, sizeof (rtls_t)); 617cde2885fSGarrett D'Amore 618cde2885fSGarrett D'Amore return (DDI_SUCCESS); 619cde2885fSGarrett D'Amore } 620cde2885fSGarrett D'Amore 621cde2885fSGarrett D'Amore /* 622cde2885fSGarrett D'Amore * quiesce(9E) entry point. 623cde2885fSGarrett D'Amore * 624cde2885fSGarrett D'Amore * This function is called when the system is single-threaded at high 625cde2885fSGarrett D'Amore * PIL with preemption disabled. Therefore, this function must not be 626cde2885fSGarrett D'Amore * blocked. 627cde2885fSGarrett D'Amore * 628cde2885fSGarrett D'Amore * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 629cde2885fSGarrett D'Amore * DDI_FAILURE indicates an error condition and should almost never happen. 630cde2885fSGarrett D'Amore */ 631cde2885fSGarrett D'Amore static int 632cde2885fSGarrett D'Amore rtls_quiesce(dev_info_t *devinfo) 633cde2885fSGarrett D'Amore { 634cde2885fSGarrett D'Amore rtls_t *rtlsp; /* our private device info */ 635cde2885fSGarrett D'Amore 636cde2885fSGarrett D'Amore /* 637cde2885fSGarrett D'Amore * Get the driver private structure 638cde2885fSGarrett D'Amore */ 639cde2885fSGarrett D'Amore if ((rtlsp = ddi_get_driver_private(devinfo)) == NULL) { 640cde2885fSGarrett D'Amore return (DDI_FAILURE); 641cde2885fSGarrett D'Amore } 642cde2885fSGarrett D'Amore return (rtls_chip_reset(rtlsp, B_TRUE)); 643cde2885fSGarrett D'Amore } 644cde2885fSGarrett D'Amore 645cde2885fSGarrett D'Amore /* 646cde2885fSGarrett D'Amore * ========== MAC Entry Points ========== 647cde2885fSGarrett D'Amore */ 648cde2885fSGarrett D'Amore 649cde2885fSGarrett D'Amore /* 650cde2885fSGarrett D'Amore * rtls_m_start() -- start the board receiving and allow transmits 651cde2885fSGarrett D'Amore */ 652cde2885fSGarrett D'Amore static int 653cde2885fSGarrett D'Amore rtls_m_start(void *arg) 654cde2885fSGarrett D'Amore { 655cde2885fSGarrett D'Amore rtls_t *rtlsp = (rtls_t *)arg; 656cde2885fSGarrett D'Amore 657cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_io_lock); 658cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_rx_lock); 659cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_tx_lock); 660cde2885fSGarrett D'Amore 661cde2885fSGarrett D'Amore if (!rtlsp->rtls_suspended) 662cde2885fSGarrett D'Amore rtls_chip_restart(rtlsp); 663cde2885fSGarrett D'Amore 664cde2885fSGarrett D'Amore rtlsp->rtls_running = B_TRUE; 665cde2885fSGarrett D'Amore 666cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_tx_lock); 667cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_rx_lock); 668cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_io_lock); 669cde2885fSGarrett D'Amore 670bbb1277bSGarrett D'Amore drv_usecwait(100); 671bbb1277bSGarrett D'Amore 672bbb1277bSGarrett D'Amore mii_start(rtlsp->mii); 673bbb1277bSGarrett D'Amore 674cde2885fSGarrett D'Amore return (0); 675cde2885fSGarrett D'Amore } 676cde2885fSGarrett D'Amore 677cde2885fSGarrett D'Amore /* 678cde2885fSGarrett D'Amore * rtls_m_stop() -- stop board receiving and transmits 679cde2885fSGarrett D'Amore */ 680cde2885fSGarrett D'Amore static void 681cde2885fSGarrett D'Amore rtls_m_stop(void *arg) 682cde2885fSGarrett D'Amore { 683cde2885fSGarrett D'Amore rtls_t *rtlsp = (rtls_t *)arg; 684cde2885fSGarrett D'Amore 685bbb1277bSGarrett D'Amore mii_stop(rtlsp->mii); 686bbb1277bSGarrett D'Amore 687cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_io_lock); 688cde2885fSGarrett D'Amore 689cde2885fSGarrett D'Amore if (!rtlsp->rtls_suspended) 690cde2885fSGarrett D'Amore rtls_chip_stop(rtlsp); 691cde2885fSGarrett D'Amore rtlsp->rtls_running = B_FALSE; 692cde2885fSGarrett D'Amore 693cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_io_lock); 694cde2885fSGarrett D'Amore } 695cde2885fSGarrett D'Amore 696cde2885fSGarrett D'Amore /* 697cde2885fSGarrett D'Amore * rtls_m_unicst() -- set the physical network address 698cde2885fSGarrett D'Amore * on the board 699cde2885fSGarrett D'Amore */ 700cde2885fSGarrett D'Amore static int 701cde2885fSGarrett D'Amore rtls_m_unicst(void *arg, const uint8_t *macaddr) 702cde2885fSGarrett D'Amore { 703cde2885fSGarrett D'Amore rtls_t *rtlsp = arg; 704cde2885fSGarrett D'Amore 705cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_io_lock); 706cde2885fSGarrett D'Amore bcopy(macaddr, rtlsp->netaddr, ETHERADDRL); 707cde2885fSGarrett D'Amore if (!rtlsp->rtls_suspended) 708cde2885fSGarrett D'Amore rtls_set_mac_addr(rtlsp, rtlsp->netaddr); 709cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_io_lock); 710cde2885fSGarrett D'Amore return (0); 711cde2885fSGarrett D'Amore } 712cde2885fSGarrett D'Amore 713cde2885fSGarrett D'Amore /* 714cde2885fSGarrett D'Amore * rtls_m_multicst() -- set(enable) or disable a multicast address 715cde2885fSGarrett D'Amore * 716cde2885fSGarrett D'Amore * Program the hardware to enable/disable the multicast address in "mcast". 717cde2885fSGarrett D'Amore */ 718cde2885fSGarrett D'Amore static int 719cde2885fSGarrett D'Amore rtls_m_multicst(void *arg, boolean_t enable, const uint8_t *mcast) 720cde2885fSGarrett D'Amore { 721cde2885fSGarrett D'Amore rtls_t *rtlsp = (rtls_t *)arg; 722cde2885fSGarrett D'Amore uint_t index; 723cde2885fSGarrett D'Amore uint32_t *hashp; 724cde2885fSGarrett D'Amore 725cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_io_lock); 726cde2885fSGarrett D'Amore hashp = rtlsp->multi_hash; 727cde2885fSGarrett D'Amore index = rtls_hash_index(mcast); 728cde2885fSGarrett D'Amore /* index value is between 0 and 63 */ 729cde2885fSGarrett D'Amore 730cde2885fSGarrett D'Amore if (enable) { 731cde2885fSGarrett D'Amore if (rtlsp->multicast_cnt[index]++) { 732cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_io_lock); 733cde2885fSGarrett D'Amore return (0); 734cde2885fSGarrett D'Amore } 735cde2885fSGarrett D'Amore hashp[index/32] |= 1<< (index % 32); 736cde2885fSGarrett D'Amore } else { 737cde2885fSGarrett D'Amore if (--rtlsp->multicast_cnt[index]) { 738cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_io_lock); 739cde2885fSGarrett D'Amore return (0); 740cde2885fSGarrett D'Amore } 741cde2885fSGarrett D'Amore hashp[index/32] &= ~(1<< (index % 32)); 742cde2885fSGarrett D'Amore } 743cde2885fSGarrett D'Amore 744cde2885fSGarrett D'Amore /* 745cde2885fSGarrett D'Amore * Set multicast register 746cde2885fSGarrett D'Amore */ 747cde2885fSGarrett D'Amore if (!rtlsp->rtls_suspended) { 748cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, MULTICAST_0_REG, hashp[0]); 749cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, MULTICAST_4_REG, hashp[1]); 750cde2885fSGarrett D'Amore } 751cde2885fSGarrett D'Amore 752cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_io_lock); 753cde2885fSGarrett D'Amore 754cde2885fSGarrett D'Amore return (0); 755cde2885fSGarrett D'Amore } 756cde2885fSGarrett D'Amore 757cde2885fSGarrett D'Amore /* 758cde2885fSGarrett D'Amore * rtls_hash_index() -- a hashing function used for setting the 759cde2885fSGarrett D'Amore * node address or a multicast address 760cde2885fSGarrett D'Amore */ 761cde2885fSGarrett D'Amore static uint_t 762cde2885fSGarrett D'Amore rtls_hash_index(const uint8_t *address) 763cde2885fSGarrett D'Amore { 764cde2885fSGarrett D'Amore uint32_t crc = (ulong_t)RTLS_HASH_CRC; 765cde2885fSGarrett D'Amore uint32_t const POLY = RTLS_HASH_POLY; 766cde2885fSGarrett D'Amore uint32_t msb; 767cde2885fSGarrett D'Amore int bytes; 768cde2885fSGarrett D'Amore uchar_t currentbyte; 769cde2885fSGarrett D'Amore uint_t index; 770cde2885fSGarrett D'Amore int bit; 771cde2885fSGarrett D'Amore 772cde2885fSGarrett D'Amore for (bytes = 0; bytes < ETHERADDRL; bytes++) { 773cde2885fSGarrett D'Amore currentbyte = address[bytes]; 774cde2885fSGarrett D'Amore for (bit = 0; bit < 8; bit++) { 775cde2885fSGarrett D'Amore msb = crc >> 31; 776cde2885fSGarrett D'Amore crc <<= 1; 777cde2885fSGarrett D'Amore if (msb ^ (currentbyte & 1)) { 778cde2885fSGarrett D'Amore crc ^= POLY; 779cde2885fSGarrett D'Amore crc |= 0x00000001; 780cde2885fSGarrett D'Amore } 781cde2885fSGarrett D'Amore currentbyte >>= 1; 782cde2885fSGarrett D'Amore } 783cde2885fSGarrett D'Amore } 784cde2885fSGarrett D'Amore 785cde2885fSGarrett D'Amore index = crc >> 26; 786cde2885fSGarrett D'Amore 787cde2885fSGarrett D'Amore return (index); 788cde2885fSGarrett D'Amore } 789cde2885fSGarrett D'Amore 790cde2885fSGarrett D'Amore /* 791cde2885fSGarrett D'Amore * rtls_m_promisc() -- set or reset promiscuous mode on the board 792cde2885fSGarrett D'Amore */ 793cde2885fSGarrett D'Amore static int 794cde2885fSGarrett D'Amore rtls_m_promisc(void *arg, boolean_t on) 795cde2885fSGarrett D'Amore { 796cde2885fSGarrett D'Amore rtls_t *rtlsp = arg; 797cde2885fSGarrett D'Amore 798cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_io_lock); 799cde2885fSGarrett D'Amore 800cde2885fSGarrett D'Amore rtlsp->promisc = on; 801cde2885fSGarrett D'Amore if (!rtlsp->rtls_suspended) { 802cde2885fSGarrett D'Amore uint32_t val32 = rtls_reg_get32(rtlsp, RX_CONFIG_REG); 803cde2885fSGarrett D'Amore if (on) { 804cde2885fSGarrett D'Amore val32 |= RX_ACCEPT_ALL_PACKET; 805cde2885fSGarrett D'Amore } else { 806cde2885fSGarrett D'Amore val32 &= ~RX_ACCEPT_ALL_PACKET; 807cde2885fSGarrett D'Amore } 808cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, RX_CONFIG_REG, val32); 809cde2885fSGarrett D'Amore } 810cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_io_lock); 811cde2885fSGarrett D'Amore 812cde2885fSGarrett D'Amore return (0); 813cde2885fSGarrett D'Amore } 814cde2885fSGarrett D'Amore 815cde2885fSGarrett D'Amore /* 816cde2885fSGarrett D'Amore * rtls_m_stat() -- retrieve statistic 817cde2885fSGarrett D'Amore * 818cde2885fSGarrett D'Amore * MAC calls this routine just before it reads the driver's statistics 819cde2885fSGarrett D'Amore * structure. If your board maintains statistics, this is the time to 820cde2885fSGarrett D'Amore * read them in and update the values in the structure. If the driver 821cde2885fSGarrett D'Amore * maintains statistics continuously, this routine need do nothing. 822cde2885fSGarrett D'Amore */ 823cde2885fSGarrett D'Amore static int 824cde2885fSGarrett D'Amore rtls_m_stat(void *arg, uint_t stat, uint64_t *val) 825cde2885fSGarrett D'Amore { 826cde2885fSGarrett D'Amore rtls_t *rtlsp = arg; 827cde2885fSGarrett D'Amore 828bbb1277bSGarrett D'Amore if (mii_m_getstat(rtlsp->mii, stat, val) == 0) { 829bbb1277bSGarrett D'Amore return (0); 830cde2885fSGarrett D'Amore } 831cde2885fSGarrett D'Amore 832cde2885fSGarrett D'Amore switch (stat) { 833cde2885fSGarrett D'Amore case MAC_STAT_IPACKETS: 834cde2885fSGarrett D'Amore *val = rtlsp->stats.ipackets; 835cde2885fSGarrett D'Amore break; 836cde2885fSGarrett D'Amore case MAC_STAT_RBYTES: 837cde2885fSGarrett D'Amore *val = rtlsp->stats.rbytes; 838cde2885fSGarrett D'Amore break; 839cde2885fSGarrett D'Amore case MAC_STAT_OPACKETS: 840cde2885fSGarrett D'Amore *val = rtlsp->stats.opackets; 841cde2885fSGarrett D'Amore break; 842cde2885fSGarrett D'Amore case MAC_STAT_OBYTES: 843cde2885fSGarrett D'Amore *val = rtlsp->stats.obytes; 844cde2885fSGarrett D'Amore break; 845cde2885fSGarrett D'Amore case MAC_STAT_IERRORS: 846cde2885fSGarrett D'Amore *val = rtlsp->stats.rcv_err; 847cde2885fSGarrett D'Amore break; 848cde2885fSGarrett D'Amore case MAC_STAT_OERRORS: 849cde2885fSGarrett D'Amore *val = rtlsp->stats.xmt_err; 850cde2885fSGarrett D'Amore break; 851cde2885fSGarrett D'Amore case MAC_STAT_MULTIRCV: 852cde2885fSGarrett D'Amore *val = rtlsp->stats.multi_rcv; 853cde2885fSGarrett D'Amore break; 854cde2885fSGarrett D'Amore case MAC_STAT_BRDCSTRCV: 855cde2885fSGarrett D'Amore *val = rtlsp->stats.brdcst_rcv; 856cde2885fSGarrett D'Amore break; 857cde2885fSGarrett D'Amore case MAC_STAT_MULTIXMT: 858cde2885fSGarrett D'Amore *val = rtlsp->stats.multi_xmt; 859cde2885fSGarrett D'Amore break; 860cde2885fSGarrett D'Amore case MAC_STAT_BRDCSTXMT: 861cde2885fSGarrett D'Amore *val = rtlsp->stats.brdcst_xmt; 862cde2885fSGarrett D'Amore break; 863cde2885fSGarrett D'Amore case MAC_STAT_UNDERFLOWS: 864cde2885fSGarrett D'Amore *val = rtlsp->stats.underflow; 865cde2885fSGarrett D'Amore break; 866cde2885fSGarrett D'Amore case MAC_STAT_OVERFLOWS: 867cde2885fSGarrett D'Amore *val = rtlsp->stats.overflow; 868cde2885fSGarrett D'Amore break; 869cde2885fSGarrett D'Amore case MAC_STAT_NORCVBUF: 870cde2885fSGarrett D'Amore *val = rtlsp->stats.no_rcvbuf; 871cde2885fSGarrett D'Amore break; 872cde2885fSGarrett D'Amore case MAC_STAT_COLLISIONS: 873cde2885fSGarrett D'Amore *val = rtlsp->stats.collisions; 874cde2885fSGarrett D'Amore break; 875cde2885fSGarrett D'Amore case ETHER_STAT_FCS_ERRORS: 876cde2885fSGarrett D'Amore *val = rtlsp->stats.crc_err; 877cde2885fSGarrett D'Amore break; 878cde2885fSGarrett D'Amore case ETHER_STAT_ALIGN_ERRORS: 879cde2885fSGarrett D'Amore *val = rtlsp->stats.frame_err; 880cde2885fSGarrett D'Amore break; 881cde2885fSGarrett D'Amore case ETHER_STAT_DEFER_XMTS: 882cde2885fSGarrett D'Amore *val = rtlsp->stats.defer; 883cde2885fSGarrett D'Amore break; 884cde2885fSGarrett D'Amore case ETHER_STAT_TX_LATE_COLLISIONS: 885cde2885fSGarrett D'Amore *val = rtlsp->stats.xmt_latecoll; 886cde2885fSGarrett D'Amore break; 887cde2885fSGarrett D'Amore case ETHER_STAT_TOOLONG_ERRORS: 888cde2885fSGarrett D'Amore *val = rtlsp->stats.too_long; 889cde2885fSGarrett D'Amore break; 890cde2885fSGarrett D'Amore case ETHER_STAT_TOOSHORT_ERRORS: 891cde2885fSGarrett D'Amore *val = rtlsp->stats.in_short; 892cde2885fSGarrett D'Amore break; 893cde2885fSGarrett D'Amore case ETHER_STAT_CARRIER_ERRORS: 894cde2885fSGarrett D'Amore *val = rtlsp->stats.no_carrier; 895cde2885fSGarrett D'Amore break; 896cde2885fSGarrett D'Amore case ETHER_STAT_FIRST_COLLISIONS: 897cde2885fSGarrett D'Amore *val = rtlsp->stats.firstcol; 898cde2885fSGarrett D'Amore break; 899cde2885fSGarrett D'Amore case ETHER_STAT_MULTI_COLLISIONS: 900cde2885fSGarrett D'Amore *val = rtlsp->stats.multicol; 901cde2885fSGarrett D'Amore break; 902cde2885fSGarrett D'Amore default: 903cde2885fSGarrett D'Amore return (ENOTSUP); 904cde2885fSGarrett D'Amore } 905cde2885fSGarrett D'Amore 906cde2885fSGarrett D'Amore /* 907cde2885fSGarrett D'Amore * RTL8139 don't support MII statistics, 908cde2885fSGarrett D'Amore * these values are maintained by the driver software. 909cde2885fSGarrett D'Amore */ 910cde2885fSGarrett D'Amore 911cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG 912cde2885fSGarrett D'Amore if (rtls_debug & RTLS_TRACE) 913cde2885fSGarrett D'Amore rtls_reg_print(rtlsp); 914cde2885fSGarrett D'Amore #endif 915cde2885fSGarrett D'Amore 916cde2885fSGarrett D'Amore return (0); 917cde2885fSGarrett D'Amore } 918cde2885fSGarrett D'Amore 919ace3c3ffSVenugopal Iyer int 920ace3c3ffSVenugopal Iyer rtls_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 921ace3c3ffSVenugopal Iyer void *val) 922ace3c3ffSVenugopal Iyer { 923ace3c3ffSVenugopal Iyer rtls_t *rtlsp = arg; 924ace3c3ffSVenugopal Iyer 925ace3c3ffSVenugopal Iyer return (mii_m_getprop(rtlsp->mii, name, num, sz, val)); 926ace3c3ffSVenugopal Iyer } 927ace3c3ffSVenugopal Iyer 928ace3c3ffSVenugopal Iyer int 929ace3c3ffSVenugopal Iyer rtls_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 930ace3c3ffSVenugopal Iyer const void *val) 931ace3c3ffSVenugopal Iyer { 932ace3c3ffSVenugopal Iyer rtls_t *rtlsp = arg; 933ace3c3ffSVenugopal Iyer 934ace3c3ffSVenugopal Iyer return (mii_m_setprop(rtlsp->mii, name, num, sz, val)); 935ace3c3ffSVenugopal Iyer } 936ace3c3ffSVenugopal Iyer 937ace3c3ffSVenugopal Iyer static void 938ace3c3ffSVenugopal Iyer rtls_m_propinfo(void *arg, const char *name, mac_prop_id_t num, 939ace3c3ffSVenugopal Iyer mac_prop_info_handle_t prh) 940ace3c3ffSVenugopal Iyer { 941ace3c3ffSVenugopal Iyer rtls_t *rtlsp = arg; 942ace3c3ffSVenugopal Iyer 943ace3c3ffSVenugopal Iyer mii_m_propinfo(rtlsp->mii, name, num, prh); 944ace3c3ffSVenugopal Iyer } 945ace3c3ffSVenugopal Iyer 946cde2885fSGarrett D'Amore /* 947cde2885fSGarrett D'Amore * rtls_send() -- send a packet 948cde2885fSGarrett D'Amore * 949cde2885fSGarrett D'Amore * Called when a packet is ready to be transmitted. A pointer to an 950cde2885fSGarrett D'Amore * M_DATA message that contains the packet is passed to this routine. 951cde2885fSGarrett D'Amore * The complete LLC header is contained in the message's first message 952cde2885fSGarrett D'Amore * block, and the remainder of the packet is contained within 953cde2885fSGarrett D'Amore * additional M_DATA message blocks linked to the first message block. 954cde2885fSGarrett D'Amore * 955cde2885fSGarrett D'Amore * Returns B_TRUE if the packet was properly disposed of, or B_FALSE if 956cde2885fSGarrett D'Amore * if the packet is being deferred and should be tried again later. 957cde2885fSGarrett D'Amore */ 958cde2885fSGarrett D'Amore 959cde2885fSGarrett D'Amore static boolean_t 960cde2885fSGarrett D'Amore rtls_send(rtls_t *rtlsp, mblk_t *mp) 961cde2885fSGarrett D'Amore { 962cde2885fSGarrett D'Amore int totlen; 963cde2885fSGarrett D'Amore int ncc; 964cde2885fSGarrett D'Amore uint16_t cur_desc; 965cde2885fSGarrett D'Amore uint32_t tx_status; 966cde2885fSGarrett D'Amore 967cde2885fSGarrett D'Amore ASSERT(mp != NULL); 968cde2885fSGarrett D'Amore ASSERT(rtlsp->rtls_running); 969cde2885fSGarrett D'Amore 970cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_tx_lock); 971cde2885fSGarrett D'Amore 972cde2885fSGarrett D'Amore if (rtlsp->rtls_suspended) { 973cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_tx_lock); 974cde2885fSGarrett D'Amore return (B_FALSE); 975cde2885fSGarrett D'Amore } 976cde2885fSGarrett D'Amore 977cde2885fSGarrett D'Amore /* 978cde2885fSGarrett D'Amore * If chip error ... 979cde2885fSGarrett D'Amore */ 980cde2885fSGarrett D'Amore if (rtlsp->chip_error) { 981cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG 982cde2885fSGarrett D'Amore cmn_err(CE_WARN, 983cde2885fSGarrett D'Amore "%s: send fail--CHIP ERROR!", 984*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh)); 985cde2885fSGarrett D'Amore #endif 986cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_tx_lock); 987cde2885fSGarrett D'Amore freemsg(mp); 988cde2885fSGarrett D'Amore return (B_TRUE); 989cde2885fSGarrett D'Amore } 990cde2885fSGarrett D'Amore 991cde2885fSGarrett D'Amore /* 992bbb1277bSGarrett D'Amore * If chip link down ... Note that experimentation shows that 993bbb1277bSGarrett D'Amore * the device seems not to care about whether or not we have 994bbb1277bSGarrett D'Amore * this check, but if we don't add the check here, it might 995bbb1277bSGarrett D'Amore * not be properly reported as a carrier error. 996cde2885fSGarrett D'Amore */ 997bbb1277bSGarrett D'Amore if (rtls_reg_get8(rtlsp, MEDIA_STATUS_REG) & MEDIA_STATUS_LINK) { 998cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG 999cde2885fSGarrett D'Amore cmn_err(CE_WARN, 1000cde2885fSGarrett D'Amore "%s: send fail--LINK DOWN!", 1001*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh)); 1002cde2885fSGarrett D'Amore #endif 1003cde2885fSGarrett D'Amore rtlsp->stats.no_carrier++; 1004cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_tx_lock); 1005cde2885fSGarrett D'Amore freemsg(mp); 1006cde2885fSGarrett D'Amore return (B_TRUE); 1007cde2885fSGarrett D'Amore } 1008cde2885fSGarrett D'Amore 1009cde2885fSGarrett D'Amore /* 1010cde2885fSGarrett D'Amore * Current transmit descriptor 1011cde2885fSGarrett D'Amore */ 1012cde2885fSGarrett D'Amore cur_desc = rtlsp->tx_current_desc; 1013cde2885fSGarrett D'Amore ASSERT(cur_desc < RTLS_MAX_TX_DESC); 1014cde2885fSGarrett D'Amore 1015cde2885fSGarrett D'Amore /* 1016cde2885fSGarrett D'Amore * RealTek 8139 has 4 tx descriptor for transmit. In the first tx loop 1017cde2885fSGarrett D'Amore * of transmit,we needn't judge transmit status. 1018cde2885fSGarrett D'Amore */ 1019cde2885fSGarrett D'Amore if (rtlsp->tx_first_loop < RTLS_MAX_TX_DESC) { 1020cde2885fSGarrett D'Amore rtlsp->tx_first_loop++; 1021cde2885fSGarrett D'Amore goto tx_ready; 1022cde2885fSGarrett D'Amore } 1023cde2885fSGarrett D'Amore 1024cde2885fSGarrett D'Amore /* 1025cde2885fSGarrett D'Amore * If it's not the first tx loop, we need judge whether the chip is 1026cde2885fSGarrett D'Amore * busy or not. Otherwise, we have to reschedule send and wait... 1027cde2885fSGarrett D'Amore */ 1028cde2885fSGarrett D'Amore tx_status = rtls_reg_get32(rtlsp, TX_STATUS_DESC0_REG + 4 * cur_desc); 1029cde2885fSGarrett D'Amore 1030cde2885fSGarrett D'Amore /* 1031cde2885fSGarrett D'Amore * H/W doesn't complete packet transmit 1032cde2885fSGarrett D'Amore */ 1033cde2885fSGarrett D'Amore if (!(tx_status & TX_COMPLETE_FLAG)) { 1034cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG 1035cde2885fSGarrett D'Amore if (rtls_debug & RTLS_SEND) { 1036cde2885fSGarrett D'Amore cmn_err(CE_NOTE, 1037*2c6a6ad1SIlya Yanok "%s: rtls_send: need_sched", mac_name(rtlsp->mh)); 1038cde2885fSGarrett D'Amore } 1039cde2885fSGarrett D'Amore #endif 1040cde2885fSGarrett D'Amore /* 1041cde2885fSGarrett D'Amore * Through test, we find RTL8139 tx status might be 1042cde2885fSGarrett D'Amore * not-completing all along. We have to reset chip 1043cde2885fSGarrett D'Amore * to make RTL8139 tansmit re-work. 1044cde2885fSGarrett D'Amore */ 1045cde2885fSGarrett D'Amore if (rtlsp->tx_retry++ > RTLS_TX_RETRY_NUM) { 1046cde2885fSGarrett D'Amore 1047cde2885fSGarrett D'Amore /* 1048cde2885fSGarrett D'Amore * Wait transmit h/w more time... 1049cde2885fSGarrett D'Amore */ 1050cde2885fSGarrett D'Amore RTLS_TX_WAIT_TIMEOUT; /* 100 ms */ 1051cde2885fSGarrett D'Amore 1052cde2885fSGarrett D'Amore /* 1053cde2885fSGarrett D'Amore * Judge tx status again, if it remains not-completing, 1054cde2885fSGarrett D'Amore * we can confirm RTL8139 is in chip error state 1055cde2885fSGarrett D'Amore * and must reset it. 1056cde2885fSGarrett D'Amore */ 1057cde2885fSGarrett D'Amore tx_status = rtls_reg_get32(rtlsp, 1058cde2885fSGarrett D'Amore TX_STATUS_DESC0_REG + 4 * cur_desc); 1059cde2885fSGarrett D'Amore if (!(tx_status & TX_COMPLETE_FLAG)) { 1060cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG 1061cde2885fSGarrett D'Amore cmn_err(CE_NOTE, "%s: tx chip_error = 0x%x", 1062*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), tx_status); 1063cde2885fSGarrett D'Amore #endif 1064cde2885fSGarrett D'Amore rtlsp->tx_retry = 0; 1065cde2885fSGarrett D'Amore rtlsp->chip_error = B_TRUE; 1066cde2885fSGarrett D'Amore rtlsp->stats.xmt_err++; 1067cde2885fSGarrett D'Amore rtlsp->stats.mac_xmt_err++; 1068cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_tx_lock); 1069cde2885fSGarrett D'Amore freemsg(mp); 1070cde2885fSGarrett D'Amore return (B_TRUE); 1071cde2885fSGarrett D'Amore } 1072cde2885fSGarrett D'Amore } else { 1073cde2885fSGarrett D'Amore rtlsp->stats.defer++; 1074cde2885fSGarrett D'Amore rtlsp->need_sched = B_TRUE; 1075cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_tx_lock); 1076cde2885fSGarrett D'Amore return (B_FALSE); 1077cde2885fSGarrett D'Amore } 1078cde2885fSGarrett D'Amore } 1079cde2885fSGarrett D'Amore 1080cde2885fSGarrett D'Amore /* 1081cde2885fSGarrett D'Amore * Transmit error? 1082cde2885fSGarrett D'Amore */ 1083cde2885fSGarrett D'Amore if (tx_status & TX_ERR_FLAG) { 1084cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG 1085cde2885fSGarrett D'Amore if (rtls_debug & RTLS_SEND) { 1086cde2885fSGarrett D'Amore cmn_err(CE_NOTE, "%s: transmit error, status = 0x%x", 1087*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), tx_status); 1088cde2885fSGarrett D'Amore } 1089cde2885fSGarrett D'Amore #endif 1090cde2885fSGarrett D'Amore rtlsp->stats.xmt_err++; 1091cde2885fSGarrett D'Amore if (tx_status & TX_STATUS_TX_UNDERRUN) 1092cde2885fSGarrett D'Amore rtlsp->stats.underflow++; 1093cde2885fSGarrett D'Amore if (tx_status & TX_STATUS_CS_LOST) 1094cde2885fSGarrett D'Amore rtlsp->stats.no_carrier++; 1095cde2885fSGarrett D'Amore if (tx_status & TX_STATUS_OWC) 1096cde2885fSGarrett D'Amore rtlsp->stats.xmt_latecoll++; 1097cde2885fSGarrett D'Amore } 1098cde2885fSGarrett D'Amore ncc = ((tx_status & TX_STATUS_NCC) >> TX_STATUS_NCC_SHIFT); 1099cde2885fSGarrett D'Amore if (ncc != 0) { 1100cde2885fSGarrett D'Amore rtlsp->stats.collisions += ncc; 1101cde2885fSGarrett D'Amore rtlsp->stats.firstcol++; 1102cde2885fSGarrett D'Amore rtlsp->stats.multicol += ncc - 1; 1103cde2885fSGarrett D'Amore } 1104cde2885fSGarrett D'Amore 1105cde2885fSGarrett D'Amore tx_ready: 1106cde2885fSGarrett D'Amore /* 1107cde2885fSGarrett D'Amore * Initialize variable 1108cde2885fSGarrett D'Amore */ 1109cde2885fSGarrett D'Amore rtlsp->tx_retry = 0; 1110cde2885fSGarrett D'Amore totlen = 0; 1111cde2885fSGarrett D'Amore 1112cde2885fSGarrett D'Amore /* 1113cde2885fSGarrett D'Amore * Copy packet to tx descriptor buffer 1114cde2885fSGarrett D'Amore */ 1115cde2885fSGarrett D'Amore totlen = msgsize(mp); 1116cde2885fSGarrett D'Amore if (totlen > (ETHERMAX + 4)) { /* 4 bytes for VLAN header */ 1117cde2885fSGarrett D'Amore cmn_err(CE_NOTE, 1118cde2885fSGarrett D'Amore "%s: rtls_send: try to send large %d packet", 1119*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), totlen); 1120cde2885fSGarrett D'Amore rtlsp->stats.mac_xmt_err++; 1121cde2885fSGarrett D'Amore rtlsp->stats.xmt_err++; 1122cde2885fSGarrett D'Amore freemsg(mp); 1123cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_tx_lock); 1124cde2885fSGarrett D'Amore return (B_TRUE); 1125cde2885fSGarrett D'Amore } 1126cde2885fSGarrett D'Amore 1127cde2885fSGarrett D'Amore /* this will free the mblk */ 1128cde2885fSGarrett D'Amore mcopymsg(mp, rtlsp->tx_buf[cur_desc]); 1129cde2885fSGarrett D'Amore 1130cde2885fSGarrett D'Amore /* update stats */ 1131cde2885fSGarrett D'Amore if (*rtlsp->tx_buf[cur_desc] & 0x1) { 1132cde2885fSGarrett D'Amore uint16_t *ptr = (void *)rtlsp->tx_buf[cur_desc]; 1133cde2885fSGarrett D'Amore if ((ptr[0] == 0xffff) && 1134cde2885fSGarrett D'Amore (ptr[1] == 0xffff) && 1135cde2885fSGarrett D'Amore (ptr[2] == 0xffff)) { 1136cde2885fSGarrett D'Amore rtlsp->stats.brdcst_xmt++; 1137cde2885fSGarrett D'Amore } else { 1138cde2885fSGarrett D'Amore rtlsp->stats.multi_xmt++; 1139cde2885fSGarrett D'Amore } 1140cde2885fSGarrett D'Amore } 1141cde2885fSGarrett D'Amore rtlsp->stats.opackets++; 1142cde2885fSGarrett D'Amore rtlsp->stats.obytes += totlen; 1143cde2885fSGarrett D'Amore 1144cde2885fSGarrett D'Amore if (totlen < ETHERMIN) { 1145cde2885fSGarrett D'Amore bzero(rtlsp->tx_buf[cur_desc] + totlen, ETHERMIN - totlen); 1146cde2885fSGarrett D'Amore totlen = ETHERMIN; 1147cde2885fSGarrett D'Amore } 1148cde2885fSGarrett D'Amore 1149cde2885fSGarrett D'Amore /* make sure caches are flushed */ 1150cde2885fSGarrett D'Amore (void) ddi_dma_sync(rtlsp->dma_area_tx[cur_desc].dma_hdl, 0, totlen, 1151cde2885fSGarrett D'Amore DDI_DMA_SYNC_FORDEV); 1152cde2885fSGarrett D'Amore 1153cde2885fSGarrett D'Amore /* 1154cde2885fSGarrett D'Amore * Start transmit 1155cde2885fSGarrett D'Amore * set transmit FIFO threshhold to 0x30*32 = 1536 bytes 1156cde2885fSGarrett D'Amore * to avoid tx underrun. 1157cde2885fSGarrett D'Amore */ 1158cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, TX_STATUS_DESC0_REG + 4 * cur_desc, 1159cde2885fSGarrett D'Amore totlen | (0x30 << TX_STATUS_TX_THRESHOLD_SHIFT)); 1160cde2885fSGarrett D'Amore 1161cde2885fSGarrett D'Amore /* 1162cde2885fSGarrett D'Amore * Update the value of current tx descriptor 1163cde2885fSGarrett D'Amore */ 1164cde2885fSGarrett D'Amore cur_desc++; 1165cde2885fSGarrett D'Amore cur_desc %= RTLS_MAX_TX_DESC; 1166cde2885fSGarrett D'Amore rtlsp->tx_current_desc = cur_desc; 1167cde2885fSGarrett D'Amore 1168cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_tx_lock); 1169cde2885fSGarrett D'Amore 1170cde2885fSGarrett D'Amore return (B_TRUE); 1171cde2885fSGarrett D'Amore } 1172cde2885fSGarrett D'Amore 1173cde2885fSGarrett D'Amore /* 1174cde2885fSGarrett D'Amore * rtls_m_tx() -- send a chain of packets, linked by mp->b_next. 1175cde2885fSGarrett D'Amore */ 1176cde2885fSGarrett D'Amore static mblk_t * 1177cde2885fSGarrett D'Amore rtls_m_tx(void *arg, mblk_t *mp) 1178cde2885fSGarrett D'Amore { 1179cde2885fSGarrett D'Amore rtls_t *rtlsp = arg; 1180cde2885fSGarrett D'Amore mblk_t *next; 1181cde2885fSGarrett D'Amore 1182cde2885fSGarrett D'Amore while (mp != NULL) { 1183cde2885fSGarrett D'Amore next = mp->b_next; 1184cde2885fSGarrett D'Amore mp->b_next = NULL; 1185cde2885fSGarrett D'Amore if (!rtls_send(rtlsp, mp)) { 1186cde2885fSGarrett D'Amore mp->b_next = next; 1187cde2885fSGarrett D'Amore break; 1188cde2885fSGarrett D'Amore } 1189cde2885fSGarrett D'Amore mp = next; 1190cde2885fSGarrett D'Amore } 1191cde2885fSGarrett D'Amore return (mp); 1192cde2885fSGarrett D'Amore } 1193cde2885fSGarrett D'Amore 1194cde2885fSGarrett D'Amore /* 1195cde2885fSGarrett D'Amore * rtls_receive() -- receive packets 1196cde2885fSGarrett D'Amore * 1197cde2885fSGarrett D'Amore * Called when receive interrupts detected 1198cde2885fSGarrett D'Amore */ 1199cde2885fSGarrett D'Amore static void 1200cde2885fSGarrett D'Amore rtls_receive(rtls_t *rtlsp) 1201cde2885fSGarrett D'Amore { 1202cde2885fSGarrett D'Amore mblk_t *head = NULL; 1203cde2885fSGarrett D'Amore mblk_t **mpp; 1204cde2885fSGarrett D'Amore mblk_t *mp; 1205cde2885fSGarrett D'Amore uint16_t rx_status; 1206cde2885fSGarrett D'Amore uint16_t packet_len; 1207cde2885fSGarrett D'Amore int wrap_size; 1208cde2885fSGarrett D'Amore uint32_t cur_rx; 1209cde2885fSGarrett D'Amore uint8_t *rx_ptr; 1210cde2885fSGarrett D'Amore 1211cde2885fSGarrett D'Amore mpp = &head; 1212cde2885fSGarrett D'Amore 1213cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_rx_lock); 1214cde2885fSGarrett D'Amore 1215cde2885fSGarrett D'Amore if (rtlsp->rtls_suspended) { 1216cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_rx_lock); 1217cde2885fSGarrett D'Amore return; 1218cde2885fSGarrett D'Amore } 1219cde2885fSGarrett D'Amore 1220cde2885fSGarrett D'Amore while ((rtls_reg_get8(rtlsp, RT_COMMAND_REG) 1221cde2885fSGarrett D'Amore & RT_COMMAND_BUFF_EMPTY) == 0) { 1222cde2885fSGarrett D'Amore 1223cde2885fSGarrett D'Amore /* 1224cde2885fSGarrett D'Amore * Chip error state 1225cde2885fSGarrett D'Amore */ 1226cde2885fSGarrett D'Amore if (rtlsp->chip_error) { 1227cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG 1228cde2885fSGarrett D'Amore cmn_err(CE_WARN, 1229cde2885fSGarrett D'Amore "%s: receive fail--CHIP ERROR!", 1230*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh)); 1231cde2885fSGarrett D'Amore #endif 1232cde2885fSGarrett D'Amore break; 1233cde2885fSGarrett D'Amore } 1234cde2885fSGarrett D'Amore 1235cde2885fSGarrett D'Amore cur_rx = rtlsp->cur_rx; 1236cde2885fSGarrett D'Amore rx_ptr = rtlsp->rx_ring + cur_rx; 1237cde2885fSGarrett D'Amore packet_len = (rx_ptr[3] << 8) | (rx_ptr[2]); 1238cde2885fSGarrett D'Amore rx_status = rx_ptr[0]; 1239cde2885fSGarrett D'Amore 1240cde2885fSGarrett D'Amore /* 1241cde2885fSGarrett D'Amore * DMA still in progress 1242cde2885fSGarrett D'Amore */ 1243cde2885fSGarrett D'Amore if (packet_len == RX_STATUS_DMA_BUSY) { 1244cde2885fSGarrett D'Amore cmn_err(CE_NOTE, "%s: Rx DMA still in progress", 1245*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh)); 1246cde2885fSGarrett D'Amore break; 1247cde2885fSGarrett D'Amore } 1248cde2885fSGarrett D'Amore 1249cde2885fSGarrett D'Amore /* 1250cde2885fSGarrett D'Amore * Check receive status 1251cde2885fSGarrett D'Amore */ 1252cde2885fSGarrett D'Amore if ((rx_status & RX_ERR_FLAGS) || 1253cde2885fSGarrett D'Amore (!(rx_status & RX_HEADER_STATUS_ROK)) || 1254cde2885fSGarrett D'Amore (packet_len < (ETHERMIN + ETHERFCSL)) || 1255cde2885fSGarrett D'Amore (packet_len > (ETHERMAX + ETHERFCSL + 4))) { 1256cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG 1257cde2885fSGarrett D'Amore cmn_err(CE_NOTE, 1258cde2885fSGarrett D'Amore "%s: receive error, status = 0x%x, length = %d", 1259*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), rx_status, packet_len); 1260cde2885fSGarrett D'Amore #endif 1261cde2885fSGarrett D'Amore /* 1262cde2885fSGarrett D'Amore * Rx error statistics 1263cde2885fSGarrett D'Amore */ 1264cde2885fSGarrett D'Amore if ((rx_status & RX_HEADER_STATUS_RUNT) || 1265cde2885fSGarrett D'Amore (packet_len < (ETHERMIN + ETHERFCSL))) 1266cde2885fSGarrett D'Amore rtlsp->stats.in_short++; 1267cde2885fSGarrett D'Amore else if (packet_len > (ETHERMAX + ETHERFCSL + 4)) 1268cde2885fSGarrett D'Amore rtlsp->stats.too_long++; 1269cde2885fSGarrett D'Amore else if (rx_status & RX_HEADER_STATUS_CRC) 1270cde2885fSGarrett D'Amore rtlsp->stats.crc_err++; 1271cde2885fSGarrett D'Amore else if (rx_status & RX_HEADER_STATUS_FAE) 1272cde2885fSGarrett D'Amore rtlsp->stats.frame_err++; 1273cde2885fSGarrett D'Amore 1274cde2885fSGarrett D'Amore /* 1275cde2885fSGarrett D'Amore * Set chip_error flag to reset chip: 1276cde2885fSGarrett D'Amore * (suggested in RealTek programming guide.) 1277cde2885fSGarrett D'Amore */ 1278cde2885fSGarrett D'Amore rtlsp->chip_error = B_TRUE; 1279cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_rx_lock); 1280cde2885fSGarrett D'Amore return; 1281cde2885fSGarrett D'Amore } 1282cde2885fSGarrett D'Amore 1283cde2885fSGarrett D'Amore /* 1284cde2885fSGarrett D'Amore * We need not up-send ETHERFCSL bytes of receive packet 1285cde2885fSGarrett D'Amore */ 1286cde2885fSGarrett D'Amore packet_len -= ETHERFCSL; 1287cde2885fSGarrett D'Amore 1288cde2885fSGarrett D'Amore /* 1289cde2885fSGarrett D'Amore * Allocate buffer to receive this good packet 1290cde2885fSGarrett D'Amore */ 1291cde2885fSGarrett D'Amore mp = allocb(packet_len, 0); 1292cde2885fSGarrett D'Amore 1293cde2885fSGarrett D'Amore /* 1294cde2885fSGarrett D'Amore * Copy the data found into the new cluster, we have (+4) 1295cde2885fSGarrett D'Amore * to get us past the packet head data that the rtl chip 1296cde2885fSGarrett D'Amore * places at the start of the message 1297cde2885fSGarrett D'Amore */ 1298cde2885fSGarrett D'Amore if ((cur_rx + packet_len + RX_HEADER_SIZE) 1299cde2885fSGarrett D'Amore > RTLS_RX_BUF_RING) { 1300cde2885fSGarrett D'Amore wrap_size = cur_rx + packet_len + RX_HEADER_SIZE 1301cde2885fSGarrett D'Amore - RTLS_RX_BUF_RING; 1302cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG 1303cde2885fSGarrett D'Amore if (rtls_debug & RTLS_RECV) { 1304cde2885fSGarrett D'Amore cmn_err(CE_NOTE, 1305cde2885fSGarrett D'Amore "%s: Rx: packet_len = %d, wrap_size = %d", 1306*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), packet_len, wrap_size); 1307cde2885fSGarrett D'Amore } 1308cde2885fSGarrett D'Amore #endif 1309cde2885fSGarrett D'Amore 1310cde2885fSGarrett D'Amore if (mp != NULL) { 1311cde2885fSGarrett D'Amore /* Flush caches */ 1312cde2885fSGarrett D'Amore (void) ddi_dma_sync(rtlsp->dma_area_rx.dma_hdl, 1313cde2885fSGarrett D'Amore cur_rx + RX_HEADER_SIZE, 1314cde2885fSGarrett D'Amore packet_len - wrap_size, 1315cde2885fSGarrett D'Amore DDI_DMA_SYNC_FORKERNEL); 1316cde2885fSGarrett D'Amore (void) ddi_dma_sync(rtlsp->dma_area_rx.dma_hdl, 1317cde2885fSGarrett D'Amore 0, wrap_size, 1318cde2885fSGarrett D'Amore DDI_DMA_SYNC_FORKERNEL); 1319cde2885fSGarrett D'Amore 1320cde2885fSGarrett D'Amore /* 1321cde2885fSGarrett D'Amore * Copy in first section of message as stored 1322cde2885fSGarrett D'Amore * at the end of the ring buffer 1323cde2885fSGarrett D'Amore */ 1324cde2885fSGarrett D'Amore bcopy(rx_ptr + RX_HEADER_SIZE, 1325cde2885fSGarrett D'Amore mp->b_wptr, packet_len - wrap_size); 1326cde2885fSGarrett D'Amore mp->b_wptr += packet_len - wrap_size; 1327cde2885fSGarrett D'Amore bcopy(rtlsp->rx_ring, mp->b_wptr, wrap_size); 1328cde2885fSGarrett D'Amore mp->b_wptr += wrap_size; 1329cde2885fSGarrett D'Amore *mpp = mp; 1330cde2885fSGarrett D'Amore mpp = &mp->b_next; 1331cde2885fSGarrett D'Amore 1332cde2885fSGarrett D'Amore rtlsp->stats.ipackets++; 1333cde2885fSGarrett D'Amore if (rx_status & RX_HEADER_STATUS_BCAST) 1334cde2885fSGarrett D'Amore rtlsp->stats.brdcst_rcv++; 1335cde2885fSGarrett D'Amore if (rx_status & RX_HEADER_STATUS_MULTI) 1336cde2885fSGarrett D'Amore rtlsp->stats.multi_rcv++; 1337cde2885fSGarrett D'Amore rtlsp->stats.rbytes += packet_len; 1338cde2885fSGarrett D'Amore } else { 1339cde2885fSGarrett D'Amore rtlsp->stats.no_rcvbuf++; 1340cde2885fSGarrett D'Amore } 1341cde2885fSGarrett D'Amore 1342cde2885fSGarrett D'Amore cur_rx = RTLS_RX_ADDR_ALIGNED(wrap_size + ETHERFCSL); 1343cde2885fSGarrett D'Amore /* 4-byte aligned */ 1344cde2885fSGarrett D'Amore } else { 1345cde2885fSGarrett D'Amore 1346cde2885fSGarrett D'Amore if (mp != NULL) { 1347cde2885fSGarrett D'Amore /* Flush caches */ 1348cde2885fSGarrett D'Amore (void) ddi_dma_sync(rtlsp->dma_area_rx.dma_hdl, 1349cde2885fSGarrett D'Amore cur_rx + RX_HEADER_SIZE, packet_len, 1350cde2885fSGarrett D'Amore DDI_DMA_SYNC_FORKERNEL); 1351cde2885fSGarrett D'Amore bcopy(rx_ptr + RX_HEADER_SIZE, mp->b_wptr, 1352cde2885fSGarrett D'Amore packet_len); 1353cde2885fSGarrett D'Amore mp->b_wptr += packet_len; 1354cde2885fSGarrett D'Amore *mpp = mp; 1355cde2885fSGarrett D'Amore mpp = &mp->b_next; 1356cde2885fSGarrett D'Amore 1357cde2885fSGarrett D'Amore rtlsp->stats.ipackets++; 1358cde2885fSGarrett D'Amore if (rx_status & RX_HEADER_STATUS_BCAST) 1359cde2885fSGarrett D'Amore rtlsp->stats.brdcst_rcv++; 1360cde2885fSGarrett D'Amore if (rx_status & RX_HEADER_STATUS_MULTI) 1361cde2885fSGarrett D'Amore rtlsp->stats.multi_rcv++; 1362cde2885fSGarrett D'Amore rtlsp->stats.rbytes += packet_len; 1363cde2885fSGarrett D'Amore } else { 1364cde2885fSGarrett D'Amore rtlsp->stats.no_rcvbuf++; 1365cde2885fSGarrett D'Amore } 1366cde2885fSGarrett D'Amore cur_rx += packet_len + RX_HEADER_SIZE + ETHERFCSL; 1367cde2885fSGarrett D'Amore 1368cde2885fSGarrett D'Amore cur_rx = RTLS_RX_ADDR_ALIGNED(cur_rx); 1369cde2885fSGarrett D'Amore /* 4-byte aligned */ 1370cde2885fSGarrett D'Amore } 1371cde2885fSGarrett D'Amore 1372cde2885fSGarrett D'Amore /* 1373cde2885fSGarrett D'Amore * Update rx buffer ring read pointer: 1374cde2885fSGarrett D'Amore * give us a little leeway to ensure no overflow 1375cde2885fSGarrett D'Amore */ 1376cde2885fSGarrett D'Amore rtlsp->cur_rx = cur_rx; 1377cde2885fSGarrett D'Amore rtls_reg_set16(rtlsp, RX_CURRENT_READ_ADDR_REG, 1378cde2885fSGarrett D'Amore cur_rx - READ_ADDR_GAP); 1379cde2885fSGarrett D'Amore } 1380cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_rx_lock); 1381cde2885fSGarrett D'Amore 1382cde2885fSGarrett D'Amore /* 1383cde2885fSGarrett D'Amore * Upsend packet 1384cde2885fSGarrett D'Amore */ 1385cde2885fSGarrett D'Amore if (head) { 1386cde2885fSGarrett D'Amore mac_rx(rtlsp->mh, NULL, head); 1387cde2885fSGarrett D'Amore } 1388cde2885fSGarrett D'Amore } 1389cde2885fSGarrett D'Amore 1390cde2885fSGarrett D'Amore /* 1391cde2885fSGarrett D'Amore * rtls_intr() -- interrupt from board to inform us that a receive or 1392cde2885fSGarrett D'Amore * link change. 1393cde2885fSGarrett D'Amore */ 1394cde2885fSGarrett D'Amore static uint_t 1395cde2885fSGarrett D'Amore rtls_intr(caddr_t arg) 1396cde2885fSGarrett D'Amore { 1397cde2885fSGarrett D'Amore rtls_t *rtlsp = (void *)arg; 1398cde2885fSGarrett D'Amore uint32_t int_status; 1399cde2885fSGarrett D'Amore uint32_t val32; 1400bbb1277bSGarrett D'Amore boolean_t resched = B_FALSE; 1401cde2885fSGarrett D'Amore 1402cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_io_lock); 1403bbb1277bSGarrett D'Amore if (rtlsp->rtls_suspended) { 1404bbb1277bSGarrett D'Amore mutex_exit(&rtlsp->rtls_io_lock); 1405bbb1277bSGarrett D'Amore return (DDI_INTR_UNCLAIMED); 1406bbb1277bSGarrett D'Amore } 1407cde2885fSGarrett D'Amore 1408cde2885fSGarrett D'Amore /* 1409cde2885fSGarrett D'Amore * Was this interrupt caused by our device... 1410cde2885fSGarrett D'Amore */ 1411cde2885fSGarrett D'Amore int_status = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG); 1412cde2885fSGarrett D'Amore if (!(int_status & rtlsp->int_mask)) { 1413cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_io_lock); 1414cde2885fSGarrett D'Amore return (DDI_INTR_UNCLAIMED); 1415cde2885fSGarrett D'Amore /* indicate it wasn't our interrupt */ 1416cde2885fSGarrett D'Amore } 1417cde2885fSGarrett D'Amore 1418cde2885fSGarrett D'Amore /* 1419cde2885fSGarrett D'Amore * Clear interrupt 1420cde2885fSGarrett D'Amore */ 1421cde2885fSGarrett D'Amore rtls_reg_set16(rtlsp, RT_INT_STATUS_REG, int_status); 1422cde2885fSGarrett D'Amore 1423cde2885fSGarrett D'Amore /* 1424cde2885fSGarrett D'Amore * If chip error, restart chip... 1425cde2885fSGarrett D'Amore */ 1426cde2885fSGarrett D'Amore if (rtlsp->chip_error) { 1427cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_rx_lock); 1428cde2885fSGarrett D'Amore mutex_enter(&rtlsp->rtls_tx_lock); 1429cde2885fSGarrett D'Amore rtls_chip_restart(rtlsp); 1430cde2885fSGarrett D'Amore rtlsp->chip_error = B_FALSE; 1431cde2885fSGarrett D'Amore rtlsp->tx_retry = 0; 1432cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_tx_lock); 1433cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_rx_lock); 1434cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_io_lock); 1435cde2885fSGarrett D'Amore return (DDI_INTR_CLAIMED); 1436cde2885fSGarrett D'Amore /* no need to hand other interrupts */ 1437cde2885fSGarrett D'Amore } 1438cde2885fSGarrett D'Amore 1439cde2885fSGarrett D'Amore /* 1440cde2885fSGarrett D'Amore * Transmit error interrupt 1441cde2885fSGarrett D'Amore */ 1442cde2885fSGarrett D'Amore if (int_status & TX_ERR_INT) { 1443cde2885fSGarrett D'Amore val32 = rtls_reg_get32(rtlsp, TX_CONFIG_REG); 1444cde2885fSGarrett D'Amore val32 |= TX_CLEAR_ABORT; 1445cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, TX_CONFIG_REG, val32); 1446*2c6a6ad1SIlya Yanok cmn_err(CE_WARN, "%s: transmit abort!!!", mac_name(rtlsp->mh)); 1447cde2885fSGarrett D'Amore } 1448cde2885fSGarrett D'Amore 1449cde2885fSGarrett D'Amore /* 1450cde2885fSGarrett D'Amore * Trigger mac_tx_update 1451cde2885fSGarrett D'Amore */ 1452bbb1277bSGarrett D'Amore if (rtlsp->need_sched) { 1453bbb1277bSGarrett D'Amore rtlsp->need_sched = B_FALSE; 1454bbb1277bSGarrett D'Amore resched = B_TRUE; 1455cde2885fSGarrett D'Amore } 1456cde2885fSGarrett D'Amore 1457cde2885fSGarrett D'Amore mutex_exit(&rtlsp->rtls_io_lock); 1458cde2885fSGarrett D'Amore 1459cde2885fSGarrett D'Amore /* 1460cde2885fSGarrett D'Amore * Receive interrupt 1461cde2885fSGarrett D'Amore */ 1462cde2885fSGarrett D'Amore if (int_status & RTLS_RX_INT) { 1463cde2885fSGarrett D'Amore if (int_status & RX_OVERFLOW_INT) { 1464cde2885fSGarrett D'Amore rtlsp->stats.overflow++; 1465cde2885fSGarrett D'Amore rtlsp->stats.rcv_err++; 1466cde2885fSGarrett D'Amore } 1467cde2885fSGarrett D'Amore rtls_receive(rtlsp); 1468cde2885fSGarrett D'Amore } 1469cde2885fSGarrett D'Amore 1470cde2885fSGarrett D'Amore /* 1471bbb1277bSGarrett D'Amore * Link change interrupt. 1472cde2885fSGarrett D'Amore */ 1473bbb1277bSGarrett D'Amore if (int_status & LINK_CHANGE_INT) { 1474bbb1277bSGarrett D'Amore mii_check(rtlsp->mii); 1475cde2885fSGarrett D'Amore } 1476cde2885fSGarrett D'Amore 1477bbb1277bSGarrett D'Amore if (resched) { 1478cde2885fSGarrett D'Amore mac_tx_update(rtlsp->mh); 1479cde2885fSGarrett D'Amore } 1480cde2885fSGarrett D'Amore 1481bbb1277bSGarrett D'Amore return (DDI_INTR_CLAIMED); /* indicate it was our interrupt */ 1482cde2885fSGarrett D'Amore } 1483cde2885fSGarrett D'Amore 1484cde2885fSGarrett D'Amore /* 1485cde2885fSGarrett D'Amore * ========== Buffer Management Routines ========== 1486cde2885fSGarrett D'Amore */ 1487cde2885fSGarrett D'Amore 1488cde2885fSGarrett D'Amore /* 1489cde2885fSGarrett D'Amore * rtls_alloc_dma_mem() -- allocate an area of memory and a DMA handle 1490cde2885fSGarrett D'Amore * for accessing it 1491cde2885fSGarrett D'Amore */ 1492cde2885fSGarrett D'Amore static int 1493cde2885fSGarrett D'Amore rtls_alloc_dma_mem(rtls_t *rtlsp, size_t memsize, 1494cde2885fSGarrett D'Amore ddi_device_acc_attr_t *attr_p, uint_t dma_flags, dma_area_t *dma_p) 1495cde2885fSGarrett D'Amore { 1496cde2885fSGarrett D'Amore caddr_t vaddr; 1497cde2885fSGarrett D'Amore int err; 1498cde2885fSGarrett D'Amore 1499cde2885fSGarrett D'Amore /* 1500cde2885fSGarrett D'Amore * Allocate handle 1501cde2885fSGarrett D'Amore */ 1502cde2885fSGarrett D'Amore err = ddi_dma_alloc_handle(rtlsp->devinfo, &dma_attr, 1503cde2885fSGarrett D'Amore DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl); 1504cde2885fSGarrett D'Amore if (err != DDI_SUCCESS) { 1505cde2885fSGarrett D'Amore cmn_err(CE_WARN, 1506cde2885fSGarrett D'Amore "%s: rtls_alloc_dma_mem: ddi_dma_alloc_handle failed: %d", 1507*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), err); 1508cde2885fSGarrett D'Amore dma_p->dma_hdl = NULL; 1509cde2885fSGarrett D'Amore return (DDI_FAILURE); 1510cde2885fSGarrett D'Amore } 1511cde2885fSGarrett D'Amore 1512cde2885fSGarrett D'Amore /* 1513cde2885fSGarrett D'Amore * Allocate memory 1514cde2885fSGarrett D'Amore */ 1515cde2885fSGarrett D'Amore err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p, 1516cde2885fSGarrett D'Amore dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING), 1517cde2885fSGarrett D'Amore DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl); 1518cde2885fSGarrett D'Amore if (err != DDI_SUCCESS) { 1519cde2885fSGarrett D'Amore cmn_err(CE_WARN, 1520cde2885fSGarrett D'Amore "%s: rtls_alloc_dma_mem: ddi_dma_mem_alloc failed: %d", 1521*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), err); 1522cde2885fSGarrett D'Amore ddi_dma_free_handle(&dma_p->dma_hdl); 1523cde2885fSGarrett D'Amore dma_p->dma_hdl = NULL; 1524cde2885fSGarrett D'Amore dma_p->acc_hdl = NULL; 1525cde2885fSGarrett D'Amore return (DDI_FAILURE); 1526cde2885fSGarrett D'Amore } 1527cde2885fSGarrett D'Amore 1528cde2885fSGarrett D'Amore /* 1529cde2885fSGarrett D'Amore * Bind the two together 1530cde2885fSGarrett D'Amore */ 1531cde2885fSGarrett D'Amore dma_p->mem_va = vaddr; 1532cde2885fSGarrett D'Amore err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 1533cde2885fSGarrett D'Amore vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL, 1534cde2885fSGarrett D'Amore &dma_p->cookie, &dma_p->ncookies); 1535cde2885fSGarrett D'Amore if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) { 1536cde2885fSGarrett D'Amore cmn_err(CE_WARN, 1537cde2885fSGarrett D'Amore "%s: rtls_alloc_dma_mem: " 1538cde2885fSGarrett D'Amore "ddi_dma_addr_bind_handle failed: %d", 1539*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), err); 1540cde2885fSGarrett D'Amore ddi_dma_mem_free(&dma_p->acc_hdl); 1541cde2885fSGarrett D'Amore ddi_dma_free_handle(&dma_p->dma_hdl); 1542cde2885fSGarrett D'Amore dma_p->acc_hdl = NULL; 1543cde2885fSGarrett D'Amore dma_p->dma_hdl = NULL; 1544cde2885fSGarrett D'Amore return (DDI_FAILURE); 1545cde2885fSGarrett D'Amore } 1546cde2885fSGarrett D'Amore 1547cde2885fSGarrett D'Amore return (DDI_SUCCESS); 1548cde2885fSGarrett D'Amore } 1549cde2885fSGarrett D'Amore 1550cde2885fSGarrett D'Amore /* 1551cde2885fSGarrett D'Amore * rtls_free_dma_mem() -- free one allocated area of DMAable memory 1552cde2885fSGarrett D'Amore */ 1553cde2885fSGarrett D'Amore static void 1554cde2885fSGarrett D'Amore rtls_free_dma_mem(dma_area_t *dma_p) 1555cde2885fSGarrett D'Amore { 1556cde2885fSGarrett D'Amore if (dma_p->dma_hdl != NULL) { 1557cde2885fSGarrett D'Amore if (dma_p->ncookies) { 1558cde2885fSGarrett D'Amore (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 1559cde2885fSGarrett D'Amore dma_p->ncookies = 0; 1560cde2885fSGarrett D'Amore } 1561cde2885fSGarrett D'Amore ddi_dma_free_handle(&dma_p->dma_hdl); 1562cde2885fSGarrett D'Amore dma_p->dma_hdl = NULL; 1563cde2885fSGarrett D'Amore } 1564cde2885fSGarrett D'Amore 1565cde2885fSGarrett D'Amore if (dma_p->acc_hdl != NULL) { 1566cde2885fSGarrett D'Amore ddi_dma_mem_free(&dma_p->acc_hdl); 1567cde2885fSGarrett D'Amore dma_p->acc_hdl = NULL; 1568cde2885fSGarrett D'Amore } 1569cde2885fSGarrett D'Amore } 1570cde2885fSGarrett D'Amore 1571cde2885fSGarrett D'Amore /* 1572cde2885fSGarrett D'Amore * rtls_alloc_bufs() -- allocate descriptors/buffers for this device instance 1573cde2885fSGarrett D'Amore */ 1574cde2885fSGarrett D'Amore static int 1575cde2885fSGarrett D'Amore rtls_alloc_bufs(rtls_t *rtlsp) 1576cde2885fSGarrett D'Amore { 1577cde2885fSGarrett D'Amore int i; 1578cde2885fSGarrett D'Amore int err; 1579cde2885fSGarrett D'Amore 1580cde2885fSGarrett D'Amore /* 1581cde2885fSGarrett D'Amore * Allocate memory & handle for Tx buffers 1582cde2885fSGarrett D'Amore */ 1583cde2885fSGarrett D'Amore for (i = 0; i < RTLS_MAX_TX_DESC; i++) { 1584cde2885fSGarrett D'Amore err = rtls_alloc_dma_mem(rtlsp, 1585cde2885fSGarrett D'Amore RTLS_TX_BUF_SIZE, 1586cde2885fSGarrett D'Amore &rtls_buf_accattr, 1587cde2885fSGarrett D'Amore DDI_DMA_WRITE | DDI_DMA_STREAMING, 1588cde2885fSGarrett D'Amore &rtlsp->dma_area_tx[i]); 1589cde2885fSGarrett D'Amore 1590cde2885fSGarrett D'Amore if (err != DDI_SUCCESS) 1591cde2885fSGarrett D'Amore return (DDI_FAILURE); 1592cde2885fSGarrett D'Amore 1593cde2885fSGarrett D'Amore rtlsp->tx_buf[i] = (uint8_t *)rtlsp->dma_area_tx[i].mem_va; 1594cde2885fSGarrett D'Amore } 1595cde2885fSGarrett D'Amore 1596cde2885fSGarrett D'Amore /* 1597cde2885fSGarrett D'Amore * Allocate memory & handle for Rx buffers 1598cde2885fSGarrett D'Amore */ 1599cde2885fSGarrett D'Amore err = rtls_alloc_dma_mem(rtlsp, 1600cde2885fSGarrett D'Amore RTLS_RX_BUF_SIZE, 1601cde2885fSGarrett D'Amore &rtls_buf_accattr, 1602cde2885fSGarrett D'Amore DDI_DMA_READ | DDI_DMA_STREAMING, 1603cde2885fSGarrett D'Amore &rtlsp->dma_area_rx); 1604cde2885fSGarrett D'Amore 1605cde2885fSGarrett D'Amore if (err != DDI_SUCCESS) 1606cde2885fSGarrett D'Amore return (DDI_FAILURE); 1607cde2885fSGarrett D'Amore 1608cde2885fSGarrett D'Amore rtlsp->rx_ring = (uint8_t *)rtlsp->dma_area_rx.mem_va; 1609cde2885fSGarrett D'Amore 1610cde2885fSGarrett D'Amore return (DDI_SUCCESS); 1611cde2885fSGarrett D'Amore } 1612cde2885fSGarrett D'Amore 1613cde2885fSGarrett D'Amore /* 1614cde2885fSGarrett D'Amore * rtls_free_bufs() -- free descriptors/buffers allocated for this 1615cde2885fSGarrett D'Amore * device instance. 1616cde2885fSGarrett D'Amore */ 1617cde2885fSGarrett D'Amore static void 1618cde2885fSGarrett D'Amore rtls_free_bufs(rtls_t *rtlsp) 1619cde2885fSGarrett D'Amore { 1620cde2885fSGarrett D'Amore int i; 1621cde2885fSGarrett D'Amore 1622cde2885fSGarrett D'Amore for (i = 0; i < RTLS_MAX_TX_DESC; i++) { 1623cde2885fSGarrett D'Amore rtls_free_dma_mem(&rtlsp->dma_area_tx[i]); 1624cde2885fSGarrett D'Amore rtlsp->tx_buf[i] = NULL; 1625cde2885fSGarrett D'Amore } 1626cde2885fSGarrett D'Amore 1627cde2885fSGarrett D'Amore rtls_free_dma_mem(&rtlsp->dma_area_rx); 1628cde2885fSGarrett D'Amore rtlsp->rx_ring = NULL; 1629cde2885fSGarrett D'Amore } 1630cde2885fSGarrett D'Amore 1631cde2885fSGarrett D'Amore /* 1632cde2885fSGarrett D'Amore * ========== Chip H/W Operation Routines ========== 1633cde2885fSGarrett D'Amore */ 1634cde2885fSGarrett D'Amore 1635cde2885fSGarrett D'Amore /* 1636cde2885fSGarrett D'Amore * rtls_chip_reset() -- reset chip 1637cde2885fSGarrett D'Amore */ 1638cde2885fSGarrett D'Amore static int 1639cde2885fSGarrett D'Amore rtls_chip_reset(rtls_t *rtlsp, boolean_t quiesce) 1640cde2885fSGarrett D'Amore { 1641cde2885fSGarrett D'Amore int i; 1642cde2885fSGarrett D'Amore uint16_t val16; 1643cde2885fSGarrett D'Amore uint8_t val8; 1644cde2885fSGarrett D'Amore 1645cde2885fSGarrett D'Amore /* 1646cde2885fSGarrett D'Amore * Chip should be in STOP state 1647cde2885fSGarrett D'Amore */ 1648cde2885fSGarrett D'Amore val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG); 1649cde2885fSGarrett D'Amore val8 &= ~(RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE); 1650cde2885fSGarrett D'Amore rtls_reg_set8(rtlsp, RT_COMMAND_REG, val8); 1651cde2885fSGarrett D'Amore 1652cde2885fSGarrett D'Amore /* 1653cde2885fSGarrett D'Amore * Disable interrupt 1654cde2885fSGarrett D'Amore */ 1655cde2885fSGarrett D'Amore val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG); 1656cde2885fSGarrett D'Amore rtls_reg_set16(rtlsp, RT_INT_MASK_REG, val16 & (~RTLS_INT_MASK_ALL)); 1657cde2885fSGarrett D'Amore rtlsp->int_mask = RTLS_INT_MASK_NONE; 1658cde2885fSGarrett D'Amore 1659cde2885fSGarrett D'Amore /* 1660cde2885fSGarrett D'Amore * Clear pended interrupt 1661cde2885fSGarrett D'Amore */ 1662cde2885fSGarrett D'Amore val16 = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG); 1663cde2885fSGarrett D'Amore rtls_reg_set16(rtlsp, RT_INT_STATUS_REG, val16); 1664cde2885fSGarrett D'Amore 1665cde2885fSGarrett D'Amore /* 1666cde2885fSGarrett D'Amore * Reset chip 1667cde2885fSGarrett D'Amore */ 1668cde2885fSGarrett D'Amore val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG); 1669cde2885fSGarrett D'Amore rtls_reg_set8(rtlsp, RT_COMMAND_REG, val8 | RT_COMMAND_RESET); 1670cde2885fSGarrett D'Amore 1671cde2885fSGarrett D'Amore /* 1672cde2885fSGarrett D'Amore * Wait for reset success 1673cde2885fSGarrett D'Amore */ 1674cde2885fSGarrett D'Amore i = 0; 1675cde2885fSGarrett D'Amore while (rtls_reg_get8(rtlsp, RT_COMMAND_REG) & RT_COMMAND_RESET) { 1676cde2885fSGarrett D'Amore if (++i > RTLS_RESET_WAIT_NUM) { 1677cde2885fSGarrett D'Amore /* 1678cde2885fSGarrett D'Amore * At quiesce path we can't call cmn_err(), as 1679cde2885fSGarrett D'Amore * it might block 1680cde2885fSGarrett D'Amore */ 1681cde2885fSGarrett D'Amore if (!quiesce) 1682cde2885fSGarrett D'Amore cmn_err(CE_WARN, 1683*2c6a6ad1SIlya Yanok "%s: chip reset fail.", 1684*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh)); 1685cde2885fSGarrett D'Amore return (DDI_FAILURE); 1686cde2885fSGarrett D'Amore } 1687cde2885fSGarrett D'Amore RTLS_RESET_WAIT_INTERVAL; 1688cde2885fSGarrett D'Amore } 1689cde2885fSGarrett D'Amore 1690cde2885fSGarrett D'Amore return (DDI_SUCCESS); 1691cde2885fSGarrett D'Amore } 1692cde2885fSGarrett D'Amore 1693cde2885fSGarrett D'Amore /* 1694cde2885fSGarrett D'Amore * rtls_chip_init() -- initialize the specified network board short of 1695cde2885fSGarrett D'Amore * actually starting the board. Call after rtls_chip_reset(). 1696cde2885fSGarrett D'Amore */ 1697cde2885fSGarrett D'Amore static void 1698cde2885fSGarrett D'Amore rtls_chip_init(rtls_t *rtlsp) 1699cde2885fSGarrett D'Amore { 1700cde2885fSGarrett D'Amore uint32_t val32; 1701cde2885fSGarrett D'Amore uint16_t val16; 1702cde2885fSGarrett D'Amore uint8_t val8; 1703cde2885fSGarrett D'Amore 1704cde2885fSGarrett D'Amore /* 1705cde2885fSGarrett D'Amore * Initialize internal data structures 1706cde2885fSGarrett D'Amore */ 1707cde2885fSGarrett D'Amore rtlsp->cur_rx = 0; 1708cde2885fSGarrett D'Amore rtlsp->tx_current_desc = 0; 1709cde2885fSGarrett D'Amore rtlsp->tx_first_loop = 0; 1710cde2885fSGarrett D'Amore 1711cde2885fSGarrett D'Amore /* 1712cde2885fSGarrett D'Amore * Set DMA physical rx/tx buffer address to register 1713cde2885fSGarrett D'Amore */ 1714cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, RX_BUFF_ADDR_REG, 1715cde2885fSGarrett D'Amore (ulong_t)rtlsp->dma_area_rx.cookie.dmac_address); 1716cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, TX_ADDR_DESC0_REG, 1717cde2885fSGarrett D'Amore (ulong_t)rtlsp->dma_area_tx[0].cookie.dmac_address); 1718cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, TX_ADDR_DESC1_REG, 1719cde2885fSGarrett D'Amore (ulong_t)rtlsp->dma_area_tx[1].cookie.dmac_address); 1720cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, TX_ADDR_DESC2_REG, 1721cde2885fSGarrett D'Amore (ulong_t)rtlsp->dma_area_tx[2].cookie.dmac_address); 1722cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, TX_ADDR_DESC3_REG, 1723cde2885fSGarrett D'Amore (ulong_t)rtlsp->dma_area_tx[3].cookie.dmac_address); 1724cde2885fSGarrett D'Amore 1725cde2885fSGarrett D'Amore /* 1726cde2885fSGarrett D'Amore * Start transmit/receive before set tx/rx configuration register 1727cde2885fSGarrett D'Amore */ 1728cde2885fSGarrett D'Amore val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG); 1729cde2885fSGarrett D'Amore rtls_reg_set8(rtlsp, RT_COMMAND_REG, 1730cde2885fSGarrett D'Amore val8 | RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE); 1731cde2885fSGarrett D'Amore 1732cde2885fSGarrett D'Amore /* 1733cde2885fSGarrett D'Amore * Set transmit configuration register 1734cde2885fSGarrett D'Amore */ 1735cde2885fSGarrett D'Amore val32 = rtls_reg_get32(rtlsp, TX_CONFIG_REG); 1736cde2885fSGarrett D'Amore val32 &= TX_CONSIG_REG_RESERVE; 1737cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, TX_CONFIG_REG, val32 | TX_CONFIG_DEFAULT); 1738cde2885fSGarrett D'Amore 1739cde2885fSGarrett D'Amore /* 1740cde2885fSGarrett D'Amore * Set receive configuration register 1741cde2885fSGarrett D'Amore */ 1742cde2885fSGarrett D'Amore val32 = rtls_reg_get32(rtlsp, RX_CONFIG_REG); 1743cde2885fSGarrett D'Amore val32 &= RX_CONSIG_REG_RESERVE; 1744cde2885fSGarrett D'Amore if (rtlsp->promisc) 1745cde2885fSGarrett D'Amore val32 |= RX_ACCEPT_ALL_PACKET; 1746cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, RX_CONFIG_REG, val32 | RX_CONFIG_DEFAULT); 1747cde2885fSGarrett D'Amore 1748cde2885fSGarrett D'Amore /* 1749cde2885fSGarrett D'Amore * Set multicast register 1750cde2885fSGarrett D'Amore */ 1751cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, MULTICAST_0_REG, rtlsp->multi_hash[0]); 1752cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, MULTICAST_4_REG, rtlsp->multi_hash[1]); 1753cde2885fSGarrett D'Amore 1754cde2885fSGarrett D'Amore /* 1755cde2885fSGarrett D'Amore * Set unicast address 1756cde2885fSGarrett D'Amore */ 1757cde2885fSGarrett D'Amore rtls_set_mac_addr(rtlsp, rtlsp->netaddr); 1758cde2885fSGarrett D'Amore 1759cde2885fSGarrett D'Amore /* 1760cde2885fSGarrett D'Amore * Set current address of packet read 1761cde2885fSGarrett D'Amore */ 1762cde2885fSGarrett D'Amore rtls_reg_set16(rtlsp, RX_CURRENT_READ_ADDR_REG, RX_READ_RESET_VAL); 1763cde2885fSGarrett D'Amore 1764cde2885fSGarrett D'Amore /* 1765cde2885fSGarrett D'Amore * No early-rx interrupts 1766cde2885fSGarrett D'Amore */ 1767cde2885fSGarrett D'Amore val16 = rtls_reg_get16(rtlsp, RT_MUL_INTSEL_REG); 1768cde2885fSGarrett D'Amore val16 &= ~RT_MUL_INTSEL_BITS; 1769cde2885fSGarrett D'Amore rtls_reg_set16(rtlsp, RT_MUL_INTSEL_REG, val16); 1770cde2885fSGarrett D'Amore } 1771cde2885fSGarrett D'Amore 1772cde2885fSGarrett D'Amore /* 1773cde2885fSGarrett D'Amore * rtls_chip_start() -- start chip 1774cde2885fSGarrett D'Amore */ 1775cde2885fSGarrett D'Amore static void 1776cde2885fSGarrett D'Amore rtls_chip_start(rtls_t *rtlsp) 1777cde2885fSGarrett D'Amore { 1778cde2885fSGarrett D'Amore uint16_t val16; 1779cde2885fSGarrett D'Amore uint8_t val8; 1780cde2885fSGarrett D'Amore 1781cde2885fSGarrett D'Amore /* 1782cde2885fSGarrett D'Amore * Start transmit/receive 1783cde2885fSGarrett D'Amore */ 1784cde2885fSGarrett D'Amore val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG); 1785cde2885fSGarrett D'Amore rtls_reg_set8(rtlsp, RT_COMMAND_REG, 1786cde2885fSGarrett D'Amore val8 | RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE); 1787cde2885fSGarrett D'Amore 1788cde2885fSGarrett D'Amore /* 1789cde2885fSGarrett D'Amore * Enable interrupt 1790cde2885fSGarrett D'Amore */ 1791cde2885fSGarrett D'Amore val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG); 1792cde2885fSGarrett D'Amore rtls_reg_set16(rtlsp, RT_INT_MASK_REG, val16 | RTLS_INT_MASK); 1793cde2885fSGarrett D'Amore rtlsp->int_mask = RTLS_INT_MASK; 1794cde2885fSGarrett D'Amore } 1795cde2885fSGarrett D'Amore 1796cde2885fSGarrett D'Amore /* 1797cde2885fSGarrett D'Amore * rtls_chip_restart() -- restart chip 1798cde2885fSGarrett D'Amore */ 1799cde2885fSGarrett D'Amore static void 1800cde2885fSGarrett D'Amore rtls_chip_restart(rtls_t *rtlsp) 1801cde2885fSGarrett D'Amore { 1802cde2885fSGarrett D'Amore (void) rtls_chip_reset(rtlsp, B_FALSE); 1803cde2885fSGarrett D'Amore rtls_chip_init(rtlsp); 1804cde2885fSGarrett D'Amore rtls_chip_start(rtlsp); 1805cde2885fSGarrett D'Amore } 1806cde2885fSGarrett D'Amore 1807cde2885fSGarrett D'Amore /* 1808cde2885fSGarrett D'Amore * rtls_chip_stop() -- stop board receiving 1809cde2885fSGarrett D'Amore */ 1810cde2885fSGarrett D'Amore static void 1811cde2885fSGarrett D'Amore rtls_chip_stop(rtls_t *rtlsp) 1812cde2885fSGarrett D'Amore { 1813cde2885fSGarrett D'Amore uint16_t val16; 1814cde2885fSGarrett D'Amore uint8_t val8; 1815cde2885fSGarrett D'Amore 1816cde2885fSGarrett D'Amore /* 1817cde2885fSGarrett D'Amore * Disable interrupt 1818cde2885fSGarrett D'Amore */ 1819cde2885fSGarrett D'Amore val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG); 1820cde2885fSGarrett D'Amore rtls_reg_set16(rtlsp, RT_INT_MASK_REG, val16 & (~RTLS_INT_MASK_ALL)); 1821cde2885fSGarrett D'Amore rtlsp->int_mask = RTLS_INT_MASK_NONE; 1822cde2885fSGarrett D'Amore 1823cde2885fSGarrett D'Amore /* 1824cde2885fSGarrett D'Amore * Clear pended interrupt 1825cde2885fSGarrett D'Amore */ 1826cde2885fSGarrett D'Amore val16 = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG); 1827cde2885fSGarrett D'Amore rtls_reg_set16(rtlsp, RT_INT_STATUS_REG, val16); 1828cde2885fSGarrett D'Amore 1829cde2885fSGarrett D'Amore /* 1830cde2885fSGarrett D'Amore * Stop the board and disable transmit/receive 1831cde2885fSGarrett D'Amore */ 1832cde2885fSGarrett D'Amore val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG); 1833cde2885fSGarrett D'Amore val8 &= ~(RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE); 1834cde2885fSGarrett D'Amore rtls_reg_set8(rtlsp, RT_COMMAND_REG, val8); 1835cde2885fSGarrett D'Amore } 1836cde2885fSGarrett D'Amore 1837cde2885fSGarrett D'Amore /* 1838cde2885fSGarrett D'Amore * rtls_get_mac_addr() -- get the physical network address on the board 1839cde2885fSGarrett D'Amore */ 1840cde2885fSGarrett D'Amore static void 1841cde2885fSGarrett D'Amore rtls_get_mac_addr(rtls_t *rtlsp, uint8_t *macaddr) 1842cde2885fSGarrett D'Amore { 1843cde2885fSGarrett D'Amore uint32_t val32; 1844cde2885fSGarrett D'Amore 1845cde2885fSGarrett D'Amore /* 1846cde2885fSGarrett D'Amore * Read first 4-byte of mac address 1847cde2885fSGarrett D'Amore */ 1848cde2885fSGarrett D'Amore val32 = rtls_reg_get32(rtlsp, ID_0_REG); 1849cde2885fSGarrett D'Amore macaddr[0] = val32 & 0xff; 1850cde2885fSGarrett D'Amore val32 = val32 >> 8; 1851cde2885fSGarrett D'Amore macaddr[1] = val32 & 0xff; 1852cde2885fSGarrett D'Amore val32 = val32 >> 8; 1853cde2885fSGarrett D'Amore macaddr[2] = val32 & 0xff; 1854cde2885fSGarrett D'Amore val32 = val32 >> 8; 1855cde2885fSGarrett D'Amore macaddr[3] = val32 & 0xff; 1856cde2885fSGarrett D'Amore 1857cde2885fSGarrett D'Amore /* 1858cde2885fSGarrett D'Amore * Read last 2-byte of mac address 1859cde2885fSGarrett D'Amore */ 1860cde2885fSGarrett D'Amore val32 = rtls_reg_get32(rtlsp, ID_4_REG); 1861cde2885fSGarrett D'Amore macaddr[4] = val32 & 0xff; 1862cde2885fSGarrett D'Amore val32 = val32 >> 8; 1863cde2885fSGarrett D'Amore macaddr[5] = val32 & 0xff; 1864cde2885fSGarrett D'Amore } 1865cde2885fSGarrett D'Amore 1866cde2885fSGarrett D'Amore static void 1867cde2885fSGarrett D'Amore rtls_set_mac_addr(rtls_t *rtlsp, const uint8_t *macaddr) 1868cde2885fSGarrett D'Amore { 1869cde2885fSGarrett D'Amore uint32_t val32; 1870cde2885fSGarrett D'Amore uint8_t val8; 1871cde2885fSGarrett D'Amore 1872cde2885fSGarrett D'Amore /* 1873cde2885fSGarrett D'Amore * Change to config register write enable mode 1874cde2885fSGarrett D'Amore */ 1875bbb1277bSGarrett D'Amore val8 = rtls_reg_get8(rtlsp, RT_93c46_COMMAND_REG); 1876cde2885fSGarrett D'Amore val8 |= RT_93c46_MODE_CONFIG; 1877bbb1277bSGarrett D'Amore rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8); 1878cde2885fSGarrett D'Amore 1879cde2885fSGarrett D'Amore /* 1880cde2885fSGarrett D'Amore * Get first 4 bytes of mac address 1881cde2885fSGarrett D'Amore */ 1882cde2885fSGarrett D'Amore val32 = macaddr[3]; 1883cde2885fSGarrett D'Amore val32 = val32 << 8; 1884cde2885fSGarrett D'Amore val32 |= macaddr[2]; 1885cde2885fSGarrett D'Amore val32 = val32 << 8; 1886cde2885fSGarrett D'Amore val32 |= macaddr[1]; 1887cde2885fSGarrett D'Amore val32 = val32 << 8; 1888cde2885fSGarrett D'Amore val32 |= macaddr[0]; 1889cde2885fSGarrett D'Amore 1890cde2885fSGarrett D'Amore /* 1891cde2885fSGarrett D'Amore * Set first 4 bytes of mac address 1892cde2885fSGarrett D'Amore */ 1893cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, ID_0_REG, val32); 1894cde2885fSGarrett D'Amore 1895cde2885fSGarrett D'Amore /* 1896cde2885fSGarrett D'Amore * Get last 2 bytes of mac address 1897cde2885fSGarrett D'Amore */ 1898cde2885fSGarrett D'Amore val32 = macaddr[5]; 1899cde2885fSGarrett D'Amore val32 = val32 << 8; 1900cde2885fSGarrett D'Amore val32 |= macaddr[4]; 1901cde2885fSGarrett D'Amore 1902cde2885fSGarrett D'Amore /* 1903cde2885fSGarrett D'Amore * Set last 2 bytes of mac address 1904cde2885fSGarrett D'Amore */ 1905cde2885fSGarrett D'Amore val32 |= rtls_reg_get32(rtlsp, ID_4_REG) & ~0xffff; 1906cde2885fSGarrett D'Amore rtls_reg_set32(rtlsp, ID_4_REG, val32); 1907cde2885fSGarrett D'Amore 1908cde2885fSGarrett D'Amore /* 1909cde2885fSGarrett D'Amore * Return to normal network/host communication mode 1910cde2885fSGarrett D'Amore */ 1911cde2885fSGarrett D'Amore val8 &= ~RT_93c46_MODE_CONFIG; 1912bbb1277bSGarrett D'Amore rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8); 1913cde2885fSGarrett D'Amore } 1914cde2885fSGarrett D'Amore 1915bbb1277bSGarrett D'Amore static uint16_t 1916bbb1277bSGarrett D'Amore rtls_mii_read(void *arg, uint8_t phy, uint8_t reg) 1917cde2885fSGarrett D'Amore { 1918bbb1277bSGarrett D'Amore rtls_t *rtlsp = arg; 1919bbb1277bSGarrett D'Amore uint16_t val; 1920bbb1277bSGarrett D'Amore 1921bbb1277bSGarrett D'Amore if (phy != 1) { 1922bbb1277bSGarrett D'Amore return (0xffff); 1923bbb1277bSGarrett D'Amore } 1924bbb1277bSGarrett D'Amore switch (reg) { 1925bbb1277bSGarrett D'Amore case MII_CONTROL: 1926bbb1277bSGarrett D'Amore val = rtls_reg_get16(rtlsp, BASIC_MODE_CONTROL_REG); 1927bbb1277bSGarrett D'Amore break; 1928bbb1277bSGarrett D'Amore case MII_STATUS: 1929bbb1277bSGarrett D'Amore val = rtls_reg_get16(rtlsp, BASIC_MODE_STATUS_REG); 1930bbb1277bSGarrett D'Amore break; 1931bbb1277bSGarrett D'Amore case MII_AN_ADVERT: 1932bbb1277bSGarrett D'Amore val = rtls_reg_get16(rtlsp, AUTO_NEGO_AD_REG); 1933bbb1277bSGarrett D'Amore break; 1934bbb1277bSGarrett D'Amore case MII_AN_LPABLE: 1935bbb1277bSGarrett D'Amore val = rtls_reg_get16(rtlsp, AUTO_NEGO_LP_REG); 1936bbb1277bSGarrett D'Amore break; 1937bbb1277bSGarrett D'Amore case MII_AN_EXPANSION: 1938bbb1277bSGarrett D'Amore val = rtls_reg_get16(rtlsp, AUTO_NEGO_EXP_REG); 1939bbb1277bSGarrett D'Amore break; 1940bbb1277bSGarrett D'Amore case MII_VENDOR(0): 1941bbb1277bSGarrett D'Amore /* 1942bbb1277bSGarrett D'Amore * We "simulate" a vendor private register so that the 1943bbb1277bSGarrett D'Amore * PHY layer can access it to determine detected link 1944bbb1277bSGarrett D'Amore * speed/duplex. 1945bbb1277bSGarrett D'Amore */ 1946bbb1277bSGarrett D'Amore val = rtls_reg_get8(rtlsp, MEDIA_STATUS_REG); 1947bbb1277bSGarrett D'Amore break; 1948bbb1277bSGarrett D'Amore case MII_PHYIDH: 1949bbb1277bSGarrett D'Amore case MII_PHYIDL: 1950bbb1277bSGarrett D'Amore default: 1951bbb1277bSGarrett D'Amore val = 0; 1952bbb1277bSGarrett D'Amore break; 1953bbb1277bSGarrett D'Amore } 1954bbb1277bSGarrett D'Amore return (val); 1955bbb1277bSGarrett D'Amore } 1956bbb1277bSGarrett D'Amore 1957bbb1277bSGarrett D'Amore void 1958bbb1277bSGarrett D'Amore rtls_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val) 1959bbb1277bSGarrett D'Amore { 1960bbb1277bSGarrett D'Amore rtls_t *rtlsp = arg; 1961cde2885fSGarrett D'Amore uint8_t val8; 1962cde2885fSGarrett D'Amore 1963bbb1277bSGarrett D'Amore if (phy != 1) { 1964bbb1277bSGarrett D'Amore return; 1965cde2885fSGarrett D'Amore } 1966bbb1277bSGarrett D'Amore switch (reg) { 1967bbb1277bSGarrett D'Amore case MII_CONTROL: 1968bbb1277bSGarrett D'Amore /* Enable writes to all bits of BMCR */ 1969bbb1277bSGarrett D'Amore val8 = rtls_reg_get8(rtlsp, RT_93c46_COMMAND_REG); 1970cde2885fSGarrett D'Amore val8 |= RT_93c46_MODE_CONFIG; 1971bbb1277bSGarrett D'Amore rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8); 1972bbb1277bSGarrett D'Amore /* write out the value */ 1973bbb1277bSGarrett D'Amore rtls_reg_set16(rtlsp, BASIC_MODE_CONTROL_REG, val); 1974cde2885fSGarrett D'Amore 1975bbb1277bSGarrett D'Amore /* Return to normal network/host communication mode */ 1976cde2885fSGarrett D'Amore val8 &= ~RT_93c46_MODE_CONFIG; 1977bbb1277bSGarrett D'Amore rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8); 1978bbb1277bSGarrett D'Amore return; 1979bbb1277bSGarrett D'Amore 1980bbb1277bSGarrett D'Amore case MII_STATUS: 1981bbb1277bSGarrett D'Amore rtls_reg_set16(rtlsp, BASIC_MODE_STATUS_REG, val); 1982bbb1277bSGarrett D'Amore break; 1983bbb1277bSGarrett D'Amore case MII_AN_ADVERT: 1984bbb1277bSGarrett D'Amore rtls_reg_set16(rtlsp, AUTO_NEGO_AD_REG, val); 1985bbb1277bSGarrett D'Amore break; 1986bbb1277bSGarrett D'Amore case MII_AN_LPABLE: 1987bbb1277bSGarrett D'Amore rtls_reg_set16(rtlsp, AUTO_NEGO_LP_REG, val); 1988bbb1277bSGarrett D'Amore break; 1989bbb1277bSGarrett D'Amore case MII_AN_EXPANSION: 1990bbb1277bSGarrett D'Amore rtls_reg_set16(rtlsp, AUTO_NEGO_EXP_REG, val); 1991bbb1277bSGarrett D'Amore break; 1992bbb1277bSGarrett D'Amore case MII_PHYIDH: 1993bbb1277bSGarrett D'Amore case MII_PHYIDL: 1994bbb1277bSGarrett D'Amore default: 1995bbb1277bSGarrett D'Amore /* these are not writable */ 1996bbb1277bSGarrett D'Amore break; 1997bbb1277bSGarrett D'Amore } 1998bbb1277bSGarrett D'Amore } 1999bbb1277bSGarrett D'Amore 2000bbb1277bSGarrett D'Amore void 2001bbb1277bSGarrett D'Amore rtls_mii_notify(void *arg, link_state_t link) 2002bbb1277bSGarrett D'Amore { 2003bbb1277bSGarrett D'Amore rtls_t *rtlsp = arg; 2004bbb1277bSGarrett D'Amore 2005bbb1277bSGarrett D'Amore mac_link_update(rtlsp->mh, link); 2006cde2885fSGarrett D'Amore } 2007cde2885fSGarrett D'Amore 2008cde2885fSGarrett D'Amore #ifdef RTLS_DEBUG 2009cde2885fSGarrett D'Amore /* 2010cde2885fSGarrett D'Amore * rtls_reg_print() -- print out reg value(for debug use only) 2011cde2885fSGarrett D'Amore */ 2012cde2885fSGarrett D'Amore static void 2013cde2885fSGarrett D'Amore rtls_reg_print(rtls_t *rtlsp) 2014cde2885fSGarrett D'Amore { 2015cde2885fSGarrett D'Amore uint8_t val8; 2016cde2885fSGarrett D'Amore uint16_t val16; 2017cde2885fSGarrett D'Amore uint32_t val32; 2018cde2885fSGarrett D'Amore 2019cde2885fSGarrett D'Amore val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG); 2020cde2885fSGarrett D'Amore cmn_err(CE_NOTE, "%s: RT_COMMAND_REG = 0x%x", 2021*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), val8); 2022cde2885fSGarrett D'Amore delay(drv_usectohz(1000)); 2023cde2885fSGarrett D'Amore 2024cde2885fSGarrett D'Amore val16 = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG); 2025cde2885fSGarrett D'Amore cmn_err(CE_NOTE, "%s: RT_INT_STATUS_REG = 0x%x", 2026*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), val16); 2027cde2885fSGarrett D'Amore delay(drv_usectohz(1000)); 2028cde2885fSGarrett D'Amore 2029cde2885fSGarrett D'Amore val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG); 2030cde2885fSGarrett D'Amore cmn_err(CE_NOTE, "%s: RT_INT_MASK_REG = 0x%x", 2031*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), val16); 2032cde2885fSGarrett D'Amore delay(drv_usectohz(1000)); 2033cde2885fSGarrett D'Amore 2034cde2885fSGarrett D'Amore val32 = rtls_reg_get32(rtlsp, RX_CONFIG_REG); 2035cde2885fSGarrett D'Amore cmn_err(CE_NOTE, "%s: RX_CONFIG_REG = 0x%x", 2036*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), val32); 2037cde2885fSGarrett D'Amore delay(drv_usectohz(1000)); 2038cde2885fSGarrett D'Amore 2039cde2885fSGarrett D'Amore val16 = rtls_reg_get16(rtlsp, TX_DESC_STAUS_REG); 2040bbb1277bSGarrett D'Amore cmn_err(CE_NOTE, "%s: TX_DESC_STAUS_REG = 0x%x, cur_desc = %d", 2041*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), val16, rtlsp->tx_current_desc); 2042cde2885fSGarrett D'Amore delay(drv_usectohz(1000)); 2043cde2885fSGarrett D'Amore 2044cde2885fSGarrett D'Amore val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC0_REG); 2045bbb1277bSGarrett D'Amore cmn_err(CE_NOTE, "%s: TX_STATUS_DESC0_REG = 0x%x", 2046*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), val32); 2047cde2885fSGarrett D'Amore delay(drv_usectohz(1000)); 2048cde2885fSGarrett D'Amore 2049cde2885fSGarrett D'Amore val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC1_REG); 2050bbb1277bSGarrett D'Amore cmn_err(CE_NOTE, "%s: TX_STATUS_DESC1_REG = 0x%x", 2051*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), val32); 2052cde2885fSGarrett D'Amore delay(drv_usectohz(1000)); 2053cde2885fSGarrett D'Amore 2054cde2885fSGarrett D'Amore val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC2_REG); 2055bbb1277bSGarrett D'Amore cmn_err(CE_NOTE, "%s: TX_STATUS_DESC2_REG = 0x%x", 2056*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), val32); 2057cde2885fSGarrett D'Amore delay(drv_usectohz(1000)); 2058cde2885fSGarrett D'Amore 2059cde2885fSGarrett D'Amore val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC3_REG); 2060bbb1277bSGarrett D'Amore cmn_err(CE_NOTE, "%s: TX_STATUS_DESC3_REG = 0x%x", 2061*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), val32); 2062cde2885fSGarrett D'Amore delay(drv_usectohz(1000)); 2063cde2885fSGarrett D'Amore 2064bbb1277bSGarrett D'Amore cmn_err(CE_NOTE, "%s: in = %llu, multicast = %llu, broadcast = %llu", 2065*2c6a6ad1SIlya Yanok mac_name(rtlsp->mh), 2066cde2885fSGarrett D'Amore (unsigned long long)rtlsp->stats.ipackets, 2067cde2885fSGarrett D'Amore (unsigned long long)rtlsp->stats.multi_rcv, 2068cde2885fSGarrett D'Amore (unsigned long long)rtlsp->stats.brdcst_rcv); 2069cde2885fSGarrett D'Amore delay(drv_usectohz(1000)); 2070cde2885fSGarrett D'Amore } 2071cde2885fSGarrett D'Amore #endif 2072