19286SGarrett.Damore@Sun.COM /* 29286SGarrett.Damore@Sun.COM * CDDL HEADER START 39286SGarrett.Damore@Sun.COM * 49286SGarrett.Damore@Sun.COM * The contents of this file are subject to the terms of the 59286SGarrett.Damore@Sun.COM * Common Development and Distribution License (the "License"). 69286SGarrett.Damore@Sun.COM * You may not use this file except in compliance with the License. 79286SGarrett.Damore@Sun.COM * 89286SGarrett.Damore@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 99286SGarrett.Damore@Sun.COM * or http://www.opensolaris.org/os/licensing. 109286SGarrett.Damore@Sun.COM * See the License for the specific language governing permissions 119286SGarrett.Damore@Sun.COM * and limitations under the License. 129286SGarrett.Damore@Sun.COM * 139286SGarrett.Damore@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 149286SGarrett.Damore@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 159286SGarrett.Damore@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 169286SGarrett.Damore@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 179286SGarrett.Damore@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 189286SGarrett.Damore@Sun.COM * 199286SGarrett.Damore@Sun.COM * CDDL HEADER END 209286SGarrett.Damore@Sun.COM */ 219286SGarrett.Damore@Sun.COM 229286SGarrett.Damore@Sun.COM /* 23*11453Sgdamore@opensolaris.org * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 249286SGarrett.Damore@Sun.COM * Use is subject to license terms. 259286SGarrett.Damore@Sun.COM */ 269286SGarrett.Damore@Sun.COM 279286SGarrett.Damore@Sun.COM /* 289286SGarrett.Damore@Sun.COM * rtls -- REALTEK 8139-serials PCI Fast Ethernet Driver, Depends on the 299286SGarrett.Damore@Sun.COM * Generic LAN Driver utility functions in /kernel/misc/mac 309286SGarrett.Damore@Sun.COM * 319286SGarrett.Damore@Sun.COM * This product is covered by one or more of the following patents: 329286SGarrett.Damore@Sun.COM * US5,307,459, US5,434,872, US5,732,094, US6,570,884, US6,115,776, and 339286SGarrett.Damore@Sun.COM * US6,327,625. 349286SGarrett.Damore@Sun.COM * 359286SGarrett.Damore@Sun.COM * Currently supports: 369286SGarrett.Damore@Sun.COM * RTL8139 379286SGarrett.Damore@Sun.COM */ 389286SGarrett.Damore@Sun.COM 399286SGarrett.Damore@Sun.COM #include <sys/types.h> 409286SGarrett.Damore@Sun.COM #include <sys/debug.h> 419286SGarrett.Damore@Sun.COM #include <sys/errno.h> 429286SGarrett.Damore@Sun.COM 439286SGarrett.Damore@Sun.COM #include <sys/stropts.h> 449286SGarrett.Damore@Sun.COM #include <sys/stream.h> 459286SGarrett.Damore@Sun.COM #include <sys/kmem.h> 469286SGarrett.Damore@Sun.COM #include <sys/conf.h> 479286SGarrett.Damore@Sun.COM #include <sys/ddi.h> 489286SGarrett.Damore@Sun.COM #include <sys/devops.h> 499286SGarrett.Damore@Sun.COM #include <sys/ksynch.h> 509286SGarrett.Damore@Sun.COM #include <sys/stat.h> 519286SGarrett.Damore@Sun.COM #include <sys/conf.h> 529286SGarrett.Damore@Sun.COM #include <sys/modctl.h> 539286SGarrett.Damore@Sun.COM #include <sys/dlpi.h> 549286SGarrett.Damore@Sun.COM #include <sys/ethernet.h> 559286SGarrett.Damore@Sun.COM #include <sys/vlan.h> 569286SGarrett.Damore@Sun.COM #include <sys/strsun.h> 579286SGarrett.Damore@Sun.COM #include <sys/pci.h> 589286SGarrett.Damore@Sun.COM #include <sys/sunddi.h> 59*11453Sgdamore@opensolaris.org #include <sys/mii.h> 60*11453Sgdamore@opensolaris.org #include <sys/miiregs.h> 619286SGarrett.Damore@Sun.COM #include <sys/mac_provider.h> 629286SGarrett.Damore@Sun.COM #include <sys/mac_ether.h> 639286SGarrett.Damore@Sun.COM 649286SGarrett.Damore@Sun.COM #include "rtls.h" 659286SGarrett.Damore@Sun.COM 669286SGarrett.Damore@Sun.COM /* 679286SGarrett.Damore@Sun.COM * Declarations and Module Linkage 689286SGarrett.Damore@Sun.COM */ 699286SGarrett.Damore@Sun.COM 709286SGarrett.Damore@Sun.COM /* 719286SGarrett.Damore@Sun.COM * This is the string displayed by modinfo, etc. 729286SGarrett.Damore@Sun.COM */ 739286SGarrett.Damore@Sun.COM static char rtls_ident[] = "RealTek 8139 Ethernet driver"; 749286SGarrett.Damore@Sun.COM 759286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG 769286SGarrett.Damore@Sun.COM int rtls_debug = 0; 779286SGarrett.Damore@Sun.COM #endif 789286SGarrett.Damore@Sun.COM 799286SGarrett.Damore@Sun.COM /* 809286SGarrett.Damore@Sun.COM * Required system entry points 819286SGarrett.Damore@Sun.COM */ 829286SGarrett.Damore@Sun.COM static int rtls_attach(dev_info_t *, ddi_attach_cmd_t); 839286SGarrett.Damore@Sun.COM static int rtls_detach(dev_info_t *, ddi_detach_cmd_t); 849286SGarrett.Damore@Sun.COM static int rtls_quiesce(dev_info_t *); 859286SGarrett.Damore@Sun.COM 869286SGarrett.Damore@Sun.COM /* 879286SGarrett.Damore@Sun.COM * Required driver entry points for MAC 889286SGarrett.Damore@Sun.COM */ 899286SGarrett.Damore@Sun.COM static int rtls_m_start(void *); 909286SGarrett.Damore@Sun.COM static void rtls_m_stop(void *); 919286SGarrett.Damore@Sun.COM static int rtls_m_unicst(void *, const uint8_t *); 929286SGarrett.Damore@Sun.COM static int rtls_m_multicst(void *, boolean_t, const uint8_t *); 939286SGarrett.Damore@Sun.COM static int rtls_m_promisc(void *, boolean_t); 949286SGarrett.Damore@Sun.COM static mblk_t *rtls_m_tx(void *, mblk_t *); 959286SGarrett.Damore@Sun.COM static int rtls_m_stat(void *, uint_t, uint64_t *); 96*11453Sgdamore@opensolaris.org static int rtls_m_getprop(void *, const char *, mac_prop_id_t, uint_t, 97*11453Sgdamore@opensolaris.org uint_t, void *, uint_t *); 98*11453Sgdamore@opensolaris.org static int rtls_m_setprop(void *, const char *, mac_prop_id_t, uint_t, 99*11453Sgdamore@opensolaris.org const void *); 1009286SGarrett.Damore@Sun.COM 1019286SGarrett.Damore@Sun.COM static uint_t rtls_intr(caddr_t); 1029286SGarrett.Damore@Sun.COM 1039286SGarrett.Damore@Sun.COM /* 104*11453Sgdamore@opensolaris.org * MII entry points 105*11453Sgdamore@opensolaris.org */ 106*11453Sgdamore@opensolaris.org static uint16_t rtls_mii_read(void *, uint8_t, uint8_t); 107*11453Sgdamore@opensolaris.org static void rtls_mii_write(void *, uint8_t, uint8_t, uint16_t); 108*11453Sgdamore@opensolaris.org static void rtls_mii_notify(void *, link_state_t); 109*11453Sgdamore@opensolaris.org 110*11453Sgdamore@opensolaris.org /* 1119286SGarrett.Damore@Sun.COM * Internal functions used by the above entry points 1129286SGarrett.Damore@Sun.COM */ 1139286SGarrett.Damore@Sun.COM static int rtls_chip_reset(rtls_t *, boolean_t); 1149286SGarrett.Damore@Sun.COM static void rtls_chip_init(rtls_t *); 1159286SGarrett.Damore@Sun.COM static void rtls_chip_stop(rtls_t *rtlsp); 1169286SGarrett.Damore@Sun.COM static void rtls_chip_start(rtls_t *rtlsp); 1179286SGarrett.Damore@Sun.COM static void rtls_chip_restart(rtls_t *rtlsp); 1189286SGarrett.Damore@Sun.COM static void rtls_get_mac_addr(rtls_t *, uint8_t *); 1199286SGarrett.Damore@Sun.COM static void rtls_set_mac_addr(rtls_t *, const uint8_t *); 1209286SGarrett.Damore@Sun.COM static uint_t rtls_hash_index(const uint8_t *); 1219286SGarrett.Damore@Sun.COM static boolean_t rtls_send(rtls_t *, mblk_t *); 1229286SGarrett.Damore@Sun.COM static void rtls_receive(rtls_t *); 1239286SGarrett.Damore@Sun.COM 1249286SGarrett.Damore@Sun.COM /* 1259286SGarrett.Damore@Sun.COM * Buffer Management Routines 1269286SGarrett.Damore@Sun.COM */ 1279286SGarrett.Damore@Sun.COM static int rtls_alloc_bufs(rtls_t *); 1289286SGarrett.Damore@Sun.COM static void rtls_free_bufs(rtls_t *); 1299286SGarrett.Damore@Sun.COM static int rtls_alloc_dma_mem(rtls_t *, size_t, ddi_device_acc_attr_t *, 1309286SGarrett.Damore@Sun.COM uint_t, dma_area_t *); 1319286SGarrett.Damore@Sun.COM static void rtls_free_dma_mem(dma_area_t *); 1329286SGarrett.Damore@Sun.COM 1339286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG 1349286SGarrett.Damore@Sun.COM static void rtls_reg_print(rtls_t *); /* debug routine */ 1359286SGarrett.Damore@Sun.COM #endif 1369286SGarrett.Damore@Sun.COM 1379286SGarrett.Damore@Sun.COM #define RTLS_DRIVER_NAME "rtls" 1389286SGarrett.Damore@Sun.COM 1399286SGarrett.Damore@Sun.COM /* 1409286SGarrett.Damore@Sun.COM * Used for buffers allocated by ddi_dma_mem_alloc() 1419286SGarrett.Damore@Sun.COM */ 1429286SGarrett.Damore@Sun.COM static ddi_dma_attr_t dma_attr = { 1439286SGarrett.Damore@Sun.COM DMA_ATTR_V0, /* dma_attr version */ 1449286SGarrett.Damore@Sun.COM 0, /* dma_attr_addr_lo */ 1459286SGarrett.Damore@Sun.COM (uint_t)0xFFFFFFFF, /* dma_attr_addr_hi */ 1469286SGarrett.Damore@Sun.COM 0x7FFFFFFF, /* dma_attr_count_max */ 1479286SGarrett.Damore@Sun.COM 4, /* dma_attr_align */ 1489286SGarrett.Damore@Sun.COM 0x3F, /* dma_attr_burstsizes */ 1499286SGarrett.Damore@Sun.COM 1, /* dma_attr_minxfer */ 1509286SGarrett.Damore@Sun.COM (uint_t)0xFFFFFFFF, /* dma_attr_maxxfer */ 1519286SGarrett.Damore@Sun.COM (uint_t)0xFFFFFFFF, /* dma_attr_seg */ 1529286SGarrett.Damore@Sun.COM 1, /* dma_attr_sgllen */ 1539286SGarrett.Damore@Sun.COM 1, /* dma_attr_granular */ 1549286SGarrett.Damore@Sun.COM 0, /* dma_attr_flags */ 1559286SGarrett.Damore@Sun.COM }; 1569286SGarrett.Damore@Sun.COM 1579286SGarrett.Damore@Sun.COM /* 1589286SGarrett.Damore@Sun.COM * PIO access attributes for registers 1599286SGarrett.Damore@Sun.COM */ 1609286SGarrett.Damore@Sun.COM static ddi_device_acc_attr_t rtls_reg_accattr = { 1619286SGarrett.Damore@Sun.COM DDI_DEVICE_ATTR_V0, 1629286SGarrett.Damore@Sun.COM DDI_STRUCTURE_LE_ACC, 1639286SGarrett.Damore@Sun.COM DDI_STRICTORDER_ACC 1649286SGarrett.Damore@Sun.COM }; 1659286SGarrett.Damore@Sun.COM 1669286SGarrett.Damore@Sun.COM /* 1679286SGarrett.Damore@Sun.COM * DMA access attributes for data 1689286SGarrett.Damore@Sun.COM */ 1699286SGarrett.Damore@Sun.COM static ddi_device_acc_attr_t rtls_buf_accattr = { 1709286SGarrett.Damore@Sun.COM DDI_DEVICE_ATTR_V0, 1719286SGarrett.Damore@Sun.COM DDI_NEVERSWAP_ACC, 1729286SGarrett.Damore@Sun.COM DDI_STRICTORDER_ACC 1739286SGarrett.Damore@Sun.COM }; 1749286SGarrett.Damore@Sun.COM 1759286SGarrett.Damore@Sun.COM uchar_t rtls_broadcastaddr[] = { 1769286SGarrett.Damore@Sun.COM 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 1779286SGarrett.Damore@Sun.COM }; 1789286SGarrett.Damore@Sun.COM 1799286SGarrett.Damore@Sun.COM static mac_callbacks_t rtls_m_callbacks = { 180*11453Sgdamore@opensolaris.org MC_SETPROP | MC_GETPROP, 1819286SGarrett.Damore@Sun.COM rtls_m_stat, 1829286SGarrett.Damore@Sun.COM rtls_m_start, 1839286SGarrett.Damore@Sun.COM rtls_m_stop, 1849286SGarrett.Damore@Sun.COM rtls_m_promisc, 1859286SGarrett.Damore@Sun.COM rtls_m_multicst, 1869286SGarrett.Damore@Sun.COM rtls_m_unicst, 1879286SGarrett.Damore@Sun.COM rtls_m_tx, 1889286SGarrett.Damore@Sun.COM NULL, /* mc_ioctl */ 189*11453Sgdamore@opensolaris.org NULL, /* mc_getcapab */ 190*11453Sgdamore@opensolaris.org NULL, /* mc_open */ 191*11453Sgdamore@opensolaris.org NULL, /* mc_close */ 192*11453Sgdamore@opensolaris.org rtls_m_setprop, 193*11453Sgdamore@opensolaris.org rtls_m_getprop, 194*11453Sgdamore@opensolaris.org }; 195*11453Sgdamore@opensolaris.org 196*11453Sgdamore@opensolaris.org static mii_ops_t rtls_mii_ops = { 197*11453Sgdamore@opensolaris.org MII_OPS_VERSION, 198*11453Sgdamore@opensolaris.org rtls_mii_read, 199*11453Sgdamore@opensolaris.org rtls_mii_write, 200*11453Sgdamore@opensolaris.org rtls_mii_notify, /* notify */ 201*11453Sgdamore@opensolaris.org NULL, /* reset */ 2029286SGarrett.Damore@Sun.COM }; 2039286SGarrett.Damore@Sun.COM 2049286SGarrett.Damore@Sun.COM DDI_DEFINE_STREAM_OPS(rtls_dev_ops, nulldev, nulldev, rtls_attach, rtls_detach, 2059286SGarrett.Damore@Sun.COM nodev, NULL, D_MP, NULL, rtls_quiesce); 2069286SGarrett.Damore@Sun.COM 2079286SGarrett.Damore@Sun.COM /* 2089286SGarrett.Damore@Sun.COM * Standard module linkage initialization for a MAC driver 2099286SGarrett.Damore@Sun.COM */ 2109286SGarrett.Damore@Sun.COM static struct modldrv rtls_modldrv = { 2119286SGarrett.Damore@Sun.COM &mod_driverops, /* type of module. This one is a driver */ 2129286SGarrett.Damore@Sun.COM rtls_ident, /* short description */ 2139286SGarrett.Damore@Sun.COM &rtls_dev_ops /* driver specific ops */ 2149286SGarrett.Damore@Sun.COM }; 2159286SGarrett.Damore@Sun.COM 2169286SGarrett.Damore@Sun.COM static struct modlinkage modlinkage = { 2179286SGarrett.Damore@Sun.COM MODREV_1, { (void *)&rtls_modldrv, NULL } 2189286SGarrett.Damore@Sun.COM }; 2199286SGarrett.Damore@Sun.COM 2209286SGarrett.Damore@Sun.COM /* 2219286SGarrett.Damore@Sun.COM * ========== RealTek chip register access Routines ========== 2229286SGarrett.Damore@Sun.COM */ 2239286SGarrett.Damore@Sun.COM static uint8_t rtls_reg_get8(rtls_t *rtlsp, uint32_t reg); 2249286SGarrett.Damore@Sun.COM #pragma inline(rtls_reg_get8) 2259286SGarrett.Damore@Sun.COM static uint8_t 2269286SGarrett.Damore@Sun.COM rtls_reg_get8(rtls_t *rtlsp, uint32_t reg) 2279286SGarrett.Damore@Sun.COM { 2289286SGarrett.Damore@Sun.COM uint8_t *addr; 2299286SGarrett.Damore@Sun.COM 2309286SGarrett.Damore@Sun.COM addr = REG8(rtlsp->io_reg, reg); 2319286SGarrett.Damore@Sun.COM return (ddi_get8(rtlsp->io_handle, addr)); 2329286SGarrett.Damore@Sun.COM } 2339286SGarrett.Damore@Sun.COM 2349286SGarrett.Damore@Sun.COM static uint16_t rtls_reg_get16(rtls_t *rtlsp, uint32_t reg); 2359286SGarrett.Damore@Sun.COM #pragma inline(rtls_reg_get16) 2369286SGarrett.Damore@Sun.COM static uint16_t 2379286SGarrett.Damore@Sun.COM rtls_reg_get16(rtls_t *rtlsp, uint32_t reg) 2389286SGarrett.Damore@Sun.COM { 2399286SGarrett.Damore@Sun.COM uint16_t *addr; 2409286SGarrett.Damore@Sun.COM 2419286SGarrett.Damore@Sun.COM addr = REG16(rtlsp->io_reg, reg); 2429286SGarrett.Damore@Sun.COM return (ddi_get16(rtlsp->io_handle, addr)); 2439286SGarrett.Damore@Sun.COM } 2449286SGarrett.Damore@Sun.COM 2459286SGarrett.Damore@Sun.COM static uint32_t rtls_reg_get32(rtls_t *rtlsp, uint32_t reg); 2469286SGarrett.Damore@Sun.COM #pragma inline(rtls_reg_get32) 2479286SGarrett.Damore@Sun.COM static uint32_t 2489286SGarrett.Damore@Sun.COM rtls_reg_get32(rtls_t *rtlsp, uint32_t reg) 2499286SGarrett.Damore@Sun.COM { 2509286SGarrett.Damore@Sun.COM uint32_t *addr; 2519286SGarrett.Damore@Sun.COM 2529286SGarrett.Damore@Sun.COM addr = REG32(rtlsp->io_reg, reg); 2539286SGarrett.Damore@Sun.COM return (ddi_get32(rtlsp->io_handle, addr)); 2549286SGarrett.Damore@Sun.COM } 2559286SGarrett.Damore@Sun.COM 2569286SGarrett.Damore@Sun.COM static void rtls_reg_set8(rtls_t *rtlsp, uint32_t reg, uint8_t value); 2579286SGarrett.Damore@Sun.COM #pragma inline(rtls_reg_set8) 2589286SGarrett.Damore@Sun.COM static void 2599286SGarrett.Damore@Sun.COM rtls_reg_set8(rtls_t *rtlsp, uint32_t reg, uint8_t value) 2609286SGarrett.Damore@Sun.COM { 2619286SGarrett.Damore@Sun.COM uint8_t *addr; 2629286SGarrett.Damore@Sun.COM 2639286SGarrett.Damore@Sun.COM addr = REG8(rtlsp->io_reg, reg); 2649286SGarrett.Damore@Sun.COM ddi_put8(rtlsp->io_handle, addr, value); 2659286SGarrett.Damore@Sun.COM } 2669286SGarrett.Damore@Sun.COM 2679286SGarrett.Damore@Sun.COM static void rtls_reg_set16(rtls_t *rtlsp, uint32_t reg, uint16_t value); 2689286SGarrett.Damore@Sun.COM #pragma inline(rtls_reg_set16) 2699286SGarrett.Damore@Sun.COM static void 2709286SGarrett.Damore@Sun.COM rtls_reg_set16(rtls_t *rtlsp, uint32_t reg, uint16_t value) 2719286SGarrett.Damore@Sun.COM { 2729286SGarrett.Damore@Sun.COM uint16_t *addr; 2739286SGarrett.Damore@Sun.COM 2749286SGarrett.Damore@Sun.COM addr = REG16(rtlsp->io_reg, reg); 2759286SGarrett.Damore@Sun.COM ddi_put16(rtlsp->io_handle, addr, value); 2769286SGarrett.Damore@Sun.COM } 2779286SGarrett.Damore@Sun.COM 2789286SGarrett.Damore@Sun.COM static void rtls_reg_set32(rtls_t *rtlsp, uint32_t reg, uint32_t value); 2799286SGarrett.Damore@Sun.COM #pragma inline(rtls_reg_set32) 2809286SGarrett.Damore@Sun.COM static void 2819286SGarrett.Damore@Sun.COM rtls_reg_set32(rtls_t *rtlsp, uint32_t reg, uint32_t value) 2829286SGarrett.Damore@Sun.COM { 2839286SGarrett.Damore@Sun.COM uint32_t *addr; 2849286SGarrett.Damore@Sun.COM 2859286SGarrett.Damore@Sun.COM addr = REG32(rtlsp->io_reg, reg); 2869286SGarrett.Damore@Sun.COM ddi_put32(rtlsp->io_handle, addr, value); 2879286SGarrett.Damore@Sun.COM } 2889286SGarrett.Damore@Sun.COM 2899286SGarrett.Damore@Sun.COM /* 2909286SGarrett.Damore@Sun.COM * ========== Module Loading Entry Points ========== 2919286SGarrett.Damore@Sun.COM */ 2929286SGarrett.Damore@Sun.COM int 2939286SGarrett.Damore@Sun.COM _init(void) 2949286SGarrett.Damore@Sun.COM { 2959286SGarrett.Damore@Sun.COM int rv; 2969286SGarrett.Damore@Sun.COM 2979286SGarrett.Damore@Sun.COM mac_init_ops(&rtls_dev_ops, RTLS_DRIVER_NAME); 2989286SGarrett.Damore@Sun.COM if ((rv = mod_install(&modlinkage)) != DDI_SUCCESS) { 2999286SGarrett.Damore@Sun.COM mac_fini_ops(&rtls_dev_ops); 3009286SGarrett.Damore@Sun.COM } 3019286SGarrett.Damore@Sun.COM return (rv); 3029286SGarrett.Damore@Sun.COM } 3039286SGarrett.Damore@Sun.COM 3049286SGarrett.Damore@Sun.COM int 3059286SGarrett.Damore@Sun.COM _fini(void) 3069286SGarrett.Damore@Sun.COM { 3079286SGarrett.Damore@Sun.COM int rv; 3089286SGarrett.Damore@Sun.COM 3099286SGarrett.Damore@Sun.COM if ((rv = mod_remove(&modlinkage)) == DDI_SUCCESS) { 3109286SGarrett.Damore@Sun.COM mac_fini_ops(&rtls_dev_ops); 3119286SGarrett.Damore@Sun.COM } 3129286SGarrett.Damore@Sun.COM return (rv); 3139286SGarrett.Damore@Sun.COM } 3149286SGarrett.Damore@Sun.COM 3159286SGarrett.Damore@Sun.COM int 3169286SGarrett.Damore@Sun.COM _info(struct modinfo *modinfop) 3179286SGarrett.Damore@Sun.COM { 3189286SGarrett.Damore@Sun.COM return (mod_info(&modlinkage, modinfop)); 3199286SGarrett.Damore@Sun.COM } 3209286SGarrett.Damore@Sun.COM 3219286SGarrett.Damore@Sun.COM 3229286SGarrett.Damore@Sun.COM /* 3239286SGarrett.Damore@Sun.COM * ========== DDI Entry Points ========== 3249286SGarrett.Damore@Sun.COM */ 3259286SGarrett.Damore@Sun.COM 3269286SGarrett.Damore@Sun.COM /* 3279286SGarrett.Damore@Sun.COM * attach(9E) -- Attach a device to the system 3289286SGarrett.Damore@Sun.COM * 3299286SGarrett.Damore@Sun.COM * Called once for each board successfully probed. 3309286SGarrett.Damore@Sun.COM */ 3319286SGarrett.Damore@Sun.COM static int 3329286SGarrett.Damore@Sun.COM rtls_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd) 3339286SGarrett.Damore@Sun.COM { 3349286SGarrett.Damore@Sun.COM rtls_t *rtlsp; /* Our private device info */ 3359286SGarrett.Damore@Sun.COM ddi_acc_handle_t pci_handle; 3369286SGarrett.Damore@Sun.COM uint16_t pci_commond; 3379286SGarrett.Damore@Sun.COM uint16_t vendorid; 3389286SGarrett.Damore@Sun.COM uint16_t deviceid; 3399286SGarrett.Damore@Sun.COM uint32_t device; 3409286SGarrett.Damore@Sun.COM mac_register_t *macp; 3419286SGarrett.Damore@Sun.COM int err; 3429286SGarrett.Damore@Sun.COM 3439286SGarrett.Damore@Sun.COM switch (cmd) { 3449286SGarrett.Damore@Sun.COM case DDI_ATTACH: 3459286SGarrett.Damore@Sun.COM break; 3469286SGarrett.Damore@Sun.COM case DDI_RESUME: 3479286SGarrett.Damore@Sun.COM if ((rtlsp = ddi_get_driver_private(devinfo)) == NULL) { 3489286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 3499286SGarrett.Damore@Sun.COM } 3509286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_io_lock); 3519286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_rx_lock); 3529286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_tx_lock); 3539286SGarrett.Damore@Sun.COM /* 3549286SGarrett.Damore@Sun.COM * Turn on Master Enable (DMA) and IO Enable bits. 3559286SGarrett.Damore@Sun.COM * Enable PCI Memory Space accesses 3569286SGarrett.Damore@Sun.COM * Disable Memory Write/Invalidate 3579286SGarrett.Damore@Sun.COM */ 3589286SGarrett.Damore@Sun.COM if (pci_config_setup(devinfo, &pci_handle) != DDI_SUCCESS) { 3599286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_tx_lock); 3609286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_rx_lock); 3619286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_io_lock); 3629286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 3639286SGarrett.Damore@Sun.COM } 3649286SGarrett.Damore@Sun.COM pci_commond = pci_config_get16(pci_handle, PCI_CONF_COMM); 3659286SGarrett.Damore@Sun.COM pci_commond &= ~PCI_COMM_MEMWR_INVAL; 3669286SGarrett.Damore@Sun.COM pci_commond |= PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_IO; 3679286SGarrett.Damore@Sun.COM pci_config_put32(pci_handle, PCI_CONF_COMM, pci_commond); 3689286SGarrett.Damore@Sun.COM pci_config_teardown(&pci_handle); 3699286SGarrett.Damore@Sun.COM 3709286SGarrett.Damore@Sun.COM rtls_chip_restart(rtlsp); 3719286SGarrett.Damore@Sun.COM rtlsp->chip_error = B_FALSE; 3729286SGarrett.Damore@Sun.COM rtlsp->tx_retry = 0; 3739286SGarrett.Damore@Sun.COM rtlsp->rtls_suspended = B_FALSE; 3749286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_tx_lock); 3759286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_rx_lock); 3769286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_io_lock); 3779286SGarrett.Damore@Sun.COM 378*11453Sgdamore@opensolaris.org mii_resume(rtlsp->mii); 379*11453Sgdamore@opensolaris.org 3809286SGarrett.Damore@Sun.COM mac_tx_update(rtlsp->mh); 3819286SGarrett.Damore@Sun.COM return (DDI_SUCCESS); 3829286SGarrett.Damore@Sun.COM default: 3839286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 3849286SGarrett.Damore@Sun.COM } 3859286SGarrett.Damore@Sun.COM 3869286SGarrett.Damore@Sun.COM /* 3879286SGarrett.Damore@Sun.COM * we don't support high level interrupts in the driver 3889286SGarrett.Damore@Sun.COM */ 3899286SGarrett.Damore@Sun.COM if (ddi_intr_hilevel(devinfo, 0) != 0) { 390*11453Sgdamore@opensolaris.org cmn_err(CE_WARN, "unsupported high level interrupt"); 3919286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 3929286SGarrett.Damore@Sun.COM } 3939286SGarrett.Damore@Sun.COM 3949286SGarrett.Damore@Sun.COM /* 3959286SGarrett.Damore@Sun.COM * Get handle to access pci configuration space 3969286SGarrett.Damore@Sun.COM */ 3979286SGarrett.Damore@Sun.COM if (pci_config_setup(devinfo, &pci_handle) != DDI_SUCCESS) { 398*11453Sgdamore@opensolaris.org cmn_err(CE_WARN, "pci_config_setup fail."); 3999286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 4009286SGarrett.Damore@Sun.COM } 4019286SGarrett.Damore@Sun.COM 4029286SGarrett.Damore@Sun.COM /* 4039286SGarrett.Damore@Sun.COM * Make sure we support this particular vendor/device 4049286SGarrett.Damore@Sun.COM */ 4059286SGarrett.Damore@Sun.COM vendorid = pci_config_get16(pci_handle, PCI_CONF_VENID); 4069286SGarrett.Damore@Sun.COM deviceid = pci_config_get16(pci_handle, PCI_CONF_DEVID); 4079286SGarrett.Damore@Sun.COM device = vendorid; 4089286SGarrett.Damore@Sun.COM device = (device << 16) | deviceid; /* combine two id together */ 4099286SGarrett.Damore@Sun.COM 4109286SGarrett.Damore@Sun.COM /* 4119286SGarrett.Damore@Sun.COM * See if we support this device 4129286SGarrett.Damore@Sun.COM * We do not return for wrong device id. It's user risk. 4139286SGarrett.Damore@Sun.COM */ 4149286SGarrett.Damore@Sun.COM switch (device) { 4159286SGarrett.Damore@Sun.COM default: 4169286SGarrett.Damore@Sun.COM cmn_err(CE_WARN, 417*11453Sgdamore@opensolaris.org "RTLS doesn't support this device: " 4189286SGarrett.Damore@Sun.COM "vendorID = 0x%x, deviceID = 0x%x", 4199286SGarrett.Damore@Sun.COM vendorid, deviceid); 4209286SGarrett.Damore@Sun.COM break; 4219286SGarrett.Damore@Sun.COM case RTLS_SUPPORT_DEVICE_1: 4229286SGarrett.Damore@Sun.COM case RTLS_SUPPORT_DEVICE_2: 4239286SGarrett.Damore@Sun.COM case RTLS_SUPPORT_DEVICE_3: 424*11453Sgdamore@opensolaris.org case RTLS_SUPPORT_DEVICE_4: 4259286SGarrett.Damore@Sun.COM break; 4269286SGarrett.Damore@Sun.COM } 4279286SGarrett.Damore@Sun.COM 4289286SGarrett.Damore@Sun.COM /* 4299286SGarrett.Damore@Sun.COM * Turn on Master Enable (DMA) and IO Enable bits. 4309286SGarrett.Damore@Sun.COM * Enable PCI Memory Space accesses 4319286SGarrett.Damore@Sun.COM * Disable Memory Write/Invalidate 4329286SGarrett.Damore@Sun.COM */ 4339286SGarrett.Damore@Sun.COM pci_commond = pci_config_get16(pci_handle, PCI_CONF_COMM); 4349286SGarrett.Damore@Sun.COM pci_commond &= ~PCI_COMM_MEMWR_INVAL; 4359286SGarrett.Damore@Sun.COM pci_commond |= PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_IO; 4369286SGarrett.Damore@Sun.COM pci_config_put32(pci_handle, PCI_CONF_COMM, pci_commond); 4379286SGarrett.Damore@Sun.COM 4389286SGarrett.Damore@Sun.COM /* 4399286SGarrett.Damore@Sun.COM * Free handle to access pci configuration space 4409286SGarrett.Damore@Sun.COM */ 4419286SGarrett.Damore@Sun.COM pci_config_teardown(&pci_handle); 4429286SGarrett.Damore@Sun.COM 4439286SGarrett.Damore@Sun.COM rtlsp = kmem_zalloc(sizeof (rtls_t), KM_SLEEP); 4449286SGarrett.Damore@Sun.COM 4459286SGarrett.Damore@Sun.COM ddi_set_driver_private(devinfo, rtlsp); 4469286SGarrett.Damore@Sun.COM rtlsp->devinfo = devinfo; 4479286SGarrett.Damore@Sun.COM rtlsp->instance = ddi_get_instance(devinfo); 4489286SGarrett.Damore@Sun.COM 4499286SGarrett.Damore@Sun.COM /* 4509286SGarrett.Damore@Sun.COM * Map operating register 4519286SGarrett.Damore@Sun.COM */ 4529286SGarrett.Damore@Sun.COM err = ddi_regs_map_setup(devinfo, 1, &rtlsp->io_reg, 4539286SGarrett.Damore@Sun.COM (offset_t)0, 0, &rtls_reg_accattr, &rtlsp->io_handle); 4549286SGarrett.Damore@Sun.COM if (err != DDI_SUCCESS) { 4559286SGarrett.Damore@Sun.COM kmem_free((caddr_t)rtlsp, sizeof (rtls_t)); 456*11453Sgdamore@opensolaris.org cmn_err(CE_WARN, "ddi_regs_map_setup fail."); 4579286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 4589286SGarrett.Damore@Sun.COM } 4599286SGarrett.Damore@Sun.COM 4609286SGarrett.Damore@Sun.COM /* 4619286SGarrett.Damore@Sun.COM * Allocate the TX and RX descriptors/buffers 4629286SGarrett.Damore@Sun.COM */ 4639286SGarrett.Damore@Sun.COM if (rtls_alloc_bufs(rtlsp) == DDI_FAILURE) { 464*11453Sgdamore@opensolaris.org cmn_err(CE_WARN, "DMA buffer allocation fail."); 4659286SGarrett.Damore@Sun.COM goto fail; 4669286SGarrett.Damore@Sun.COM } 4679286SGarrett.Damore@Sun.COM 4689286SGarrett.Damore@Sun.COM /* 4699286SGarrett.Damore@Sun.COM * Reset the chip 4709286SGarrett.Damore@Sun.COM */ 4719286SGarrett.Damore@Sun.COM err = rtls_chip_reset(rtlsp, B_FALSE); 4729286SGarrett.Damore@Sun.COM if (err != DDI_SUCCESS) 4739286SGarrett.Damore@Sun.COM goto fail; 4749286SGarrett.Damore@Sun.COM 4759286SGarrett.Damore@Sun.COM /* 4769286SGarrett.Damore@Sun.COM * Init rtls_t structure 4779286SGarrett.Damore@Sun.COM */ 4789286SGarrett.Damore@Sun.COM rtls_get_mac_addr(rtlsp, rtlsp->netaddr); 4799286SGarrett.Damore@Sun.COM 4809286SGarrett.Damore@Sun.COM /* 4819286SGarrett.Damore@Sun.COM * Add the interrupt handler 4829286SGarrett.Damore@Sun.COM * 4839286SGarrett.Damore@Sun.COM * This will prevent receiving interrupts before device is ready, as 4849286SGarrett.Damore@Sun.COM * we are initializing device after setting the interrupts. So we 4859286SGarrett.Damore@Sun.COM * will not get our interrupt handler invoked by OS while our device 4869286SGarrett.Damore@Sun.COM * is still coming up or timer routines will not start till we are 4879286SGarrett.Damore@Sun.COM * all set to process... 4889286SGarrett.Damore@Sun.COM */ 4899286SGarrett.Damore@Sun.COM 4909286SGarrett.Damore@Sun.COM if (ddi_add_intr(devinfo, 0, &rtlsp->iblk, NULL, rtls_intr, 4919286SGarrett.Damore@Sun.COM (caddr_t)rtlsp) != DDI_SUCCESS) { 492*11453Sgdamore@opensolaris.org cmn_err(CE_WARN, "ddi_add_intr fail."); 4939286SGarrett.Damore@Sun.COM goto late_fail; 4949286SGarrett.Damore@Sun.COM } 4959286SGarrett.Damore@Sun.COM 496*11453Sgdamore@opensolaris.org if ((rtlsp->mii = mii_alloc(rtlsp, devinfo, &rtls_mii_ops)) == NULL) { 497*11453Sgdamore@opensolaris.org ddi_remove_intr(devinfo, 0, rtlsp->iblk); 498*11453Sgdamore@opensolaris.org goto late_fail; 499*11453Sgdamore@opensolaris.org } 500*11453Sgdamore@opensolaris.org /* 501*11453Sgdamore@opensolaris.org * Note: Some models of 8139 can support pause, but we have 502*11453Sgdamore@opensolaris.org * not implemented support for it at this time. This might be 503*11453Sgdamore@opensolaris.org * an interesting feature to add later. 504*11453Sgdamore@opensolaris.org */ 505*11453Sgdamore@opensolaris.org mii_set_pauseable(rtlsp->mii, B_FALSE, B_FALSE); 506*11453Sgdamore@opensolaris.org 5079286SGarrett.Damore@Sun.COM if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 508*11453Sgdamore@opensolaris.org cmn_err(CE_WARN, "mac_alloc fail."); 5099286SGarrett.Damore@Sun.COM ddi_remove_intr(devinfo, 0, rtlsp->iblk); 5109286SGarrett.Damore@Sun.COM goto late_fail; 5119286SGarrett.Damore@Sun.COM } 5129286SGarrett.Damore@Sun.COM 5139286SGarrett.Damore@Sun.COM /* 5149286SGarrett.Damore@Sun.COM * Init mutex 5159286SGarrett.Damore@Sun.COM */ 5169286SGarrett.Damore@Sun.COM mutex_init(&rtlsp->rtls_io_lock, NULL, MUTEX_DRIVER, rtlsp->iblk); 5179286SGarrett.Damore@Sun.COM mutex_init(&rtlsp->rtls_tx_lock, NULL, MUTEX_DRIVER, rtlsp->iblk); 5189286SGarrett.Damore@Sun.COM mutex_init(&rtlsp->rtls_rx_lock, NULL, MUTEX_DRIVER, rtlsp->iblk); 5199286SGarrett.Damore@Sun.COM 5209286SGarrett.Damore@Sun.COM /* 5219286SGarrett.Damore@Sun.COM * Initialize pointers to device specific functions which will be 5229286SGarrett.Damore@Sun.COM * used by the generic layer. 5239286SGarrett.Damore@Sun.COM */ 5249286SGarrett.Damore@Sun.COM macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 5259286SGarrett.Damore@Sun.COM macp->m_driver = rtlsp; 5269286SGarrett.Damore@Sun.COM macp->m_dip = devinfo; 5279286SGarrett.Damore@Sun.COM macp->m_src_addr = rtlsp->netaddr; 5289286SGarrett.Damore@Sun.COM macp->m_callbacks = &rtls_m_callbacks; 5299286SGarrett.Damore@Sun.COM macp->m_min_sdu = 0; 5309286SGarrett.Damore@Sun.COM macp->m_max_sdu = ETHERMTU; 5319286SGarrett.Damore@Sun.COM macp->m_margin = VLAN_TAGSZ; 5329286SGarrett.Damore@Sun.COM 5339286SGarrett.Damore@Sun.COM if (mac_register(macp, &rtlsp->mh) != 0) { 5349286SGarrett.Damore@Sun.COM ddi_remove_intr(devinfo, 0, rtlsp->iblk); 5359286SGarrett.Damore@Sun.COM mutex_destroy(&rtlsp->rtls_io_lock); 5369286SGarrett.Damore@Sun.COM mutex_destroy(&rtlsp->rtls_tx_lock); 5379286SGarrett.Damore@Sun.COM mutex_destroy(&rtlsp->rtls_rx_lock); 5389286SGarrett.Damore@Sun.COM goto late_fail; 5399286SGarrett.Damore@Sun.COM } 5409286SGarrett.Damore@Sun.COM 5419286SGarrett.Damore@Sun.COM mac_free(macp); 5429286SGarrett.Damore@Sun.COM 5439286SGarrett.Damore@Sun.COM return (DDI_SUCCESS); 5449286SGarrett.Damore@Sun.COM 5459286SGarrett.Damore@Sun.COM late_fail: 5469286SGarrett.Damore@Sun.COM if (macp) 5479286SGarrett.Damore@Sun.COM mac_free(macp); 548*11453Sgdamore@opensolaris.org if (rtlsp->mii) 549*11453Sgdamore@opensolaris.org mii_free(rtlsp->mii); 5509286SGarrett.Damore@Sun.COM 5519286SGarrett.Damore@Sun.COM fail: 5529286SGarrett.Damore@Sun.COM ddi_regs_map_free(&rtlsp->io_handle); 5539286SGarrett.Damore@Sun.COM rtls_free_bufs(rtlsp); 5549286SGarrett.Damore@Sun.COM kmem_free(rtlsp, sizeof (rtls_t)); 5559286SGarrett.Damore@Sun.COM 5569286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 5579286SGarrett.Damore@Sun.COM } 5589286SGarrett.Damore@Sun.COM 5599286SGarrett.Damore@Sun.COM /* 5609286SGarrett.Damore@Sun.COM * detach(9E) -- Detach a device from the system 5619286SGarrett.Damore@Sun.COM */ 5629286SGarrett.Damore@Sun.COM static int 5639286SGarrett.Damore@Sun.COM rtls_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd) 5649286SGarrett.Damore@Sun.COM { 5659286SGarrett.Damore@Sun.COM rtls_t *rtlsp; /* our private device info */ 5669286SGarrett.Damore@Sun.COM 5679286SGarrett.Damore@Sun.COM /* 5689286SGarrett.Damore@Sun.COM * Get the driver private structure 5699286SGarrett.Damore@Sun.COM */ 5709286SGarrett.Damore@Sun.COM if ((rtlsp = ddi_get_driver_private(devinfo)) == NULL) { 5719286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 5729286SGarrett.Damore@Sun.COM } 5739286SGarrett.Damore@Sun.COM 5749286SGarrett.Damore@Sun.COM switch (cmd) { 5759286SGarrett.Damore@Sun.COM case DDI_DETACH: 5769286SGarrett.Damore@Sun.COM break; 5779286SGarrett.Damore@Sun.COM 5789286SGarrett.Damore@Sun.COM case DDI_SUSPEND: 579*11453Sgdamore@opensolaris.org mii_suspend(rtlsp->mii); 580*11453Sgdamore@opensolaris.org 5819286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_io_lock); 5829286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_rx_lock); 5839286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_tx_lock); 5849286SGarrett.Damore@Sun.COM 5859286SGarrett.Damore@Sun.COM rtlsp->rtls_suspended = B_TRUE; 5869286SGarrett.Damore@Sun.COM rtls_chip_stop(rtlsp); 5879286SGarrett.Damore@Sun.COM 5889286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_tx_lock); 5899286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_rx_lock); 5909286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_io_lock); 5919286SGarrett.Damore@Sun.COM return (DDI_SUCCESS); 5929286SGarrett.Damore@Sun.COM 5939286SGarrett.Damore@Sun.COM default: 5949286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 5959286SGarrett.Damore@Sun.COM } 5969286SGarrett.Damore@Sun.COM 5979286SGarrett.Damore@Sun.COM if (mac_unregister(rtlsp->mh) != 0) { 5989286SGarrett.Damore@Sun.COM /* device busy */ 5999286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 6009286SGarrett.Damore@Sun.COM } 6019286SGarrett.Damore@Sun.COM 6029286SGarrett.Damore@Sun.COM ddi_remove_intr(devinfo, 0, rtlsp->iblk); 6039286SGarrett.Damore@Sun.COM 604*11453Sgdamore@opensolaris.org mii_free(rtlsp->mii); 6059286SGarrett.Damore@Sun.COM 6069286SGarrett.Damore@Sun.COM mutex_destroy(&rtlsp->rtls_io_lock); 6079286SGarrett.Damore@Sun.COM mutex_destroy(&rtlsp->rtls_tx_lock); 6089286SGarrett.Damore@Sun.COM mutex_destroy(&rtlsp->rtls_rx_lock); 6099286SGarrett.Damore@Sun.COM 6109286SGarrett.Damore@Sun.COM ddi_regs_map_free(&rtlsp->io_handle); 6119286SGarrett.Damore@Sun.COM rtls_free_bufs(rtlsp); 6129286SGarrett.Damore@Sun.COM kmem_free(rtlsp, sizeof (rtls_t)); 6139286SGarrett.Damore@Sun.COM 6149286SGarrett.Damore@Sun.COM return (DDI_SUCCESS); 6159286SGarrett.Damore@Sun.COM } 6169286SGarrett.Damore@Sun.COM 6179286SGarrett.Damore@Sun.COM /* 6189286SGarrett.Damore@Sun.COM * quiesce(9E) entry point. 6199286SGarrett.Damore@Sun.COM * 6209286SGarrett.Damore@Sun.COM * This function is called when the system is single-threaded at high 6219286SGarrett.Damore@Sun.COM * PIL with preemption disabled. Therefore, this function must not be 6229286SGarrett.Damore@Sun.COM * blocked. 6239286SGarrett.Damore@Sun.COM * 6249286SGarrett.Damore@Sun.COM * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure. 6259286SGarrett.Damore@Sun.COM * DDI_FAILURE indicates an error condition and should almost never happen. 6269286SGarrett.Damore@Sun.COM */ 6279286SGarrett.Damore@Sun.COM static int 6289286SGarrett.Damore@Sun.COM rtls_quiesce(dev_info_t *devinfo) 6299286SGarrett.Damore@Sun.COM { 6309286SGarrett.Damore@Sun.COM rtls_t *rtlsp; /* our private device info */ 6319286SGarrett.Damore@Sun.COM 6329286SGarrett.Damore@Sun.COM /* 6339286SGarrett.Damore@Sun.COM * Get the driver private structure 6349286SGarrett.Damore@Sun.COM */ 6359286SGarrett.Damore@Sun.COM if ((rtlsp = ddi_get_driver_private(devinfo)) == NULL) { 6369286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 6379286SGarrett.Damore@Sun.COM } 6389286SGarrett.Damore@Sun.COM return (rtls_chip_reset(rtlsp, B_TRUE)); 6399286SGarrett.Damore@Sun.COM } 6409286SGarrett.Damore@Sun.COM 6419286SGarrett.Damore@Sun.COM /* 6429286SGarrett.Damore@Sun.COM * ========== MAC Entry Points ========== 6439286SGarrett.Damore@Sun.COM */ 6449286SGarrett.Damore@Sun.COM 6459286SGarrett.Damore@Sun.COM /* 6469286SGarrett.Damore@Sun.COM * rtls_m_start() -- start the board receiving and allow transmits 6479286SGarrett.Damore@Sun.COM */ 6489286SGarrett.Damore@Sun.COM static int 6499286SGarrett.Damore@Sun.COM rtls_m_start(void *arg) 6509286SGarrett.Damore@Sun.COM { 6519286SGarrett.Damore@Sun.COM rtls_t *rtlsp = (rtls_t *)arg; 6529286SGarrett.Damore@Sun.COM 6539286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_io_lock); 6549286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_rx_lock); 6559286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_tx_lock); 6569286SGarrett.Damore@Sun.COM 6579286SGarrett.Damore@Sun.COM if (!rtlsp->rtls_suspended) 6589286SGarrett.Damore@Sun.COM rtls_chip_restart(rtlsp); 6599286SGarrett.Damore@Sun.COM 6609286SGarrett.Damore@Sun.COM rtlsp->rtls_running = B_TRUE; 6619286SGarrett.Damore@Sun.COM 6629286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_tx_lock); 6639286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_rx_lock); 6649286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_io_lock); 6659286SGarrett.Damore@Sun.COM 666*11453Sgdamore@opensolaris.org drv_usecwait(100); 667*11453Sgdamore@opensolaris.org 668*11453Sgdamore@opensolaris.org mii_start(rtlsp->mii); 669*11453Sgdamore@opensolaris.org 6709286SGarrett.Damore@Sun.COM return (0); 6719286SGarrett.Damore@Sun.COM } 6729286SGarrett.Damore@Sun.COM 6739286SGarrett.Damore@Sun.COM /* 6749286SGarrett.Damore@Sun.COM * rtls_m_stop() -- stop board receiving and transmits 6759286SGarrett.Damore@Sun.COM */ 6769286SGarrett.Damore@Sun.COM static void 6779286SGarrett.Damore@Sun.COM rtls_m_stop(void *arg) 6789286SGarrett.Damore@Sun.COM { 6799286SGarrett.Damore@Sun.COM rtls_t *rtlsp = (rtls_t *)arg; 6809286SGarrett.Damore@Sun.COM 681*11453Sgdamore@opensolaris.org mii_stop(rtlsp->mii); 682*11453Sgdamore@opensolaris.org 6839286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_io_lock); 6849286SGarrett.Damore@Sun.COM 6859286SGarrett.Damore@Sun.COM if (!rtlsp->rtls_suspended) 6869286SGarrett.Damore@Sun.COM rtls_chip_stop(rtlsp); 6879286SGarrett.Damore@Sun.COM rtlsp->rtls_running = B_FALSE; 6889286SGarrett.Damore@Sun.COM 6899286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_io_lock); 6909286SGarrett.Damore@Sun.COM } 6919286SGarrett.Damore@Sun.COM 6929286SGarrett.Damore@Sun.COM /* 6939286SGarrett.Damore@Sun.COM * rtls_m_unicst() -- set the physical network address 6949286SGarrett.Damore@Sun.COM * on the board 6959286SGarrett.Damore@Sun.COM */ 6969286SGarrett.Damore@Sun.COM static int 6979286SGarrett.Damore@Sun.COM rtls_m_unicst(void *arg, const uint8_t *macaddr) 6989286SGarrett.Damore@Sun.COM { 6999286SGarrett.Damore@Sun.COM rtls_t *rtlsp = arg; 7009286SGarrett.Damore@Sun.COM 7019286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_io_lock); 7029286SGarrett.Damore@Sun.COM bcopy(macaddr, rtlsp->netaddr, ETHERADDRL); 7039286SGarrett.Damore@Sun.COM if (!rtlsp->rtls_suspended) 7049286SGarrett.Damore@Sun.COM rtls_set_mac_addr(rtlsp, rtlsp->netaddr); 7059286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_io_lock); 7069286SGarrett.Damore@Sun.COM return (0); 7079286SGarrett.Damore@Sun.COM } 7089286SGarrett.Damore@Sun.COM 7099286SGarrett.Damore@Sun.COM /* 7109286SGarrett.Damore@Sun.COM * rtls_m_multicst() -- set(enable) or disable a multicast address 7119286SGarrett.Damore@Sun.COM * 7129286SGarrett.Damore@Sun.COM * Program the hardware to enable/disable the multicast address in "mcast". 7139286SGarrett.Damore@Sun.COM */ 7149286SGarrett.Damore@Sun.COM static int 7159286SGarrett.Damore@Sun.COM rtls_m_multicst(void *arg, boolean_t enable, const uint8_t *mcast) 7169286SGarrett.Damore@Sun.COM { 7179286SGarrett.Damore@Sun.COM rtls_t *rtlsp = (rtls_t *)arg; 7189286SGarrett.Damore@Sun.COM uint_t index; 7199286SGarrett.Damore@Sun.COM uint32_t *hashp; 7209286SGarrett.Damore@Sun.COM 7219286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_io_lock); 7229286SGarrett.Damore@Sun.COM hashp = rtlsp->multi_hash; 7239286SGarrett.Damore@Sun.COM index = rtls_hash_index(mcast); 7249286SGarrett.Damore@Sun.COM /* index value is between 0 and 63 */ 7259286SGarrett.Damore@Sun.COM 7269286SGarrett.Damore@Sun.COM if (enable) { 7279286SGarrett.Damore@Sun.COM if (rtlsp->multicast_cnt[index]++) { 7289286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_io_lock); 7299286SGarrett.Damore@Sun.COM return (0); 7309286SGarrett.Damore@Sun.COM } 7319286SGarrett.Damore@Sun.COM hashp[index/32] |= 1<< (index % 32); 7329286SGarrett.Damore@Sun.COM } else { 7339286SGarrett.Damore@Sun.COM if (--rtlsp->multicast_cnt[index]) { 7349286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_io_lock); 7359286SGarrett.Damore@Sun.COM return (0); 7369286SGarrett.Damore@Sun.COM } 7379286SGarrett.Damore@Sun.COM hashp[index/32] &= ~(1<< (index % 32)); 7389286SGarrett.Damore@Sun.COM } 7399286SGarrett.Damore@Sun.COM 7409286SGarrett.Damore@Sun.COM /* 7419286SGarrett.Damore@Sun.COM * Set multicast register 7429286SGarrett.Damore@Sun.COM */ 7439286SGarrett.Damore@Sun.COM if (!rtlsp->rtls_suspended) { 7449286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, MULTICAST_0_REG, hashp[0]); 7459286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, MULTICAST_4_REG, hashp[1]); 7469286SGarrett.Damore@Sun.COM } 7479286SGarrett.Damore@Sun.COM 7489286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_io_lock); 7499286SGarrett.Damore@Sun.COM 7509286SGarrett.Damore@Sun.COM return (0); 7519286SGarrett.Damore@Sun.COM } 7529286SGarrett.Damore@Sun.COM 7539286SGarrett.Damore@Sun.COM /* 7549286SGarrett.Damore@Sun.COM * rtls_hash_index() -- a hashing function used for setting the 7559286SGarrett.Damore@Sun.COM * node address or a multicast address 7569286SGarrett.Damore@Sun.COM */ 7579286SGarrett.Damore@Sun.COM static uint_t 7589286SGarrett.Damore@Sun.COM rtls_hash_index(const uint8_t *address) 7599286SGarrett.Damore@Sun.COM { 7609286SGarrett.Damore@Sun.COM uint32_t crc = (ulong_t)RTLS_HASH_CRC; 7619286SGarrett.Damore@Sun.COM uint32_t const POLY = RTLS_HASH_POLY; 7629286SGarrett.Damore@Sun.COM uint32_t msb; 7639286SGarrett.Damore@Sun.COM int bytes; 7649286SGarrett.Damore@Sun.COM uchar_t currentbyte; 7659286SGarrett.Damore@Sun.COM uint_t index; 7669286SGarrett.Damore@Sun.COM int bit; 7679286SGarrett.Damore@Sun.COM 7689286SGarrett.Damore@Sun.COM for (bytes = 0; bytes < ETHERADDRL; bytes++) { 7699286SGarrett.Damore@Sun.COM currentbyte = address[bytes]; 7709286SGarrett.Damore@Sun.COM for (bit = 0; bit < 8; bit++) { 7719286SGarrett.Damore@Sun.COM msb = crc >> 31; 7729286SGarrett.Damore@Sun.COM crc <<= 1; 7739286SGarrett.Damore@Sun.COM if (msb ^ (currentbyte & 1)) { 7749286SGarrett.Damore@Sun.COM crc ^= POLY; 7759286SGarrett.Damore@Sun.COM crc |= 0x00000001; 7769286SGarrett.Damore@Sun.COM } 7779286SGarrett.Damore@Sun.COM currentbyte >>= 1; 7789286SGarrett.Damore@Sun.COM } 7799286SGarrett.Damore@Sun.COM } 7809286SGarrett.Damore@Sun.COM 7819286SGarrett.Damore@Sun.COM index = crc >> 26; 7829286SGarrett.Damore@Sun.COM 7839286SGarrett.Damore@Sun.COM return (index); 7849286SGarrett.Damore@Sun.COM } 7859286SGarrett.Damore@Sun.COM 7869286SGarrett.Damore@Sun.COM /* 7879286SGarrett.Damore@Sun.COM * rtls_m_promisc() -- set or reset promiscuous mode on the board 7889286SGarrett.Damore@Sun.COM */ 7899286SGarrett.Damore@Sun.COM static int 7909286SGarrett.Damore@Sun.COM rtls_m_promisc(void *arg, boolean_t on) 7919286SGarrett.Damore@Sun.COM { 7929286SGarrett.Damore@Sun.COM rtls_t *rtlsp = arg; 7939286SGarrett.Damore@Sun.COM 7949286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_io_lock); 7959286SGarrett.Damore@Sun.COM 7969286SGarrett.Damore@Sun.COM rtlsp->promisc = on; 7979286SGarrett.Damore@Sun.COM if (!rtlsp->rtls_suspended) { 7989286SGarrett.Damore@Sun.COM uint32_t val32 = rtls_reg_get32(rtlsp, RX_CONFIG_REG); 7999286SGarrett.Damore@Sun.COM if (on) { 8009286SGarrett.Damore@Sun.COM val32 |= RX_ACCEPT_ALL_PACKET; 8019286SGarrett.Damore@Sun.COM } else { 8029286SGarrett.Damore@Sun.COM val32 &= ~RX_ACCEPT_ALL_PACKET; 8039286SGarrett.Damore@Sun.COM } 8049286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, RX_CONFIG_REG, val32); 8059286SGarrett.Damore@Sun.COM } 8069286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_io_lock); 8079286SGarrett.Damore@Sun.COM 8089286SGarrett.Damore@Sun.COM return (0); 8099286SGarrett.Damore@Sun.COM } 8109286SGarrett.Damore@Sun.COM 8119286SGarrett.Damore@Sun.COM /* 8129286SGarrett.Damore@Sun.COM * rtls_m_stat() -- retrieve statistic 8139286SGarrett.Damore@Sun.COM * 8149286SGarrett.Damore@Sun.COM * MAC calls this routine just before it reads the driver's statistics 8159286SGarrett.Damore@Sun.COM * structure. If your board maintains statistics, this is the time to 8169286SGarrett.Damore@Sun.COM * read them in and update the values in the structure. If the driver 8179286SGarrett.Damore@Sun.COM * maintains statistics continuously, this routine need do nothing. 8189286SGarrett.Damore@Sun.COM */ 8199286SGarrett.Damore@Sun.COM static int 8209286SGarrett.Damore@Sun.COM rtls_m_stat(void *arg, uint_t stat, uint64_t *val) 8219286SGarrett.Damore@Sun.COM { 8229286SGarrett.Damore@Sun.COM rtls_t *rtlsp = arg; 8239286SGarrett.Damore@Sun.COM 824*11453Sgdamore@opensolaris.org if (mii_m_getstat(rtlsp->mii, stat, val) == 0) { 825*11453Sgdamore@opensolaris.org return (0); 8269286SGarrett.Damore@Sun.COM } 8279286SGarrett.Damore@Sun.COM 8289286SGarrett.Damore@Sun.COM switch (stat) { 8299286SGarrett.Damore@Sun.COM case MAC_STAT_IPACKETS: 8309286SGarrett.Damore@Sun.COM *val = rtlsp->stats.ipackets; 8319286SGarrett.Damore@Sun.COM break; 8329286SGarrett.Damore@Sun.COM case MAC_STAT_RBYTES: 8339286SGarrett.Damore@Sun.COM *val = rtlsp->stats.rbytes; 8349286SGarrett.Damore@Sun.COM break; 8359286SGarrett.Damore@Sun.COM case MAC_STAT_OPACKETS: 8369286SGarrett.Damore@Sun.COM *val = rtlsp->stats.opackets; 8379286SGarrett.Damore@Sun.COM break; 8389286SGarrett.Damore@Sun.COM case MAC_STAT_OBYTES: 8399286SGarrett.Damore@Sun.COM *val = rtlsp->stats.obytes; 8409286SGarrett.Damore@Sun.COM break; 8419286SGarrett.Damore@Sun.COM case MAC_STAT_IERRORS: 8429286SGarrett.Damore@Sun.COM *val = rtlsp->stats.rcv_err; 8439286SGarrett.Damore@Sun.COM break; 8449286SGarrett.Damore@Sun.COM case MAC_STAT_OERRORS: 8459286SGarrett.Damore@Sun.COM *val = rtlsp->stats.xmt_err; 8469286SGarrett.Damore@Sun.COM break; 8479286SGarrett.Damore@Sun.COM case MAC_STAT_MULTIRCV: 8489286SGarrett.Damore@Sun.COM *val = rtlsp->stats.multi_rcv; 8499286SGarrett.Damore@Sun.COM break; 8509286SGarrett.Damore@Sun.COM case MAC_STAT_BRDCSTRCV: 8519286SGarrett.Damore@Sun.COM *val = rtlsp->stats.brdcst_rcv; 8529286SGarrett.Damore@Sun.COM break; 8539286SGarrett.Damore@Sun.COM case MAC_STAT_MULTIXMT: 8549286SGarrett.Damore@Sun.COM *val = rtlsp->stats.multi_xmt; 8559286SGarrett.Damore@Sun.COM break; 8569286SGarrett.Damore@Sun.COM case MAC_STAT_BRDCSTXMT: 8579286SGarrett.Damore@Sun.COM *val = rtlsp->stats.brdcst_xmt; 8589286SGarrett.Damore@Sun.COM break; 8599286SGarrett.Damore@Sun.COM case MAC_STAT_UNDERFLOWS: 8609286SGarrett.Damore@Sun.COM *val = rtlsp->stats.underflow; 8619286SGarrett.Damore@Sun.COM break; 8629286SGarrett.Damore@Sun.COM case MAC_STAT_OVERFLOWS: 8639286SGarrett.Damore@Sun.COM *val = rtlsp->stats.overflow; 8649286SGarrett.Damore@Sun.COM break; 8659286SGarrett.Damore@Sun.COM case MAC_STAT_NORCVBUF: 8669286SGarrett.Damore@Sun.COM *val = rtlsp->stats.no_rcvbuf; 8679286SGarrett.Damore@Sun.COM break; 8689286SGarrett.Damore@Sun.COM case MAC_STAT_COLLISIONS: 8699286SGarrett.Damore@Sun.COM *val = rtlsp->stats.collisions; 8709286SGarrett.Damore@Sun.COM break; 8719286SGarrett.Damore@Sun.COM case ETHER_STAT_FCS_ERRORS: 8729286SGarrett.Damore@Sun.COM *val = rtlsp->stats.crc_err; 8739286SGarrett.Damore@Sun.COM break; 8749286SGarrett.Damore@Sun.COM case ETHER_STAT_ALIGN_ERRORS: 8759286SGarrett.Damore@Sun.COM *val = rtlsp->stats.frame_err; 8769286SGarrett.Damore@Sun.COM break; 8779286SGarrett.Damore@Sun.COM case ETHER_STAT_DEFER_XMTS: 8789286SGarrett.Damore@Sun.COM *val = rtlsp->stats.defer; 8799286SGarrett.Damore@Sun.COM break; 8809286SGarrett.Damore@Sun.COM case ETHER_STAT_TX_LATE_COLLISIONS: 8819286SGarrett.Damore@Sun.COM *val = rtlsp->stats.xmt_latecoll; 8829286SGarrett.Damore@Sun.COM break; 8839286SGarrett.Damore@Sun.COM case ETHER_STAT_TOOLONG_ERRORS: 8849286SGarrett.Damore@Sun.COM *val = rtlsp->stats.too_long; 8859286SGarrett.Damore@Sun.COM break; 8869286SGarrett.Damore@Sun.COM case ETHER_STAT_TOOSHORT_ERRORS: 8879286SGarrett.Damore@Sun.COM *val = rtlsp->stats.in_short; 8889286SGarrett.Damore@Sun.COM break; 8899286SGarrett.Damore@Sun.COM case ETHER_STAT_CARRIER_ERRORS: 8909286SGarrett.Damore@Sun.COM *val = rtlsp->stats.no_carrier; 8919286SGarrett.Damore@Sun.COM break; 8929286SGarrett.Damore@Sun.COM case ETHER_STAT_FIRST_COLLISIONS: 8939286SGarrett.Damore@Sun.COM *val = rtlsp->stats.firstcol; 8949286SGarrett.Damore@Sun.COM break; 8959286SGarrett.Damore@Sun.COM case ETHER_STAT_MULTI_COLLISIONS: 8969286SGarrett.Damore@Sun.COM *val = rtlsp->stats.multicol; 8979286SGarrett.Damore@Sun.COM break; 8989286SGarrett.Damore@Sun.COM default: 8999286SGarrett.Damore@Sun.COM return (ENOTSUP); 9009286SGarrett.Damore@Sun.COM } 9019286SGarrett.Damore@Sun.COM 9029286SGarrett.Damore@Sun.COM /* 9039286SGarrett.Damore@Sun.COM * RTL8139 don't support MII statistics, 9049286SGarrett.Damore@Sun.COM * these values are maintained by the driver software. 9059286SGarrett.Damore@Sun.COM */ 9069286SGarrett.Damore@Sun.COM 9079286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG 9089286SGarrett.Damore@Sun.COM if (rtls_debug & RTLS_TRACE) 9099286SGarrett.Damore@Sun.COM rtls_reg_print(rtlsp); 9109286SGarrett.Damore@Sun.COM #endif 9119286SGarrett.Damore@Sun.COM 9129286SGarrett.Damore@Sun.COM return (0); 9139286SGarrett.Damore@Sun.COM } 9149286SGarrett.Damore@Sun.COM 915*11453Sgdamore@opensolaris.org int 916*11453Sgdamore@opensolaris.org rtls_m_getprop(void *arg, const char *name, mac_prop_id_t num, uint_t flags, 917*11453Sgdamore@opensolaris.org uint_t sz, void *val, uint_t *perm) 918*11453Sgdamore@opensolaris.org { 919*11453Sgdamore@opensolaris.org rtls_t *rtlsp = arg; 920*11453Sgdamore@opensolaris.org 921*11453Sgdamore@opensolaris.org return (mii_m_getprop(rtlsp->mii, name, num, flags, sz, val, perm)); 922*11453Sgdamore@opensolaris.org } 923*11453Sgdamore@opensolaris.org 924*11453Sgdamore@opensolaris.org int 925*11453Sgdamore@opensolaris.org rtls_m_setprop(void *arg, const char *name, mac_prop_id_t num, uint_t sz, 926*11453Sgdamore@opensolaris.org const void *val) 927*11453Sgdamore@opensolaris.org { 928*11453Sgdamore@opensolaris.org rtls_t *rtlsp = arg; 929*11453Sgdamore@opensolaris.org 930*11453Sgdamore@opensolaris.org return (mii_m_setprop(rtlsp->mii, name, num, sz, val)); 931*11453Sgdamore@opensolaris.org } 932*11453Sgdamore@opensolaris.org 9339286SGarrett.Damore@Sun.COM /* 9349286SGarrett.Damore@Sun.COM * rtls_send() -- send a packet 9359286SGarrett.Damore@Sun.COM * 9369286SGarrett.Damore@Sun.COM * Called when a packet is ready to be transmitted. A pointer to an 9379286SGarrett.Damore@Sun.COM * M_DATA message that contains the packet is passed to this routine. 9389286SGarrett.Damore@Sun.COM * The complete LLC header is contained in the message's first message 9399286SGarrett.Damore@Sun.COM * block, and the remainder of the packet is contained within 9409286SGarrett.Damore@Sun.COM * additional M_DATA message blocks linked to the first message block. 9419286SGarrett.Damore@Sun.COM * 9429286SGarrett.Damore@Sun.COM * Returns B_TRUE if the packet was properly disposed of, or B_FALSE if 9439286SGarrett.Damore@Sun.COM * if the packet is being deferred and should be tried again later. 9449286SGarrett.Damore@Sun.COM */ 9459286SGarrett.Damore@Sun.COM 9469286SGarrett.Damore@Sun.COM static boolean_t 9479286SGarrett.Damore@Sun.COM rtls_send(rtls_t *rtlsp, mblk_t *mp) 9489286SGarrett.Damore@Sun.COM { 9499286SGarrett.Damore@Sun.COM int totlen; 9509286SGarrett.Damore@Sun.COM int ncc; 9519286SGarrett.Damore@Sun.COM uint16_t cur_desc; 9529286SGarrett.Damore@Sun.COM uint32_t tx_status; 9539286SGarrett.Damore@Sun.COM 9549286SGarrett.Damore@Sun.COM ASSERT(mp != NULL); 9559286SGarrett.Damore@Sun.COM ASSERT(rtlsp->rtls_running); 9569286SGarrett.Damore@Sun.COM 9579286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_tx_lock); 9589286SGarrett.Damore@Sun.COM 9599286SGarrett.Damore@Sun.COM if (rtlsp->rtls_suspended) { 9609286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_tx_lock); 9619286SGarrett.Damore@Sun.COM return (B_FALSE); 9629286SGarrett.Damore@Sun.COM } 9639286SGarrett.Damore@Sun.COM 9649286SGarrett.Damore@Sun.COM /* 9659286SGarrett.Damore@Sun.COM * If chip error ... 9669286SGarrett.Damore@Sun.COM */ 9679286SGarrett.Damore@Sun.COM if (rtlsp->chip_error) { 9689286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG 9699286SGarrett.Damore@Sun.COM cmn_err(CE_WARN, 9709286SGarrett.Damore@Sun.COM "%s: send fail--CHIP ERROR!", 9719286SGarrett.Damore@Sun.COM rtlsp->ifname); 9729286SGarrett.Damore@Sun.COM #endif 9739286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_tx_lock); 9749286SGarrett.Damore@Sun.COM freemsg(mp); 9759286SGarrett.Damore@Sun.COM return (B_TRUE); 9769286SGarrett.Damore@Sun.COM } 9779286SGarrett.Damore@Sun.COM 9789286SGarrett.Damore@Sun.COM /* 979*11453Sgdamore@opensolaris.org * If chip link down ... Note that experimentation shows that 980*11453Sgdamore@opensolaris.org * the device seems not to care about whether or not we have 981*11453Sgdamore@opensolaris.org * this check, but if we don't add the check here, it might 982*11453Sgdamore@opensolaris.org * not be properly reported as a carrier error. 9839286SGarrett.Damore@Sun.COM */ 984*11453Sgdamore@opensolaris.org if (rtls_reg_get8(rtlsp, MEDIA_STATUS_REG) & MEDIA_STATUS_LINK) { 9859286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG 9869286SGarrett.Damore@Sun.COM cmn_err(CE_WARN, 9879286SGarrett.Damore@Sun.COM "%s: send fail--LINK DOWN!", 9889286SGarrett.Damore@Sun.COM rtlsp->ifname); 9899286SGarrett.Damore@Sun.COM #endif 9909286SGarrett.Damore@Sun.COM rtlsp->stats.no_carrier++; 9919286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_tx_lock); 9929286SGarrett.Damore@Sun.COM freemsg(mp); 9939286SGarrett.Damore@Sun.COM return (B_TRUE); 9949286SGarrett.Damore@Sun.COM } 9959286SGarrett.Damore@Sun.COM 9969286SGarrett.Damore@Sun.COM /* 9979286SGarrett.Damore@Sun.COM * Current transmit descriptor 9989286SGarrett.Damore@Sun.COM */ 9999286SGarrett.Damore@Sun.COM cur_desc = rtlsp->tx_current_desc; 10009286SGarrett.Damore@Sun.COM ASSERT(cur_desc < RTLS_MAX_TX_DESC); 10019286SGarrett.Damore@Sun.COM 10029286SGarrett.Damore@Sun.COM /* 10039286SGarrett.Damore@Sun.COM * RealTek 8139 has 4 tx descriptor for transmit. In the first tx loop 10049286SGarrett.Damore@Sun.COM * of transmit,we needn't judge transmit status. 10059286SGarrett.Damore@Sun.COM */ 10069286SGarrett.Damore@Sun.COM if (rtlsp->tx_first_loop < RTLS_MAX_TX_DESC) { 10079286SGarrett.Damore@Sun.COM rtlsp->tx_first_loop++; 10089286SGarrett.Damore@Sun.COM goto tx_ready; 10099286SGarrett.Damore@Sun.COM } 10109286SGarrett.Damore@Sun.COM 10119286SGarrett.Damore@Sun.COM /* 10129286SGarrett.Damore@Sun.COM * If it's not the first tx loop, we need judge whether the chip is 10139286SGarrett.Damore@Sun.COM * busy or not. Otherwise, we have to reschedule send and wait... 10149286SGarrett.Damore@Sun.COM */ 10159286SGarrett.Damore@Sun.COM tx_status = rtls_reg_get32(rtlsp, TX_STATUS_DESC0_REG + 4 * cur_desc); 10169286SGarrett.Damore@Sun.COM 10179286SGarrett.Damore@Sun.COM /* 10189286SGarrett.Damore@Sun.COM * H/W doesn't complete packet transmit 10199286SGarrett.Damore@Sun.COM */ 10209286SGarrett.Damore@Sun.COM if (!(tx_status & TX_COMPLETE_FLAG)) { 10219286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG 10229286SGarrett.Damore@Sun.COM if (rtls_debug & RTLS_SEND) { 10239286SGarrett.Damore@Sun.COM cmn_err(CE_NOTE, 10249286SGarrett.Damore@Sun.COM "%s: rtls_send: need_sched", rtlsp->ifname); 10259286SGarrett.Damore@Sun.COM } 10269286SGarrett.Damore@Sun.COM #endif 10279286SGarrett.Damore@Sun.COM /* 10289286SGarrett.Damore@Sun.COM * Through test, we find RTL8139 tx status might be 10299286SGarrett.Damore@Sun.COM * not-completing all along. We have to reset chip 10309286SGarrett.Damore@Sun.COM * to make RTL8139 tansmit re-work. 10319286SGarrett.Damore@Sun.COM */ 10329286SGarrett.Damore@Sun.COM if (rtlsp->tx_retry++ > RTLS_TX_RETRY_NUM) { 10339286SGarrett.Damore@Sun.COM 10349286SGarrett.Damore@Sun.COM /* 10359286SGarrett.Damore@Sun.COM * Wait transmit h/w more time... 10369286SGarrett.Damore@Sun.COM */ 10379286SGarrett.Damore@Sun.COM RTLS_TX_WAIT_TIMEOUT; /* 100 ms */ 10389286SGarrett.Damore@Sun.COM 10399286SGarrett.Damore@Sun.COM /* 10409286SGarrett.Damore@Sun.COM * Judge tx status again, if it remains not-completing, 10419286SGarrett.Damore@Sun.COM * we can confirm RTL8139 is in chip error state 10429286SGarrett.Damore@Sun.COM * and must reset it. 10439286SGarrett.Damore@Sun.COM */ 10449286SGarrett.Damore@Sun.COM tx_status = rtls_reg_get32(rtlsp, 10459286SGarrett.Damore@Sun.COM TX_STATUS_DESC0_REG + 4 * cur_desc); 10469286SGarrett.Damore@Sun.COM if (!(tx_status & TX_COMPLETE_FLAG)) { 10479286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG 10489286SGarrett.Damore@Sun.COM cmn_err(CE_NOTE, "%s: tx chip_error = 0x%x", 10499286SGarrett.Damore@Sun.COM rtlsp->ifname, tx_status); 10509286SGarrett.Damore@Sun.COM #endif 10519286SGarrett.Damore@Sun.COM rtlsp->tx_retry = 0; 10529286SGarrett.Damore@Sun.COM rtlsp->chip_error = B_TRUE; 10539286SGarrett.Damore@Sun.COM rtlsp->stats.xmt_err++; 10549286SGarrett.Damore@Sun.COM rtlsp->stats.mac_xmt_err++; 10559286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_tx_lock); 10569286SGarrett.Damore@Sun.COM freemsg(mp); 10579286SGarrett.Damore@Sun.COM return (B_TRUE); 10589286SGarrett.Damore@Sun.COM } 10599286SGarrett.Damore@Sun.COM } else { 10609286SGarrett.Damore@Sun.COM rtlsp->stats.defer++; 10619286SGarrett.Damore@Sun.COM rtlsp->need_sched = B_TRUE; 10629286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_tx_lock); 10639286SGarrett.Damore@Sun.COM return (B_FALSE); 10649286SGarrett.Damore@Sun.COM } 10659286SGarrett.Damore@Sun.COM } 10669286SGarrett.Damore@Sun.COM 10679286SGarrett.Damore@Sun.COM /* 10689286SGarrett.Damore@Sun.COM * Transmit error? 10699286SGarrett.Damore@Sun.COM */ 10709286SGarrett.Damore@Sun.COM if (tx_status & TX_ERR_FLAG) { 10719286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG 10729286SGarrett.Damore@Sun.COM if (rtls_debug & RTLS_SEND) { 10739286SGarrett.Damore@Sun.COM cmn_err(CE_NOTE, "%s: transmit error, status = 0x%x", 10749286SGarrett.Damore@Sun.COM rtlsp->ifname, tx_status); 10759286SGarrett.Damore@Sun.COM } 10769286SGarrett.Damore@Sun.COM #endif 10779286SGarrett.Damore@Sun.COM rtlsp->stats.xmt_err++; 10789286SGarrett.Damore@Sun.COM if (tx_status & TX_STATUS_TX_UNDERRUN) 10799286SGarrett.Damore@Sun.COM rtlsp->stats.underflow++; 10809286SGarrett.Damore@Sun.COM if (tx_status & TX_STATUS_CS_LOST) 10819286SGarrett.Damore@Sun.COM rtlsp->stats.no_carrier++; 10829286SGarrett.Damore@Sun.COM if (tx_status & TX_STATUS_OWC) 10839286SGarrett.Damore@Sun.COM rtlsp->stats.xmt_latecoll++; 10849286SGarrett.Damore@Sun.COM } 10859286SGarrett.Damore@Sun.COM ncc = ((tx_status & TX_STATUS_NCC) >> TX_STATUS_NCC_SHIFT); 10869286SGarrett.Damore@Sun.COM if (ncc != 0) { 10879286SGarrett.Damore@Sun.COM rtlsp->stats.collisions += ncc; 10889286SGarrett.Damore@Sun.COM rtlsp->stats.firstcol++; 10899286SGarrett.Damore@Sun.COM rtlsp->stats.multicol += ncc - 1; 10909286SGarrett.Damore@Sun.COM } 10919286SGarrett.Damore@Sun.COM 10929286SGarrett.Damore@Sun.COM tx_ready: 10939286SGarrett.Damore@Sun.COM /* 10949286SGarrett.Damore@Sun.COM * Initialize variable 10959286SGarrett.Damore@Sun.COM */ 10969286SGarrett.Damore@Sun.COM rtlsp->tx_retry = 0; 10979286SGarrett.Damore@Sun.COM totlen = 0; 10989286SGarrett.Damore@Sun.COM 10999286SGarrett.Damore@Sun.COM /* 11009286SGarrett.Damore@Sun.COM * Copy packet to tx descriptor buffer 11019286SGarrett.Damore@Sun.COM */ 11029286SGarrett.Damore@Sun.COM totlen = msgsize(mp); 11039286SGarrett.Damore@Sun.COM if (totlen > (ETHERMAX + 4)) { /* 4 bytes for VLAN header */ 11049286SGarrett.Damore@Sun.COM cmn_err(CE_NOTE, 11059286SGarrett.Damore@Sun.COM "%s: rtls_send: try to send large %d packet", 11069286SGarrett.Damore@Sun.COM rtlsp->ifname, totlen); 11079286SGarrett.Damore@Sun.COM rtlsp->stats.mac_xmt_err++; 11089286SGarrett.Damore@Sun.COM rtlsp->stats.xmt_err++; 11099286SGarrett.Damore@Sun.COM freemsg(mp); 11109286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_tx_lock); 11119286SGarrett.Damore@Sun.COM return (B_TRUE); 11129286SGarrett.Damore@Sun.COM } 11139286SGarrett.Damore@Sun.COM 11149286SGarrett.Damore@Sun.COM /* this will free the mblk */ 11159286SGarrett.Damore@Sun.COM mcopymsg(mp, rtlsp->tx_buf[cur_desc]); 11169286SGarrett.Damore@Sun.COM 11179286SGarrett.Damore@Sun.COM /* update stats */ 11189286SGarrett.Damore@Sun.COM if (*rtlsp->tx_buf[cur_desc] & 0x1) { 11199286SGarrett.Damore@Sun.COM uint16_t *ptr = (void *)rtlsp->tx_buf[cur_desc]; 11209286SGarrett.Damore@Sun.COM if ((ptr[0] == 0xffff) && 11219286SGarrett.Damore@Sun.COM (ptr[1] == 0xffff) && 11229286SGarrett.Damore@Sun.COM (ptr[2] == 0xffff)) { 11239286SGarrett.Damore@Sun.COM rtlsp->stats.brdcst_xmt++; 11249286SGarrett.Damore@Sun.COM } else { 11259286SGarrett.Damore@Sun.COM rtlsp->stats.multi_xmt++; 11269286SGarrett.Damore@Sun.COM } 11279286SGarrett.Damore@Sun.COM } 11289286SGarrett.Damore@Sun.COM rtlsp->stats.opackets++; 11299286SGarrett.Damore@Sun.COM rtlsp->stats.obytes += totlen; 11309286SGarrett.Damore@Sun.COM 11319286SGarrett.Damore@Sun.COM if (totlen < ETHERMIN) { 11329286SGarrett.Damore@Sun.COM bzero(rtlsp->tx_buf[cur_desc] + totlen, ETHERMIN - totlen); 11339286SGarrett.Damore@Sun.COM totlen = ETHERMIN; 11349286SGarrett.Damore@Sun.COM } 11359286SGarrett.Damore@Sun.COM 11369286SGarrett.Damore@Sun.COM /* make sure caches are flushed */ 11379286SGarrett.Damore@Sun.COM (void) ddi_dma_sync(rtlsp->dma_area_tx[cur_desc].dma_hdl, 0, totlen, 11389286SGarrett.Damore@Sun.COM DDI_DMA_SYNC_FORDEV); 11399286SGarrett.Damore@Sun.COM 11409286SGarrett.Damore@Sun.COM /* 11419286SGarrett.Damore@Sun.COM * Start transmit 11429286SGarrett.Damore@Sun.COM * set transmit FIFO threshhold to 0x30*32 = 1536 bytes 11439286SGarrett.Damore@Sun.COM * to avoid tx underrun. 11449286SGarrett.Damore@Sun.COM */ 11459286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, TX_STATUS_DESC0_REG + 4 * cur_desc, 11469286SGarrett.Damore@Sun.COM totlen | (0x30 << TX_STATUS_TX_THRESHOLD_SHIFT)); 11479286SGarrett.Damore@Sun.COM 11489286SGarrett.Damore@Sun.COM /* 11499286SGarrett.Damore@Sun.COM * Update the value of current tx descriptor 11509286SGarrett.Damore@Sun.COM */ 11519286SGarrett.Damore@Sun.COM cur_desc++; 11529286SGarrett.Damore@Sun.COM cur_desc %= RTLS_MAX_TX_DESC; 11539286SGarrett.Damore@Sun.COM rtlsp->tx_current_desc = cur_desc; 11549286SGarrett.Damore@Sun.COM 11559286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_tx_lock); 11569286SGarrett.Damore@Sun.COM 11579286SGarrett.Damore@Sun.COM return (B_TRUE); 11589286SGarrett.Damore@Sun.COM } 11599286SGarrett.Damore@Sun.COM 11609286SGarrett.Damore@Sun.COM /* 11619286SGarrett.Damore@Sun.COM * rtls_m_tx() -- send a chain of packets, linked by mp->b_next. 11629286SGarrett.Damore@Sun.COM */ 11639286SGarrett.Damore@Sun.COM static mblk_t * 11649286SGarrett.Damore@Sun.COM rtls_m_tx(void *arg, mblk_t *mp) 11659286SGarrett.Damore@Sun.COM { 11669286SGarrett.Damore@Sun.COM rtls_t *rtlsp = arg; 11679286SGarrett.Damore@Sun.COM mblk_t *next; 11689286SGarrett.Damore@Sun.COM 11699286SGarrett.Damore@Sun.COM while (mp != NULL) { 11709286SGarrett.Damore@Sun.COM next = mp->b_next; 11719286SGarrett.Damore@Sun.COM mp->b_next = NULL; 11729286SGarrett.Damore@Sun.COM if (!rtls_send(rtlsp, mp)) { 11739286SGarrett.Damore@Sun.COM mp->b_next = next; 11749286SGarrett.Damore@Sun.COM break; 11759286SGarrett.Damore@Sun.COM } 11769286SGarrett.Damore@Sun.COM mp = next; 11779286SGarrett.Damore@Sun.COM } 11789286SGarrett.Damore@Sun.COM return (mp); 11799286SGarrett.Damore@Sun.COM } 11809286SGarrett.Damore@Sun.COM 11819286SGarrett.Damore@Sun.COM /* 11829286SGarrett.Damore@Sun.COM * rtls_receive() -- receive packets 11839286SGarrett.Damore@Sun.COM * 11849286SGarrett.Damore@Sun.COM * Called when receive interrupts detected 11859286SGarrett.Damore@Sun.COM */ 11869286SGarrett.Damore@Sun.COM static void 11879286SGarrett.Damore@Sun.COM rtls_receive(rtls_t *rtlsp) 11889286SGarrett.Damore@Sun.COM { 11899286SGarrett.Damore@Sun.COM mblk_t *head = NULL; 11909286SGarrett.Damore@Sun.COM mblk_t **mpp; 11919286SGarrett.Damore@Sun.COM mblk_t *mp; 11929286SGarrett.Damore@Sun.COM uint16_t rx_status; 11939286SGarrett.Damore@Sun.COM uint16_t packet_len; 11949286SGarrett.Damore@Sun.COM int wrap_size; 11959286SGarrett.Damore@Sun.COM uint32_t cur_rx; 11969286SGarrett.Damore@Sun.COM uint8_t *rx_ptr; 11979286SGarrett.Damore@Sun.COM 11989286SGarrett.Damore@Sun.COM mpp = &head; 11999286SGarrett.Damore@Sun.COM 12009286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_rx_lock); 12019286SGarrett.Damore@Sun.COM 12029286SGarrett.Damore@Sun.COM if (rtlsp->rtls_suspended) { 12039286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_rx_lock); 12049286SGarrett.Damore@Sun.COM return; 12059286SGarrett.Damore@Sun.COM } 12069286SGarrett.Damore@Sun.COM 12079286SGarrett.Damore@Sun.COM while ((rtls_reg_get8(rtlsp, RT_COMMAND_REG) 12089286SGarrett.Damore@Sun.COM & RT_COMMAND_BUFF_EMPTY) == 0) { 12099286SGarrett.Damore@Sun.COM 12109286SGarrett.Damore@Sun.COM /* 12119286SGarrett.Damore@Sun.COM * Chip error state 12129286SGarrett.Damore@Sun.COM */ 12139286SGarrett.Damore@Sun.COM if (rtlsp->chip_error) { 12149286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG 12159286SGarrett.Damore@Sun.COM cmn_err(CE_WARN, 12169286SGarrett.Damore@Sun.COM "%s: receive fail--CHIP ERROR!", 12179286SGarrett.Damore@Sun.COM rtlsp->ifname); 12189286SGarrett.Damore@Sun.COM #endif 12199286SGarrett.Damore@Sun.COM break; 12209286SGarrett.Damore@Sun.COM } 12219286SGarrett.Damore@Sun.COM 12229286SGarrett.Damore@Sun.COM cur_rx = rtlsp->cur_rx; 12239286SGarrett.Damore@Sun.COM rx_ptr = rtlsp->rx_ring + cur_rx; 12249286SGarrett.Damore@Sun.COM packet_len = (rx_ptr[3] << 8) | (rx_ptr[2]); 12259286SGarrett.Damore@Sun.COM rx_status = rx_ptr[0]; 12269286SGarrett.Damore@Sun.COM 12279286SGarrett.Damore@Sun.COM /* 12289286SGarrett.Damore@Sun.COM * DMA still in progress 12299286SGarrett.Damore@Sun.COM */ 12309286SGarrett.Damore@Sun.COM if (packet_len == RX_STATUS_DMA_BUSY) { 12319286SGarrett.Damore@Sun.COM cmn_err(CE_NOTE, "%s: Rx DMA still in progress", 12329286SGarrett.Damore@Sun.COM rtlsp->ifname); 12339286SGarrett.Damore@Sun.COM break; 12349286SGarrett.Damore@Sun.COM } 12359286SGarrett.Damore@Sun.COM 12369286SGarrett.Damore@Sun.COM /* 12379286SGarrett.Damore@Sun.COM * Check receive status 12389286SGarrett.Damore@Sun.COM */ 12399286SGarrett.Damore@Sun.COM if ((rx_status & RX_ERR_FLAGS) || 12409286SGarrett.Damore@Sun.COM (!(rx_status & RX_HEADER_STATUS_ROK)) || 12419286SGarrett.Damore@Sun.COM (packet_len < (ETHERMIN + ETHERFCSL)) || 12429286SGarrett.Damore@Sun.COM (packet_len > (ETHERMAX + ETHERFCSL + 4))) { 12439286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG 12449286SGarrett.Damore@Sun.COM cmn_err(CE_NOTE, 12459286SGarrett.Damore@Sun.COM "%s: receive error, status = 0x%x, length = %d", 12469286SGarrett.Damore@Sun.COM rtlsp->ifname, rx_status, packet_len); 12479286SGarrett.Damore@Sun.COM #endif 12489286SGarrett.Damore@Sun.COM /* 12499286SGarrett.Damore@Sun.COM * Rx error statistics 12509286SGarrett.Damore@Sun.COM */ 12519286SGarrett.Damore@Sun.COM if ((rx_status & RX_HEADER_STATUS_RUNT) || 12529286SGarrett.Damore@Sun.COM (packet_len < (ETHERMIN + ETHERFCSL))) 12539286SGarrett.Damore@Sun.COM rtlsp->stats.in_short++; 12549286SGarrett.Damore@Sun.COM else if (packet_len > (ETHERMAX + ETHERFCSL + 4)) 12559286SGarrett.Damore@Sun.COM rtlsp->stats.too_long++; 12569286SGarrett.Damore@Sun.COM else if (rx_status & RX_HEADER_STATUS_CRC) 12579286SGarrett.Damore@Sun.COM rtlsp->stats.crc_err++; 12589286SGarrett.Damore@Sun.COM else if (rx_status & RX_HEADER_STATUS_FAE) 12599286SGarrett.Damore@Sun.COM rtlsp->stats.frame_err++; 12609286SGarrett.Damore@Sun.COM 12619286SGarrett.Damore@Sun.COM /* 12629286SGarrett.Damore@Sun.COM * Set chip_error flag to reset chip: 12639286SGarrett.Damore@Sun.COM * (suggested in RealTek programming guide.) 12649286SGarrett.Damore@Sun.COM */ 12659286SGarrett.Damore@Sun.COM rtlsp->chip_error = B_TRUE; 12669286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_rx_lock); 12679286SGarrett.Damore@Sun.COM return; 12689286SGarrett.Damore@Sun.COM } 12699286SGarrett.Damore@Sun.COM 12709286SGarrett.Damore@Sun.COM /* 12719286SGarrett.Damore@Sun.COM * We need not up-send ETHERFCSL bytes of receive packet 12729286SGarrett.Damore@Sun.COM */ 12739286SGarrett.Damore@Sun.COM packet_len -= ETHERFCSL; 12749286SGarrett.Damore@Sun.COM 12759286SGarrett.Damore@Sun.COM /* 12769286SGarrett.Damore@Sun.COM * Allocate buffer to receive this good packet 12779286SGarrett.Damore@Sun.COM */ 12789286SGarrett.Damore@Sun.COM mp = allocb(packet_len, 0); 12799286SGarrett.Damore@Sun.COM 12809286SGarrett.Damore@Sun.COM /* 12819286SGarrett.Damore@Sun.COM * Copy the data found into the new cluster, we have (+4) 12829286SGarrett.Damore@Sun.COM * to get us past the packet head data that the rtl chip 12839286SGarrett.Damore@Sun.COM * places at the start of the message 12849286SGarrett.Damore@Sun.COM */ 12859286SGarrett.Damore@Sun.COM if ((cur_rx + packet_len + RX_HEADER_SIZE) 12869286SGarrett.Damore@Sun.COM > RTLS_RX_BUF_RING) { 12879286SGarrett.Damore@Sun.COM wrap_size = cur_rx + packet_len + RX_HEADER_SIZE 12889286SGarrett.Damore@Sun.COM - RTLS_RX_BUF_RING; 12899286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG 12909286SGarrett.Damore@Sun.COM if (rtls_debug & RTLS_RECV) { 12919286SGarrett.Damore@Sun.COM cmn_err(CE_NOTE, 12929286SGarrett.Damore@Sun.COM "%s: Rx: packet_len = %d, wrap_size = %d", 12939286SGarrett.Damore@Sun.COM rtlsp->ifname, packet_len, wrap_size); 12949286SGarrett.Damore@Sun.COM } 12959286SGarrett.Damore@Sun.COM #endif 12969286SGarrett.Damore@Sun.COM 12979286SGarrett.Damore@Sun.COM if (mp != NULL) { 12989286SGarrett.Damore@Sun.COM /* Flush caches */ 12999286SGarrett.Damore@Sun.COM (void) ddi_dma_sync(rtlsp->dma_area_rx.dma_hdl, 13009286SGarrett.Damore@Sun.COM cur_rx + RX_HEADER_SIZE, 13019286SGarrett.Damore@Sun.COM packet_len - wrap_size, 13029286SGarrett.Damore@Sun.COM DDI_DMA_SYNC_FORKERNEL); 13039286SGarrett.Damore@Sun.COM (void) ddi_dma_sync(rtlsp->dma_area_rx.dma_hdl, 13049286SGarrett.Damore@Sun.COM 0, wrap_size, 13059286SGarrett.Damore@Sun.COM DDI_DMA_SYNC_FORKERNEL); 13069286SGarrett.Damore@Sun.COM 13079286SGarrett.Damore@Sun.COM /* 13089286SGarrett.Damore@Sun.COM * Copy in first section of message as stored 13099286SGarrett.Damore@Sun.COM * at the end of the ring buffer 13109286SGarrett.Damore@Sun.COM */ 13119286SGarrett.Damore@Sun.COM bcopy(rx_ptr + RX_HEADER_SIZE, 13129286SGarrett.Damore@Sun.COM mp->b_wptr, packet_len - wrap_size); 13139286SGarrett.Damore@Sun.COM mp->b_wptr += packet_len - wrap_size; 13149286SGarrett.Damore@Sun.COM bcopy(rtlsp->rx_ring, mp->b_wptr, wrap_size); 13159286SGarrett.Damore@Sun.COM mp->b_wptr += wrap_size; 13169286SGarrett.Damore@Sun.COM *mpp = mp; 13179286SGarrett.Damore@Sun.COM mpp = &mp->b_next; 13189286SGarrett.Damore@Sun.COM 13199286SGarrett.Damore@Sun.COM rtlsp->stats.ipackets++; 13209286SGarrett.Damore@Sun.COM if (rx_status & RX_HEADER_STATUS_BCAST) 13219286SGarrett.Damore@Sun.COM rtlsp->stats.brdcst_rcv++; 13229286SGarrett.Damore@Sun.COM if (rx_status & RX_HEADER_STATUS_MULTI) 13239286SGarrett.Damore@Sun.COM rtlsp->stats.multi_rcv++; 13249286SGarrett.Damore@Sun.COM rtlsp->stats.rbytes += packet_len; 13259286SGarrett.Damore@Sun.COM } else { 13269286SGarrett.Damore@Sun.COM rtlsp->stats.no_rcvbuf++; 13279286SGarrett.Damore@Sun.COM } 13289286SGarrett.Damore@Sun.COM 13299286SGarrett.Damore@Sun.COM cur_rx = RTLS_RX_ADDR_ALIGNED(wrap_size + ETHERFCSL); 13309286SGarrett.Damore@Sun.COM /* 4-byte aligned */ 13319286SGarrett.Damore@Sun.COM } else { 13329286SGarrett.Damore@Sun.COM 13339286SGarrett.Damore@Sun.COM if (mp != NULL) { 13349286SGarrett.Damore@Sun.COM /* Flush caches */ 13359286SGarrett.Damore@Sun.COM (void) ddi_dma_sync(rtlsp->dma_area_rx.dma_hdl, 13369286SGarrett.Damore@Sun.COM cur_rx + RX_HEADER_SIZE, packet_len, 13379286SGarrett.Damore@Sun.COM DDI_DMA_SYNC_FORKERNEL); 13389286SGarrett.Damore@Sun.COM bcopy(rx_ptr + RX_HEADER_SIZE, mp->b_wptr, 13399286SGarrett.Damore@Sun.COM packet_len); 13409286SGarrett.Damore@Sun.COM mp->b_wptr += packet_len; 13419286SGarrett.Damore@Sun.COM *mpp = mp; 13429286SGarrett.Damore@Sun.COM mpp = &mp->b_next; 13439286SGarrett.Damore@Sun.COM 13449286SGarrett.Damore@Sun.COM rtlsp->stats.ipackets++; 13459286SGarrett.Damore@Sun.COM if (rx_status & RX_HEADER_STATUS_BCAST) 13469286SGarrett.Damore@Sun.COM rtlsp->stats.brdcst_rcv++; 13479286SGarrett.Damore@Sun.COM if (rx_status & RX_HEADER_STATUS_MULTI) 13489286SGarrett.Damore@Sun.COM rtlsp->stats.multi_rcv++; 13499286SGarrett.Damore@Sun.COM rtlsp->stats.rbytes += packet_len; 13509286SGarrett.Damore@Sun.COM } else { 13519286SGarrett.Damore@Sun.COM rtlsp->stats.no_rcvbuf++; 13529286SGarrett.Damore@Sun.COM } 13539286SGarrett.Damore@Sun.COM cur_rx += packet_len + RX_HEADER_SIZE + ETHERFCSL; 13549286SGarrett.Damore@Sun.COM 13559286SGarrett.Damore@Sun.COM cur_rx = RTLS_RX_ADDR_ALIGNED(cur_rx); 13569286SGarrett.Damore@Sun.COM /* 4-byte aligned */ 13579286SGarrett.Damore@Sun.COM } 13589286SGarrett.Damore@Sun.COM 13599286SGarrett.Damore@Sun.COM /* 13609286SGarrett.Damore@Sun.COM * Update rx buffer ring read pointer: 13619286SGarrett.Damore@Sun.COM * give us a little leeway to ensure no overflow 13629286SGarrett.Damore@Sun.COM */ 13639286SGarrett.Damore@Sun.COM rtlsp->cur_rx = cur_rx; 13649286SGarrett.Damore@Sun.COM rtls_reg_set16(rtlsp, RX_CURRENT_READ_ADDR_REG, 13659286SGarrett.Damore@Sun.COM cur_rx - READ_ADDR_GAP); 13669286SGarrett.Damore@Sun.COM } 13679286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_rx_lock); 13689286SGarrett.Damore@Sun.COM 13699286SGarrett.Damore@Sun.COM /* 13709286SGarrett.Damore@Sun.COM * Upsend packet 13719286SGarrett.Damore@Sun.COM */ 13729286SGarrett.Damore@Sun.COM if (head) { 13739286SGarrett.Damore@Sun.COM mac_rx(rtlsp->mh, NULL, head); 13749286SGarrett.Damore@Sun.COM } 13759286SGarrett.Damore@Sun.COM } 13769286SGarrett.Damore@Sun.COM 13779286SGarrett.Damore@Sun.COM /* 13789286SGarrett.Damore@Sun.COM * rtls_intr() -- interrupt from board to inform us that a receive or 13799286SGarrett.Damore@Sun.COM * link change. 13809286SGarrett.Damore@Sun.COM */ 13819286SGarrett.Damore@Sun.COM static uint_t 13829286SGarrett.Damore@Sun.COM rtls_intr(caddr_t arg) 13839286SGarrett.Damore@Sun.COM { 13849286SGarrett.Damore@Sun.COM rtls_t *rtlsp = (void *)arg; 13859286SGarrett.Damore@Sun.COM uint32_t int_status; 13869286SGarrett.Damore@Sun.COM uint32_t val32; 1387*11453Sgdamore@opensolaris.org boolean_t resched = B_FALSE; 13889286SGarrett.Damore@Sun.COM 13899286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_io_lock); 1390*11453Sgdamore@opensolaris.org if (rtlsp->rtls_suspended) { 1391*11453Sgdamore@opensolaris.org mutex_exit(&rtlsp->rtls_io_lock); 1392*11453Sgdamore@opensolaris.org return (DDI_INTR_UNCLAIMED); 1393*11453Sgdamore@opensolaris.org } 13949286SGarrett.Damore@Sun.COM 13959286SGarrett.Damore@Sun.COM /* 13969286SGarrett.Damore@Sun.COM * Was this interrupt caused by our device... 13979286SGarrett.Damore@Sun.COM */ 13989286SGarrett.Damore@Sun.COM int_status = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG); 13999286SGarrett.Damore@Sun.COM if (!(int_status & rtlsp->int_mask)) { 14009286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_io_lock); 14019286SGarrett.Damore@Sun.COM return (DDI_INTR_UNCLAIMED); 14029286SGarrett.Damore@Sun.COM /* indicate it wasn't our interrupt */ 14039286SGarrett.Damore@Sun.COM } 14049286SGarrett.Damore@Sun.COM 14059286SGarrett.Damore@Sun.COM /* 14069286SGarrett.Damore@Sun.COM * Clear interrupt 14079286SGarrett.Damore@Sun.COM */ 14089286SGarrett.Damore@Sun.COM rtls_reg_set16(rtlsp, RT_INT_STATUS_REG, int_status); 14099286SGarrett.Damore@Sun.COM 14109286SGarrett.Damore@Sun.COM /* 14119286SGarrett.Damore@Sun.COM * If chip error, restart chip... 14129286SGarrett.Damore@Sun.COM */ 14139286SGarrett.Damore@Sun.COM if (rtlsp->chip_error) { 14149286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_rx_lock); 14159286SGarrett.Damore@Sun.COM mutex_enter(&rtlsp->rtls_tx_lock); 14169286SGarrett.Damore@Sun.COM rtls_chip_restart(rtlsp); 14179286SGarrett.Damore@Sun.COM rtlsp->chip_error = B_FALSE; 14189286SGarrett.Damore@Sun.COM rtlsp->tx_retry = 0; 14199286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_tx_lock); 14209286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_rx_lock); 14219286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_io_lock); 14229286SGarrett.Damore@Sun.COM return (DDI_INTR_CLAIMED); 14239286SGarrett.Damore@Sun.COM /* no need to hand other interrupts */ 14249286SGarrett.Damore@Sun.COM } 14259286SGarrett.Damore@Sun.COM 14269286SGarrett.Damore@Sun.COM /* 14279286SGarrett.Damore@Sun.COM * Transmit error interrupt 14289286SGarrett.Damore@Sun.COM */ 14299286SGarrett.Damore@Sun.COM if (int_status & TX_ERR_INT) { 14309286SGarrett.Damore@Sun.COM val32 = rtls_reg_get32(rtlsp, TX_CONFIG_REG); 14319286SGarrett.Damore@Sun.COM val32 |= TX_CLEAR_ABORT; 14329286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, TX_CONFIG_REG, val32); 14339286SGarrett.Damore@Sun.COM cmn_err(CE_WARN, "%s: transmit abort!!!", rtlsp->ifname); 14349286SGarrett.Damore@Sun.COM } 14359286SGarrett.Damore@Sun.COM 14369286SGarrett.Damore@Sun.COM /* 14379286SGarrett.Damore@Sun.COM * Trigger mac_tx_update 14389286SGarrett.Damore@Sun.COM */ 1439*11453Sgdamore@opensolaris.org if (rtlsp->need_sched) { 1440*11453Sgdamore@opensolaris.org rtlsp->need_sched = B_FALSE; 1441*11453Sgdamore@opensolaris.org resched = B_TRUE; 14429286SGarrett.Damore@Sun.COM } 14439286SGarrett.Damore@Sun.COM 14449286SGarrett.Damore@Sun.COM mutex_exit(&rtlsp->rtls_io_lock); 14459286SGarrett.Damore@Sun.COM 14469286SGarrett.Damore@Sun.COM /* 14479286SGarrett.Damore@Sun.COM * Receive interrupt 14489286SGarrett.Damore@Sun.COM */ 14499286SGarrett.Damore@Sun.COM if (int_status & RTLS_RX_INT) { 14509286SGarrett.Damore@Sun.COM if (int_status & RX_OVERFLOW_INT) { 14519286SGarrett.Damore@Sun.COM rtlsp->stats.overflow++; 14529286SGarrett.Damore@Sun.COM rtlsp->stats.rcv_err++; 14539286SGarrett.Damore@Sun.COM } 14549286SGarrett.Damore@Sun.COM rtls_receive(rtlsp); 14559286SGarrett.Damore@Sun.COM } 14569286SGarrett.Damore@Sun.COM 1457*11453Sgdamore@opensolaris.org /* 1458*11453Sgdamore@opensolaris.org * Link change interrupt. 1459*11453Sgdamore@opensolaris.org */ 1460*11453Sgdamore@opensolaris.org if (int_status & LINK_CHANGE_INT) { 1461*11453Sgdamore@opensolaris.org mii_check(rtlsp->mii); 14629286SGarrett.Damore@Sun.COM } 14639286SGarrett.Damore@Sun.COM 1464*11453Sgdamore@opensolaris.org if (resched) { 14659286SGarrett.Damore@Sun.COM mac_tx_update(rtlsp->mh); 14669286SGarrett.Damore@Sun.COM } 14679286SGarrett.Damore@Sun.COM 1468*11453Sgdamore@opensolaris.org return (DDI_INTR_CLAIMED); /* indicate it was our interrupt */ 14699286SGarrett.Damore@Sun.COM } 14709286SGarrett.Damore@Sun.COM 14719286SGarrett.Damore@Sun.COM /* 14729286SGarrett.Damore@Sun.COM * ========== Buffer Management Routines ========== 14739286SGarrett.Damore@Sun.COM */ 14749286SGarrett.Damore@Sun.COM 14759286SGarrett.Damore@Sun.COM /* 14769286SGarrett.Damore@Sun.COM * rtls_alloc_dma_mem() -- allocate an area of memory and a DMA handle 14779286SGarrett.Damore@Sun.COM * for accessing it 14789286SGarrett.Damore@Sun.COM */ 14799286SGarrett.Damore@Sun.COM static int 14809286SGarrett.Damore@Sun.COM rtls_alloc_dma_mem(rtls_t *rtlsp, size_t memsize, 14819286SGarrett.Damore@Sun.COM ddi_device_acc_attr_t *attr_p, uint_t dma_flags, dma_area_t *dma_p) 14829286SGarrett.Damore@Sun.COM { 14839286SGarrett.Damore@Sun.COM caddr_t vaddr; 14849286SGarrett.Damore@Sun.COM int err; 14859286SGarrett.Damore@Sun.COM 14869286SGarrett.Damore@Sun.COM /* 14879286SGarrett.Damore@Sun.COM * Allocate handle 14889286SGarrett.Damore@Sun.COM */ 14899286SGarrett.Damore@Sun.COM err = ddi_dma_alloc_handle(rtlsp->devinfo, &dma_attr, 14909286SGarrett.Damore@Sun.COM DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl); 14919286SGarrett.Damore@Sun.COM if (err != DDI_SUCCESS) { 14929286SGarrett.Damore@Sun.COM cmn_err(CE_WARN, 14939286SGarrett.Damore@Sun.COM "%s: rtls_alloc_dma_mem: ddi_dma_alloc_handle failed: %d", 14949286SGarrett.Damore@Sun.COM rtlsp->ifname, err); 14959286SGarrett.Damore@Sun.COM dma_p->dma_hdl = NULL; 14969286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 14979286SGarrett.Damore@Sun.COM } 14989286SGarrett.Damore@Sun.COM 14999286SGarrett.Damore@Sun.COM /* 15009286SGarrett.Damore@Sun.COM * Allocate memory 15019286SGarrett.Damore@Sun.COM */ 15029286SGarrett.Damore@Sun.COM err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p, 15039286SGarrett.Damore@Sun.COM dma_flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING), 15049286SGarrett.Damore@Sun.COM DDI_DMA_SLEEP, NULL, &vaddr, &dma_p->alength, &dma_p->acc_hdl); 15059286SGarrett.Damore@Sun.COM if (err != DDI_SUCCESS) { 15069286SGarrett.Damore@Sun.COM cmn_err(CE_WARN, 15079286SGarrett.Damore@Sun.COM "%s: rtls_alloc_dma_mem: ddi_dma_mem_alloc failed: %d", 15089286SGarrett.Damore@Sun.COM rtlsp->ifname, err); 15099286SGarrett.Damore@Sun.COM ddi_dma_free_handle(&dma_p->dma_hdl); 15109286SGarrett.Damore@Sun.COM dma_p->dma_hdl = NULL; 15119286SGarrett.Damore@Sun.COM dma_p->acc_hdl = NULL; 15129286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 15139286SGarrett.Damore@Sun.COM } 15149286SGarrett.Damore@Sun.COM 15159286SGarrett.Damore@Sun.COM /* 15169286SGarrett.Damore@Sun.COM * Bind the two together 15179286SGarrett.Damore@Sun.COM */ 15189286SGarrett.Damore@Sun.COM dma_p->mem_va = vaddr; 15199286SGarrett.Damore@Sun.COM err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL, 15209286SGarrett.Damore@Sun.COM vaddr, dma_p->alength, dma_flags, DDI_DMA_SLEEP, NULL, 15219286SGarrett.Damore@Sun.COM &dma_p->cookie, &dma_p->ncookies); 15229286SGarrett.Damore@Sun.COM if (err != DDI_DMA_MAPPED || dma_p->ncookies != 1) { 15239286SGarrett.Damore@Sun.COM cmn_err(CE_WARN, 15249286SGarrett.Damore@Sun.COM "%s: rtls_alloc_dma_mem: " 15259286SGarrett.Damore@Sun.COM "ddi_dma_addr_bind_handle failed: %d", 15269286SGarrett.Damore@Sun.COM rtlsp->ifname, err); 15279286SGarrett.Damore@Sun.COM ddi_dma_mem_free(&dma_p->acc_hdl); 15289286SGarrett.Damore@Sun.COM ddi_dma_free_handle(&dma_p->dma_hdl); 15299286SGarrett.Damore@Sun.COM dma_p->acc_hdl = NULL; 15309286SGarrett.Damore@Sun.COM dma_p->dma_hdl = NULL; 15319286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 15329286SGarrett.Damore@Sun.COM } 15339286SGarrett.Damore@Sun.COM 15349286SGarrett.Damore@Sun.COM return (DDI_SUCCESS); 15359286SGarrett.Damore@Sun.COM } 15369286SGarrett.Damore@Sun.COM 15379286SGarrett.Damore@Sun.COM /* 15389286SGarrett.Damore@Sun.COM * rtls_free_dma_mem() -- free one allocated area of DMAable memory 15399286SGarrett.Damore@Sun.COM */ 15409286SGarrett.Damore@Sun.COM static void 15419286SGarrett.Damore@Sun.COM rtls_free_dma_mem(dma_area_t *dma_p) 15429286SGarrett.Damore@Sun.COM { 15439286SGarrett.Damore@Sun.COM if (dma_p->dma_hdl != NULL) { 15449286SGarrett.Damore@Sun.COM if (dma_p->ncookies) { 15459286SGarrett.Damore@Sun.COM (void) ddi_dma_unbind_handle(dma_p->dma_hdl); 15469286SGarrett.Damore@Sun.COM dma_p->ncookies = 0; 15479286SGarrett.Damore@Sun.COM } 15489286SGarrett.Damore@Sun.COM ddi_dma_free_handle(&dma_p->dma_hdl); 15499286SGarrett.Damore@Sun.COM dma_p->dma_hdl = NULL; 15509286SGarrett.Damore@Sun.COM } 15519286SGarrett.Damore@Sun.COM 15529286SGarrett.Damore@Sun.COM if (dma_p->acc_hdl != NULL) { 15539286SGarrett.Damore@Sun.COM ddi_dma_mem_free(&dma_p->acc_hdl); 15549286SGarrett.Damore@Sun.COM dma_p->acc_hdl = NULL; 15559286SGarrett.Damore@Sun.COM } 15569286SGarrett.Damore@Sun.COM } 15579286SGarrett.Damore@Sun.COM 15589286SGarrett.Damore@Sun.COM /* 15599286SGarrett.Damore@Sun.COM * rtls_alloc_bufs() -- allocate descriptors/buffers for this device instance 15609286SGarrett.Damore@Sun.COM */ 15619286SGarrett.Damore@Sun.COM static int 15629286SGarrett.Damore@Sun.COM rtls_alloc_bufs(rtls_t *rtlsp) 15639286SGarrett.Damore@Sun.COM { 15649286SGarrett.Damore@Sun.COM int i; 15659286SGarrett.Damore@Sun.COM int err; 15669286SGarrett.Damore@Sun.COM 15679286SGarrett.Damore@Sun.COM /* 15689286SGarrett.Damore@Sun.COM * Allocate memory & handle for Tx buffers 15699286SGarrett.Damore@Sun.COM */ 15709286SGarrett.Damore@Sun.COM for (i = 0; i < RTLS_MAX_TX_DESC; i++) { 15719286SGarrett.Damore@Sun.COM err = rtls_alloc_dma_mem(rtlsp, 15729286SGarrett.Damore@Sun.COM RTLS_TX_BUF_SIZE, 15739286SGarrett.Damore@Sun.COM &rtls_buf_accattr, 15749286SGarrett.Damore@Sun.COM DDI_DMA_WRITE | DDI_DMA_STREAMING, 15759286SGarrett.Damore@Sun.COM &rtlsp->dma_area_tx[i]); 15769286SGarrett.Damore@Sun.COM 15779286SGarrett.Damore@Sun.COM if (err != DDI_SUCCESS) 15789286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 15799286SGarrett.Damore@Sun.COM 15809286SGarrett.Damore@Sun.COM rtlsp->tx_buf[i] = (uint8_t *)rtlsp->dma_area_tx[i].mem_va; 15819286SGarrett.Damore@Sun.COM } 15829286SGarrett.Damore@Sun.COM 15839286SGarrett.Damore@Sun.COM /* 15849286SGarrett.Damore@Sun.COM * Allocate memory & handle for Rx buffers 15859286SGarrett.Damore@Sun.COM */ 15869286SGarrett.Damore@Sun.COM err = rtls_alloc_dma_mem(rtlsp, 15879286SGarrett.Damore@Sun.COM RTLS_RX_BUF_SIZE, 15889286SGarrett.Damore@Sun.COM &rtls_buf_accattr, 15899286SGarrett.Damore@Sun.COM DDI_DMA_READ | DDI_DMA_STREAMING, 15909286SGarrett.Damore@Sun.COM &rtlsp->dma_area_rx); 15919286SGarrett.Damore@Sun.COM 15929286SGarrett.Damore@Sun.COM if (err != DDI_SUCCESS) 15939286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 15949286SGarrett.Damore@Sun.COM 15959286SGarrett.Damore@Sun.COM rtlsp->rx_ring = (uint8_t *)rtlsp->dma_area_rx.mem_va; 15969286SGarrett.Damore@Sun.COM 15979286SGarrett.Damore@Sun.COM return (DDI_SUCCESS); 15989286SGarrett.Damore@Sun.COM } 15999286SGarrett.Damore@Sun.COM 16009286SGarrett.Damore@Sun.COM /* 16019286SGarrett.Damore@Sun.COM * rtls_free_bufs() -- free descriptors/buffers allocated for this 16029286SGarrett.Damore@Sun.COM * device instance. 16039286SGarrett.Damore@Sun.COM */ 16049286SGarrett.Damore@Sun.COM static void 16059286SGarrett.Damore@Sun.COM rtls_free_bufs(rtls_t *rtlsp) 16069286SGarrett.Damore@Sun.COM { 16079286SGarrett.Damore@Sun.COM int i; 16089286SGarrett.Damore@Sun.COM 16099286SGarrett.Damore@Sun.COM for (i = 0; i < RTLS_MAX_TX_DESC; i++) { 16109286SGarrett.Damore@Sun.COM rtls_free_dma_mem(&rtlsp->dma_area_tx[i]); 16119286SGarrett.Damore@Sun.COM rtlsp->tx_buf[i] = NULL; 16129286SGarrett.Damore@Sun.COM } 16139286SGarrett.Damore@Sun.COM 16149286SGarrett.Damore@Sun.COM rtls_free_dma_mem(&rtlsp->dma_area_rx); 16159286SGarrett.Damore@Sun.COM rtlsp->rx_ring = NULL; 16169286SGarrett.Damore@Sun.COM } 16179286SGarrett.Damore@Sun.COM 16189286SGarrett.Damore@Sun.COM /* 16199286SGarrett.Damore@Sun.COM * ========== Chip H/W Operation Routines ========== 16209286SGarrett.Damore@Sun.COM */ 16219286SGarrett.Damore@Sun.COM 16229286SGarrett.Damore@Sun.COM /* 16239286SGarrett.Damore@Sun.COM * rtls_chip_reset() -- reset chip 16249286SGarrett.Damore@Sun.COM */ 16259286SGarrett.Damore@Sun.COM static int 16269286SGarrett.Damore@Sun.COM rtls_chip_reset(rtls_t *rtlsp, boolean_t quiesce) 16279286SGarrett.Damore@Sun.COM { 16289286SGarrett.Damore@Sun.COM int i; 16299286SGarrett.Damore@Sun.COM uint16_t val16; 16309286SGarrett.Damore@Sun.COM uint8_t val8; 16319286SGarrett.Damore@Sun.COM 16329286SGarrett.Damore@Sun.COM /* 16339286SGarrett.Damore@Sun.COM * Chip should be in STOP state 16349286SGarrett.Damore@Sun.COM */ 16359286SGarrett.Damore@Sun.COM val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG); 16369286SGarrett.Damore@Sun.COM val8 &= ~(RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE); 16379286SGarrett.Damore@Sun.COM rtls_reg_set8(rtlsp, RT_COMMAND_REG, val8); 16389286SGarrett.Damore@Sun.COM 16399286SGarrett.Damore@Sun.COM /* 16409286SGarrett.Damore@Sun.COM * Disable interrupt 16419286SGarrett.Damore@Sun.COM */ 16429286SGarrett.Damore@Sun.COM val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG); 16439286SGarrett.Damore@Sun.COM rtls_reg_set16(rtlsp, RT_INT_MASK_REG, val16 & (~RTLS_INT_MASK_ALL)); 16449286SGarrett.Damore@Sun.COM rtlsp->int_mask = RTLS_INT_MASK_NONE; 16459286SGarrett.Damore@Sun.COM 16469286SGarrett.Damore@Sun.COM /* 16479286SGarrett.Damore@Sun.COM * Clear pended interrupt 16489286SGarrett.Damore@Sun.COM */ 16499286SGarrett.Damore@Sun.COM val16 = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG); 16509286SGarrett.Damore@Sun.COM rtls_reg_set16(rtlsp, RT_INT_STATUS_REG, val16); 16519286SGarrett.Damore@Sun.COM 16529286SGarrett.Damore@Sun.COM /* 16539286SGarrett.Damore@Sun.COM * Reset chip 16549286SGarrett.Damore@Sun.COM */ 16559286SGarrett.Damore@Sun.COM val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG); 16569286SGarrett.Damore@Sun.COM rtls_reg_set8(rtlsp, RT_COMMAND_REG, val8 | RT_COMMAND_RESET); 16579286SGarrett.Damore@Sun.COM 16589286SGarrett.Damore@Sun.COM /* 16599286SGarrett.Damore@Sun.COM * Wait for reset success 16609286SGarrett.Damore@Sun.COM */ 16619286SGarrett.Damore@Sun.COM i = 0; 16629286SGarrett.Damore@Sun.COM while (rtls_reg_get8(rtlsp, RT_COMMAND_REG) & RT_COMMAND_RESET) { 16639286SGarrett.Damore@Sun.COM if (++i > RTLS_RESET_WAIT_NUM) { 16649286SGarrett.Damore@Sun.COM /* 16659286SGarrett.Damore@Sun.COM * At quiesce path we can't call cmn_err(), as 16669286SGarrett.Damore@Sun.COM * it might block 16679286SGarrett.Damore@Sun.COM */ 16689286SGarrett.Damore@Sun.COM if (!quiesce) 16699286SGarrett.Damore@Sun.COM cmn_err(CE_WARN, 16709286SGarrett.Damore@Sun.COM "%s: chip reset fail.", rtlsp->ifname); 16719286SGarrett.Damore@Sun.COM return (DDI_FAILURE); 16729286SGarrett.Damore@Sun.COM } 16739286SGarrett.Damore@Sun.COM RTLS_RESET_WAIT_INTERVAL; 16749286SGarrett.Damore@Sun.COM } 16759286SGarrett.Damore@Sun.COM 16769286SGarrett.Damore@Sun.COM return (DDI_SUCCESS); 16779286SGarrett.Damore@Sun.COM } 16789286SGarrett.Damore@Sun.COM 16799286SGarrett.Damore@Sun.COM /* 16809286SGarrett.Damore@Sun.COM * rtls_chip_init() -- initialize the specified network board short of 16819286SGarrett.Damore@Sun.COM * actually starting the board. Call after rtls_chip_reset(). 16829286SGarrett.Damore@Sun.COM */ 16839286SGarrett.Damore@Sun.COM static void 16849286SGarrett.Damore@Sun.COM rtls_chip_init(rtls_t *rtlsp) 16859286SGarrett.Damore@Sun.COM { 16869286SGarrett.Damore@Sun.COM uint32_t val32; 16879286SGarrett.Damore@Sun.COM uint16_t val16; 16889286SGarrett.Damore@Sun.COM uint8_t val8; 16899286SGarrett.Damore@Sun.COM 16909286SGarrett.Damore@Sun.COM /* 16919286SGarrett.Damore@Sun.COM * Initialize internal data structures 16929286SGarrett.Damore@Sun.COM */ 16939286SGarrett.Damore@Sun.COM rtlsp->cur_rx = 0; 16949286SGarrett.Damore@Sun.COM rtlsp->tx_current_desc = 0; 16959286SGarrett.Damore@Sun.COM rtlsp->tx_first_loop = 0; 16969286SGarrett.Damore@Sun.COM 16979286SGarrett.Damore@Sun.COM /* 16989286SGarrett.Damore@Sun.COM * Set DMA physical rx/tx buffer address to register 16999286SGarrett.Damore@Sun.COM */ 17009286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, RX_BUFF_ADDR_REG, 17019286SGarrett.Damore@Sun.COM (ulong_t)rtlsp->dma_area_rx.cookie.dmac_address); 17029286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, TX_ADDR_DESC0_REG, 17039286SGarrett.Damore@Sun.COM (ulong_t)rtlsp->dma_area_tx[0].cookie.dmac_address); 17049286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, TX_ADDR_DESC1_REG, 17059286SGarrett.Damore@Sun.COM (ulong_t)rtlsp->dma_area_tx[1].cookie.dmac_address); 17069286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, TX_ADDR_DESC2_REG, 17079286SGarrett.Damore@Sun.COM (ulong_t)rtlsp->dma_area_tx[2].cookie.dmac_address); 17089286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, TX_ADDR_DESC3_REG, 17099286SGarrett.Damore@Sun.COM (ulong_t)rtlsp->dma_area_tx[3].cookie.dmac_address); 17109286SGarrett.Damore@Sun.COM 17119286SGarrett.Damore@Sun.COM /* 17129286SGarrett.Damore@Sun.COM * Start transmit/receive before set tx/rx configuration register 17139286SGarrett.Damore@Sun.COM */ 17149286SGarrett.Damore@Sun.COM val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG); 17159286SGarrett.Damore@Sun.COM rtls_reg_set8(rtlsp, RT_COMMAND_REG, 17169286SGarrett.Damore@Sun.COM val8 | RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE); 17179286SGarrett.Damore@Sun.COM 17189286SGarrett.Damore@Sun.COM /* 17199286SGarrett.Damore@Sun.COM * Set transmit configuration register 17209286SGarrett.Damore@Sun.COM */ 17219286SGarrett.Damore@Sun.COM val32 = rtls_reg_get32(rtlsp, TX_CONFIG_REG); 17229286SGarrett.Damore@Sun.COM val32 &= TX_CONSIG_REG_RESERVE; 17239286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, TX_CONFIG_REG, val32 | TX_CONFIG_DEFAULT); 17249286SGarrett.Damore@Sun.COM 17259286SGarrett.Damore@Sun.COM /* 17269286SGarrett.Damore@Sun.COM * Set receive configuration register 17279286SGarrett.Damore@Sun.COM */ 17289286SGarrett.Damore@Sun.COM val32 = rtls_reg_get32(rtlsp, RX_CONFIG_REG); 17299286SGarrett.Damore@Sun.COM val32 &= RX_CONSIG_REG_RESERVE; 17309286SGarrett.Damore@Sun.COM if (rtlsp->promisc) 17319286SGarrett.Damore@Sun.COM val32 |= RX_ACCEPT_ALL_PACKET; 17329286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, RX_CONFIG_REG, val32 | RX_CONFIG_DEFAULT); 17339286SGarrett.Damore@Sun.COM 17349286SGarrett.Damore@Sun.COM /* 17359286SGarrett.Damore@Sun.COM * Set multicast register 17369286SGarrett.Damore@Sun.COM */ 17379286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, MULTICAST_0_REG, rtlsp->multi_hash[0]); 17389286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, MULTICAST_4_REG, rtlsp->multi_hash[1]); 17399286SGarrett.Damore@Sun.COM 17409286SGarrett.Damore@Sun.COM /* 17419286SGarrett.Damore@Sun.COM * Set unicast address 17429286SGarrett.Damore@Sun.COM */ 17439286SGarrett.Damore@Sun.COM rtls_set_mac_addr(rtlsp, rtlsp->netaddr); 17449286SGarrett.Damore@Sun.COM 17459286SGarrett.Damore@Sun.COM /* 17469286SGarrett.Damore@Sun.COM * Set current address of packet read 17479286SGarrett.Damore@Sun.COM */ 17489286SGarrett.Damore@Sun.COM rtls_reg_set16(rtlsp, RX_CURRENT_READ_ADDR_REG, RX_READ_RESET_VAL); 17499286SGarrett.Damore@Sun.COM 17509286SGarrett.Damore@Sun.COM /* 17519286SGarrett.Damore@Sun.COM * No early-rx interrupts 17529286SGarrett.Damore@Sun.COM */ 17539286SGarrett.Damore@Sun.COM val16 = rtls_reg_get16(rtlsp, RT_MUL_INTSEL_REG); 17549286SGarrett.Damore@Sun.COM val16 &= ~RT_MUL_INTSEL_BITS; 17559286SGarrett.Damore@Sun.COM rtls_reg_set16(rtlsp, RT_MUL_INTSEL_REG, val16); 17569286SGarrett.Damore@Sun.COM } 17579286SGarrett.Damore@Sun.COM 17589286SGarrett.Damore@Sun.COM /* 17599286SGarrett.Damore@Sun.COM * rtls_chip_start() -- start chip 17609286SGarrett.Damore@Sun.COM */ 17619286SGarrett.Damore@Sun.COM static void 17629286SGarrett.Damore@Sun.COM rtls_chip_start(rtls_t *rtlsp) 17639286SGarrett.Damore@Sun.COM { 17649286SGarrett.Damore@Sun.COM uint16_t val16; 17659286SGarrett.Damore@Sun.COM uint8_t val8; 17669286SGarrett.Damore@Sun.COM 17679286SGarrett.Damore@Sun.COM /* 17689286SGarrett.Damore@Sun.COM * Start transmit/receive 17699286SGarrett.Damore@Sun.COM */ 17709286SGarrett.Damore@Sun.COM val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG); 17719286SGarrett.Damore@Sun.COM rtls_reg_set8(rtlsp, RT_COMMAND_REG, 17729286SGarrett.Damore@Sun.COM val8 | RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE); 17739286SGarrett.Damore@Sun.COM 17749286SGarrett.Damore@Sun.COM /* 17759286SGarrett.Damore@Sun.COM * Enable interrupt 17769286SGarrett.Damore@Sun.COM */ 17779286SGarrett.Damore@Sun.COM val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG); 17789286SGarrett.Damore@Sun.COM rtls_reg_set16(rtlsp, RT_INT_MASK_REG, val16 | RTLS_INT_MASK); 17799286SGarrett.Damore@Sun.COM rtlsp->int_mask = RTLS_INT_MASK; 17809286SGarrett.Damore@Sun.COM } 17819286SGarrett.Damore@Sun.COM 17829286SGarrett.Damore@Sun.COM /* 17839286SGarrett.Damore@Sun.COM * rtls_chip_restart() -- restart chip 17849286SGarrett.Damore@Sun.COM */ 17859286SGarrett.Damore@Sun.COM static void 17869286SGarrett.Damore@Sun.COM rtls_chip_restart(rtls_t *rtlsp) 17879286SGarrett.Damore@Sun.COM { 17889286SGarrett.Damore@Sun.COM (void) rtls_chip_reset(rtlsp, B_FALSE); 17899286SGarrett.Damore@Sun.COM rtls_chip_init(rtlsp); 17909286SGarrett.Damore@Sun.COM rtls_chip_start(rtlsp); 17919286SGarrett.Damore@Sun.COM } 17929286SGarrett.Damore@Sun.COM 17939286SGarrett.Damore@Sun.COM /* 17949286SGarrett.Damore@Sun.COM * rtls_chip_stop() -- stop board receiving 17959286SGarrett.Damore@Sun.COM */ 17969286SGarrett.Damore@Sun.COM static void 17979286SGarrett.Damore@Sun.COM rtls_chip_stop(rtls_t *rtlsp) 17989286SGarrett.Damore@Sun.COM { 17999286SGarrett.Damore@Sun.COM uint16_t val16; 18009286SGarrett.Damore@Sun.COM uint8_t val8; 18019286SGarrett.Damore@Sun.COM 18029286SGarrett.Damore@Sun.COM /* 18039286SGarrett.Damore@Sun.COM * Disable interrupt 18049286SGarrett.Damore@Sun.COM */ 18059286SGarrett.Damore@Sun.COM val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG); 18069286SGarrett.Damore@Sun.COM rtls_reg_set16(rtlsp, RT_INT_MASK_REG, val16 & (~RTLS_INT_MASK_ALL)); 18079286SGarrett.Damore@Sun.COM rtlsp->int_mask = RTLS_INT_MASK_NONE; 18089286SGarrett.Damore@Sun.COM 18099286SGarrett.Damore@Sun.COM /* 18109286SGarrett.Damore@Sun.COM * Clear pended interrupt 18119286SGarrett.Damore@Sun.COM */ 18129286SGarrett.Damore@Sun.COM val16 = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG); 18139286SGarrett.Damore@Sun.COM rtls_reg_set16(rtlsp, RT_INT_STATUS_REG, val16); 18149286SGarrett.Damore@Sun.COM 18159286SGarrett.Damore@Sun.COM /* 18169286SGarrett.Damore@Sun.COM * Stop the board and disable transmit/receive 18179286SGarrett.Damore@Sun.COM */ 18189286SGarrett.Damore@Sun.COM val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG); 18199286SGarrett.Damore@Sun.COM val8 &= ~(RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE); 18209286SGarrett.Damore@Sun.COM rtls_reg_set8(rtlsp, RT_COMMAND_REG, val8); 18219286SGarrett.Damore@Sun.COM } 18229286SGarrett.Damore@Sun.COM 18239286SGarrett.Damore@Sun.COM /* 18249286SGarrett.Damore@Sun.COM * rtls_get_mac_addr() -- get the physical network address on the board 18259286SGarrett.Damore@Sun.COM */ 18269286SGarrett.Damore@Sun.COM static void 18279286SGarrett.Damore@Sun.COM rtls_get_mac_addr(rtls_t *rtlsp, uint8_t *macaddr) 18289286SGarrett.Damore@Sun.COM { 18299286SGarrett.Damore@Sun.COM uint32_t val32; 18309286SGarrett.Damore@Sun.COM 18319286SGarrett.Damore@Sun.COM /* 18329286SGarrett.Damore@Sun.COM * Read first 4-byte of mac address 18339286SGarrett.Damore@Sun.COM */ 18349286SGarrett.Damore@Sun.COM val32 = rtls_reg_get32(rtlsp, ID_0_REG); 18359286SGarrett.Damore@Sun.COM macaddr[0] = val32 & 0xff; 18369286SGarrett.Damore@Sun.COM val32 = val32 >> 8; 18379286SGarrett.Damore@Sun.COM macaddr[1] = val32 & 0xff; 18389286SGarrett.Damore@Sun.COM val32 = val32 >> 8; 18399286SGarrett.Damore@Sun.COM macaddr[2] = val32 & 0xff; 18409286SGarrett.Damore@Sun.COM val32 = val32 >> 8; 18419286SGarrett.Damore@Sun.COM macaddr[3] = val32 & 0xff; 18429286SGarrett.Damore@Sun.COM 18439286SGarrett.Damore@Sun.COM /* 18449286SGarrett.Damore@Sun.COM * Read last 2-byte of mac address 18459286SGarrett.Damore@Sun.COM */ 18469286SGarrett.Damore@Sun.COM val32 = rtls_reg_get32(rtlsp, ID_4_REG); 18479286SGarrett.Damore@Sun.COM macaddr[4] = val32 & 0xff; 18489286SGarrett.Damore@Sun.COM val32 = val32 >> 8; 18499286SGarrett.Damore@Sun.COM macaddr[5] = val32 & 0xff; 18509286SGarrett.Damore@Sun.COM } 18519286SGarrett.Damore@Sun.COM 18529286SGarrett.Damore@Sun.COM static void 18539286SGarrett.Damore@Sun.COM rtls_set_mac_addr(rtls_t *rtlsp, const uint8_t *macaddr) 18549286SGarrett.Damore@Sun.COM { 18559286SGarrett.Damore@Sun.COM uint32_t val32; 18569286SGarrett.Damore@Sun.COM uint8_t val8; 18579286SGarrett.Damore@Sun.COM 18589286SGarrett.Damore@Sun.COM /* 18599286SGarrett.Damore@Sun.COM * Change to config register write enable mode 18609286SGarrett.Damore@Sun.COM */ 1861*11453Sgdamore@opensolaris.org val8 = rtls_reg_get8(rtlsp, RT_93c46_COMMAND_REG); 18629286SGarrett.Damore@Sun.COM val8 |= RT_93c46_MODE_CONFIG; 1863*11453Sgdamore@opensolaris.org rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8); 18649286SGarrett.Damore@Sun.COM 18659286SGarrett.Damore@Sun.COM /* 18669286SGarrett.Damore@Sun.COM * Get first 4 bytes of mac address 18679286SGarrett.Damore@Sun.COM */ 18689286SGarrett.Damore@Sun.COM val32 = macaddr[3]; 18699286SGarrett.Damore@Sun.COM val32 = val32 << 8; 18709286SGarrett.Damore@Sun.COM val32 |= macaddr[2]; 18719286SGarrett.Damore@Sun.COM val32 = val32 << 8; 18729286SGarrett.Damore@Sun.COM val32 |= macaddr[1]; 18739286SGarrett.Damore@Sun.COM val32 = val32 << 8; 18749286SGarrett.Damore@Sun.COM val32 |= macaddr[0]; 18759286SGarrett.Damore@Sun.COM 18769286SGarrett.Damore@Sun.COM /* 18779286SGarrett.Damore@Sun.COM * Set first 4 bytes of mac address 18789286SGarrett.Damore@Sun.COM */ 18799286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, ID_0_REG, val32); 18809286SGarrett.Damore@Sun.COM 18819286SGarrett.Damore@Sun.COM /* 18829286SGarrett.Damore@Sun.COM * Get last 2 bytes of mac address 18839286SGarrett.Damore@Sun.COM */ 18849286SGarrett.Damore@Sun.COM val32 = macaddr[5]; 18859286SGarrett.Damore@Sun.COM val32 = val32 << 8; 18869286SGarrett.Damore@Sun.COM val32 |= macaddr[4]; 18879286SGarrett.Damore@Sun.COM 18889286SGarrett.Damore@Sun.COM /* 18899286SGarrett.Damore@Sun.COM * Set last 2 bytes of mac address 18909286SGarrett.Damore@Sun.COM */ 18919286SGarrett.Damore@Sun.COM val32 |= rtls_reg_get32(rtlsp, ID_4_REG) & ~0xffff; 18929286SGarrett.Damore@Sun.COM rtls_reg_set32(rtlsp, ID_4_REG, val32); 18939286SGarrett.Damore@Sun.COM 18949286SGarrett.Damore@Sun.COM /* 18959286SGarrett.Damore@Sun.COM * Return to normal network/host communication mode 18969286SGarrett.Damore@Sun.COM */ 18979286SGarrett.Damore@Sun.COM val8 &= ~RT_93c46_MODE_CONFIG; 1898*11453Sgdamore@opensolaris.org rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8); 1899*11453Sgdamore@opensolaris.org } 1900*11453Sgdamore@opensolaris.org 1901*11453Sgdamore@opensolaris.org static uint16_t 1902*11453Sgdamore@opensolaris.org rtls_mii_read(void *arg, uint8_t phy, uint8_t reg) 1903*11453Sgdamore@opensolaris.org { 1904*11453Sgdamore@opensolaris.org rtls_t *rtlsp = arg; 1905*11453Sgdamore@opensolaris.org uint16_t val; 1906*11453Sgdamore@opensolaris.org 1907*11453Sgdamore@opensolaris.org if (phy != 1) { 1908*11453Sgdamore@opensolaris.org return (0xffff); 1909*11453Sgdamore@opensolaris.org } 1910*11453Sgdamore@opensolaris.org switch (reg) { 1911*11453Sgdamore@opensolaris.org case MII_CONTROL: 1912*11453Sgdamore@opensolaris.org val = rtls_reg_get16(rtlsp, BASIC_MODE_CONTROL_REG); 1913*11453Sgdamore@opensolaris.org break; 1914*11453Sgdamore@opensolaris.org case MII_STATUS: 1915*11453Sgdamore@opensolaris.org val = rtls_reg_get16(rtlsp, BASIC_MODE_STATUS_REG); 1916*11453Sgdamore@opensolaris.org break; 1917*11453Sgdamore@opensolaris.org case MII_AN_ADVERT: 1918*11453Sgdamore@opensolaris.org val = rtls_reg_get16(rtlsp, AUTO_NEGO_AD_REG); 1919*11453Sgdamore@opensolaris.org break; 1920*11453Sgdamore@opensolaris.org case MII_AN_LPABLE: 1921*11453Sgdamore@opensolaris.org val = rtls_reg_get16(rtlsp, AUTO_NEGO_LP_REG); 1922*11453Sgdamore@opensolaris.org break; 1923*11453Sgdamore@opensolaris.org case MII_AN_EXPANSION: 1924*11453Sgdamore@opensolaris.org val = rtls_reg_get16(rtlsp, AUTO_NEGO_EXP_REG); 1925*11453Sgdamore@opensolaris.org break; 1926*11453Sgdamore@opensolaris.org case MII_VENDOR(0): 1927*11453Sgdamore@opensolaris.org /* 1928*11453Sgdamore@opensolaris.org * We "simulate" a vendor private register so that the 1929*11453Sgdamore@opensolaris.org * PHY layer can access it to determine detected link 1930*11453Sgdamore@opensolaris.org * speed/duplex. 1931*11453Sgdamore@opensolaris.org */ 1932*11453Sgdamore@opensolaris.org val = rtls_reg_get8(rtlsp, MEDIA_STATUS_REG); 1933*11453Sgdamore@opensolaris.org break; 1934*11453Sgdamore@opensolaris.org case MII_PHYIDH: 1935*11453Sgdamore@opensolaris.org case MII_PHYIDL: 1936*11453Sgdamore@opensolaris.org default: 1937*11453Sgdamore@opensolaris.org val = 0; 1938*11453Sgdamore@opensolaris.org break; 1939*11453Sgdamore@opensolaris.org } 1940*11453Sgdamore@opensolaris.org return (val); 19419286SGarrett.Damore@Sun.COM } 19429286SGarrett.Damore@Sun.COM 1943*11453Sgdamore@opensolaris.org void 1944*11453Sgdamore@opensolaris.org rtls_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val) 19459286SGarrett.Damore@Sun.COM { 1946*11453Sgdamore@opensolaris.org rtls_t *rtlsp = arg; 1947*11453Sgdamore@opensolaris.org uint8_t val8; 19489286SGarrett.Damore@Sun.COM 1949*11453Sgdamore@opensolaris.org if (phy != 1) { 1950*11453Sgdamore@opensolaris.org return; 19519286SGarrett.Damore@Sun.COM } 1952*11453Sgdamore@opensolaris.org switch (reg) { 1953*11453Sgdamore@opensolaris.org case MII_CONTROL: 1954*11453Sgdamore@opensolaris.org /* Enable writes to all bits of BMCR */ 1955*11453Sgdamore@opensolaris.org val8 = rtls_reg_get8(rtlsp, RT_93c46_COMMAND_REG); 1956*11453Sgdamore@opensolaris.org val8 |= RT_93c46_MODE_CONFIG; 1957*11453Sgdamore@opensolaris.org rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8); 1958*11453Sgdamore@opensolaris.org /* write out the value */ 1959*11453Sgdamore@opensolaris.org rtls_reg_set16(rtlsp, BASIC_MODE_CONTROL_REG, val); 1960*11453Sgdamore@opensolaris.org 1961*11453Sgdamore@opensolaris.org /* Return to normal network/host communication mode */ 1962*11453Sgdamore@opensolaris.org val8 &= ~RT_93c46_MODE_CONFIG; 1963*11453Sgdamore@opensolaris.org rtls_reg_set8(rtlsp, RT_93c46_COMMAND_REG, val8); 1964*11453Sgdamore@opensolaris.org return; 1965*11453Sgdamore@opensolaris.org 1966*11453Sgdamore@opensolaris.org case MII_STATUS: 1967*11453Sgdamore@opensolaris.org rtls_reg_set16(rtlsp, BASIC_MODE_STATUS_REG, val); 19689286SGarrett.Damore@Sun.COM break; 1969*11453Sgdamore@opensolaris.org case MII_AN_ADVERT: 1970*11453Sgdamore@opensolaris.org rtls_reg_set16(rtlsp, AUTO_NEGO_AD_REG, val); 19719286SGarrett.Damore@Sun.COM break; 1972*11453Sgdamore@opensolaris.org case MII_AN_LPABLE: 1973*11453Sgdamore@opensolaris.org rtls_reg_set16(rtlsp, AUTO_NEGO_LP_REG, val); 19749286SGarrett.Damore@Sun.COM break; 1975*11453Sgdamore@opensolaris.org case MII_AN_EXPANSION: 1976*11453Sgdamore@opensolaris.org rtls_reg_set16(rtlsp, AUTO_NEGO_EXP_REG, val); 19779286SGarrett.Damore@Sun.COM break; 1978*11453Sgdamore@opensolaris.org case MII_PHYIDH: 1979*11453Sgdamore@opensolaris.org case MII_PHYIDL: 1980*11453Sgdamore@opensolaris.org default: 1981*11453Sgdamore@opensolaris.org /* these are not writable */ 19829286SGarrett.Damore@Sun.COM break; 19839286SGarrett.Damore@Sun.COM } 1984*11453Sgdamore@opensolaris.org } 19859286SGarrett.Damore@Sun.COM 1986*11453Sgdamore@opensolaris.org void 1987*11453Sgdamore@opensolaris.org rtls_mii_notify(void *arg, link_state_t link) 1988*11453Sgdamore@opensolaris.org { 1989*11453Sgdamore@opensolaris.org rtls_t *rtlsp = arg; 19909286SGarrett.Damore@Sun.COM 1991*11453Sgdamore@opensolaris.org mac_link_update(rtlsp->mh, link); 19929286SGarrett.Damore@Sun.COM } 19939286SGarrett.Damore@Sun.COM 19949286SGarrett.Damore@Sun.COM #ifdef RTLS_DEBUG 19959286SGarrett.Damore@Sun.COM /* 19969286SGarrett.Damore@Sun.COM * rtls_reg_print() -- print out reg value(for debug use only) 19979286SGarrett.Damore@Sun.COM */ 19989286SGarrett.Damore@Sun.COM static void 19999286SGarrett.Damore@Sun.COM rtls_reg_print(rtls_t *rtlsp) 20009286SGarrett.Damore@Sun.COM { 20019286SGarrett.Damore@Sun.COM uint8_t val8; 20029286SGarrett.Damore@Sun.COM uint16_t val16; 20039286SGarrett.Damore@Sun.COM uint32_t val32; 20049286SGarrett.Damore@Sun.COM 20059286SGarrett.Damore@Sun.COM val8 = rtls_reg_get8(rtlsp, RT_COMMAND_REG); 20069286SGarrett.Damore@Sun.COM cmn_err(CE_NOTE, "%s: RT_COMMAND_REG = 0x%x", 20079286SGarrett.Damore@Sun.COM rtlsp->ifname, val8); 20089286SGarrett.Damore@Sun.COM delay(drv_usectohz(1000)); 20099286SGarrett.Damore@Sun.COM 20109286SGarrett.Damore@Sun.COM val16 = rtls_reg_get16(rtlsp, RT_INT_STATUS_REG); 20119286SGarrett.Damore@Sun.COM cmn_err(CE_NOTE, "%s: RT_INT_STATUS_REG = 0x%x", 20129286SGarrett.Damore@Sun.COM rtlsp->ifname, val16); 20139286SGarrett.Damore@Sun.COM delay(drv_usectohz(1000)); 20149286SGarrett.Damore@Sun.COM 20159286SGarrett.Damore@Sun.COM val16 = rtls_reg_get16(rtlsp, RT_INT_MASK_REG); 20169286SGarrett.Damore@Sun.COM cmn_err(CE_NOTE, "%s: RT_INT_MASK_REG = 0x%x", 20179286SGarrett.Damore@Sun.COM rtlsp->ifname, val16); 20189286SGarrett.Damore@Sun.COM delay(drv_usectohz(1000)); 20199286SGarrett.Damore@Sun.COM 20209286SGarrett.Damore@Sun.COM val32 = rtls_reg_get32(rtlsp, RX_CONFIG_REG); 20219286SGarrett.Damore@Sun.COM cmn_err(CE_NOTE, "%s: RX_CONFIG_REG = 0x%x", 20229286SGarrett.Damore@Sun.COM rtlsp->ifname, val32); 20239286SGarrett.Damore@Sun.COM delay(drv_usectohz(1000)); 20249286SGarrett.Damore@Sun.COM 20259286SGarrett.Damore@Sun.COM val16 = rtls_reg_get16(rtlsp, TX_DESC_STAUS_REG); 2026*11453Sgdamore@opensolaris.org cmn_err(CE_NOTE, "%s: TX_DESC_STAUS_REG = 0x%x, cur_desc = %d", 20279286SGarrett.Damore@Sun.COM rtlsp->ifname, val16, rtlsp->tx_current_desc); 20289286SGarrett.Damore@Sun.COM delay(drv_usectohz(1000)); 20299286SGarrett.Damore@Sun.COM 20309286SGarrett.Damore@Sun.COM val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC0_REG); 2031*11453Sgdamore@opensolaris.org cmn_err(CE_NOTE, "%s: TX_STATUS_DESC0_REG = 0x%x", 20329286SGarrett.Damore@Sun.COM rtlsp->ifname, val32); 20339286SGarrett.Damore@Sun.COM delay(drv_usectohz(1000)); 20349286SGarrett.Damore@Sun.COM 20359286SGarrett.Damore@Sun.COM val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC1_REG); 2036*11453Sgdamore@opensolaris.org cmn_err(CE_NOTE, "%s: TX_STATUS_DESC1_REG = 0x%x", 20379286SGarrett.Damore@Sun.COM rtlsp->ifname, val32); 20389286SGarrett.Damore@Sun.COM delay(drv_usectohz(1000)); 20399286SGarrett.Damore@Sun.COM 20409286SGarrett.Damore@Sun.COM val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC2_REG); 2041*11453Sgdamore@opensolaris.org cmn_err(CE_NOTE, "%s: TX_STATUS_DESC2_REG = 0x%x", 20429286SGarrett.Damore@Sun.COM rtlsp->ifname, val32); 20439286SGarrett.Damore@Sun.COM delay(drv_usectohz(1000)); 20449286SGarrett.Damore@Sun.COM 20459286SGarrett.Damore@Sun.COM val32 = rtls_reg_get32(rtlsp, TX_STATUS_DESC3_REG); 2046*11453Sgdamore@opensolaris.org cmn_err(CE_NOTE, "%s: TX_STATUS_DESC3_REG = 0x%x", 20479286SGarrett.Damore@Sun.COM rtlsp->ifname, val32); 20489286SGarrett.Damore@Sun.COM delay(drv_usectohz(1000)); 20499286SGarrett.Damore@Sun.COM 2050*11453Sgdamore@opensolaris.org cmn_err(CE_NOTE, "%s: in = %llu, multicast = %llu, broadcast = %llu", 20519286SGarrett.Damore@Sun.COM rtlsp->ifname, 20529286SGarrett.Damore@Sun.COM (unsigned long long)rtlsp->stats.ipackets, 20539286SGarrett.Damore@Sun.COM (unsigned long long)rtlsp->stats.multi_rcv, 20549286SGarrett.Damore@Sun.COM (unsigned long long)rtlsp->stats.brdcst_rcv); 20559286SGarrett.Damore@Sun.COM delay(drv_usectohz(1000)); 20569286SGarrett.Damore@Sun.COM } 20579286SGarrett.Damore@Sun.COM #endif 2058