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