11816cb70SBarry Harding /* 2*3661c01dSGarrett D'Amore * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 31816cb70SBarry Harding */ 41816cb70SBarry Harding 51816cb70SBarry Harding /* 61816cb70SBarry Harding * This driver was derived from the FreeBSD if_msk.c driver, which 71816cb70SBarry Harding * bears the following copyright attributions and licenses. 81816cb70SBarry Harding */ 91816cb70SBarry Harding 101816cb70SBarry Harding /* 111816cb70SBarry Harding * 121816cb70SBarry Harding * LICENSE: 131816cb70SBarry Harding * Copyright (C) Marvell International Ltd. and/or its affiliates 141816cb70SBarry Harding * 151816cb70SBarry Harding * The computer program files contained in this folder ("Files") 161816cb70SBarry Harding * are provided to you under the BSD-type license terms provided 171816cb70SBarry Harding * below, and any use of such Files and any derivative works 181816cb70SBarry Harding * thereof created by you shall be governed by the following terms 191816cb70SBarry Harding * and conditions: 201816cb70SBarry Harding * 211816cb70SBarry Harding * - Redistributions of source code must retain the above copyright 221816cb70SBarry Harding * notice, this list of conditions and the following disclaimer. 231816cb70SBarry Harding * - Redistributions in binary form must reproduce the above 241816cb70SBarry Harding * copyright notice, this list of conditions and the following 251816cb70SBarry Harding * disclaimer in the documentation and/or other materials provided 261816cb70SBarry Harding * with the distribution. 271816cb70SBarry Harding * - Neither the name of Marvell nor the names of its contributors 281816cb70SBarry Harding * may be used to endorse or promote products derived from this 291816cb70SBarry Harding * software without specific prior written permission. 301816cb70SBarry Harding * 311816cb70SBarry Harding * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 321816cb70SBarry Harding * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 331816cb70SBarry Harding * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 341816cb70SBarry Harding * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 351816cb70SBarry Harding * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 361816cb70SBarry Harding * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 371816cb70SBarry Harding * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 381816cb70SBarry Harding * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 391816cb70SBarry Harding * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 401816cb70SBarry Harding * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 411816cb70SBarry Harding * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 421816cb70SBarry Harding * OF THE POSSIBILITY OF SUCH DAMAGE. 431816cb70SBarry Harding * /LICENSE 441816cb70SBarry Harding * 451816cb70SBarry Harding */ 461816cb70SBarry Harding /* 471816cb70SBarry Harding * Copyright (c) 1997, 1998, 1999, 2000 481816cb70SBarry Harding * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 491816cb70SBarry Harding * 501816cb70SBarry Harding * Redistribution and use in source and binary forms, with or without 511816cb70SBarry Harding * modification, are permitted provided that the following conditions 521816cb70SBarry Harding * are met: 531816cb70SBarry Harding * 1. Redistributions of source code must retain the above copyright 541816cb70SBarry Harding * notice, this list of conditions and the following disclaimer. 551816cb70SBarry Harding * 2. Redistributions in binary form must reproduce the above copyright 561816cb70SBarry Harding * notice, this list of conditions and the following disclaimer in the 571816cb70SBarry Harding * documentation and/or other materials provided with the distribution. 581816cb70SBarry Harding * 3. All advertising materials mentioning features or use of this software 591816cb70SBarry Harding * must display the following acknowledgement: 601816cb70SBarry Harding * This product includes software developed by Bill Paul. 611816cb70SBarry Harding * 4. Neither the name of the author nor the names of any co-contributors 621816cb70SBarry Harding * may be used to endorse or promote products derived from this software 631816cb70SBarry Harding * without specific prior written permission. 641816cb70SBarry Harding * 651816cb70SBarry Harding * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 661816cb70SBarry Harding * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 671816cb70SBarry Harding * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 681816cb70SBarry Harding * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 691816cb70SBarry Harding * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 701816cb70SBarry Harding * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 711816cb70SBarry Harding * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 721816cb70SBarry Harding * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 731816cb70SBarry Harding * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 741816cb70SBarry Harding * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 751816cb70SBarry Harding * THE POSSIBILITY OF SUCH DAMAGE. 761816cb70SBarry Harding */ 771816cb70SBarry Harding /* 781816cb70SBarry Harding * Copyright (c) 2003 Nathan L. Binkert <binkertn@umich.edu> 791816cb70SBarry Harding * 801816cb70SBarry Harding * Permission to use, copy, modify, and distribute this software for any 811816cb70SBarry Harding * purpose with or without fee is hereby granted, provided that the above 821816cb70SBarry Harding * copyright notice and this permission notice appear in all copies. 831816cb70SBarry Harding * 841816cb70SBarry Harding * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 851816cb70SBarry Harding * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 861816cb70SBarry Harding * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 871816cb70SBarry Harding * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 881816cb70SBarry Harding * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 891816cb70SBarry Harding * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 901816cb70SBarry Harding * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 911816cb70SBarry Harding */ 921816cb70SBarry Harding 931816cb70SBarry Harding #include <sys/varargs.h> 941816cb70SBarry Harding #include <sys/types.h> 951816cb70SBarry Harding #include <sys/modctl.h> 961816cb70SBarry Harding #include <sys/conf.h> 971816cb70SBarry Harding #include <sys/devops.h> 981816cb70SBarry Harding #include <sys/stream.h> 991816cb70SBarry Harding #include <sys/strsun.h> 1001816cb70SBarry Harding #include <sys/cmn_err.h> 1011816cb70SBarry Harding #include <sys/ethernet.h> 1021816cb70SBarry Harding #include <sys/kmem.h> 1031816cb70SBarry Harding #include <sys/time.h> 1041816cb70SBarry Harding #include <sys/pci.h> 1051816cb70SBarry Harding #include <sys/mii.h> 1061816cb70SBarry Harding #include <sys/miiregs.h> 1071816cb70SBarry Harding #include <sys/mac.h> 1081816cb70SBarry Harding #include <sys/mac_ether.h> 1091816cb70SBarry Harding #include <sys/mac_provider.h> 1101816cb70SBarry Harding #include <sys/debug.h> 1111816cb70SBarry Harding #include <sys/note.h> 1121816cb70SBarry Harding #include <sys/ddi.h> 1131816cb70SBarry Harding #include <sys/sunddi.h> 1141816cb70SBarry Harding #include <sys/vlan.h> 1151816cb70SBarry Harding 1161816cb70SBarry Harding #include "yge.h" 1171816cb70SBarry Harding 1181816cb70SBarry Harding static struct ddi_device_acc_attr yge_regs_attr = { 1191816cb70SBarry Harding DDI_DEVICE_ATTR_V0, 1201816cb70SBarry Harding DDI_STRUCTURE_LE_ACC, 121837c1ac4SStephen Hanson DDI_STRICTORDER_ACC 1221816cb70SBarry Harding }; 1231816cb70SBarry Harding 1241816cb70SBarry Harding static struct ddi_device_acc_attr yge_ring_attr = { 1251816cb70SBarry Harding DDI_DEVICE_ATTR_V0, 1261816cb70SBarry Harding DDI_STRUCTURE_LE_ACC, 1271816cb70SBarry Harding DDI_STRICTORDER_ACC 1281816cb70SBarry Harding }; 1291816cb70SBarry Harding 1301816cb70SBarry Harding static struct ddi_device_acc_attr yge_buf_attr = { 1311816cb70SBarry Harding DDI_DEVICE_ATTR_V0, 1321816cb70SBarry Harding DDI_NEVERSWAP_ACC, 1331816cb70SBarry Harding DDI_STRICTORDER_ACC 1341816cb70SBarry Harding }; 1351816cb70SBarry Harding 1361816cb70SBarry Harding #define DESC_ALIGN 0x1000 1371816cb70SBarry Harding 1381816cb70SBarry Harding static ddi_dma_attr_t yge_ring_dma_attr = { 1391816cb70SBarry Harding DMA_ATTR_V0, /* dma_attr_version */ 1401816cb70SBarry Harding 0, /* dma_attr_addr_lo */ 1411816cb70SBarry Harding 0x00000000ffffffffull, /* dma_attr_addr_hi */ 1421816cb70SBarry Harding 0x00000000ffffffffull, /* dma_attr_count_max */ 1431816cb70SBarry Harding DESC_ALIGN, /* dma_attr_align */ 1441816cb70SBarry Harding 0x000007fc, /* dma_attr_burstsizes */ 1451816cb70SBarry Harding 1, /* dma_attr_minxfer */ 1461816cb70SBarry Harding 0x00000000ffffffffull, /* dma_attr_maxxfer */ 1471816cb70SBarry Harding 0x00000000ffffffffull, /* dma_attr_seg */ 1481816cb70SBarry Harding 1, /* dma_attr_sgllen */ 1491816cb70SBarry Harding 1, /* dma_attr_granular */ 1501816cb70SBarry Harding 0 /* dma_attr_flags */ 1511816cb70SBarry Harding }; 1521816cb70SBarry Harding 1531816cb70SBarry Harding static ddi_dma_attr_t yge_buf_dma_attr = { 1541816cb70SBarry Harding DMA_ATTR_V0, /* dma_attr_version */ 1551816cb70SBarry Harding 0, /* dma_attr_addr_lo */ 1561816cb70SBarry Harding 0x00000000ffffffffull, /* dma_attr_addr_hi */ 1571816cb70SBarry Harding 0x00000000ffffffffull, /* dma_attr_count_max */ 1581816cb70SBarry Harding 1, /* dma_attr_align */ 1591816cb70SBarry Harding 0x0000fffc, /* dma_attr_burstsizes */ 1601816cb70SBarry Harding 1, /* dma_attr_minxfer */ 1611816cb70SBarry Harding 0x000000000000ffffull, /* dma_attr_maxxfer */ 1621816cb70SBarry Harding 0x00000000ffffffffull, /* dma_attr_seg */ 1631816cb70SBarry Harding 8, /* dma_attr_sgllen */ 1641816cb70SBarry Harding 1, /* dma_attr_granular */ 1651816cb70SBarry Harding 0 /* dma_attr_flags */ 1661816cb70SBarry Harding }; 1671816cb70SBarry Harding 1681816cb70SBarry Harding 1691816cb70SBarry Harding static int yge_attach(yge_dev_t *); 1701816cb70SBarry Harding static void yge_detach(yge_dev_t *); 1711816cb70SBarry Harding static int yge_suspend(yge_dev_t *); 1721816cb70SBarry Harding static int yge_resume(yge_dev_t *); 1731816cb70SBarry Harding 1741816cb70SBarry Harding static void yge_reset(yge_dev_t *); 1751816cb70SBarry Harding static void yge_setup_rambuffer(yge_dev_t *); 1761816cb70SBarry Harding 1771816cb70SBarry Harding static int yge_init_port(yge_port_t *); 1781816cb70SBarry Harding static void yge_uninit_port(yge_port_t *); 1791816cb70SBarry Harding static int yge_register_port(yge_port_t *); 1801816cb70SBarry Harding 1811816cb70SBarry Harding static void yge_tick(void *); 1821816cb70SBarry Harding static uint_t yge_intr(caddr_t, caddr_t); 1831816cb70SBarry Harding static int yge_intr_gmac(yge_port_t *); 1841816cb70SBarry Harding static void yge_intr_enable(yge_dev_t *); 1851816cb70SBarry Harding static void yge_intr_disable(yge_dev_t *); 1861816cb70SBarry Harding static boolean_t yge_handle_events(yge_dev_t *, mblk_t **, mblk_t **, int *); 1871816cb70SBarry Harding static void yge_handle_hwerr(yge_port_t *, uint32_t); 1881816cb70SBarry Harding static void yge_intr_hwerr(yge_dev_t *); 1891816cb70SBarry Harding static mblk_t *yge_rxeof(yge_port_t *, uint32_t, int); 1901816cb70SBarry Harding static void yge_txeof(yge_port_t *, int); 1911816cb70SBarry Harding static boolean_t yge_send(yge_port_t *, mblk_t *); 1921816cb70SBarry Harding static void yge_set_prefetch(yge_dev_t *, int, yge_ring_t *); 1931816cb70SBarry Harding static void yge_set_rambuffer(yge_port_t *); 1941816cb70SBarry Harding static void yge_start_port(yge_port_t *); 1951816cb70SBarry Harding static void yge_stop_port(yge_port_t *); 1961816cb70SBarry Harding static void yge_phy_power(yge_dev_t *, boolean_t); 1971816cb70SBarry Harding static int yge_alloc_ring(yge_port_t *, yge_dev_t *, yge_ring_t *, uint32_t); 1981816cb70SBarry Harding static void yge_free_ring(yge_ring_t *); 1991816cb70SBarry Harding static uint8_t yge_find_capability(yge_dev_t *, uint8_t); 2001816cb70SBarry Harding 2011816cb70SBarry Harding static int yge_txrx_dma_alloc(yge_port_t *); 2021816cb70SBarry Harding static void yge_txrx_dma_free(yge_port_t *); 2031816cb70SBarry Harding static void yge_init_rx_ring(yge_port_t *); 2041816cb70SBarry Harding static void yge_init_tx_ring(yge_port_t *); 2051816cb70SBarry Harding 2061816cb70SBarry Harding static uint16_t yge_mii_readreg(yge_port_t *, uint8_t, uint8_t); 2071816cb70SBarry Harding static void yge_mii_writereg(yge_port_t *, uint8_t, uint8_t, uint16_t); 2081816cb70SBarry Harding 2091816cb70SBarry Harding static uint16_t yge_mii_read(void *, uint8_t, uint8_t); 2101816cb70SBarry Harding static void yge_mii_write(void *, uint8_t, uint8_t, uint16_t); 2111816cb70SBarry Harding static void yge_mii_notify(void *, link_state_t); 2121816cb70SBarry Harding 2131816cb70SBarry Harding static void yge_setrxfilt(yge_port_t *); 2141816cb70SBarry Harding static void yge_restart_task(yge_dev_t *); 2151816cb70SBarry Harding static void yge_task(void *); 2161816cb70SBarry Harding static void yge_dispatch(yge_dev_t *, int); 2171816cb70SBarry Harding 2181816cb70SBarry Harding static void yge_stats_clear(yge_port_t *); 2191816cb70SBarry Harding static void yge_stats_update(yge_port_t *); 2201816cb70SBarry Harding static uint32_t yge_hashbit(const uint8_t *); 2211816cb70SBarry Harding 2221816cb70SBarry Harding static int yge_m_unicst(void *, const uint8_t *); 2231816cb70SBarry Harding static int yge_m_multicst(void *, boolean_t, const uint8_t *); 2241816cb70SBarry Harding static int yge_m_promisc(void *, boolean_t); 2251816cb70SBarry Harding static mblk_t *yge_m_tx(void *, mblk_t *); 2261816cb70SBarry Harding static int yge_m_stat(void *, uint_t, uint64_t *); 2271816cb70SBarry Harding static int yge_m_start(void *); 2281816cb70SBarry Harding static void yge_m_stop(void *); 2290dc2366fSVenugopal Iyer static int yge_m_getprop(void *, const char *, mac_prop_id_t, uint_t, void *); 2300dc2366fSVenugopal Iyer static void yge_m_propinfo(void *, const char *, mac_prop_id_t, 2310dc2366fSVenugopal Iyer mac_prop_info_handle_t); 2321816cb70SBarry Harding static int yge_m_setprop(void *, const char *, mac_prop_id_t, uint_t, 2331816cb70SBarry Harding const void *); 2341816cb70SBarry Harding static void yge_m_ioctl(void *, queue_t *, mblk_t *); 2351816cb70SBarry Harding 2361816cb70SBarry Harding void yge_error(yge_dev_t *, yge_port_t *, char *, ...); 2371816cb70SBarry Harding extern void yge_phys_update(yge_port_t *); 2381816cb70SBarry Harding extern int yge_phys_restart(yge_port_t *, boolean_t); 2391816cb70SBarry Harding extern int yge_phys_init(yge_port_t *, phy_readreg_t, phy_writereg_t); 2401816cb70SBarry Harding 2411816cb70SBarry Harding static mac_callbacks_t yge_m_callbacks = { 2420dc2366fSVenugopal Iyer MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO, 2431816cb70SBarry Harding yge_m_stat, 2441816cb70SBarry Harding yge_m_start, 2451816cb70SBarry Harding yge_m_stop, 2461816cb70SBarry Harding yge_m_promisc, 2471816cb70SBarry Harding yge_m_multicst, 2481816cb70SBarry Harding yge_m_unicst, 2491816cb70SBarry Harding yge_m_tx, 2500dc2366fSVenugopal Iyer NULL, 2511816cb70SBarry Harding yge_m_ioctl, 2521816cb70SBarry Harding NULL, /* mc_getcapab */ 2531816cb70SBarry Harding NULL, /* mc_open */ 2541816cb70SBarry Harding NULL, /* mc_close */ 2551816cb70SBarry Harding yge_m_setprop, 2561816cb70SBarry Harding yge_m_getprop, 2570dc2366fSVenugopal Iyer yge_m_propinfo 2581816cb70SBarry Harding }; 2591816cb70SBarry Harding 2601816cb70SBarry Harding static mii_ops_t yge_mii_ops = { 2611816cb70SBarry Harding MII_OPS_VERSION, 2621816cb70SBarry Harding yge_mii_read, 2631816cb70SBarry Harding yge_mii_write, 2641816cb70SBarry Harding yge_mii_notify, 2651816cb70SBarry Harding NULL /* reset */ 2661816cb70SBarry Harding }; 2671816cb70SBarry Harding 2681816cb70SBarry Harding /* 2691816cb70SBarry Harding * This is the low level interface routine to read from the PHY 2701816cb70SBarry Harding * MII registers. There is multiple steps to these accesses. First 2711816cb70SBarry Harding * the register number is written to an address register. Then after 2721816cb70SBarry Harding * a specified delay status is checked until the data is present. 2731816cb70SBarry Harding */ 2741816cb70SBarry Harding static uint16_t 2751816cb70SBarry Harding yge_mii_readreg(yge_port_t *port, uint8_t phy, uint8_t reg) 2761816cb70SBarry Harding { 2771816cb70SBarry Harding yge_dev_t *dev = port->p_dev; 2781816cb70SBarry Harding int pnum = port->p_port; 2791816cb70SBarry Harding uint16_t val; 2801816cb70SBarry Harding 2811816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_SMI_CTRL, 2821816cb70SBarry Harding GM_SMI_CT_PHY_AD(phy) | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD); 2831816cb70SBarry Harding 2841816cb70SBarry Harding for (int i = 0; i < YGE_TIMEOUT; i += 10) { 2851816cb70SBarry Harding drv_usecwait(10); 2861816cb70SBarry Harding val = GMAC_READ_2(dev, pnum, GM_SMI_CTRL); 2871816cb70SBarry Harding if ((val & GM_SMI_CT_RD_VAL) != 0) { 2881816cb70SBarry Harding val = GMAC_READ_2(dev, pnum, GM_SMI_DATA); 2891816cb70SBarry Harding return (val); 2901816cb70SBarry Harding } 2911816cb70SBarry Harding } 2921816cb70SBarry Harding 2931816cb70SBarry Harding return (0xffff); 2941816cb70SBarry Harding } 2951816cb70SBarry Harding 2961816cb70SBarry Harding /* 2971816cb70SBarry Harding * This is the low level interface routine to write to the PHY 2981816cb70SBarry Harding * MII registers. There is multiple steps to these accesses. The 2991816cb70SBarry Harding * data and the target registers address are written to the PHY. 3001816cb70SBarry Harding * Then the PHY is polled until it is done with the write. Note 3011816cb70SBarry Harding * that the delays are specified and required! 3021816cb70SBarry Harding */ 3031816cb70SBarry Harding static void 3041816cb70SBarry Harding yge_mii_writereg(yge_port_t *port, uint8_t phy, uint8_t reg, uint16_t val) 3051816cb70SBarry Harding { 3061816cb70SBarry Harding yge_dev_t *dev = port->p_dev; 3071816cb70SBarry Harding int pnum = port->p_port; 3081816cb70SBarry Harding 3091816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_SMI_DATA, val); 3101816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_SMI_CTRL, 3111816cb70SBarry Harding GM_SMI_CT_PHY_AD(phy) | GM_SMI_CT_REG_AD(reg)); 3121816cb70SBarry Harding 3131816cb70SBarry Harding for (int i = 0; i < YGE_TIMEOUT; i += 10) { 3141816cb70SBarry Harding drv_usecwait(10); 3151816cb70SBarry Harding if ((GMAC_READ_2(dev, pnum, GM_SMI_CTRL) & GM_SMI_CT_BUSY) == 0) 3161816cb70SBarry Harding return; 3171816cb70SBarry Harding } 3181816cb70SBarry Harding 3191816cb70SBarry Harding yge_error(NULL, port, "phy write timeout"); 3201816cb70SBarry Harding } 3211816cb70SBarry Harding 3221816cb70SBarry Harding static uint16_t 3231816cb70SBarry Harding yge_mii_read(void *arg, uint8_t phy, uint8_t reg) 3241816cb70SBarry Harding { 3251816cb70SBarry Harding yge_port_t *port = arg; 3261816cb70SBarry Harding uint16_t rv; 3271816cb70SBarry Harding 3281816cb70SBarry Harding PHY_LOCK(port->p_dev); 3291816cb70SBarry Harding rv = yge_mii_readreg(port, phy, reg); 3301816cb70SBarry Harding PHY_UNLOCK(port->p_dev); 3311816cb70SBarry Harding return (rv); 3321816cb70SBarry Harding } 3331816cb70SBarry Harding 3341816cb70SBarry Harding static void 3351816cb70SBarry Harding yge_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val) 3361816cb70SBarry Harding { 3371816cb70SBarry Harding yge_port_t *port = arg; 3381816cb70SBarry Harding 3391816cb70SBarry Harding PHY_LOCK(port->p_dev); 3401816cb70SBarry Harding yge_mii_writereg(port, phy, reg, val); 3411816cb70SBarry Harding PHY_UNLOCK(port->p_dev); 3421816cb70SBarry Harding } 3431816cb70SBarry Harding 3441816cb70SBarry Harding /* 3451816cb70SBarry Harding * The MII common code calls this function to let the MAC driver 3461816cb70SBarry Harding * know when there has been a change in status. 3471816cb70SBarry Harding */ 3481816cb70SBarry Harding void 3491816cb70SBarry Harding yge_mii_notify(void *arg, link_state_t link) 3501816cb70SBarry Harding { 3511816cb70SBarry Harding yge_port_t *port = arg; 3521816cb70SBarry Harding yge_dev_t *dev = port->p_dev; 3531816cb70SBarry Harding uint32_t gmac; 3541816cb70SBarry Harding uint32_t gpcr; 3551816cb70SBarry Harding link_flowctrl_t fc; 3561816cb70SBarry Harding link_duplex_t duplex; 3571816cb70SBarry Harding int speed; 3581816cb70SBarry Harding 3591816cb70SBarry Harding fc = mii_get_flowctrl(port->p_mii); 3601816cb70SBarry Harding duplex = mii_get_duplex(port->p_mii); 3611816cb70SBarry Harding speed = mii_get_speed(port->p_mii); 3621816cb70SBarry Harding 3631816cb70SBarry Harding DEV_LOCK(dev); 3641816cb70SBarry Harding 3651816cb70SBarry Harding if (link == LINK_STATE_UP) { 3661816cb70SBarry Harding 3671816cb70SBarry Harding /* Enable Tx FIFO Underrun. */ 3681816cb70SBarry Harding CSR_WRITE_1(dev, MR_ADDR(port->p_port, GMAC_IRQ_MSK), 3691816cb70SBarry Harding GM_IS_TX_FF_UR | /* TX FIFO underflow */ 3701816cb70SBarry Harding GM_IS_RX_FF_OR); /* RX FIFO overflow */ 3711816cb70SBarry Harding 3721816cb70SBarry Harding gpcr = GM_GPCR_AU_ALL_DIS; 3731816cb70SBarry Harding 3741816cb70SBarry Harding switch (fc) { 3751816cb70SBarry Harding case LINK_FLOWCTRL_BI: 3761816cb70SBarry Harding gmac = GMC_PAUSE_ON; 3771816cb70SBarry Harding gpcr &= ~(GM_GPCR_FC_RX_DIS | GM_GPCR_FC_TX_DIS); 3781816cb70SBarry Harding break; 3791816cb70SBarry Harding case LINK_FLOWCTRL_TX: 3801816cb70SBarry Harding gmac = GMC_PAUSE_ON; 3811816cb70SBarry Harding gpcr |= GM_GPCR_FC_RX_DIS; 3821816cb70SBarry Harding break; 3831816cb70SBarry Harding case LINK_FLOWCTRL_RX: 3841816cb70SBarry Harding gmac = GMC_PAUSE_ON; 3851816cb70SBarry Harding gpcr |= GM_GPCR_FC_TX_DIS; 3861816cb70SBarry Harding break; 3871816cb70SBarry Harding case LINK_FLOWCTRL_NONE: 3881816cb70SBarry Harding default: 3891816cb70SBarry Harding gmac = GMC_PAUSE_OFF; 3901816cb70SBarry Harding gpcr |= GM_GPCR_FC_RX_DIS; 3911816cb70SBarry Harding gpcr |= GM_GPCR_FC_TX_DIS; 3921816cb70SBarry Harding break; 3931816cb70SBarry Harding } 3941816cb70SBarry Harding 3951816cb70SBarry Harding gpcr &= ~((GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100)); 3961816cb70SBarry Harding switch (speed) { 3971816cb70SBarry Harding case 1000: 3981816cb70SBarry Harding gpcr |= GM_GPCR_SPEED_1000; 3991816cb70SBarry Harding break; 4001816cb70SBarry Harding case 100: 4011816cb70SBarry Harding gpcr |= GM_GPCR_SPEED_100; 4021816cb70SBarry Harding break; 4031816cb70SBarry Harding case 10: 4041816cb70SBarry Harding default: 4051816cb70SBarry Harding break; 4061816cb70SBarry Harding } 4071816cb70SBarry Harding 4081816cb70SBarry Harding if (duplex == LINK_DUPLEX_FULL) { 4091816cb70SBarry Harding gpcr |= GM_GPCR_DUP_FULL; 4101816cb70SBarry Harding } else { 4111816cb70SBarry Harding gpcr &= ~(GM_GPCR_DUP_FULL); 4121816cb70SBarry Harding gmac = GMC_PAUSE_OFF; 4131816cb70SBarry Harding gpcr |= GM_GPCR_FC_RX_DIS; 4141816cb70SBarry Harding gpcr |= GM_GPCR_FC_TX_DIS; 4151816cb70SBarry Harding } 4161816cb70SBarry Harding 4171816cb70SBarry Harding gpcr |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA; 4181816cb70SBarry Harding GMAC_WRITE_2(dev, port->p_port, GM_GP_CTRL, gpcr); 4191816cb70SBarry Harding 4201816cb70SBarry Harding /* Read again to ensure writing. */ 4211816cb70SBarry Harding (void) GMAC_READ_2(dev, port->p_port, GM_GP_CTRL); 4221816cb70SBarry Harding 4231816cb70SBarry Harding /* write out the flow control gmac setting */ 4241816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(port->p_port, GMAC_CTRL), gmac); 4251816cb70SBarry Harding 4261816cb70SBarry Harding } else { 4271816cb70SBarry Harding /* Disable Rx/Tx MAC. */ 4281816cb70SBarry Harding gpcr = GMAC_READ_2(dev, port->p_port, GM_GP_CTRL); 4291816cb70SBarry Harding gpcr &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); 4301816cb70SBarry Harding GMAC_WRITE_2(dev, port->p_port, GM_GP_CTRL, gpcr); 4311816cb70SBarry Harding 4321816cb70SBarry Harding /* Read again to ensure writing. */ 4331816cb70SBarry Harding (void) GMAC_READ_2(dev, port->p_port, GM_GP_CTRL); 4341816cb70SBarry Harding } 4351816cb70SBarry Harding 4361816cb70SBarry Harding DEV_UNLOCK(dev); 4371816cb70SBarry Harding 4381816cb70SBarry Harding mac_link_update(port->p_mh, link); 4391816cb70SBarry Harding 4401816cb70SBarry Harding if (port->p_running && (link == LINK_STATE_UP)) { 4411816cb70SBarry Harding mac_tx_update(port->p_mh); 4421816cb70SBarry Harding } 4431816cb70SBarry Harding } 4441816cb70SBarry Harding 4451816cb70SBarry Harding static void 4461816cb70SBarry Harding yge_setrxfilt(yge_port_t *port) 4471816cb70SBarry Harding { 4481816cb70SBarry Harding yge_dev_t *dev; 4491816cb70SBarry Harding uint16_t mode; 4501816cb70SBarry Harding uint8_t *ea; 4511816cb70SBarry Harding uint32_t *mchash; 4521816cb70SBarry Harding int pnum; 4531816cb70SBarry Harding 4541816cb70SBarry Harding dev = port->p_dev; 4551816cb70SBarry Harding pnum = port->p_port; 4561816cb70SBarry Harding ea = port->p_curraddr; 4571816cb70SBarry Harding mchash = port->p_mchash; 4581816cb70SBarry Harding 4591816cb70SBarry Harding if (dev->d_suspended) 4601816cb70SBarry Harding return; 4611816cb70SBarry Harding 4621816cb70SBarry Harding /* Set station address. */ 4631816cb70SBarry Harding for (int i = 0; i < (ETHERADDRL / 2); i++) { 4641816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_SRC_ADDR_1L + i * 4, 4651816cb70SBarry Harding ((uint16_t)ea[i * 2] | ((uint16_t)ea[(i * 2) + 1] << 8))); 4661816cb70SBarry Harding } 4671816cb70SBarry Harding for (int i = 0; i < (ETHERADDRL / 2); i++) { 4681816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_SRC_ADDR_2L + i * 4, 4691816cb70SBarry Harding ((uint16_t)ea[i * 2] | ((uint16_t)ea[(i * 2) + 1] << 8))); 4701816cb70SBarry Harding } 4711816cb70SBarry Harding 4721816cb70SBarry Harding /* Figure out receive filtering mode. */ 4731816cb70SBarry Harding mode = GMAC_READ_2(dev, pnum, GM_RX_CTRL); 4741816cb70SBarry Harding if (port->p_promisc) { 4751816cb70SBarry Harding mode &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); 4761816cb70SBarry Harding } else { 4771816cb70SBarry Harding mode |= (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); 4781816cb70SBarry Harding } 4791816cb70SBarry Harding /* Write the multicast filter. */ 4801816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_MC_ADDR_H1, mchash[0] & 0xffff); 4811816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_MC_ADDR_H2, (mchash[0] >> 16) & 0xffff); 4821816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_MC_ADDR_H3, mchash[1] & 0xffff); 4831816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_MC_ADDR_H4, (mchash[1] >> 16) & 0xffff); 4841816cb70SBarry Harding /* Write the receive filtering mode. */ 4851816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_RX_CTRL, mode); 4861816cb70SBarry Harding } 4871816cb70SBarry Harding 4881816cb70SBarry Harding static void 4891816cb70SBarry Harding yge_init_rx_ring(yge_port_t *port) 4901816cb70SBarry Harding { 4911816cb70SBarry Harding yge_buf_t *rxb; 4921816cb70SBarry Harding yge_ring_t *ring; 4931816cb70SBarry Harding int prod; 4941816cb70SBarry Harding 4951816cb70SBarry Harding port->p_rx_cons = 0; 4961816cb70SBarry Harding port->p_rx_putwm = YGE_PUT_WM; 4971816cb70SBarry Harding ring = &port->p_rx_ring; 4981816cb70SBarry Harding 4991816cb70SBarry Harding /* ala bzero, but uses safer acch access */ 5001816cb70SBarry Harding CLEARRING(ring); 5011816cb70SBarry Harding 5021816cb70SBarry Harding for (prod = 0; prod < YGE_RX_RING_CNT; prod++) { 5031816cb70SBarry Harding /* Hang out receive buffers. */ 5041816cb70SBarry Harding rxb = &port->p_rx_buf[prod]; 5051816cb70SBarry Harding 5061816cb70SBarry Harding PUTADDR(ring, prod, rxb->b_paddr); 5071816cb70SBarry Harding PUTCTRL(ring, prod, port->p_framesize | OP_PACKET | HW_OWNER); 5081816cb70SBarry Harding } 5091816cb70SBarry Harding 5101816cb70SBarry Harding SYNCRING(ring, DDI_DMA_SYNC_FORDEV); 5111816cb70SBarry Harding 5121816cb70SBarry Harding yge_set_prefetch(port->p_dev, port->p_rxq, ring); 5131816cb70SBarry Harding 5141816cb70SBarry Harding /* Update prefetch unit. */ 5151816cb70SBarry Harding CSR_WRITE_2(port->p_dev, 5161816cb70SBarry Harding Y2_PREF_Q_ADDR(port->p_rxq, PREF_UNIT_PUT_IDX_REG), 5171816cb70SBarry Harding YGE_RX_RING_CNT - 1); 5181816cb70SBarry Harding } 5191816cb70SBarry Harding 5201816cb70SBarry Harding static void 5211816cb70SBarry Harding yge_init_tx_ring(yge_port_t *port) 5221816cb70SBarry Harding { 5231816cb70SBarry Harding yge_ring_t *ring = &port->p_tx_ring; 5241816cb70SBarry Harding 5251816cb70SBarry Harding port->p_tx_prod = 0; 5261816cb70SBarry Harding port->p_tx_cons = 0; 5271816cb70SBarry Harding port->p_tx_cnt = 0; 5281816cb70SBarry Harding 5291816cb70SBarry Harding CLEARRING(ring); 5301816cb70SBarry Harding SYNCRING(ring, DDI_DMA_SYNC_FORDEV); 5311816cb70SBarry Harding 5321816cb70SBarry Harding yge_set_prefetch(port->p_dev, port->p_txq, ring); 5331816cb70SBarry Harding } 5341816cb70SBarry Harding 5351816cb70SBarry Harding static void 5361816cb70SBarry Harding yge_setup_rambuffer(yge_dev_t *dev) 5371816cb70SBarry Harding { 5381816cb70SBarry Harding int next; 5391816cb70SBarry Harding int i; 5401816cb70SBarry Harding 5411816cb70SBarry Harding /* Get adapter SRAM size. */ 5421816cb70SBarry Harding dev->d_ramsize = CSR_READ_1(dev, B2_E_0) * 4; 5431816cb70SBarry Harding if (dev->d_ramsize == 0) 5441816cb70SBarry Harding return; 5451816cb70SBarry Harding 5461816cb70SBarry Harding dev->d_pflags |= PORT_FLAG_RAMBUF; 5471816cb70SBarry Harding /* 5481816cb70SBarry Harding * Give receiver 2/3 of memory and round down to the multiple 5491816cb70SBarry Harding * of 1024. Tx/Rx RAM buffer size of Yukon 2 should be multiple 5501816cb70SBarry Harding * of 1024. 5511816cb70SBarry Harding */ 5521816cb70SBarry Harding dev->d_rxqsize = (((dev->d_ramsize * 1024 * 2) / 3) & ~(1024 - 1)); 5531816cb70SBarry Harding dev->d_txqsize = (dev->d_ramsize * 1024) - dev->d_rxqsize; 5541816cb70SBarry Harding 5551816cb70SBarry Harding for (i = 0, next = 0; i < dev->d_num_port; i++) { 5561816cb70SBarry Harding dev->d_rxqstart[i] = next; 5571816cb70SBarry Harding dev->d_rxqend[i] = next + dev->d_rxqsize - 1; 5581816cb70SBarry Harding next = dev->d_rxqend[i] + 1; 5591816cb70SBarry Harding dev->d_txqstart[i] = next; 5601816cb70SBarry Harding dev->d_txqend[i] = next + dev->d_txqsize - 1; 5611816cb70SBarry Harding next = dev->d_txqend[i] + 1; 5621816cb70SBarry Harding } 5631816cb70SBarry Harding } 5641816cb70SBarry Harding 5651816cb70SBarry Harding static void 5661816cb70SBarry Harding yge_phy_power(yge_dev_t *dev, boolean_t powerup) 5671816cb70SBarry Harding { 5681816cb70SBarry Harding uint32_t val; 5691816cb70SBarry Harding int i; 5701816cb70SBarry Harding 5711816cb70SBarry Harding if (powerup) { 5721816cb70SBarry Harding /* Switch power to VCC (WA for VAUX problem). */ 5731816cb70SBarry Harding CSR_WRITE_1(dev, B0_POWER_CTRL, 5741816cb70SBarry Harding PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON); 5751816cb70SBarry Harding /* Disable Core Clock Division, set Clock Select to 0. */ 5761816cb70SBarry Harding CSR_WRITE_4(dev, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS); 5771816cb70SBarry Harding 5781816cb70SBarry Harding val = 0; 5791816cb70SBarry Harding if (dev->d_hw_id == CHIP_ID_YUKON_XL && 5801816cb70SBarry Harding dev->d_hw_rev > CHIP_REV_YU_XL_A1) { 5811816cb70SBarry Harding /* Enable bits are inverted. */ 5821816cb70SBarry Harding val = Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS | 5831816cb70SBarry Harding Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS | 5841816cb70SBarry Harding Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS; 5851816cb70SBarry Harding } 5861816cb70SBarry Harding /* 5871816cb70SBarry Harding * Enable PCI & Core Clock, enable clock gating for both Links. 5881816cb70SBarry Harding */ 5891816cb70SBarry Harding CSR_WRITE_1(dev, B2_Y2_CLK_GATE, val); 5901816cb70SBarry Harding 5911816cb70SBarry Harding val = pci_config_get32(dev->d_pcih, PCI_OUR_REG_1); 5921816cb70SBarry Harding val &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); 5931816cb70SBarry Harding if (dev->d_hw_id == CHIP_ID_YUKON_XL && 5941816cb70SBarry Harding dev->d_hw_rev > CHIP_REV_YU_XL_A1) { 5951816cb70SBarry Harding /* Deassert Low Power for 1st PHY. */ 5961816cb70SBarry Harding val |= PCI_Y2_PHY1_COMA; 5971816cb70SBarry Harding if (dev->d_num_port > 1) 5981816cb70SBarry Harding val |= PCI_Y2_PHY2_COMA; 5991816cb70SBarry Harding } 6001816cb70SBarry Harding 6011816cb70SBarry Harding /* Release PHY from PowerDown/COMA mode. */ 6021816cb70SBarry Harding pci_config_put32(dev->d_pcih, PCI_OUR_REG_1, val); 6031816cb70SBarry Harding 6041816cb70SBarry Harding switch (dev->d_hw_id) { 6051816cb70SBarry Harding case CHIP_ID_YUKON_EC_U: 6061816cb70SBarry Harding case CHIP_ID_YUKON_EX: 6071816cb70SBarry Harding case CHIP_ID_YUKON_FE_P: { 6081816cb70SBarry Harding uint32_t our; 6091816cb70SBarry Harding 6101816cb70SBarry Harding CSR_WRITE_2(dev, B0_CTST, Y2_HW_WOL_OFF); 6111816cb70SBarry Harding 6121816cb70SBarry Harding /* Enable all clocks. */ 6131816cb70SBarry Harding pci_config_put32(dev->d_pcih, PCI_OUR_REG_3, 0); 6141816cb70SBarry Harding 6151816cb70SBarry Harding our = pci_config_get32(dev->d_pcih, PCI_OUR_REG_4); 6161816cb70SBarry Harding our &= (PCI_FORCE_ASPM_REQUEST|PCI_ASPM_GPHY_LINK_DOWN| 6171816cb70SBarry Harding PCI_ASPM_INT_FIFO_EMPTY|PCI_ASPM_CLKRUN_REQUEST); 6181816cb70SBarry Harding /* Set all bits to 0 except bits 15..12. */ 6191816cb70SBarry Harding pci_config_put32(dev->d_pcih, PCI_OUR_REG_4, our); 6201816cb70SBarry Harding 6211816cb70SBarry Harding /* Set to default value. */ 6221816cb70SBarry Harding our = pci_config_get32(dev->d_pcih, PCI_OUR_REG_5); 6231816cb70SBarry Harding our &= P_CTL_TIM_VMAIN_AV_MSK; 6241816cb70SBarry Harding pci_config_put32(dev->d_pcih, PCI_OUR_REG_5, our); 6251816cb70SBarry Harding 6261816cb70SBarry Harding pci_config_put32(dev->d_pcih, PCI_OUR_REG_1, 0); 6271816cb70SBarry Harding 6281816cb70SBarry Harding /* 6291816cb70SBarry Harding * Enable workaround for dev 4.107 on Yukon-Ultra 6301816cb70SBarry Harding * and Extreme 6311816cb70SBarry Harding */ 6321816cb70SBarry Harding our = CSR_READ_4(dev, B2_GP_IO); 6331816cb70SBarry Harding our |= GLB_GPIO_STAT_RACE_DIS; 6341816cb70SBarry Harding CSR_WRITE_4(dev, B2_GP_IO, our); 6351816cb70SBarry Harding 6361816cb70SBarry Harding (void) CSR_READ_4(dev, B2_GP_IO); 6371816cb70SBarry Harding break; 6381816cb70SBarry Harding } 6391816cb70SBarry Harding default: 6401816cb70SBarry Harding break; 6411816cb70SBarry Harding } 6421816cb70SBarry Harding 6431816cb70SBarry Harding for (i = 0; i < dev->d_num_port; i++) { 6441816cb70SBarry Harding CSR_WRITE_2(dev, MR_ADDR(i, GMAC_LINK_CTRL), 6451816cb70SBarry Harding GMLC_RST_SET); 6461816cb70SBarry Harding CSR_WRITE_2(dev, MR_ADDR(i, GMAC_LINK_CTRL), 6471816cb70SBarry Harding GMLC_RST_CLR); 6481816cb70SBarry Harding } 6491816cb70SBarry Harding } else { 6501816cb70SBarry Harding val = pci_config_get32(dev->d_pcih, PCI_OUR_REG_1); 6511816cb70SBarry Harding if (dev->d_hw_id == CHIP_ID_YUKON_XL && 6521816cb70SBarry Harding dev->d_hw_rev > CHIP_REV_YU_XL_A1) { 6531816cb70SBarry Harding val &= ~PCI_Y2_PHY1_COMA; 6541816cb70SBarry Harding if (dev->d_num_port > 1) 6551816cb70SBarry Harding val &= ~PCI_Y2_PHY2_COMA; 6561816cb70SBarry Harding val &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); 6571816cb70SBarry Harding } else { 6581816cb70SBarry Harding val |= (PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); 6591816cb70SBarry Harding } 6601816cb70SBarry Harding pci_config_put32(dev->d_pcih, PCI_OUR_REG_1, val); 6611816cb70SBarry Harding 6621816cb70SBarry Harding val = Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS | 6631816cb70SBarry Harding Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS | 6641816cb70SBarry Harding Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS; 6651816cb70SBarry Harding if (dev->d_hw_id == CHIP_ID_YUKON_XL && 6661816cb70SBarry Harding dev->d_hw_rev > CHIP_REV_YU_XL_A1) { 6671816cb70SBarry Harding /* Enable bits are inverted. */ 6681816cb70SBarry Harding val = 0; 6691816cb70SBarry Harding } 6701816cb70SBarry Harding /* 6711816cb70SBarry Harding * Disable PCI & Core Clock, disable clock gating for 6721816cb70SBarry Harding * both Links. 6731816cb70SBarry Harding */ 6741816cb70SBarry Harding CSR_WRITE_1(dev, B2_Y2_CLK_GATE, val); 6751816cb70SBarry Harding CSR_WRITE_1(dev, B0_POWER_CTRL, 6761816cb70SBarry Harding PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF); 6771816cb70SBarry Harding } 6781816cb70SBarry Harding } 6791816cb70SBarry Harding 6801816cb70SBarry Harding static void 6811816cb70SBarry Harding yge_reset(yge_dev_t *dev) 6821816cb70SBarry Harding { 6831816cb70SBarry Harding uint64_t addr; 6841816cb70SBarry Harding uint16_t status; 6851816cb70SBarry Harding uint32_t val; 6861816cb70SBarry Harding int i; 6871816cb70SBarry Harding ddi_acc_handle_t pcih = dev->d_pcih; 6881816cb70SBarry Harding 6891816cb70SBarry Harding /* Turn off ASF */ 6901816cb70SBarry Harding if (dev->d_hw_id == CHIP_ID_YUKON_EX) { 6911816cb70SBarry Harding status = CSR_READ_2(dev, B28_Y2_ASF_STAT_CMD); 6921816cb70SBarry Harding /* Clear AHB bridge & microcontroller reset */ 6931816cb70SBarry Harding status &= ~Y2_ASF_CPU_MODE; 6941816cb70SBarry Harding status &= ~Y2_ASF_AHB_RST; 6951816cb70SBarry Harding /* Clear ASF microcontroller state */ 6961816cb70SBarry Harding status &= ~Y2_ASF_STAT_MSK; 6971816cb70SBarry Harding CSR_WRITE_2(dev, B28_Y2_ASF_STAT_CMD, status); 6981816cb70SBarry Harding } else { 6991816cb70SBarry Harding CSR_WRITE_1(dev, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); 7001816cb70SBarry Harding } 7011816cb70SBarry Harding CSR_WRITE_2(dev, B0_CTST, Y2_ASF_DISABLE); 7021816cb70SBarry Harding 7031816cb70SBarry Harding /* 7041816cb70SBarry Harding * Since we disabled ASF, S/W reset is required for Power Management. 7051816cb70SBarry Harding */ 7061816cb70SBarry Harding CSR_WRITE_1(dev, B0_CTST, CS_RST_SET); 7071816cb70SBarry Harding CSR_WRITE_1(dev, B0_CTST, CS_RST_CLR); 7081816cb70SBarry Harding 7091816cb70SBarry Harding /* Allow writes to PCI config space */ 7101816cb70SBarry Harding CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_ON); 7111816cb70SBarry Harding 7121816cb70SBarry Harding /* Clear all error bits in the PCI status register. */ 7131816cb70SBarry Harding status = pci_config_get16(pcih, PCI_CONF_STAT); 7141816cb70SBarry Harding CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_ON); 7151816cb70SBarry Harding 7161816cb70SBarry Harding status |= (PCI_STAT_S_PERROR | PCI_STAT_S_SYSERR | PCI_STAT_R_MAST_AB | 7171816cb70SBarry Harding PCI_STAT_R_TARG_AB | PCI_STAT_PERROR); 7181816cb70SBarry Harding pci_config_put16(pcih, PCI_CONF_STAT, status); 7191816cb70SBarry Harding 7201816cb70SBarry Harding CSR_WRITE_1(dev, B0_CTST, CS_MRST_CLR); 7211816cb70SBarry Harding 7221816cb70SBarry Harding switch (dev->d_bustype) { 7231816cb70SBarry Harding case PEX_BUS: 7241816cb70SBarry Harding /* Clear all PEX errors. */ 7251816cb70SBarry Harding CSR_PCI_WRITE_4(dev, Y2_CFG_AER + AER_UNCOR_ERR, 0xffffffff); 7261816cb70SBarry Harding 7271816cb70SBarry Harding /* is error bit status stuck? */ 7281816cb70SBarry Harding val = CSR_PCI_READ_4(dev, PEX_UNC_ERR_STAT); 7291816cb70SBarry Harding if ((val & PEX_RX_OV) != 0) { 7301816cb70SBarry Harding dev->d_intrmask &= ~Y2_IS_HW_ERR; 7311816cb70SBarry Harding dev->d_intrhwemask &= ~Y2_IS_PCI_EXP; 7321816cb70SBarry Harding } 7331816cb70SBarry Harding break; 7341816cb70SBarry Harding case PCI_BUS: 7351816cb70SBarry Harding /* Set Cache Line Size to 2 (8 bytes) if configured to 0. */ 7361816cb70SBarry Harding if (pci_config_get8(pcih, PCI_CONF_CACHE_LINESZ) == 0) 7371816cb70SBarry Harding pci_config_put16(pcih, PCI_CONF_CACHE_LINESZ, 2); 7381816cb70SBarry Harding break; 7391816cb70SBarry Harding case PCIX_BUS: 7401816cb70SBarry Harding /* Set Cache Line Size to 2 (8 bytes) if configured to 0. */ 7411816cb70SBarry Harding if (pci_config_get8(pcih, PCI_CONF_CACHE_LINESZ) == 0) 7421816cb70SBarry Harding pci_config_put16(pcih, PCI_CONF_CACHE_LINESZ, 2); 7431816cb70SBarry Harding 7441816cb70SBarry Harding /* Set Cache Line Size opt. */ 7451816cb70SBarry Harding val = pci_config_get32(pcih, PCI_OUR_REG_1); 7461816cb70SBarry Harding val |= PCI_CLS_OPT; 7471816cb70SBarry Harding pci_config_put32(pcih, PCI_OUR_REG_1, val); 7481816cb70SBarry Harding break; 7491816cb70SBarry Harding } 7501816cb70SBarry Harding 7511816cb70SBarry Harding /* Set PHY power state. */ 7521816cb70SBarry Harding yge_phy_power(dev, B_TRUE); 7531816cb70SBarry Harding 7541816cb70SBarry Harding /* Reset GPHY/GMAC Control */ 7551816cb70SBarry Harding for (i = 0; i < dev->d_num_port; i++) { 7561816cb70SBarry Harding /* GPHY Control reset. */ 7571816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(i, GPHY_CTRL), GPC_RST_SET); 7581816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(i, GPHY_CTRL), GPC_RST_CLR); 7591816cb70SBarry Harding /* GMAC Control reset. */ 7601816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(i, GMAC_CTRL), GMC_RST_SET); 7611816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(i, GMAC_CTRL), GMC_RST_CLR); 7621816cb70SBarry Harding if (dev->d_hw_id == CHIP_ID_YUKON_EX || 7631816cb70SBarry Harding dev->d_hw_id == CHIP_ID_YUKON_SUPR) { 7641816cb70SBarry Harding CSR_WRITE_2(dev, MR_ADDR(i, GMAC_CTRL), 7651816cb70SBarry Harding (GMC_BYP_RETR_ON | GMC_BYP_MACSECRX_ON | 7661816cb70SBarry Harding GMC_BYP_MACSECTX_ON)); 7671816cb70SBarry Harding } 7681816cb70SBarry Harding CSR_WRITE_2(dev, MR_ADDR(i, GMAC_CTRL), GMC_F_LOOPB_OFF); 7691816cb70SBarry Harding 7701816cb70SBarry Harding } 7711816cb70SBarry Harding CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 7721816cb70SBarry Harding 7731816cb70SBarry Harding /* LED On. */ 7741816cb70SBarry Harding CSR_WRITE_2(dev, B0_CTST, Y2_LED_STAT_ON); 7751816cb70SBarry Harding 7761816cb70SBarry Harding /* Clear TWSI IRQ. */ 7771816cb70SBarry Harding CSR_WRITE_4(dev, B2_I2C_IRQ, I2C_CLR_IRQ); 7781816cb70SBarry Harding 7791816cb70SBarry Harding /* Turn off hardware timer. */ 7801816cb70SBarry Harding CSR_WRITE_1(dev, B2_TI_CTRL, TIM_STOP); 7811816cb70SBarry Harding CSR_WRITE_1(dev, B2_TI_CTRL, TIM_CLR_IRQ); 7821816cb70SBarry Harding 7831816cb70SBarry Harding /* Turn off descriptor polling. */ 7841816cb70SBarry Harding CSR_WRITE_1(dev, B28_DPT_CTRL, DPT_STOP); 7851816cb70SBarry Harding 7861816cb70SBarry Harding /* Turn off time stamps. */ 7871816cb70SBarry Harding CSR_WRITE_1(dev, GMAC_TI_ST_CTRL, GMT_ST_STOP); 7881816cb70SBarry Harding CSR_WRITE_1(dev, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ); 7891816cb70SBarry Harding 7901816cb70SBarry Harding /* Don't permit config space writing */ 7911816cb70SBarry Harding CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 7921816cb70SBarry Harding 7931816cb70SBarry Harding /* enable TX Arbiters */ 7941816cb70SBarry Harding for (i = 0; i < dev->d_num_port; i++) 7951816cb70SBarry Harding CSR_WRITE_1(dev, MR_ADDR(i, TXA_CTRL), TXA_ENA_ARB); 7961816cb70SBarry Harding 7971816cb70SBarry Harding /* Configure timeout values. */ 7981816cb70SBarry Harding for (i = 0; i < dev->d_num_port; i++) { 7991816cb70SBarry Harding CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_CTRL), RI_RST_CLR); 8001816cb70SBarry Harding 8011816cb70SBarry Harding CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_WTO_R1), RI_TO_53); 8021816cb70SBarry Harding CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_WTO_XA1), RI_TO_53); 8031816cb70SBarry Harding CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_WTO_XS1), RI_TO_53); 8041816cb70SBarry Harding CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_RTO_R1), RI_TO_53); 8051816cb70SBarry Harding CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_RTO_XA1), RI_TO_53); 8061816cb70SBarry Harding CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_RTO_XS1), RI_TO_53); 8071816cb70SBarry Harding CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_WTO_R2), RI_TO_53); 8081816cb70SBarry Harding CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_WTO_XA2), RI_TO_53); 8091816cb70SBarry Harding CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_WTO_XS2), RI_TO_53); 8101816cb70SBarry Harding CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_RTO_R2), RI_TO_53); 8111816cb70SBarry Harding CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_RTO_XA2), RI_TO_53); 8121816cb70SBarry Harding CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_RTO_XS2), RI_TO_53); 8131816cb70SBarry Harding } 8141816cb70SBarry Harding 8151816cb70SBarry Harding /* Disable all interrupts. */ 8161816cb70SBarry Harding CSR_WRITE_4(dev, B0_HWE_IMSK, 0); 8171816cb70SBarry Harding (void) CSR_READ_4(dev, B0_HWE_IMSK); 8181816cb70SBarry Harding CSR_WRITE_4(dev, B0_IMSK, 0); 8191816cb70SBarry Harding (void) CSR_READ_4(dev, B0_IMSK); 8201816cb70SBarry Harding 8211816cb70SBarry Harding /* 8221816cb70SBarry Harding * On dual port PCI-X card, there is an problem where status 8231816cb70SBarry Harding * can be received out of order due to split transactions. 8241816cb70SBarry Harding */ 8251816cb70SBarry Harding if (dev->d_bustype == PCIX_BUS && dev->d_num_port > 1) { 8261816cb70SBarry Harding int pcix; 8271816cb70SBarry Harding uint16_t pcix_cmd; 8281816cb70SBarry Harding 8291816cb70SBarry Harding if ((pcix = yge_find_capability(dev, PCI_CAP_ID_PCIX)) != 0) { 8301816cb70SBarry Harding pcix_cmd = pci_config_get16(pcih, pcix + 2); 8311816cb70SBarry Harding /* Clear Max Outstanding Split Transactions. */ 8321816cb70SBarry Harding pcix_cmd &= ~0x70; 8331816cb70SBarry Harding CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_ON); 8341816cb70SBarry Harding pci_config_put16(pcih, pcix + 2, pcix_cmd); 8351816cb70SBarry Harding CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 8361816cb70SBarry Harding } 8371816cb70SBarry Harding } 8381816cb70SBarry Harding if (dev->d_bustype == PEX_BUS) { 8391816cb70SBarry Harding uint16_t v, width; 8401816cb70SBarry Harding 8411816cb70SBarry Harding v = pci_config_get16(pcih, PEX_DEV_CTRL); 8421816cb70SBarry Harding /* Change Max. Read Request Size to 4096 bytes. */ 8431816cb70SBarry Harding v &= ~PEX_DC_MAX_RRS_MSK; 8441816cb70SBarry Harding v |= PEX_DC_MAX_RD_RQ_SIZE(5); 8451816cb70SBarry Harding pci_config_put16(pcih, PEX_DEV_CTRL, v); 8461816cb70SBarry Harding width = pci_config_get16(pcih, PEX_LNK_STAT); 8471816cb70SBarry Harding width = (width & PEX_LS_LINK_WI_MSK) >> 4; 8481816cb70SBarry Harding v = pci_config_get16(pcih, PEX_LNK_CAP); 8491816cb70SBarry Harding v = (v & PEX_LS_LINK_WI_MSK) >> 4; 8501816cb70SBarry Harding if (v != width) 8511816cb70SBarry Harding yge_error(dev, NULL, 8521816cb70SBarry Harding "Negotiated width of PCIe link(x%d) != " 8531816cb70SBarry Harding "max. width of link(x%d)\n", width, v); 8541816cb70SBarry Harding } 8551816cb70SBarry Harding 8561816cb70SBarry Harding /* Clear status list. */ 8571816cb70SBarry Harding CLEARRING(&dev->d_status_ring); 8581816cb70SBarry Harding SYNCRING(&dev->d_status_ring, DDI_DMA_SYNC_FORDEV); 8591816cb70SBarry Harding 8601816cb70SBarry Harding dev->d_stat_cons = 0; 8611816cb70SBarry Harding 8621816cb70SBarry Harding CSR_WRITE_4(dev, STAT_CTRL, SC_STAT_RST_SET); 8631816cb70SBarry Harding CSR_WRITE_4(dev, STAT_CTRL, SC_STAT_RST_CLR); 8641816cb70SBarry Harding 8651816cb70SBarry Harding /* Set the status list base address. */ 8661816cb70SBarry Harding addr = dev->d_status_ring.r_paddr; 8671816cb70SBarry Harding CSR_WRITE_4(dev, STAT_LIST_ADDR_LO, YGE_ADDR_LO(addr)); 8681816cb70SBarry Harding CSR_WRITE_4(dev, STAT_LIST_ADDR_HI, YGE_ADDR_HI(addr)); 8691816cb70SBarry Harding 8701816cb70SBarry Harding /* Set the status list last index. */ 8711816cb70SBarry Harding CSR_WRITE_2(dev, STAT_LAST_IDX, YGE_STAT_RING_CNT - 1); 8721816cb70SBarry Harding CSR_WRITE_2(dev, STAT_PUT_IDX, 0); 8731816cb70SBarry Harding 8741816cb70SBarry Harding if (dev->d_hw_id == CHIP_ID_YUKON_EC && 8751816cb70SBarry Harding dev->d_hw_rev == CHIP_REV_YU_EC_A1) { 8761816cb70SBarry Harding /* WA for dev. #4.3 */ 8771816cb70SBarry Harding CSR_WRITE_2(dev, STAT_TX_IDX_TH, ST_TXTH_IDX_MASK); 8781816cb70SBarry Harding /* WA for dev #4.18 */ 8791816cb70SBarry Harding CSR_WRITE_1(dev, STAT_FIFO_WM, 0x21); 8801816cb70SBarry Harding CSR_WRITE_1(dev, STAT_FIFO_ISR_WM, 7); 8811816cb70SBarry Harding } else { 8821816cb70SBarry Harding CSR_WRITE_2(dev, STAT_TX_IDX_TH, 10); 8831816cb70SBarry Harding CSR_WRITE_1(dev, STAT_FIFO_WM, 16); 8841816cb70SBarry Harding 8851816cb70SBarry Harding /* ISR status FIFO watermark */ 8861816cb70SBarry Harding if (dev->d_hw_id == CHIP_ID_YUKON_XL && 8871816cb70SBarry Harding dev->d_hw_rev == CHIP_REV_YU_XL_A0) 8881816cb70SBarry Harding CSR_WRITE_1(dev, STAT_FIFO_ISR_WM, 4); 8891816cb70SBarry Harding else 8901816cb70SBarry Harding CSR_WRITE_1(dev, STAT_FIFO_ISR_WM, 16); 8911816cb70SBarry Harding 8921816cb70SBarry Harding CSR_WRITE_4(dev, STAT_ISR_TIMER_INI, 0x0190); 8931816cb70SBarry Harding } 8941816cb70SBarry Harding 8951816cb70SBarry Harding /* 8961816cb70SBarry Harding * Use default value for STAT_ISR_TIMER_INI, STAT_LEV_TIMER_INI. 8971816cb70SBarry Harding */ 8981816cb70SBarry Harding CSR_WRITE_4(dev, STAT_TX_TIMER_INI, YGE_USECS(dev, 1000)); 8991816cb70SBarry Harding 9001816cb70SBarry Harding /* Enable status unit. */ 9011816cb70SBarry Harding CSR_WRITE_4(dev, STAT_CTRL, SC_STAT_OP_ON); 9021816cb70SBarry Harding 9031816cb70SBarry Harding CSR_WRITE_1(dev, STAT_TX_TIMER_CTRL, TIM_START); 9041816cb70SBarry Harding CSR_WRITE_1(dev, STAT_LEV_TIMER_CTRL, TIM_START); 9051816cb70SBarry Harding CSR_WRITE_1(dev, STAT_ISR_TIMER_CTRL, TIM_START); 9061816cb70SBarry Harding } 9071816cb70SBarry Harding 9081816cb70SBarry Harding static int 9091816cb70SBarry Harding yge_init_port(yge_port_t *port) 9101816cb70SBarry Harding { 9111816cb70SBarry Harding yge_dev_t *dev = port->p_dev; 9121816cb70SBarry Harding int i; 9131816cb70SBarry Harding mac_register_t *macp; 9141816cb70SBarry Harding 9151816cb70SBarry Harding port->p_flags = dev->d_pflags; 9161816cb70SBarry Harding port->p_ppa = ddi_get_instance(dev->d_dip) + (port->p_port * 100); 9171816cb70SBarry Harding 9181816cb70SBarry Harding port->p_tx_buf = kmem_zalloc(sizeof (yge_buf_t) * YGE_TX_RING_CNT, 9191816cb70SBarry Harding KM_SLEEP); 9201816cb70SBarry Harding port->p_rx_buf = kmem_zalloc(sizeof (yge_buf_t) * YGE_RX_RING_CNT, 9211816cb70SBarry Harding KM_SLEEP); 9221816cb70SBarry Harding 9231816cb70SBarry Harding /* Setup Tx/Rx queue register offsets. */ 9241816cb70SBarry Harding if (port->p_port == YGE_PORT_A) { 9251816cb70SBarry Harding port->p_txq = Q_XA1; 9261816cb70SBarry Harding port->p_txsq = Q_XS1; 9271816cb70SBarry Harding port->p_rxq = Q_R1; 9281816cb70SBarry Harding } else { 9291816cb70SBarry Harding port->p_txq = Q_XA2; 9301816cb70SBarry Harding port->p_txsq = Q_XS2; 9311816cb70SBarry Harding port->p_rxq = Q_R2; 9321816cb70SBarry Harding } 9331816cb70SBarry Harding 9341816cb70SBarry Harding /* Disable jumbo frame for Yukon FE. */ 9351816cb70SBarry Harding if (dev->d_hw_id == CHIP_ID_YUKON_FE) 9361816cb70SBarry Harding port->p_flags |= PORT_FLAG_NOJUMBO; 9371816cb70SBarry Harding 9381816cb70SBarry Harding /* 9391816cb70SBarry Harding * Start out assuming a regular MTU. Users can change this 9401816cb70SBarry Harding * with dladm. The dladm daemon is supposed to issue commands 9411816cb70SBarry Harding * to change the default MTU using m_setprop during early boot 9421816cb70SBarry Harding * (before the interface is plumbed) if the user has so 9431816cb70SBarry Harding * requested. 9441816cb70SBarry Harding */ 9451816cb70SBarry Harding port->p_mtu = ETHERMTU; 9461816cb70SBarry Harding 9471816cb70SBarry Harding port->p_mii = mii_alloc(port, dev->d_dip, &yge_mii_ops); 9481816cb70SBarry Harding if (port->p_mii == NULL) { 9491816cb70SBarry Harding yge_error(NULL, port, "MII handle allocation failed"); 9501816cb70SBarry Harding return (DDI_FAILURE); 9511816cb70SBarry Harding } 9521816cb70SBarry Harding /* We assume all parts support asymmetric pause */ 9531816cb70SBarry Harding mii_set_pauseable(port->p_mii, B_TRUE, B_TRUE); 9541816cb70SBarry Harding 9551816cb70SBarry Harding /* 9561816cb70SBarry Harding * Get station address for this interface. Note that 9571816cb70SBarry Harding * dual port cards actually come with three station 9581816cb70SBarry Harding * addresses: one for each port, plus an extra. The 9591816cb70SBarry Harding * extra one is used by the SysKonnect driver software 9601816cb70SBarry Harding * as a 'virtual' station address for when both ports 9611816cb70SBarry Harding * are operating in failover mode. Currently we don't 9621816cb70SBarry Harding * use this extra address. 9631816cb70SBarry Harding */ 9641816cb70SBarry Harding for (i = 0; i < ETHERADDRL; i++) { 9651816cb70SBarry Harding port->p_curraddr[i] = 9661816cb70SBarry Harding CSR_READ_1(dev, B2_MAC_1 + (port->p_port * 8) + i); 9671816cb70SBarry Harding } 9681816cb70SBarry Harding 9691816cb70SBarry Harding /* Register with Nemo. */ 9701816cb70SBarry Harding if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 9711816cb70SBarry Harding yge_error(NULL, port, "MAC handle allocation failed"); 9721816cb70SBarry Harding return (DDI_FAILURE); 9731816cb70SBarry Harding } 9741816cb70SBarry Harding macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 9751816cb70SBarry Harding macp->m_driver = port; 9761816cb70SBarry Harding macp->m_dip = dev->d_dip; 9771816cb70SBarry Harding macp->m_src_addr = port->p_curraddr; 9781816cb70SBarry Harding macp->m_callbacks = &yge_m_callbacks; 9791816cb70SBarry Harding macp->m_min_sdu = 0; 9801816cb70SBarry Harding macp->m_max_sdu = port->p_mtu; 9811816cb70SBarry Harding macp->m_instance = port->p_ppa; 9821816cb70SBarry Harding macp->m_margin = VLAN_TAGSZ; 9831816cb70SBarry Harding 9841816cb70SBarry Harding port->p_mreg = macp; 9851816cb70SBarry Harding 9861816cb70SBarry Harding return (DDI_SUCCESS); 9871816cb70SBarry Harding } 9881816cb70SBarry Harding 9891816cb70SBarry Harding static int 9901816cb70SBarry Harding yge_add_intr(yge_dev_t *dev, int intr_type) 9911816cb70SBarry Harding { 9921816cb70SBarry Harding dev_info_t *dip; 9931816cb70SBarry Harding int count; 9941816cb70SBarry Harding int actual; 9951816cb70SBarry Harding int rv; 9961816cb70SBarry Harding int i, j; 9971816cb70SBarry Harding 9981816cb70SBarry Harding dip = dev->d_dip; 9991816cb70SBarry Harding 10001816cb70SBarry Harding rv = ddi_intr_get_nintrs(dip, intr_type, &count); 10011816cb70SBarry Harding if ((rv != DDI_SUCCESS) || (count == 0)) { 10021816cb70SBarry Harding yge_error(dev, NULL, 10031816cb70SBarry Harding "ddi_intr_get_nintrs failed, rv %d, count %d", rv, count); 10041816cb70SBarry Harding return (DDI_FAILURE); 10051816cb70SBarry Harding } 10061816cb70SBarry Harding 10071816cb70SBarry Harding /* 10081816cb70SBarry Harding * Allocate the interrupt. Note that we only bother with a single 10091816cb70SBarry Harding * interrupt. One could argue that for MSI devices with dual ports, 10101816cb70SBarry Harding * it would be nice to have a separate interrupt per port. But right 10111816cb70SBarry Harding * now I don't know how to configure that, so we'll just settle for 10121816cb70SBarry Harding * a single interrupt. 10131816cb70SBarry Harding */ 10141816cb70SBarry Harding dev->d_intrcnt = 1; 10151816cb70SBarry Harding 10161816cb70SBarry Harding dev->d_intrsize = count * sizeof (ddi_intr_handle_t); 10171816cb70SBarry Harding dev->d_intrh = kmem_zalloc(dev->d_intrsize, KM_SLEEP); 10181816cb70SBarry Harding if (dev->d_intrh == NULL) { 10191816cb70SBarry Harding yge_error(dev, NULL, "Unable to allocate interrupt handle"); 10201816cb70SBarry Harding return (DDI_FAILURE); 10211816cb70SBarry Harding } 10221816cb70SBarry Harding 10231816cb70SBarry Harding rv = ddi_intr_alloc(dip, dev->d_intrh, intr_type, 0, dev->d_intrcnt, 10241816cb70SBarry Harding &actual, DDI_INTR_ALLOC_STRICT); 10251816cb70SBarry Harding if ((rv != DDI_SUCCESS) || (actual == 0)) { 10261816cb70SBarry Harding yge_error(dev, NULL, 10271816cb70SBarry Harding "Unable to allocate interrupt, %d, count %d", 10281816cb70SBarry Harding rv, actual); 10291816cb70SBarry Harding kmem_free(dev->d_intrh, dev->d_intrsize); 10301816cb70SBarry Harding return (DDI_FAILURE); 10311816cb70SBarry Harding } 10321816cb70SBarry Harding 10331816cb70SBarry Harding if ((rv = ddi_intr_get_pri(dev->d_intrh[0], &dev->d_intrpri)) != 10341816cb70SBarry Harding DDI_SUCCESS) { 10351816cb70SBarry Harding for (i = 0; i < dev->d_intrcnt; i++) 10361816cb70SBarry Harding (void) ddi_intr_free(dev->d_intrh[i]); 10371816cb70SBarry Harding yge_error(dev, NULL, 10381816cb70SBarry Harding "Unable to get interrupt priority, %d", rv); 10391816cb70SBarry Harding kmem_free(dev->d_intrh, dev->d_intrsize); 10401816cb70SBarry Harding return (DDI_FAILURE); 10411816cb70SBarry Harding } 10421816cb70SBarry Harding 10431816cb70SBarry Harding if ((rv = ddi_intr_get_cap(dev->d_intrh[0], &dev->d_intrcap)) != 10441816cb70SBarry Harding DDI_SUCCESS) { 10451816cb70SBarry Harding yge_error(dev, NULL, 10461816cb70SBarry Harding "Unable to get interrupt capabilities, %d", rv); 10471816cb70SBarry Harding for (i = 0; i < dev->d_intrcnt; i++) 10481816cb70SBarry Harding (void) ddi_intr_free(dev->d_intrh[i]); 10491816cb70SBarry Harding kmem_free(dev->d_intrh, dev->d_intrsize); 10501816cb70SBarry Harding return (DDI_FAILURE); 10511816cb70SBarry Harding } 10521816cb70SBarry Harding 10531816cb70SBarry Harding /* register interrupt handler to kernel */ 10541816cb70SBarry Harding for (i = 0; i < dev->d_intrcnt; i++) { 10551816cb70SBarry Harding if ((rv = ddi_intr_add_handler(dev->d_intrh[i], yge_intr, 10561816cb70SBarry Harding dev, NULL)) != DDI_SUCCESS) { 10571816cb70SBarry Harding yge_error(dev, NULL, 10581816cb70SBarry Harding "Unable to add interrupt handler, %d", rv); 10591816cb70SBarry Harding for (j = 0; j < i; j++) 10601816cb70SBarry Harding (void) ddi_intr_remove_handler(dev->d_intrh[j]); 10611816cb70SBarry Harding for (i = 0; i < dev->d_intrcnt; i++) 10621816cb70SBarry Harding (void) ddi_intr_free(dev->d_intrh[i]); 10631816cb70SBarry Harding kmem_free(dev->d_intrh, dev->d_intrsize); 10641816cb70SBarry Harding return (DDI_FAILURE); 10651816cb70SBarry Harding } 10661816cb70SBarry Harding } 10671816cb70SBarry Harding 10681816cb70SBarry Harding mutex_init(&dev->d_rxlock, NULL, MUTEX_DRIVER, 10691816cb70SBarry Harding DDI_INTR_PRI(dev->d_intrpri)); 10701816cb70SBarry Harding mutex_init(&dev->d_txlock, NULL, MUTEX_DRIVER, 10711816cb70SBarry Harding DDI_INTR_PRI(dev->d_intrpri)); 10721816cb70SBarry Harding mutex_init(&dev->d_phylock, NULL, MUTEX_DRIVER, 10731816cb70SBarry Harding DDI_INTR_PRI(dev->d_intrpri)); 10741816cb70SBarry Harding mutex_init(&dev->d_task_mtx, NULL, MUTEX_DRIVER, 10751816cb70SBarry Harding DDI_INTR_PRI(dev->d_intrpri)); 10761816cb70SBarry Harding 10771816cb70SBarry Harding return (DDI_SUCCESS); 10781816cb70SBarry Harding } 10791816cb70SBarry Harding 10801816cb70SBarry Harding static int 10811816cb70SBarry Harding yge_attach_intr(yge_dev_t *dev) 10821816cb70SBarry Harding { 10831816cb70SBarry Harding dev_info_t *dip = dev->d_dip; 10841816cb70SBarry Harding int intr_types; 10851816cb70SBarry Harding int rv; 10861816cb70SBarry Harding 10871816cb70SBarry Harding /* Allocate IRQ resources. */ 10881816cb70SBarry Harding rv = ddi_intr_get_supported_types(dip, &intr_types); 10891816cb70SBarry Harding if (rv != DDI_SUCCESS) { 10901816cb70SBarry Harding yge_error(dev, NULL, 10911816cb70SBarry Harding "Unable to determine supported interrupt types, %d", rv); 10921816cb70SBarry Harding return (DDI_FAILURE); 10931816cb70SBarry Harding } 10941816cb70SBarry Harding 10951816cb70SBarry Harding /* 10961816cb70SBarry Harding * We default to not supporting MSI. We've found some device 10971816cb70SBarry Harding * and motherboard combinations don't always work well with 10981816cb70SBarry Harding * MSI interrupts. Users may override this if they choose. 10991816cb70SBarry Harding */ 11001816cb70SBarry Harding if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "msi_enable", 0) == 0) { 11011816cb70SBarry Harding /* If msi disable property present, disable both msix/msi. */ 11021816cb70SBarry Harding if (intr_types & DDI_INTR_TYPE_FIXED) { 11031816cb70SBarry Harding intr_types &= ~(DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_MSIX); 11041816cb70SBarry Harding } 11051816cb70SBarry Harding } 11061816cb70SBarry Harding 11071816cb70SBarry Harding if (intr_types & DDI_INTR_TYPE_MSIX) { 11081816cb70SBarry Harding if ((rv = yge_add_intr(dev, DDI_INTR_TYPE_MSIX)) == 11091816cb70SBarry Harding DDI_SUCCESS) 11101816cb70SBarry Harding return (DDI_SUCCESS); 11111816cb70SBarry Harding } 11121816cb70SBarry Harding 11131816cb70SBarry Harding if (intr_types & DDI_INTR_TYPE_MSI) { 11141816cb70SBarry Harding if ((rv = yge_add_intr(dev, DDI_INTR_TYPE_MSI)) == 11151816cb70SBarry Harding DDI_SUCCESS) 11161816cb70SBarry Harding return (DDI_SUCCESS); 11171816cb70SBarry Harding } 11181816cb70SBarry Harding 11191816cb70SBarry Harding if (intr_types & DDI_INTR_TYPE_FIXED) { 11201816cb70SBarry Harding if ((rv = yge_add_intr(dev, DDI_INTR_TYPE_FIXED)) == 11211816cb70SBarry Harding DDI_SUCCESS) 11221816cb70SBarry Harding return (DDI_SUCCESS); 11231816cb70SBarry Harding } 11241816cb70SBarry Harding 11251816cb70SBarry Harding yge_error(dev, NULL, "Unable to configure any interrupts"); 11261816cb70SBarry Harding return (DDI_FAILURE); 11271816cb70SBarry Harding } 11281816cb70SBarry Harding 11291816cb70SBarry Harding static void 11301816cb70SBarry Harding yge_intr_enable(yge_dev_t *dev) 11311816cb70SBarry Harding { 11321816cb70SBarry Harding int i; 11331816cb70SBarry Harding if (dev->d_intrcap & DDI_INTR_FLAG_BLOCK) { 11341816cb70SBarry Harding /* Call ddi_intr_block_enable() for MSI interrupts */ 11351816cb70SBarry Harding (void) ddi_intr_block_enable(dev->d_intrh, dev->d_intrcnt); 11361816cb70SBarry Harding } else { 11371816cb70SBarry Harding /* Call ddi_intr_enable for FIXED interrupts */ 11381816cb70SBarry Harding for (i = 0; i < dev->d_intrcnt; i++) 11391816cb70SBarry Harding (void) ddi_intr_enable(dev->d_intrh[i]); 11401816cb70SBarry Harding } 11411816cb70SBarry Harding } 11421816cb70SBarry Harding 11431816cb70SBarry Harding void 11441816cb70SBarry Harding yge_intr_disable(yge_dev_t *dev) 11451816cb70SBarry Harding { 11461816cb70SBarry Harding int i; 11471816cb70SBarry Harding 11481816cb70SBarry Harding if (dev->d_intrcap & DDI_INTR_FLAG_BLOCK) { 11491816cb70SBarry Harding (void) ddi_intr_block_disable(dev->d_intrh, dev->d_intrcnt); 11501816cb70SBarry Harding } else { 11511816cb70SBarry Harding for (i = 0; i < dev->d_intrcnt; i++) 11521816cb70SBarry Harding (void) ddi_intr_disable(dev->d_intrh[i]); 11531816cb70SBarry Harding } 11541816cb70SBarry Harding } 11551816cb70SBarry Harding 11561816cb70SBarry Harding static uint8_t 11571816cb70SBarry Harding yge_find_capability(yge_dev_t *dev, uint8_t cap) 11581816cb70SBarry Harding { 11591816cb70SBarry Harding uint8_t ptr; 11601816cb70SBarry Harding uint16_t capit; 11611816cb70SBarry Harding ddi_acc_handle_t pcih = dev->d_pcih; 11621816cb70SBarry Harding 11631816cb70SBarry Harding if ((pci_config_get16(pcih, PCI_CONF_STAT) & PCI_STAT_CAP) == 0) { 11641816cb70SBarry Harding return (0); 11651816cb70SBarry Harding } 11661816cb70SBarry Harding /* This assumes PCI, and not CardBus. */ 11671816cb70SBarry Harding ptr = pci_config_get8(pcih, PCI_CONF_CAP_PTR); 11681816cb70SBarry Harding while (ptr != 0) { 11691816cb70SBarry Harding capit = pci_config_get8(pcih, ptr + PCI_CAP_ID); 11701816cb70SBarry Harding if (capit == cap) { 11711816cb70SBarry Harding return (ptr); 11721816cb70SBarry Harding } 11731816cb70SBarry Harding ptr = pci_config_get8(pcih, ptr + PCI_CAP_NEXT_PTR); 11741816cb70SBarry Harding } 11751816cb70SBarry Harding return (0); 11761816cb70SBarry Harding } 11771816cb70SBarry Harding 11781816cb70SBarry Harding static int 11791816cb70SBarry Harding yge_attach(yge_dev_t *dev) 11801816cb70SBarry Harding { 11811816cb70SBarry Harding dev_info_t *dip = dev->d_dip; 11821816cb70SBarry Harding int rv; 11831816cb70SBarry Harding int nattached; 11841816cb70SBarry Harding uint8_t pm_cap; 11851816cb70SBarry Harding 11861816cb70SBarry Harding if (pci_config_setup(dip, &dev->d_pcih) != DDI_SUCCESS) { 11871816cb70SBarry Harding yge_error(dev, NULL, "Unable to map PCI configuration space"); 11881816cb70SBarry Harding goto fail; 11891816cb70SBarry Harding } 11901816cb70SBarry Harding 11911816cb70SBarry Harding /* 11921816cb70SBarry Harding * Map control/status registers. 11931816cb70SBarry Harding */ 11941816cb70SBarry Harding 11951816cb70SBarry Harding /* ensure the pmcsr status is D0 state */ 11961816cb70SBarry Harding pm_cap = yge_find_capability(dev, PCI_CAP_ID_PM); 11971816cb70SBarry Harding if (pm_cap != 0) { 11981816cb70SBarry Harding uint16_t pmcsr; 11991816cb70SBarry Harding pmcsr = pci_config_get16(dev->d_pcih, pm_cap + PCI_PMCSR); 12001816cb70SBarry Harding pmcsr &= ~PCI_PMCSR_STATE_MASK; 12011816cb70SBarry Harding pci_config_put16(dev->d_pcih, pm_cap + PCI_PMCSR, 12021816cb70SBarry Harding pmcsr | PCI_PMCSR_D0); 12031816cb70SBarry Harding } 12041816cb70SBarry Harding 12051816cb70SBarry Harding /* Enable PCI access and bus master. */ 12061816cb70SBarry Harding pci_config_put16(dev->d_pcih, PCI_CONF_COMM, 12071816cb70SBarry Harding pci_config_get16(dev->d_pcih, PCI_CONF_COMM) | 12081816cb70SBarry Harding PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME); 12091816cb70SBarry Harding 12101816cb70SBarry Harding 12111816cb70SBarry Harding /* Allocate I/O resource */ 12121816cb70SBarry Harding rv = ddi_regs_map_setup(dip, 1, &dev->d_regs, 0, 0, &yge_regs_attr, 12131816cb70SBarry Harding &dev->d_regsh); 12141816cb70SBarry Harding if (rv != DDI_SUCCESS) { 12151816cb70SBarry Harding yge_error(dev, NULL, "Unable to map device registers"); 12161816cb70SBarry Harding goto fail; 12171816cb70SBarry Harding } 12181816cb70SBarry Harding 12191816cb70SBarry Harding 12201816cb70SBarry Harding /* Enable all clocks. */ 12211816cb70SBarry Harding CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_ON); 12221816cb70SBarry Harding pci_config_put32(dev->d_pcih, PCI_OUR_REG_3, 0); 12231816cb70SBarry Harding CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 12241816cb70SBarry Harding 12251816cb70SBarry Harding CSR_WRITE_2(dev, B0_CTST, CS_RST_CLR); 12261816cb70SBarry Harding dev->d_hw_id = CSR_READ_1(dev, B2_CHIP_ID); 12271816cb70SBarry Harding dev->d_hw_rev = (CSR_READ_1(dev, B2_MAC_CFG) >> 4) & 0x0f; 12281816cb70SBarry Harding 12291816cb70SBarry Harding 12301816cb70SBarry Harding /* 12311816cb70SBarry Harding * Bail out if chip is not recognized. Note that we only enforce 12321816cb70SBarry Harding * this in production builds. The Ultra-2 (88e8057) has a problem 12331816cb70SBarry Harding * right now where TX works fine, but RX seems not to. So we've 12341816cb70SBarry Harding * disabled that for now. 12351816cb70SBarry Harding */ 12361816cb70SBarry Harding if (dev->d_hw_id < CHIP_ID_YUKON_XL || 12371816cb70SBarry Harding dev->d_hw_id >= CHIP_ID_YUKON_UL_2) { 12381816cb70SBarry Harding yge_error(dev, NULL, "Unknown device: id=0x%02x, rev=0x%02x", 12391816cb70SBarry Harding dev->d_hw_id, dev->d_hw_rev); 12401816cb70SBarry Harding #ifndef DEBUG 12411816cb70SBarry Harding goto fail; 12421816cb70SBarry Harding #endif 12431816cb70SBarry Harding } 12441816cb70SBarry Harding 12451816cb70SBarry Harding /* Soft reset. */ 12461816cb70SBarry Harding CSR_WRITE_2(dev, B0_CTST, CS_RST_SET); 12471816cb70SBarry Harding CSR_WRITE_2(dev, B0_CTST, CS_RST_CLR); 12481816cb70SBarry Harding dev->d_pmd = CSR_READ_1(dev, B2_PMD_TYP); 12491816cb70SBarry Harding if (dev->d_pmd == 'L' || dev->d_pmd == 'S' || dev->d_pmd == 'P') 12501816cb70SBarry Harding dev->d_coppertype = 0; 12511816cb70SBarry Harding else 12521816cb70SBarry Harding dev->d_coppertype = 1; 12531816cb70SBarry Harding /* Check number of MACs. */ 12541816cb70SBarry Harding dev->d_num_port = 1; 12551816cb70SBarry Harding if ((CSR_READ_1(dev, B2_Y2_HW_RES) & CFG_DUAL_MAC_MSK) == 12561816cb70SBarry Harding CFG_DUAL_MAC_MSK) { 12571816cb70SBarry Harding if (!(CSR_READ_1(dev, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC)) 12581816cb70SBarry Harding dev->d_num_port++; 12591816cb70SBarry Harding } 12601816cb70SBarry Harding 12611816cb70SBarry Harding /* Check bus type. */ 12621816cb70SBarry Harding if (yge_find_capability(dev, PCI_CAP_ID_PCI_E) != 0) { 12631816cb70SBarry Harding dev->d_bustype = PEX_BUS; 12641816cb70SBarry Harding } else if (yge_find_capability(dev, PCI_CAP_ID_PCIX) != 0) { 12651816cb70SBarry Harding dev->d_bustype = PCIX_BUS; 12661816cb70SBarry Harding } else { 12671816cb70SBarry Harding dev->d_bustype = PCI_BUS; 12681816cb70SBarry Harding } 12691816cb70SBarry Harding 12701816cb70SBarry Harding switch (dev->d_hw_id) { 12711816cb70SBarry Harding case CHIP_ID_YUKON_EC: 12721816cb70SBarry Harding dev->d_clock = 125; /* 125 Mhz */ 12731816cb70SBarry Harding break; 12741816cb70SBarry Harding case CHIP_ID_YUKON_UL_2: 12751816cb70SBarry Harding dev->d_clock = 125; /* 125 Mhz */ 12761816cb70SBarry Harding break; 12771816cb70SBarry Harding case CHIP_ID_YUKON_SUPR: 12781816cb70SBarry Harding dev->d_clock = 125; /* 125 Mhz */ 12791816cb70SBarry Harding break; 12801816cb70SBarry Harding case CHIP_ID_YUKON_EC_U: 12811816cb70SBarry Harding dev->d_clock = 125; /* 125 Mhz */ 12821816cb70SBarry Harding break; 12831816cb70SBarry Harding case CHIP_ID_YUKON_EX: 12841816cb70SBarry Harding dev->d_clock = 125; /* 125 Mhz */ 12851816cb70SBarry Harding break; 12861816cb70SBarry Harding case CHIP_ID_YUKON_FE: 12871816cb70SBarry Harding dev->d_clock = 100; /* 100 Mhz */ 12881816cb70SBarry Harding break; 12891816cb70SBarry Harding case CHIP_ID_YUKON_FE_P: 12901816cb70SBarry Harding dev->d_clock = 50; /* 50 Mhz */ 12911816cb70SBarry Harding break; 12921816cb70SBarry Harding case CHIP_ID_YUKON_XL: 12931816cb70SBarry Harding dev->d_clock = 156; /* 156 Mhz */ 12941816cb70SBarry Harding break; 12951816cb70SBarry Harding default: 12961816cb70SBarry Harding dev->d_clock = 156; /* 156 Mhz */ 12971816cb70SBarry Harding break; 12981816cb70SBarry Harding } 12991816cb70SBarry Harding 13001816cb70SBarry Harding dev->d_process_limit = YGE_RX_RING_CNT/2; 13011816cb70SBarry Harding 13021816cb70SBarry Harding rv = yge_alloc_ring(NULL, dev, &dev->d_status_ring, YGE_STAT_RING_CNT); 13031816cb70SBarry Harding if (rv != DDI_SUCCESS) 13041816cb70SBarry Harding goto fail; 13051816cb70SBarry Harding 13061816cb70SBarry Harding /* Setup event taskq. */ 13071816cb70SBarry Harding dev->d_task_q = ddi_taskq_create(dip, "tq", 1, TASKQ_DEFAULTPRI, 0); 13081816cb70SBarry Harding if (dev->d_task_q == NULL) { 13091816cb70SBarry Harding yge_error(dev, NULL, "failed to create taskq"); 13101816cb70SBarry Harding goto fail; 13111816cb70SBarry Harding } 13121816cb70SBarry Harding 13131816cb70SBarry Harding /* Init the condition variable */ 13141816cb70SBarry Harding cv_init(&dev->d_task_cv, NULL, CV_DRIVER, NULL); 13151816cb70SBarry Harding 13161816cb70SBarry Harding /* Allocate IRQ resources. */ 13171816cb70SBarry Harding if ((rv = yge_attach_intr(dev)) != DDI_SUCCESS) { 13181816cb70SBarry Harding goto fail; 13191816cb70SBarry Harding } 13201816cb70SBarry Harding 13211816cb70SBarry Harding /* Set base interrupt mask. */ 13221816cb70SBarry Harding dev->d_intrmask = Y2_IS_HW_ERR | Y2_IS_STAT_BMU; 13231816cb70SBarry Harding dev->d_intrhwemask = Y2_IS_TIST_OV | Y2_IS_MST_ERR | 13241816cb70SBarry Harding Y2_IS_IRQ_STAT | Y2_IS_PCI_EXP | Y2_IS_PCI_NEXP; 13251816cb70SBarry Harding 13261816cb70SBarry Harding /* Reset the adapter. */ 13271816cb70SBarry Harding yge_reset(dev); 13281816cb70SBarry Harding 13291816cb70SBarry Harding yge_setup_rambuffer(dev); 13301816cb70SBarry Harding 13311816cb70SBarry Harding nattached = 0; 13321816cb70SBarry Harding for (int i = 0; i < dev->d_num_port; i++) { 13331816cb70SBarry Harding yge_port_t *port = dev->d_port[i]; 13341816cb70SBarry Harding if (yge_init_port(port) != DDI_SUCCESS) { 13351816cb70SBarry Harding goto fail; 13361816cb70SBarry Harding } 13371816cb70SBarry Harding } 13381816cb70SBarry Harding 13391816cb70SBarry Harding yge_intr_enable(dev); 13401816cb70SBarry Harding 13411816cb70SBarry Harding /* set up the periodic to run once per second */ 13421816cb70SBarry Harding dev->d_periodic = ddi_periodic_add(yge_tick, dev, 1000000000, 0); 13431816cb70SBarry Harding 13441816cb70SBarry Harding for (int i = 0; i < dev->d_num_port; i++) { 13451816cb70SBarry Harding yge_port_t *port = dev->d_port[i]; 13461816cb70SBarry Harding if (yge_register_port(port) == DDI_SUCCESS) { 13471816cb70SBarry Harding nattached++; 13481816cb70SBarry Harding } 13491816cb70SBarry Harding } 13501816cb70SBarry Harding 13511816cb70SBarry Harding if (nattached == 0) { 13521816cb70SBarry Harding goto fail; 13531816cb70SBarry Harding } 13541816cb70SBarry Harding 13551816cb70SBarry Harding /* Dispatch the taskq */ 13561816cb70SBarry Harding if (ddi_taskq_dispatch(dev->d_task_q, yge_task, dev, DDI_SLEEP) != 13571816cb70SBarry Harding DDI_SUCCESS) { 13581816cb70SBarry Harding yge_error(dev, NULL, "failed to start taskq"); 13591816cb70SBarry Harding goto fail; 13601816cb70SBarry Harding } 13611816cb70SBarry Harding 13621816cb70SBarry Harding ddi_report_dev(dip); 13631816cb70SBarry Harding 13641816cb70SBarry Harding return (DDI_SUCCESS); 13651816cb70SBarry Harding 13661816cb70SBarry Harding fail: 13671816cb70SBarry Harding yge_detach(dev); 13681816cb70SBarry Harding return (DDI_FAILURE); 13691816cb70SBarry Harding } 13701816cb70SBarry Harding 13711816cb70SBarry Harding static int 13721816cb70SBarry Harding yge_register_port(yge_port_t *port) 13731816cb70SBarry Harding { 13741816cb70SBarry Harding if (mac_register(port->p_mreg, &port->p_mh) != DDI_SUCCESS) { 13751816cb70SBarry Harding yge_error(NULL, port, "MAC registration failed"); 13761816cb70SBarry Harding return (DDI_FAILURE); 13771816cb70SBarry Harding } 13781816cb70SBarry Harding 13791816cb70SBarry Harding return (DDI_SUCCESS); 13801816cb70SBarry Harding } 13811816cb70SBarry Harding 13821816cb70SBarry Harding /* 13831816cb70SBarry Harding * Free up port specific resources. This is called only when the 13841816cb70SBarry Harding * port is not registered (and hence not running). 13851816cb70SBarry Harding */ 13861816cb70SBarry Harding static void 13871816cb70SBarry Harding yge_uninit_port(yge_port_t *port) 13881816cb70SBarry Harding { 13891816cb70SBarry Harding ASSERT(!port->p_running); 13901816cb70SBarry Harding 13911816cb70SBarry Harding if (port->p_mreg) 13921816cb70SBarry Harding mac_free(port->p_mreg); 13931816cb70SBarry Harding 13941816cb70SBarry Harding if (port->p_mii) 13951816cb70SBarry Harding mii_free(port->p_mii); 13961816cb70SBarry Harding 13971816cb70SBarry Harding yge_txrx_dma_free(port); 13981816cb70SBarry Harding 13991816cb70SBarry Harding if (port->p_tx_buf) 14001816cb70SBarry Harding kmem_free(port->p_tx_buf, 14011816cb70SBarry Harding sizeof (yge_buf_t) * YGE_TX_RING_CNT); 14021816cb70SBarry Harding if (port->p_rx_buf) 14031816cb70SBarry Harding kmem_free(port->p_rx_buf, 14041816cb70SBarry Harding sizeof (yge_buf_t) * YGE_RX_RING_CNT); 14051816cb70SBarry Harding } 14061816cb70SBarry Harding 14071816cb70SBarry Harding static void 14081816cb70SBarry Harding yge_detach(yge_dev_t *dev) 14091816cb70SBarry Harding { 14101816cb70SBarry Harding /* 14111816cb70SBarry Harding * Turn off the periodic. 14121816cb70SBarry Harding */ 14131816cb70SBarry Harding if (dev->d_periodic) 14141816cb70SBarry Harding ddi_periodic_delete(dev->d_periodic); 14151816cb70SBarry Harding 14161816cb70SBarry Harding for (int i = 0; i < dev->d_num_port; i++) { 14171816cb70SBarry Harding yge_uninit_port(dev->d_port[i]); 14181816cb70SBarry Harding } 14191816cb70SBarry Harding 14201816cb70SBarry Harding /* 14211816cb70SBarry Harding * Make sure all interrupts are disabled. 14221816cb70SBarry Harding */ 14231816cb70SBarry Harding CSR_WRITE_4(dev, B0_IMSK, 0); 14241816cb70SBarry Harding (void) CSR_READ_4(dev, B0_IMSK); 14251816cb70SBarry Harding CSR_WRITE_4(dev, B0_HWE_IMSK, 0); 14261816cb70SBarry Harding (void) CSR_READ_4(dev, B0_HWE_IMSK); 14271816cb70SBarry Harding 14281816cb70SBarry Harding /* LED Off. */ 14291816cb70SBarry Harding CSR_WRITE_2(dev, B0_CTST, Y2_LED_STAT_OFF); 14301816cb70SBarry Harding 14311816cb70SBarry Harding /* Put hardware reset. */ 14321816cb70SBarry Harding CSR_WRITE_2(dev, B0_CTST, CS_RST_SET); 14331816cb70SBarry Harding 14341816cb70SBarry Harding yge_free_ring(&dev->d_status_ring); 14351816cb70SBarry Harding 14361816cb70SBarry Harding if (dev->d_task_q != NULL) { 14371816cb70SBarry Harding yge_dispatch(dev, YGE_TASK_EXIT); 14381816cb70SBarry Harding ddi_taskq_destroy(dev->d_task_q); 14391816cb70SBarry Harding dev->d_task_q = NULL; 14401816cb70SBarry Harding } 14411816cb70SBarry Harding 14421816cb70SBarry Harding cv_destroy(&dev->d_task_cv); 14431816cb70SBarry Harding 14441816cb70SBarry Harding yge_intr_disable(dev); 14451816cb70SBarry Harding 14461816cb70SBarry Harding if (dev->d_intrh != NULL) { 14471816cb70SBarry Harding for (int i = 0; i < dev->d_intrcnt; i++) { 14481816cb70SBarry Harding (void) ddi_intr_remove_handler(dev->d_intrh[i]); 14491816cb70SBarry Harding (void) ddi_intr_free(dev->d_intrh[i]); 14501816cb70SBarry Harding } 14511816cb70SBarry Harding kmem_free(dev->d_intrh, dev->d_intrsize); 14521816cb70SBarry Harding mutex_destroy(&dev->d_phylock); 14531816cb70SBarry Harding mutex_destroy(&dev->d_txlock); 14541816cb70SBarry Harding mutex_destroy(&dev->d_rxlock); 14551816cb70SBarry Harding mutex_destroy(&dev->d_task_mtx); 14561816cb70SBarry Harding } 14571816cb70SBarry Harding if (dev->d_regsh != NULL) 14581816cb70SBarry Harding ddi_regs_map_free(&dev->d_regsh); 14591816cb70SBarry Harding 14601816cb70SBarry Harding if (dev->d_pcih != NULL) 14611816cb70SBarry Harding pci_config_teardown(&dev->d_pcih); 14621816cb70SBarry Harding } 14631816cb70SBarry Harding 14641816cb70SBarry Harding static int 14651816cb70SBarry Harding yge_alloc_ring(yge_port_t *port, yge_dev_t *dev, yge_ring_t *ring, uint32_t num) 14661816cb70SBarry Harding { 14671816cb70SBarry Harding dev_info_t *dip; 14681816cb70SBarry Harding caddr_t kaddr; 14691816cb70SBarry Harding size_t len; 14701816cb70SBarry Harding int rv; 14711816cb70SBarry Harding ddi_dma_cookie_t dmac; 14721816cb70SBarry Harding unsigned ndmac; 14731816cb70SBarry Harding 14741816cb70SBarry Harding if (port && !dev) 14751816cb70SBarry Harding dev = port->p_dev; 14761816cb70SBarry Harding dip = dev->d_dip; 14771816cb70SBarry Harding 14781816cb70SBarry Harding ring->r_num = num; 14791816cb70SBarry Harding 14801816cb70SBarry Harding rv = ddi_dma_alloc_handle(dip, &yge_ring_dma_attr, DDI_DMA_DONTWAIT, 14811816cb70SBarry Harding NULL, &ring->r_dmah); 14821816cb70SBarry Harding if (rv != DDI_SUCCESS) { 14831816cb70SBarry Harding yge_error(dev, port, "Unable to allocate ring DMA handle"); 14841816cb70SBarry Harding return (DDI_FAILURE); 14851816cb70SBarry Harding } 14861816cb70SBarry Harding 14871816cb70SBarry Harding rv = ddi_dma_mem_alloc(ring->r_dmah, num * sizeof (yge_desc_t), 14881816cb70SBarry Harding &yge_ring_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 14891816cb70SBarry Harding &kaddr, &len, &ring->r_acch); 14901816cb70SBarry Harding if (rv != DDI_SUCCESS) { 14911816cb70SBarry Harding yge_error(dev, port, "Unable to allocate ring DMA memory"); 14921816cb70SBarry Harding return (DDI_FAILURE); 14931816cb70SBarry Harding } 14941816cb70SBarry Harding ring->r_size = len; 14951816cb70SBarry Harding ring->r_kaddr = (void *)kaddr; 14961816cb70SBarry Harding 14971816cb70SBarry Harding bzero(kaddr, len); 14981816cb70SBarry Harding 14991816cb70SBarry Harding rv = ddi_dma_addr_bind_handle(ring->r_dmah, NULL, kaddr, 15001816cb70SBarry Harding len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 15011816cb70SBarry Harding &dmac, &ndmac); 15021816cb70SBarry Harding if (rv != DDI_DMA_MAPPED) { 15031816cb70SBarry Harding yge_error(dev, port, "Unable to bind ring DMA handle"); 15041816cb70SBarry Harding return (DDI_FAILURE); 15051816cb70SBarry Harding } 15061816cb70SBarry Harding ASSERT(ndmac == 1); 15071816cb70SBarry Harding ring->r_paddr = dmac.dmac_address; 15081816cb70SBarry Harding 15091816cb70SBarry Harding return (DDI_SUCCESS); 15101816cb70SBarry Harding } 15111816cb70SBarry Harding 15121816cb70SBarry Harding static void 15131816cb70SBarry Harding yge_free_ring(yge_ring_t *ring) 15141816cb70SBarry Harding { 15151816cb70SBarry Harding if (ring->r_paddr) 15161816cb70SBarry Harding (void) ddi_dma_unbind_handle(ring->r_dmah); 15171816cb70SBarry Harding ring->r_paddr = 0; 15181816cb70SBarry Harding if (ring->r_acch) 15191816cb70SBarry Harding ddi_dma_mem_free(&ring->r_acch); 15201816cb70SBarry Harding ring->r_kaddr = NULL; 15211816cb70SBarry Harding ring->r_acch = NULL; 15221816cb70SBarry Harding if (ring->r_dmah) 15231816cb70SBarry Harding ddi_dma_free_handle(&ring->r_dmah); 15241816cb70SBarry Harding ring->r_dmah = NULL; 15251816cb70SBarry Harding } 15261816cb70SBarry Harding 15271816cb70SBarry Harding static int 15281816cb70SBarry Harding yge_alloc_buf(yge_port_t *port, yge_buf_t *b, size_t bufsz, int flag) 15291816cb70SBarry Harding { 15301816cb70SBarry Harding yge_dev_t *dev = port->p_dev; 15311816cb70SBarry Harding size_t l; 15321816cb70SBarry Harding int sflag; 15331816cb70SBarry Harding int rv; 15341816cb70SBarry Harding ddi_dma_cookie_t dmac; 15351816cb70SBarry Harding unsigned ndmac; 15361816cb70SBarry Harding 15371816cb70SBarry Harding sflag = flag & (DDI_DMA_STREAMING | DDI_DMA_CONSISTENT); 15381816cb70SBarry Harding 15391816cb70SBarry Harding /* Now allocate Tx buffers. */ 15401816cb70SBarry Harding rv = ddi_dma_alloc_handle(dev->d_dip, &yge_buf_dma_attr, 15411816cb70SBarry Harding DDI_DMA_DONTWAIT, NULL, &b->b_dmah); 15421816cb70SBarry Harding if (rv != DDI_SUCCESS) { 15431816cb70SBarry Harding yge_error(NULL, port, "Unable to alloc DMA handle for buffer"); 15441816cb70SBarry Harding return (DDI_FAILURE); 15451816cb70SBarry Harding } 15461816cb70SBarry Harding 15471816cb70SBarry Harding rv = ddi_dma_mem_alloc(b->b_dmah, bufsz, &yge_buf_attr, 15481816cb70SBarry Harding sflag, DDI_DMA_DONTWAIT, NULL, &b->b_buf, &l, &b->b_acch); 15491816cb70SBarry Harding if (rv != DDI_SUCCESS) { 15501816cb70SBarry Harding yge_error(NULL, port, "Unable to alloc DMA memory for buffer"); 15511816cb70SBarry Harding return (DDI_FAILURE); 15521816cb70SBarry Harding } 15531816cb70SBarry Harding 15541816cb70SBarry Harding rv = ddi_dma_addr_bind_handle(b->b_dmah, NULL, b->b_buf, l, flag, 15551816cb70SBarry Harding DDI_DMA_DONTWAIT, NULL, &dmac, &ndmac); 15561816cb70SBarry Harding if (rv != DDI_DMA_MAPPED) { 15571816cb70SBarry Harding yge_error(NULL, port, "Unable to bind DMA handle for buffer"); 15581816cb70SBarry Harding return (DDI_FAILURE); 15591816cb70SBarry Harding } 15601816cb70SBarry Harding ASSERT(ndmac == 1); 15611816cb70SBarry Harding b->b_paddr = dmac.dmac_address; 15621816cb70SBarry Harding return (DDI_SUCCESS); 15631816cb70SBarry Harding } 15641816cb70SBarry Harding 15651816cb70SBarry Harding static void 15661816cb70SBarry Harding yge_free_buf(yge_buf_t *b) 15671816cb70SBarry Harding { 15681816cb70SBarry Harding if (b->b_paddr) 15691816cb70SBarry Harding (void) ddi_dma_unbind_handle(b->b_dmah); 15701816cb70SBarry Harding b->b_paddr = 0; 15711816cb70SBarry Harding if (b->b_acch) 15721816cb70SBarry Harding ddi_dma_mem_free(&b->b_acch); 15731816cb70SBarry Harding b->b_buf = NULL; 15741816cb70SBarry Harding b->b_acch = NULL; 15751816cb70SBarry Harding if (b->b_dmah) 15761816cb70SBarry Harding ddi_dma_free_handle(&b->b_dmah); 15771816cb70SBarry Harding b->b_dmah = NULL; 15781816cb70SBarry Harding } 15791816cb70SBarry Harding 15801816cb70SBarry Harding static int 15811816cb70SBarry Harding yge_txrx_dma_alloc(yge_port_t *port) 15821816cb70SBarry Harding { 15831816cb70SBarry Harding uint32_t bufsz; 15841816cb70SBarry Harding int rv; 15851816cb70SBarry Harding int i; 15861816cb70SBarry Harding yge_buf_t *b; 15871816cb70SBarry Harding 15881816cb70SBarry Harding /* 15891816cb70SBarry Harding * It seems that Yukon II supports full 64 bit DMA operations. 15901816cb70SBarry Harding * But we limit it to 32 bits only for now. The 64 bit 15911816cb70SBarry Harding * operation would require substantially more complex 15921816cb70SBarry Harding * descriptor handling, since in such a case we would need two 15931816cb70SBarry Harding * LEs to represent a single physical address. 15941816cb70SBarry Harding * 15951816cb70SBarry Harding * If we find that this is limiting us, then we should go back 15961816cb70SBarry Harding * and re-examine it. 15971816cb70SBarry Harding */ 15981816cb70SBarry Harding 15991816cb70SBarry Harding /* Note our preferred buffer size. */ 16001816cb70SBarry Harding bufsz = port->p_mtu; 16011816cb70SBarry Harding 16021816cb70SBarry Harding /* Allocate Tx ring. */ 16031816cb70SBarry Harding rv = yge_alloc_ring(port, NULL, &port->p_tx_ring, YGE_TX_RING_CNT); 16041816cb70SBarry Harding if (rv != DDI_SUCCESS) { 16051816cb70SBarry Harding return (DDI_FAILURE); 16061816cb70SBarry Harding } 16071816cb70SBarry Harding 16081816cb70SBarry Harding /* Now allocate Tx buffers. */ 16091816cb70SBarry Harding b = port->p_tx_buf; 16101816cb70SBarry Harding for (i = 0; i < YGE_TX_RING_CNT; i++) { 16111816cb70SBarry Harding rv = yge_alloc_buf(port, b, bufsz, 16121816cb70SBarry Harding DDI_DMA_STREAMING | DDI_DMA_WRITE); 16131816cb70SBarry Harding if (rv != DDI_SUCCESS) { 16141816cb70SBarry Harding return (DDI_FAILURE); 16151816cb70SBarry Harding } 16161816cb70SBarry Harding b++; 16171816cb70SBarry Harding } 16181816cb70SBarry Harding 16191816cb70SBarry Harding /* Allocate Rx ring. */ 16201816cb70SBarry Harding rv = yge_alloc_ring(port, NULL, &port->p_rx_ring, YGE_RX_RING_CNT); 16211816cb70SBarry Harding if (rv != DDI_SUCCESS) { 16221816cb70SBarry Harding return (DDI_FAILURE); 16231816cb70SBarry Harding } 16241816cb70SBarry Harding 16251816cb70SBarry Harding /* Now allocate Rx buffers. */ 16261816cb70SBarry Harding b = port->p_rx_buf; 16271816cb70SBarry Harding for (i = 0; i < YGE_RX_RING_CNT; i++) { 16281816cb70SBarry Harding rv = yge_alloc_buf(port, b, bufsz, 16291816cb70SBarry Harding DDI_DMA_STREAMING | DDI_DMA_READ); 16301816cb70SBarry Harding if (rv != DDI_SUCCESS) { 16311816cb70SBarry Harding return (DDI_FAILURE); 16321816cb70SBarry Harding } 16331816cb70SBarry Harding b++; 16341816cb70SBarry Harding } 16351816cb70SBarry Harding 16361816cb70SBarry Harding return (DDI_SUCCESS); 16371816cb70SBarry Harding } 16381816cb70SBarry Harding 16391816cb70SBarry Harding static void 16401816cb70SBarry Harding yge_txrx_dma_free(yge_port_t *port) 16411816cb70SBarry Harding { 16421816cb70SBarry Harding yge_buf_t *b; 16431816cb70SBarry Harding 16441816cb70SBarry Harding /* Tx ring. */ 16451816cb70SBarry Harding yge_free_ring(&port->p_tx_ring); 16461816cb70SBarry Harding 16471816cb70SBarry Harding /* Rx ring. */ 16481816cb70SBarry Harding yge_free_ring(&port->p_rx_ring); 16491816cb70SBarry Harding 16501816cb70SBarry Harding /* Tx buffers. */ 16511816cb70SBarry Harding b = port->p_tx_buf; 16521816cb70SBarry Harding for (int i = 0; i < YGE_TX_RING_CNT; i++, b++) { 16531816cb70SBarry Harding yge_free_buf(b); 16541816cb70SBarry Harding } 16551816cb70SBarry Harding /* Rx buffers. */ 16561816cb70SBarry Harding b = port->p_rx_buf; 16571816cb70SBarry Harding for (int i = 0; i < YGE_RX_RING_CNT; i++, b++) { 16581816cb70SBarry Harding yge_free_buf(b); 16591816cb70SBarry Harding } 16601816cb70SBarry Harding } 16611816cb70SBarry Harding 16621816cb70SBarry Harding boolean_t 16631816cb70SBarry Harding yge_send(yge_port_t *port, mblk_t *mp) 16641816cb70SBarry Harding { 16651816cb70SBarry Harding yge_ring_t *ring = &port->p_tx_ring; 16661816cb70SBarry Harding yge_buf_t *txb; 16671816cb70SBarry Harding int16_t prod; 16681816cb70SBarry Harding size_t len; 16691816cb70SBarry Harding 16701816cb70SBarry Harding /* 16711816cb70SBarry Harding * For now we're not going to support checksum offload or LSO. 16721816cb70SBarry Harding */ 16731816cb70SBarry Harding 16741816cb70SBarry Harding len = msgsize(mp); 16751816cb70SBarry Harding if (len > port->p_framesize) { 16761816cb70SBarry Harding /* too big! */ 16771816cb70SBarry Harding freemsg(mp); 16781816cb70SBarry Harding return (B_TRUE); 16791816cb70SBarry Harding } 16801816cb70SBarry Harding 16811816cb70SBarry Harding /* Check number of available descriptors. */ 16821816cb70SBarry Harding if (port->p_tx_cnt + 1 >= 16831816cb70SBarry Harding (YGE_TX_RING_CNT - YGE_RESERVED_TX_DESC_CNT)) { 16841816cb70SBarry Harding port->p_wantw = B_TRUE; 16851816cb70SBarry Harding return (B_FALSE); 16861816cb70SBarry Harding } 16871816cb70SBarry Harding 16881816cb70SBarry Harding prod = port->p_tx_prod; 16891816cb70SBarry Harding 16901816cb70SBarry Harding txb = &port->p_tx_buf[prod]; 16911816cb70SBarry Harding mcopymsg(mp, txb->b_buf); 16921816cb70SBarry Harding SYNCBUF(txb, DDI_DMA_SYNC_FORDEV); 16931816cb70SBarry Harding 16941816cb70SBarry Harding PUTADDR(ring, prod, txb->b_paddr); 16951816cb70SBarry Harding PUTCTRL(ring, prod, len | OP_PACKET | HW_OWNER | EOP); 16961816cb70SBarry Harding SYNCENTRY(ring, prod, DDI_DMA_SYNC_FORDEV); 16971816cb70SBarry Harding port->p_tx_cnt++; 16981816cb70SBarry Harding 16991816cb70SBarry Harding YGE_INC(prod, YGE_TX_RING_CNT); 17001816cb70SBarry Harding 17011816cb70SBarry Harding /* Update producer index. */ 17021816cb70SBarry Harding port->p_tx_prod = prod; 17031816cb70SBarry Harding 17041816cb70SBarry Harding return (B_TRUE); 17051816cb70SBarry Harding } 17061816cb70SBarry Harding 17071816cb70SBarry Harding static int 17081816cb70SBarry Harding yge_suspend(yge_dev_t *dev) 17091816cb70SBarry Harding { 17101816cb70SBarry Harding for (int i = 0; i < dev->d_num_port; i++) { 17111816cb70SBarry Harding yge_port_t *port = dev->d_port[i]; 17121816cb70SBarry Harding mii_suspend(port->p_mii); 17131816cb70SBarry Harding } 17141816cb70SBarry Harding 17151816cb70SBarry Harding 17161816cb70SBarry Harding DEV_LOCK(dev); 17171816cb70SBarry Harding 17181816cb70SBarry Harding for (int i = 0; i < dev->d_num_port; i++) { 17191816cb70SBarry Harding yge_port_t *port = dev->d_port[i]; 17201816cb70SBarry Harding 17211816cb70SBarry Harding if (port->p_running) { 17221816cb70SBarry Harding yge_stop_port(port); 17231816cb70SBarry Harding } 17241816cb70SBarry Harding } 17251816cb70SBarry Harding 17261816cb70SBarry Harding /* Disable all interrupts. */ 17271816cb70SBarry Harding CSR_WRITE_4(dev, B0_IMSK, 0); 17281816cb70SBarry Harding (void) CSR_READ_4(dev, B0_IMSK); 17291816cb70SBarry Harding CSR_WRITE_4(dev, B0_HWE_IMSK, 0); 17301816cb70SBarry Harding (void) CSR_READ_4(dev, B0_HWE_IMSK); 17311816cb70SBarry Harding 17321816cb70SBarry Harding yge_phy_power(dev, B_FALSE); 17331816cb70SBarry Harding 17341816cb70SBarry Harding /* Put hardware reset. */ 17351816cb70SBarry Harding CSR_WRITE_2(dev, B0_CTST, CS_RST_SET); 17361816cb70SBarry Harding dev->d_suspended = B_TRUE; 17371816cb70SBarry Harding 17381816cb70SBarry Harding DEV_UNLOCK(dev); 17391816cb70SBarry Harding 17401816cb70SBarry Harding return (DDI_SUCCESS); 17411816cb70SBarry Harding } 17421816cb70SBarry Harding 17431816cb70SBarry Harding static int 17441816cb70SBarry Harding yge_resume(yge_dev_t *dev) 17451816cb70SBarry Harding { 17461816cb70SBarry Harding uint8_t pm_cap; 17471816cb70SBarry Harding 17481816cb70SBarry Harding DEV_LOCK(dev); 17491816cb70SBarry Harding 17501816cb70SBarry Harding /* ensure the pmcsr status is D0 state */ 17511816cb70SBarry Harding CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_ON); 17521816cb70SBarry Harding 17531816cb70SBarry Harding if ((pm_cap = yge_find_capability(dev, PCI_CAP_ID_PM)) != 0) { 17541816cb70SBarry Harding uint16_t pmcsr; 17551816cb70SBarry Harding pmcsr = pci_config_get16(dev->d_pcih, pm_cap + PCI_PMCSR); 17561816cb70SBarry Harding pmcsr &= ~PCI_PMCSR_STATE_MASK; 17571816cb70SBarry Harding pci_config_put16(dev->d_pcih, pm_cap + PCI_PMCSR, 17581816cb70SBarry Harding pmcsr | PCI_PMCSR_D0); 17591816cb70SBarry Harding } 17601816cb70SBarry Harding 17611816cb70SBarry Harding /* Enable PCI access and bus master. */ 17621816cb70SBarry Harding pci_config_put16(dev->d_pcih, PCI_CONF_COMM, 17631816cb70SBarry Harding pci_config_get16(dev->d_pcih, PCI_CONF_COMM) | 17641816cb70SBarry Harding PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME); 17651816cb70SBarry Harding 17661816cb70SBarry Harding /* Enable all clocks. */ 17671816cb70SBarry Harding switch (dev->d_hw_id) { 17681816cb70SBarry Harding case CHIP_ID_YUKON_EX: 17691816cb70SBarry Harding case CHIP_ID_YUKON_EC_U: 17701816cb70SBarry Harding case CHIP_ID_YUKON_FE_P: 17711816cb70SBarry Harding pci_config_put32(dev->d_pcih, PCI_OUR_REG_3, 0); 17721816cb70SBarry Harding break; 17731816cb70SBarry Harding } 17741816cb70SBarry Harding 17751816cb70SBarry Harding CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 17761816cb70SBarry Harding 17771816cb70SBarry Harding yge_reset(dev); 17781816cb70SBarry Harding 17791816cb70SBarry Harding /* Make sure interrupts are reenabled */ 17801816cb70SBarry Harding CSR_WRITE_4(dev, B0_IMSK, 0); 17811816cb70SBarry Harding CSR_WRITE_4(dev, B0_IMSK, Y2_IS_HW_ERR | Y2_IS_STAT_BMU); 17821816cb70SBarry Harding CSR_WRITE_4(dev, B0_HWE_IMSK, 17831816cb70SBarry Harding Y2_IS_TIST_OV | Y2_IS_MST_ERR | 17841816cb70SBarry Harding Y2_IS_IRQ_STAT | Y2_IS_PCI_EXP | Y2_IS_PCI_NEXP); 17851816cb70SBarry Harding 17861816cb70SBarry Harding for (int i = 0; i < dev->d_num_port; i++) { 17871816cb70SBarry Harding yge_port_t *port = dev->d_port[i]; 17881816cb70SBarry Harding 17891816cb70SBarry Harding if (port != NULL && port->p_running) { 17901816cb70SBarry Harding yge_start_port(port); 17911816cb70SBarry Harding } 17921816cb70SBarry Harding } 17931816cb70SBarry Harding dev->d_suspended = B_FALSE; 17941816cb70SBarry Harding 17951816cb70SBarry Harding DEV_UNLOCK(dev); 17961816cb70SBarry Harding 17971816cb70SBarry Harding /* Reset MII layer */ 17981816cb70SBarry Harding for (int i = 0; i < dev->d_num_port; i++) { 17991816cb70SBarry Harding yge_port_t *port = dev->d_port[i]; 18001816cb70SBarry Harding 18011816cb70SBarry Harding if (port->p_running) { 18021816cb70SBarry Harding mii_resume(port->p_mii); 18031816cb70SBarry Harding mac_tx_update(port->p_mh); 18041816cb70SBarry Harding } 18051816cb70SBarry Harding } 18061816cb70SBarry Harding 18071816cb70SBarry Harding return (DDI_SUCCESS); 18081816cb70SBarry Harding } 18091816cb70SBarry Harding 18101816cb70SBarry Harding static mblk_t * 18111816cb70SBarry Harding yge_rxeof(yge_port_t *port, uint32_t status, int len) 18121816cb70SBarry Harding { 18131816cb70SBarry Harding yge_dev_t *dev = port->p_dev; 18141816cb70SBarry Harding mblk_t *mp; 18151816cb70SBarry Harding int cons, rxlen; 18161816cb70SBarry Harding yge_buf_t *rxb; 18171816cb70SBarry Harding yge_ring_t *ring; 18181816cb70SBarry Harding 18191816cb70SBarry Harding ASSERT(mutex_owned(&dev->d_rxlock)); 18201816cb70SBarry Harding 18211816cb70SBarry Harding if (!port->p_running) 18221816cb70SBarry Harding return (NULL); 18231816cb70SBarry Harding 18241816cb70SBarry Harding ring = &port->p_rx_ring; 18251816cb70SBarry Harding cons = port->p_rx_cons; 18261816cb70SBarry Harding rxlen = status >> 16; 18271816cb70SBarry Harding rxb = &port->p_rx_buf[cons]; 18281816cb70SBarry Harding mp = NULL; 18291816cb70SBarry Harding 18301816cb70SBarry Harding 18311816cb70SBarry Harding if ((dev->d_hw_id == CHIP_ID_YUKON_FE_P) && 18321816cb70SBarry Harding (dev->d_hw_rev == CHIP_REV_YU_FE2_A0)) { 18331816cb70SBarry Harding /* 18341816cb70SBarry Harding * Apparently the status for this chip is not reliable. 18351816cb70SBarry Harding * Only perform minimal consistency checking; the MAC 18361816cb70SBarry Harding * and upper protocols will have to filter any garbage. 18371816cb70SBarry Harding */ 18381816cb70SBarry Harding if ((len > port->p_framesize) || (rxlen != len)) { 18391816cb70SBarry Harding goto bad; 18401816cb70SBarry Harding } 18411816cb70SBarry Harding } else { 18421816cb70SBarry Harding if ((len > port->p_framesize) || (rxlen != len) || 18431816cb70SBarry Harding ((status & GMR_FS_ANY_ERR) != 0) || 18441816cb70SBarry Harding ((status & GMR_FS_RX_OK) == 0)) { 18451816cb70SBarry Harding goto bad; 18461816cb70SBarry Harding } 18471816cb70SBarry Harding } 18481816cb70SBarry Harding 18491816cb70SBarry Harding if ((mp = allocb(len + YGE_HEADROOM, BPRI_HI)) != NULL) { 18501816cb70SBarry Harding 18511816cb70SBarry Harding /* good packet - yay */ 18521816cb70SBarry Harding mp->b_rptr += YGE_HEADROOM; 18531816cb70SBarry Harding SYNCBUF(rxb, DDI_DMA_SYNC_FORKERNEL); 18541816cb70SBarry Harding bcopy(rxb->b_buf, mp->b_rptr, len); 18551816cb70SBarry Harding mp->b_wptr = mp->b_rptr + len; 18561816cb70SBarry Harding } else { 18571816cb70SBarry Harding port->p_stats.rx_nobuf++; 18581816cb70SBarry Harding } 18591816cb70SBarry Harding 18601816cb70SBarry Harding bad: 18611816cb70SBarry Harding 18621816cb70SBarry Harding PUTCTRL(ring, cons, port->p_framesize | OP_PACKET | HW_OWNER); 18631816cb70SBarry Harding SYNCENTRY(ring, cons, DDI_DMA_SYNC_FORDEV); 18641816cb70SBarry Harding 18651816cb70SBarry Harding CSR_WRITE_2(dev, 18661816cb70SBarry Harding Y2_PREF_Q_ADDR(port->p_rxq, PREF_UNIT_PUT_IDX_REG), 18671816cb70SBarry Harding cons); 18681816cb70SBarry Harding 18691816cb70SBarry Harding YGE_INC(port->p_rx_cons, YGE_RX_RING_CNT); 18701816cb70SBarry Harding 18711816cb70SBarry Harding return (mp); 18721816cb70SBarry Harding } 18731816cb70SBarry Harding 18741816cb70SBarry Harding static boolean_t 18751816cb70SBarry Harding yge_txeof_locked(yge_port_t *port, int idx) 18761816cb70SBarry Harding { 18771816cb70SBarry Harding int prog; 18781816cb70SBarry Harding int16_t cons; 18791816cb70SBarry Harding boolean_t resched; 18801816cb70SBarry Harding 18811816cb70SBarry Harding if (!port->p_running) { 18821816cb70SBarry Harding return (B_FALSE); 18831816cb70SBarry Harding } 18841816cb70SBarry Harding 18851816cb70SBarry Harding cons = port->p_tx_cons; 18861816cb70SBarry Harding prog = 0; 18871816cb70SBarry Harding for (; cons != idx; YGE_INC(cons, YGE_TX_RING_CNT)) { 18881816cb70SBarry Harding if (port->p_tx_cnt <= 0) 18891816cb70SBarry Harding break; 18901816cb70SBarry Harding prog++; 18911816cb70SBarry Harding port->p_tx_cnt--; 18921816cb70SBarry Harding /* No need to sync LEs as we didn't update LEs. */ 18931816cb70SBarry Harding } 18941816cb70SBarry Harding 18951816cb70SBarry Harding port->p_tx_cons = cons; 18961816cb70SBarry Harding 18971816cb70SBarry Harding if (prog > 0) { 18981816cb70SBarry Harding resched = port->p_wantw; 18991816cb70SBarry Harding port->p_tx_wdog = 0; 19001816cb70SBarry Harding port->p_wantw = B_FALSE; 19011816cb70SBarry Harding return (resched); 19021816cb70SBarry Harding } else { 19031816cb70SBarry Harding return (B_FALSE); 19041816cb70SBarry Harding } 19051816cb70SBarry Harding } 19061816cb70SBarry Harding 19071816cb70SBarry Harding static void 19081816cb70SBarry Harding yge_txeof(yge_port_t *port, int idx) 19091816cb70SBarry Harding { 19101816cb70SBarry Harding boolean_t resched; 19111816cb70SBarry Harding 19121816cb70SBarry Harding TX_LOCK(port->p_dev); 19131816cb70SBarry Harding 19141816cb70SBarry Harding resched = yge_txeof_locked(port, idx); 19151816cb70SBarry Harding 19161816cb70SBarry Harding TX_UNLOCK(port->p_dev); 19171816cb70SBarry Harding 19181816cb70SBarry Harding if (resched && port->p_running) { 19191816cb70SBarry Harding mac_tx_update(port->p_mh); 19201816cb70SBarry Harding } 19211816cb70SBarry Harding } 19221816cb70SBarry Harding 19231816cb70SBarry Harding static void 19241816cb70SBarry Harding yge_restart_task(yge_dev_t *dev) 19251816cb70SBarry Harding { 19261816cb70SBarry Harding yge_port_t *port; 19271816cb70SBarry Harding 19281816cb70SBarry Harding DEV_LOCK(dev); 19291816cb70SBarry Harding 19301816cb70SBarry Harding /* Cancel pending I/O and free all Rx/Tx buffers. */ 19311816cb70SBarry Harding for (int i = 0; i < dev->d_num_port; i++) { 19321816cb70SBarry Harding port = dev->d_port[i]; 19331816cb70SBarry Harding if (port->p_running) 19341816cb70SBarry Harding yge_stop_port(dev->d_port[i]); 19351816cb70SBarry Harding } 19361816cb70SBarry Harding yge_reset(dev); 19371816cb70SBarry Harding for (int i = 0; i < dev->d_num_port; i++) { 19381816cb70SBarry Harding port = dev->d_port[i]; 19391816cb70SBarry Harding 19401816cb70SBarry Harding if (port->p_running) 19411816cb70SBarry Harding yge_start_port(port); 19421816cb70SBarry Harding } 19431816cb70SBarry Harding 19441816cb70SBarry Harding DEV_UNLOCK(dev); 19451816cb70SBarry Harding 19461816cb70SBarry Harding for (int i = 0; i < dev->d_num_port; i++) { 19471816cb70SBarry Harding port = dev->d_port[i]; 19481816cb70SBarry Harding 19491816cb70SBarry Harding mii_reset(port->p_mii); 19501816cb70SBarry Harding if (port->p_running) 19511816cb70SBarry Harding mac_tx_update(port->p_mh); 19521816cb70SBarry Harding } 19531816cb70SBarry Harding } 19541816cb70SBarry Harding 19551816cb70SBarry Harding static void 19561816cb70SBarry Harding yge_tick(void *arg) 19571816cb70SBarry Harding { 19581816cb70SBarry Harding yge_dev_t *dev = arg; 19591816cb70SBarry Harding yge_port_t *port; 19601816cb70SBarry Harding boolean_t restart = B_FALSE; 19611816cb70SBarry Harding boolean_t resched = B_FALSE; 19621816cb70SBarry Harding int idx; 19631816cb70SBarry Harding 19641816cb70SBarry Harding DEV_LOCK(dev); 19651816cb70SBarry Harding 19661816cb70SBarry Harding if (dev->d_suspended) { 19671816cb70SBarry Harding DEV_UNLOCK(dev); 19681816cb70SBarry Harding return; 19691816cb70SBarry Harding } 19701816cb70SBarry Harding 19711816cb70SBarry Harding for (int i = 0; i < dev->d_num_port; i++) { 19721816cb70SBarry Harding port = dev->d_port[i]; 19731816cb70SBarry Harding 19741816cb70SBarry Harding if (!port->p_running) 19751816cb70SBarry Harding continue; 19761816cb70SBarry Harding 19771816cb70SBarry Harding if (port->p_tx_cnt) { 19781816cb70SBarry Harding uint32_t ridx; 19791816cb70SBarry Harding 19801816cb70SBarry Harding /* 19811816cb70SBarry Harding * Reclaim first as there is a possibility of losing 19821816cb70SBarry Harding * Tx completion interrupts. 19831816cb70SBarry Harding */ 19841816cb70SBarry Harding ridx = port->p_port == YGE_PORT_A ? 19851816cb70SBarry Harding STAT_TXA1_RIDX : STAT_TXA2_RIDX; 19861816cb70SBarry Harding idx = CSR_READ_2(dev, ridx); 19871816cb70SBarry Harding if (port->p_tx_cons != idx) { 19881816cb70SBarry Harding resched = yge_txeof_locked(port, idx); 19891816cb70SBarry Harding 19901816cb70SBarry Harding } else { 19911816cb70SBarry Harding 19921816cb70SBarry Harding /* detect TX hang */ 19931816cb70SBarry Harding port->p_tx_wdog++; 19941816cb70SBarry Harding if (port->p_tx_wdog > YGE_TX_TIMEOUT) { 19951816cb70SBarry Harding port->p_tx_wdog = 0; 19961816cb70SBarry Harding yge_error(NULL, port, 19971816cb70SBarry Harding "TX hang detected!"); 19981816cb70SBarry Harding restart = B_TRUE; 19991816cb70SBarry Harding } 20001816cb70SBarry Harding } 20011816cb70SBarry Harding } 20021816cb70SBarry Harding } 20031816cb70SBarry Harding 20041816cb70SBarry Harding DEV_UNLOCK(dev); 20051816cb70SBarry Harding if (restart) { 20061816cb70SBarry Harding yge_dispatch(dev, YGE_TASK_RESTART); 20071816cb70SBarry Harding } else { 20081816cb70SBarry Harding if (resched) { 20091816cb70SBarry Harding for (int i = 0; i < dev->d_num_port; i++) { 20101816cb70SBarry Harding port = dev->d_port[i]; 20111816cb70SBarry Harding 20121816cb70SBarry Harding if (port->p_running) 20131816cb70SBarry Harding mac_tx_update(port->p_mh); 20141816cb70SBarry Harding } 20151816cb70SBarry Harding } 20161816cb70SBarry Harding } 20171816cb70SBarry Harding } 20181816cb70SBarry Harding 20191816cb70SBarry Harding static int 20201816cb70SBarry Harding yge_intr_gmac(yge_port_t *port) 20211816cb70SBarry Harding { 20221816cb70SBarry Harding yge_dev_t *dev = port->p_dev; 20231816cb70SBarry Harding int pnum = port->p_port; 20241816cb70SBarry Harding uint8_t status; 20251816cb70SBarry Harding int dispatch_wrk = 0; 20261816cb70SBarry Harding 20271816cb70SBarry Harding status = CSR_READ_1(dev, MR_ADDR(pnum, GMAC_IRQ_SRC)); 20281816cb70SBarry Harding 20291816cb70SBarry Harding /* GMAC Rx FIFO overrun. */ 20301816cb70SBarry Harding if ((status & GM_IS_RX_FF_OR) != 0) { 20311816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_CTRL_T), GMF_CLI_RX_FO); 20321816cb70SBarry Harding yge_error(NULL, port, "Rx FIFO overrun!"); 20331816cb70SBarry Harding dispatch_wrk |= YGE_TASK_RESTART; 20341816cb70SBarry Harding } 20351816cb70SBarry Harding /* GMAC Tx FIFO underrun. */ 20361816cb70SBarry Harding if ((status & GM_IS_TX_FF_UR) != 0) { 20371816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), GMF_CLI_TX_FU); 20381816cb70SBarry Harding yge_error(NULL, port, "Tx FIFO underrun!"); 20391816cb70SBarry Harding /* 20401816cb70SBarry Harding * In case of Tx underrun, we may need to flush/reset 20411816cb70SBarry Harding * Tx MAC but that would also require 20421816cb70SBarry Harding * resynchronization with status LEs. Reinitializing 20431816cb70SBarry Harding * status LEs would affect the other port in dual MAC 20441816cb70SBarry Harding * configuration so it should be avoided if we can. 20451816cb70SBarry Harding * Due to lack of documentation it's all vague guess 20461816cb70SBarry Harding * but it needs more investigation. 20471816cb70SBarry Harding */ 20481816cb70SBarry Harding } 20491816cb70SBarry Harding return (dispatch_wrk); 20501816cb70SBarry Harding } 20511816cb70SBarry Harding 20521816cb70SBarry Harding static void 20531816cb70SBarry Harding yge_handle_hwerr(yge_port_t *port, uint32_t status) 20541816cb70SBarry Harding { 20551816cb70SBarry Harding yge_dev_t *dev = port->p_dev; 20561816cb70SBarry Harding 20571816cb70SBarry Harding if ((status & Y2_IS_PAR_RD1) != 0) { 20581816cb70SBarry Harding yge_error(NULL, port, "RAM buffer read parity error"); 20591816cb70SBarry Harding /* Clear IRQ. */ 20601816cb70SBarry Harding CSR_WRITE_2(dev, SELECT_RAM_BUFFER(port->p_port, B3_RI_CTRL), 20611816cb70SBarry Harding RI_CLR_RD_PERR); 20621816cb70SBarry Harding } 20631816cb70SBarry Harding if ((status & Y2_IS_PAR_WR1) != 0) { 20641816cb70SBarry Harding yge_error(NULL, port, "RAM buffer write parity error"); 20651816cb70SBarry Harding /* Clear IRQ. */ 20661816cb70SBarry Harding CSR_WRITE_2(dev, SELECT_RAM_BUFFER(port->p_port, B3_RI_CTRL), 20671816cb70SBarry Harding RI_CLR_WR_PERR); 20681816cb70SBarry Harding } 20691816cb70SBarry Harding if ((status & Y2_IS_PAR_MAC1) != 0) { 20701816cb70SBarry Harding yge_error(NULL, port, "Tx MAC parity error"); 20711816cb70SBarry Harding /* Clear IRQ. */ 20721816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(port->p_port, TX_GMF_CTRL_T), 20731816cb70SBarry Harding GMF_CLI_TX_PE); 20741816cb70SBarry Harding } 20751816cb70SBarry Harding if ((status & Y2_IS_PAR_RX1) != 0) { 20761816cb70SBarry Harding yge_error(NULL, port, "Rx parity error"); 20771816cb70SBarry Harding /* Clear IRQ. */ 20781816cb70SBarry Harding CSR_WRITE_4(dev, Q_ADDR(port->p_rxq, Q_CSR), BMU_CLR_IRQ_PAR); 20791816cb70SBarry Harding } 20801816cb70SBarry Harding if ((status & (Y2_IS_TCP_TXS1 | Y2_IS_TCP_TXA1)) != 0) { 20811816cb70SBarry Harding yge_error(NULL, port, "TCP segmentation error"); 20821816cb70SBarry Harding /* Clear IRQ. */ 20831816cb70SBarry Harding CSR_WRITE_4(dev, Q_ADDR(port->p_txq, Q_CSR), BMU_CLR_IRQ_TCP); 20841816cb70SBarry Harding } 20851816cb70SBarry Harding } 20861816cb70SBarry Harding 20871816cb70SBarry Harding static void 20881816cb70SBarry Harding yge_intr_hwerr(yge_dev_t *dev) 20891816cb70SBarry Harding { 20901816cb70SBarry Harding uint32_t status; 20911816cb70SBarry Harding uint32_t tlphead[4]; 20921816cb70SBarry Harding 20931816cb70SBarry Harding status = CSR_READ_4(dev, B0_HWE_ISRC); 20941816cb70SBarry Harding /* Time Stamp timer overflow. */ 20951816cb70SBarry Harding if ((status & Y2_IS_TIST_OV) != 0) 20961816cb70SBarry Harding CSR_WRITE_1(dev, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ); 20971816cb70SBarry Harding if ((status & Y2_IS_PCI_NEXP) != 0) { 20981816cb70SBarry Harding /* 20991816cb70SBarry Harding * PCI Express Error occurred which is not described in PEX 21001816cb70SBarry Harding * spec. 21011816cb70SBarry Harding * This error is also mapped either to Master Abort( 21021816cb70SBarry Harding * Y2_IS_MST_ERR) or Target Abort (Y2_IS_IRQ_STAT) bit and 21031816cb70SBarry Harding * can only be cleared there. 21041816cb70SBarry Harding */ 21051816cb70SBarry Harding yge_error(dev, NULL, "PCI Express protocol violation error"); 21061816cb70SBarry Harding } 21071816cb70SBarry Harding 21081816cb70SBarry Harding if ((status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) != 0) { 21091816cb70SBarry Harding uint16_t v16; 21101816cb70SBarry Harding 21111816cb70SBarry Harding if ((status & Y2_IS_IRQ_STAT) != 0) 21121816cb70SBarry Harding yge_error(dev, NULL, "Unexpected IRQ Status error"); 21131816cb70SBarry Harding if ((status & Y2_IS_MST_ERR) != 0) 21141816cb70SBarry Harding yge_error(dev, NULL, "Unexpected IRQ Master error"); 21151816cb70SBarry Harding /* Reset all bits in the PCI status register. */ 21161816cb70SBarry Harding v16 = pci_config_get16(dev->d_pcih, PCI_CONF_STAT); 21171816cb70SBarry Harding CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_ON); 21181816cb70SBarry Harding pci_config_put16(dev->d_pcih, PCI_CONF_STAT, v16 | 21191816cb70SBarry Harding PCI_STAT_S_PERROR | PCI_STAT_S_SYSERR | PCI_STAT_R_MAST_AB | 21201816cb70SBarry Harding PCI_STAT_R_TARG_AB | PCI_STAT_PERROR); 21211816cb70SBarry Harding CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 21221816cb70SBarry Harding } 21231816cb70SBarry Harding 21241816cb70SBarry Harding /* Check for PCI Express Uncorrectable Error. */ 21251816cb70SBarry Harding if ((status & Y2_IS_PCI_EXP) != 0) { 21261816cb70SBarry Harding uint32_t v32; 21271816cb70SBarry Harding 21281816cb70SBarry Harding /* 21291816cb70SBarry Harding * On PCI Express bus bridges are called root complexes (RC). 21301816cb70SBarry Harding * PCI Express errors are recognized by the root complex too, 21311816cb70SBarry Harding * which requests the system to handle the problem. After 21321816cb70SBarry Harding * error occurrence it may be that no access to the adapter 21331816cb70SBarry Harding * may be performed any longer. 21341816cb70SBarry Harding */ 21351816cb70SBarry Harding 21361816cb70SBarry Harding v32 = CSR_PCI_READ_4(dev, PEX_UNC_ERR_STAT); 21371816cb70SBarry Harding if ((v32 & PEX_UNSUP_REQ) != 0) { 21381816cb70SBarry Harding /* Ignore unsupported request error. */ 21391816cb70SBarry Harding yge_error(dev, NULL, 21401816cb70SBarry Harding "Uncorrectable PCI Express error"); 21411816cb70SBarry Harding } 21421816cb70SBarry Harding if ((v32 & (PEX_FATAL_ERRORS | PEX_POIS_TLP)) != 0) { 21431816cb70SBarry Harding int i; 21441816cb70SBarry Harding 21451816cb70SBarry Harding /* Get TLP header form Log Registers. */ 21461816cb70SBarry Harding for (i = 0; i < 4; i++) 21471816cb70SBarry Harding tlphead[i] = CSR_PCI_READ_4(dev, 21481816cb70SBarry Harding PEX_HEADER_LOG + i * 4); 21491816cb70SBarry Harding /* Check for vendor defined broadcast message. */ 21501816cb70SBarry Harding if (!(tlphead[0] == 0x73004001 && tlphead[1] == 0x7f)) { 21511816cb70SBarry Harding dev->d_intrhwemask &= ~Y2_IS_PCI_EXP; 21521816cb70SBarry Harding CSR_WRITE_4(dev, B0_HWE_IMSK, 21531816cb70SBarry Harding dev->d_intrhwemask); 21541816cb70SBarry Harding (void) CSR_READ_4(dev, B0_HWE_IMSK); 21551816cb70SBarry Harding } 21561816cb70SBarry Harding } 21571816cb70SBarry Harding /* Clear the interrupt. */ 21581816cb70SBarry Harding CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_ON); 21591816cb70SBarry Harding CSR_PCI_WRITE_4(dev, PEX_UNC_ERR_STAT, 0xffffffff); 21601816cb70SBarry Harding CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 21611816cb70SBarry Harding } 21621816cb70SBarry Harding 21631816cb70SBarry Harding if ((status & Y2_HWE_L1_MASK) != 0 && dev->d_port[YGE_PORT_A] != NULL) 21641816cb70SBarry Harding yge_handle_hwerr(dev->d_port[YGE_PORT_A], status); 21651816cb70SBarry Harding if ((status & Y2_HWE_L2_MASK) != 0 && dev->d_port[YGE_PORT_B] != NULL) 21661816cb70SBarry Harding yge_handle_hwerr(dev->d_port[YGE_PORT_B], status >> 8); 21671816cb70SBarry Harding } 21681816cb70SBarry Harding 21691816cb70SBarry Harding /* 21701816cb70SBarry Harding * Returns B_TRUE if there is potentially more work to do. 21711816cb70SBarry Harding */ 21721816cb70SBarry Harding static boolean_t 21731816cb70SBarry Harding yge_handle_events(yge_dev_t *dev, mblk_t **heads, mblk_t **tails, int *txindex) 21741816cb70SBarry Harding { 21751816cb70SBarry Harding yge_port_t *port; 21761816cb70SBarry Harding yge_ring_t *ring; 21771816cb70SBarry Harding uint32_t control, status; 21781816cb70SBarry Harding int cons, idx, len, pnum; 21791816cb70SBarry Harding mblk_t *mp; 21801816cb70SBarry Harding uint32_t rxprogs[2]; 21811816cb70SBarry Harding 21821816cb70SBarry Harding rxprogs[0] = rxprogs[1] = 0; 21831816cb70SBarry Harding 21841816cb70SBarry Harding idx = CSR_READ_2(dev, STAT_PUT_IDX); 21851816cb70SBarry Harding if (idx == dev->d_stat_cons) { 21861816cb70SBarry Harding return (B_FALSE); 21871816cb70SBarry Harding } 21881816cb70SBarry Harding 21891816cb70SBarry Harding ring = &dev->d_status_ring; 21901816cb70SBarry Harding 21911816cb70SBarry Harding for (cons = dev->d_stat_cons; cons != idx; ) { 21921816cb70SBarry Harding /* Sync status LE. */ 21931816cb70SBarry Harding SYNCENTRY(ring, cons, DDI_DMA_SYNC_FORKERNEL); 21941816cb70SBarry Harding control = GETCTRL(ring, cons); 21951816cb70SBarry Harding if ((control & HW_OWNER) == 0) { 21961816cb70SBarry Harding yge_error(dev, NULL, "Status descriptor error: " 21971816cb70SBarry Harding "index %d, control %x", cons, control); 21981816cb70SBarry Harding break; 21991816cb70SBarry Harding } 22001816cb70SBarry Harding 22011816cb70SBarry Harding status = GETSTAT(ring, cons); 22021816cb70SBarry Harding 22031816cb70SBarry Harding control &= ~HW_OWNER; 22041816cb70SBarry Harding len = control & STLE_LEN_MASK; 22051816cb70SBarry Harding pnum = ((control >> 16) & 0x01); 22061816cb70SBarry Harding port = dev->d_port[pnum]; 22071816cb70SBarry Harding if (port == NULL) { 22081816cb70SBarry Harding yge_error(dev, NULL, "Invalid port opcode: 0x%08x", 22091816cb70SBarry Harding control & STLE_OP_MASK); 22101816cb70SBarry Harding goto finish; 22111816cb70SBarry Harding } 22121816cb70SBarry Harding 22131816cb70SBarry Harding switch (control & STLE_OP_MASK) { 22141816cb70SBarry Harding case OP_RXSTAT: 22151816cb70SBarry Harding mp = yge_rxeof(port, status, len); 22161816cb70SBarry Harding if (mp != NULL) { 22171816cb70SBarry Harding if (heads[pnum] == NULL) 22181816cb70SBarry Harding heads[pnum] = mp; 22191816cb70SBarry Harding else 22201816cb70SBarry Harding tails[pnum]->b_next = mp; 22211816cb70SBarry Harding tails[pnum] = mp; 22221816cb70SBarry Harding } 22231816cb70SBarry Harding 22241816cb70SBarry Harding rxprogs[pnum]++; 22251816cb70SBarry Harding break; 22261816cb70SBarry Harding 22271816cb70SBarry Harding case OP_TXINDEXLE: 22281816cb70SBarry Harding txindex[0] = status & STLE_TXA1_MSKL; 22291816cb70SBarry Harding txindex[1] = 22301816cb70SBarry Harding ((status & STLE_TXA2_MSKL) >> STLE_TXA2_SHIFTL) | 22311816cb70SBarry Harding ((len & STLE_TXA2_MSKH) << STLE_TXA2_SHIFTH); 22321816cb70SBarry Harding break; 22331816cb70SBarry Harding default: 22341816cb70SBarry Harding yge_error(dev, NULL, "Unhandled opcode: 0x%08x", 22351816cb70SBarry Harding control & STLE_OP_MASK); 22361816cb70SBarry Harding break; 22371816cb70SBarry Harding } 22381816cb70SBarry Harding finish: 22391816cb70SBarry Harding 22401816cb70SBarry Harding /* Give it back to HW. */ 22411816cb70SBarry Harding PUTCTRL(ring, cons, control); 22421816cb70SBarry Harding SYNCENTRY(ring, cons, DDI_DMA_SYNC_FORDEV); 22431816cb70SBarry Harding 22441816cb70SBarry Harding YGE_INC(cons, YGE_STAT_RING_CNT); 22451816cb70SBarry Harding if (rxprogs[pnum] > dev->d_process_limit) { 22461816cb70SBarry Harding break; 22471816cb70SBarry Harding } 22481816cb70SBarry Harding } 22491816cb70SBarry Harding 22501816cb70SBarry Harding dev->d_stat_cons = cons; 22511816cb70SBarry Harding if (dev->d_stat_cons != CSR_READ_2(dev, STAT_PUT_IDX)) 22521816cb70SBarry Harding return (B_TRUE); 22531816cb70SBarry Harding else 22541816cb70SBarry Harding return (B_FALSE); 22551816cb70SBarry Harding } 22561816cb70SBarry Harding 22571816cb70SBarry Harding /*ARGSUSED1*/ 22581816cb70SBarry Harding static uint_t 22591816cb70SBarry Harding yge_intr(caddr_t arg1, caddr_t arg2) 22601816cb70SBarry Harding { 22611816cb70SBarry Harding yge_dev_t *dev; 22621816cb70SBarry Harding yge_port_t *port1; 22631816cb70SBarry Harding yge_port_t *port2; 22641816cb70SBarry Harding uint32_t status; 22651816cb70SBarry Harding mblk_t *heads[2], *tails[2]; 22661816cb70SBarry Harding int txindex[2]; 22671816cb70SBarry Harding int dispatch_wrk; 22681816cb70SBarry Harding 22691816cb70SBarry Harding dev = (void *)arg1; 22701816cb70SBarry Harding 22711816cb70SBarry Harding heads[0] = heads[1] = NULL; 22721816cb70SBarry Harding tails[0] = tails[1] = NULL; 22731816cb70SBarry Harding txindex[0] = txindex[1] = -1; 22741816cb70SBarry Harding dispatch_wrk = 0; 22751816cb70SBarry Harding 22761816cb70SBarry Harding port1 = dev->d_port[YGE_PORT_A]; 22771816cb70SBarry Harding port2 = dev->d_port[YGE_PORT_B]; 22781816cb70SBarry Harding 22791816cb70SBarry Harding RX_LOCK(dev); 22801816cb70SBarry Harding 22811816cb70SBarry Harding if (dev->d_suspended) { 22821816cb70SBarry Harding RX_UNLOCK(dev); 22831816cb70SBarry Harding return (DDI_INTR_UNCLAIMED); 22841816cb70SBarry Harding } 22851816cb70SBarry Harding 22861816cb70SBarry Harding /* Get interrupt source. */ 22871816cb70SBarry Harding status = CSR_READ_4(dev, B0_Y2_SP_ISRC2); 22881816cb70SBarry Harding if (status == 0 || status == 0xffffffff || 22891816cb70SBarry Harding (status & dev->d_intrmask) == 0) { /* Stray interrupt ? */ 22901816cb70SBarry Harding /* Reenable interrupts. */ 22911816cb70SBarry Harding CSR_WRITE_4(dev, B0_Y2_SP_ICR, 2); 22921816cb70SBarry Harding RX_UNLOCK(dev); 22931816cb70SBarry Harding return (DDI_INTR_UNCLAIMED); 22941816cb70SBarry Harding } 22951816cb70SBarry Harding 22961816cb70SBarry Harding if ((status & Y2_IS_HW_ERR) != 0) { 22971816cb70SBarry Harding yge_intr_hwerr(dev); 22981816cb70SBarry Harding } 22991816cb70SBarry Harding 23001816cb70SBarry Harding if (status & Y2_IS_IRQ_MAC1) { 23011816cb70SBarry Harding dispatch_wrk |= yge_intr_gmac(port1); 23021816cb70SBarry Harding } 23031816cb70SBarry Harding if (status & Y2_IS_IRQ_MAC2) { 23041816cb70SBarry Harding dispatch_wrk |= yge_intr_gmac(port2); 23051816cb70SBarry Harding } 23061816cb70SBarry Harding 23071816cb70SBarry Harding if ((status & (Y2_IS_CHK_RX1 | Y2_IS_CHK_RX2)) != 0) { 23081816cb70SBarry Harding yge_error(NULL, status & Y2_IS_CHK_RX1 ? port1 : port2, 23091816cb70SBarry Harding "Rx descriptor error"); 23101816cb70SBarry Harding dev->d_intrmask &= ~(Y2_IS_CHK_RX1 | Y2_IS_CHK_RX2); 23111816cb70SBarry Harding CSR_WRITE_4(dev, B0_IMSK, dev->d_intrmask); 23121816cb70SBarry Harding (void) CSR_READ_4(dev, B0_IMSK); 23131816cb70SBarry Harding } 23141816cb70SBarry Harding if ((status & (Y2_IS_CHK_TXA1 | Y2_IS_CHK_TXA2)) != 0) { 23151816cb70SBarry Harding yge_error(NULL, status & Y2_IS_CHK_TXA1 ? port1 : port2, 23161816cb70SBarry Harding "Tx descriptor error"); 23171816cb70SBarry Harding dev->d_intrmask &= ~(Y2_IS_CHK_TXA1 | Y2_IS_CHK_TXA2); 23181816cb70SBarry Harding CSR_WRITE_4(dev, B0_IMSK, dev->d_intrmask); 23191816cb70SBarry Harding (void) CSR_READ_4(dev, B0_IMSK); 23201816cb70SBarry Harding } 23211816cb70SBarry Harding 23221816cb70SBarry Harding /* handle events until it returns false */ 23231816cb70SBarry Harding while (yge_handle_events(dev, heads, tails, txindex)) 23241816cb70SBarry Harding /* NOP */; 23251816cb70SBarry Harding 23261816cb70SBarry Harding /* Do receive/transmit events */ 23271816cb70SBarry Harding if ((status & Y2_IS_STAT_BMU)) { 23281816cb70SBarry Harding CSR_WRITE_4(dev, STAT_CTRL, SC_STAT_CLR_IRQ); 23291816cb70SBarry Harding } 23301816cb70SBarry Harding 23311816cb70SBarry Harding /* Reenable interrupts. */ 23321816cb70SBarry Harding CSR_WRITE_4(dev, B0_Y2_SP_ICR, 2); 23331816cb70SBarry Harding 23341816cb70SBarry Harding RX_UNLOCK(dev); 23351816cb70SBarry Harding 23361816cb70SBarry Harding if (dispatch_wrk) { 23371816cb70SBarry Harding yge_dispatch(dev, dispatch_wrk); 23381816cb70SBarry Harding } 23391816cb70SBarry Harding 23401816cb70SBarry Harding if (port1->p_running) { 23411816cb70SBarry Harding if (txindex[0] >= 0) { 23421816cb70SBarry Harding yge_txeof(port1, txindex[0]); 23431816cb70SBarry Harding } 23441816cb70SBarry Harding if (heads[0]) 23451816cb70SBarry Harding mac_rx(port1->p_mh, NULL, heads[0]); 23461816cb70SBarry Harding } else { 23471816cb70SBarry Harding if (heads[0]) { 23481816cb70SBarry Harding mblk_t *mp; 23491816cb70SBarry Harding while ((mp = heads[0]) != NULL) { 23501816cb70SBarry Harding heads[0] = mp->b_next; 23511816cb70SBarry Harding freemsg(mp); 23521816cb70SBarry Harding } 23531816cb70SBarry Harding } 23541816cb70SBarry Harding } 23551816cb70SBarry Harding 23561816cb70SBarry Harding if (port2->p_running) { 23571816cb70SBarry Harding if (txindex[1] >= 0) { 23581816cb70SBarry Harding yge_txeof(port2, txindex[1]); 23591816cb70SBarry Harding } 23601816cb70SBarry Harding if (heads[1]) 23611816cb70SBarry Harding mac_rx(port2->p_mh, NULL, heads[1]); 23621816cb70SBarry Harding } else { 23631816cb70SBarry Harding if (heads[1]) { 23641816cb70SBarry Harding mblk_t *mp; 23651816cb70SBarry Harding while ((mp = heads[1]) != NULL) { 23661816cb70SBarry Harding heads[1] = mp->b_next; 23671816cb70SBarry Harding freemsg(mp); 23681816cb70SBarry Harding } 23691816cb70SBarry Harding } 23701816cb70SBarry Harding } 23711816cb70SBarry Harding 23721816cb70SBarry Harding return (DDI_INTR_CLAIMED); 23731816cb70SBarry Harding } 23741816cb70SBarry Harding 23751816cb70SBarry Harding static void 23761816cb70SBarry Harding yge_set_tx_stfwd(yge_port_t *port) 23771816cb70SBarry Harding { 23781816cb70SBarry Harding yge_dev_t *dev = port->p_dev; 23791816cb70SBarry Harding int pnum = port->p_port; 23801816cb70SBarry Harding 23811816cb70SBarry Harding switch (dev->d_hw_id) { 23821816cb70SBarry Harding case CHIP_ID_YUKON_EX: 23831816cb70SBarry Harding if (dev->d_hw_rev == CHIP_REV_YU_EX_A0) 23841816cb70SBarry Harding goto yukon_ex_workaround; 23851816cb70SBarry Harding 23861816cb70SBarry Harding if (port->p_mtu > ETHERMTU) 23871816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), 23881816cb70SBarry Harding TX_JUMBO_ENA | TX_STFW_ENA); 23891816cb70SBarry Harding else 23901816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), 23911816cb70SBarry Harding TX_JUMBO_DIS | TX_STFW_ENA); 23921816cb70SBarry Harding break; 23931816cb70SBarry Harding default: 23941816cb70SBarry Harding yukon_ex_workaround: 23951816cb70SBarry Harding if (port->p_mtu > ETHERMTU) { 23961816cb70SBarry Harding /* Set Tx GMAC FIFO Almost Empty Threshold. */ 23971816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_AE_THR), 23981816cb70SBarry Harding MSK_ECU_JUMBO_WM << 16 | MSK_ECU_AE_THR); 23991816cb70SBarry Harding /* Disable Store & Forward mode for Tx. */ 24001816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), 24011816cb70SBarry Harding TX_JUMBO_ENA | TX_STFW_DIS); 24021816cb70SBarry Harding } else { 24031816cb70SBarry Harding /* Enable Store & Forward mode for Tx. */ 24041816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), 24051816cb70SBarry Harding TX_JUMBO_DIS | TX_STFW_ENA); 24061816cb70SBarry Harding } 24071816cb70SBarry Harding break; 24081816cb70SBarry Harding } 24091816cb70SBarry Harding } 24101816cb70SBarry Harding 24111816cb70SBarry Harding static void 24121816cb70SBarry Harding yge_start_port(yge_port_t *port) 24131816cb70SBarry Harding { 24141816cb70SBarry Harding yge_dev_t *dev = port->p_dev; 24151816cb70SBarry Harding uint16_t gmac; 24161816cb70SBarry Harding int32_t pnum; 24171816cb70SBarry Harding int32_t rxq; 24181816cb70SBarry Harding int32_t txq; 24191816cb70SBarry Harding uint32_t reg; 24201816cb70SBarry Harding 24211816cb70SBarry Harding pnum = port->p_port; 24221816cb70SBarry Harding txq = port->p_txq; 24231816cb70SBarry Harding rxq = port->p_rxq; 24241816cb70SBarry Harding 24251816cb70SBarry Harding if (port->p_mtu < ETHERMTU) 24261816cb70SBarry Harding port->p_framesize = ETHERMTU; 24271816cb70SBarry Harding else 24281816cb70SBarry Harding port->p_framesize = port->p_mtu; 24291816cb70SBarry Harding port->p_framesize += sizeof (struct ether_vlan_header); 24301816cb70SBarry Harding 24311816cb70SBarry Harding /* 24321816cb70SBarry Harding * Note for the future, if we enable offloads: 24331816cb70SBarry Harding * In Yukon EC Ultra, TSO & checksum offload is not 24341816cb70SBarry Harding * supported for jumbo frame. 24351816cb70SBarry Harding */ 24361816cb70SBarry Harding 24371816cb70SBarry Harding /* GMAC Control reset */ 24381816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, GMAC_CTRL), GMC_RST_SET); 24391816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, GMAC_CTRL), GMC_RST_CLR); 24401816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, GMAC_CTRL), GMC_F_LOOPB_OFF); 24411816cb70SBarry Harding if (dev->d_hw_id == CHIP_ID_YUKON_EX) 24421816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, GMAC_CTRL), 24431816cb70SBarry Harding GMC_BYP_MACSECRX_ON | GMC_BYP_MACSECTX_ON | 24441816cb70SBarry Harding GMC_BYP_RETR_ON); 24451816cb70SBarry Harding /* 24461816cb70SBarry Harding * Initialize GMAC first such that speed/duplex/flow-control 24471816cb70SBarry Harding * parameters are renegotiated with the interface is brought up. 24481816cb70SBarry Harding */ 24491816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_GP_CTRL, 0); 24501816cb70SBarry Harding 24511816cb70SBarry Harding /* Dummy read the Interrupt Source Register. */ 24521816cb70SBarry Harding (void) CSR_READ_1(dev, MR_ADDR(pnum, GMAC_IRQ_SRC)); 24531816cb70SBarry Harding 24541816cb70SBarry Harding /* Clear MIB stats. */ 24551816cb70SBarry Harding yge_stats_clear(port); 24561816cb70SBarry Harding 24571816cb70SBarry Harding /* Disable FCS. */ 24581816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_RX_CTRL, GM_RXCR_CRC_DIS); 24591816cb70SBarry Harding 24601816cb70SBarry Harding /* Setup Transmit Control Register. */ 24611816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF)); 24621816cb70SBarry Harding 24631816cb70SBarry Harding /* Setup Transmit Flow Control Register. */ 24641816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_TX_FLOW_CTRL, 0xffff); 24651816cb70SBarry Harding 24661816cb70SBarry Harding /* Setup Transmit Parameter Register. */ 24671816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_TX_PARAM, 24681816cb70SBarry Harding TX_JAM_LEN_VAL(TX_JAM_LEN_DEF) | TX_JAM_IPG_VAL(TX_JAM_IPG_DEF) | 24691816cb70SBarry Harding TX_IPG_JAM_DATA(TX_IPG_JAM_DEF) | TX_BACK_OFF_LIM(TX_BOF_LIM_DEF)); 24701816cb70SBarry Harding 24711816cb70SBarry Harding gmac = DATA_BLIND_VAL(DATA_BLIND_DEF) | 24721816cb70SBarry Harding GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF); 24731816cb70SBarry Harding 24741816cb70SBarry Harding if (port->p_mtu > ETHERMTU) 24751816cb70SBarry Harding gmac |= GM_SMOD_JUMBO_ENA; 24761816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_SERIAL_MODE, gmac); 24771816cb70SBarry Harding 24781816cb70SBarry Harding /* Disable interrupts for counter overflows. */ 24791816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_TX_IRQ_MSK, 0); 24801816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_RX_IRQ_MSK, 0); 24811816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_TR_IRQ_MSK, 0); 24821816cb70SBarry Harding 24831816cb70SBarry Harding /* Configure Rx MAC FIFO. */ 24841816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_CTRL_T), GMF_RST_SET); 24851816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_CTRL_T), GMF_RST_CLR); 24861816cb70SBarry Harding reg = GMF_OPER_ON | GMF_RX_F_FL_ON; 24871816cb70SBarry Harding if (dev->d_hw_id == CHIP_ID_YUKON_FE_P || 24881816cb70SBarry Harding dev->d_hw_id == CHIP_ID_YUKON_EX) 24891816cb70SBarry Harding reg |= GMF_RX_OVER_ON; 24901816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_CTRL_T), reg); 24911816cb70SBarry Harding 24921816cb70SBarry Harding /* Set receive filter. */ 24931816cb70SBarry Harding yge_setrxfilt(port); 24941816cb70SBarry Harding 24951816cb70SBarry Harding /* Flush Rx MAC FIFO on any flow control or error. */ 24961816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_FL_MSK), GMR_FS_ANY_ERR); 24971816cb70SBarry Harding 24981816cb70SBarry Harding /* 24991816cb70SBarry Harding * Set Rx FIFO flush threshold to 64 bytes + 1 FIFO word 25001816cb70SBarry Harding * due to hardware hang on receipt of pause frames. 25011816cb70SBarry Harding */ 25021816cb70SBarry Harding reg = RX_GMF_FL_THR_DEF + 1; 25031816cb70SBarry Harding /* FE+ magic */ 25041816cb70SBarry Harding if ((dev->d_hw_id == CHIP_ID_YUKON_FE_P) && 25051816cb70SBarry Harding (dev->d_hw_rev == CHIP_REV_YU_FE2_A0)) 25061816cb70SBarry Harding reg = 0x178; 25071816cb70SBarry Harding 25081816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_FL_THR), reg); 25091816cb70SBarry Harding 25101816cb70SBarry Harding /* Configure Tx MAC FIFO. */ 25111816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), GMF_RST_SET); 25121816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), GMF_RST_CLR); 25131816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), GMF_OPER_ON); 25141816cb70SBarry Harding 25151816cb70SBarry Harding /* Disable hardware VLAN tag insertion/stripping. */ 25161816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_CTRL_T), RX_VLAN_STRIP_OFF); 25171816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), TX_VLAN_TAG_OFF); 25181816cb70SBarry Harding 25191816cb70SBarry Harding if ((port->p_flags & PORT_FLAG_RAMBUF) == 0) { 25201816cb70SBarry Harding /* Set Rx Pause threshold. */ 25211816cb70SBarry Harding if ((dev->d_hw_id == CHIP_ID_YUKON_FE_P) && 25221816cb70SBarry Harding (dev->d_hw_rev == CHIP_REV_YU_FE2_A0)) { 25231816cb70SBarry Harding CSR_WRITE_1(dev, MR_ADDR(pnum, RX_GMF_LP_THR), 25241816cb70SBarry Harding MSK_ECU_LLPP); 25251816cb70SBarry Harding CSR_WRITE_1(dev, MR_ADDR(pnum, RX_GMF_UP_THR), 25261816cb70SBarry Harding MSK_FEP_ULPP); 25271816cb70SBarry Harding } else { 25281816cb70SBarry Harding CSR_WRITE_1(dev, MR_ADDR(pnum, RX_GMF_LP_THR), 25291816cb70SBarry Harding MSK_ECU_LLPP); 25301816cb70SBarry Harding CSR_WRITE_1(dev, MR_ADDR(pnum, RX_GMF_UP_THR), 25311816cb70SBarry Harding MSK_ECU_ULPP); 25321816cb70SBarry Harding } 25331816cb70SBarry Harding /* Configure store-and-forward for TX */ 25341816cb70SBarry Harding yge_set_tx_stfwd(port); 25351816cb70SBarry Harding } 25361816cb70SBarry Harding 25371816cb70SBarry Harding if ((dev->d_hw_id == CHIP_ID_YUKON_FE_P) && 25381816cb70SBarry Harding (dev->d_hw_rev == CHIP_REV_YU_FE2_A0)) { 25391816cb70SBarry Harding /* Disable dynamic watermark */ 25401816cb70SBarry Harding reg = CSR_READ_4(dev, MR_ADDR(pnum, TX_GMF_EA)); 25411816cb70SBarry Harding reg &= ~TX_DYN_WM_ENA; 25421816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_EA), reg); 25431816cb70SBarry Harding } 25441816cb70SBarry Harding 25451816cb70SBarry Harding /* 25461816cb70SBarry Harding * Disable Force Sync bit and Alloc bit in Tx RAM interface 25471816cb70SBarry Harding * arbiter as we don't use Sync Tx queue. 25481816cb70SBarry Harding */ 25491816cb70SBarry Harding CSR_WRITE_1(dev, MR_ADDR(pnum, TXA_CTRL), 25501816cb70SBarry Harding TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC); 25511816cb70SBarry Harding /* Enable the RAM Interface Arbiter. */ 25521816cb70SBarry Harding CSR_WRITE_1(dev, MR_ADDR(pnum, TXA_CTRL), TXA_ENA_ARB); 25531816cb70SBarry Harding 25541816cb70SBarry Harding /* Setup RAM buffer. */ 25551816cb70SBarry Harding yge_set_rambuffer(port); 25561816cb70SBarry Harding 25571816cb70SBarry Harding /* Disable Tx sync Queue. */ 25581816cb70SBarry Harding CSR_WRITE_1(dev, RB_ADDR(port->p_txsq, RB_CTRL), RB_RST_SET); 25591816cb70SBarry Harding 25601816cb70SBarry Harding /* Setup Tx Queue Bus Memory Interface. */ 25611816cb70SBarry Harding CSR_WRITE_4(dev, Q_ADDR(txq, Q_CSR), BMU_CLR_RESET); 25621816cb70SBarry Harding CSR_WRITE_4(dev, Q_ADDR(txq, Q_CSR), BMU_OPER_INIT); 25631816cb70SBarry Harding CSR_WRITE_4(dev, Q_ADDR(txq, Q_CSR), BMU_FIFO_OP_ON); 25641816cb70SBarry Harding CSR_WRITE_2(dev, Q_ADDR(txq, Q_WM), MSK_BMU_TX_WM); 25651816cb70SBarry Harding 25661816cb70SBarry Harding switch (dev->d_hw_id) { 25671816cb70SBarry Harding case CHIP_ID_YUKON_EC_U: 25681816cb70SBarry Harding if (dev->d_hw_rev == CHIP_REV_YU_EC_U_A0) { 25691816cb70SBarry Harding /* Fix for Yukon-EC Ultra: set BMU FIFO level */ 25701816cb70SBarry Harding CSR_WRITE_2(dev, Q_ADDR(txq, Q_AL), MSK_ECU_TXFF_LEV); 25711816cb70SBarry Harding } 25721816cb70SBarry Harding break; 25731816cb70SBarry Harding case CHIP_ID_YUKON_EX: 25741816cb70SBarry Harding /* 25751816cb70SBarry Harding * Yukon Extreme seems to have silicon bug for 25761816cb70SBarry Harding * automatic Tx checksum calculation capability. 25771816cb70SBarry Harding */ 25781816cb70SBarry Harding if (dev->d_hw_rev == CHIP_REV_YU_EX_B0) 25791816cb70SBarry Harding CSR_WRITE_4(dev, Q_ADDR(txq, Q_F), F_TX_CHK_AUTO_OFF); 25801816cb70SBarry Harding break; 25811816cb70SBarry Harding } 25821816cb70SBarry Harding 25831816cb70SBarry Harding /* Setup Rx Queue Bus Memory Interface. */ 25841816cb70SBarry Harding CSR_WRITE_4(dev, Q_ADDR(rxq, Q_CSR), BMU_CLR_RESET); 25851816cb70SBarry Harding CSR_WRITE_4(dev, Q_ADDR(rxq, Q_CSR), BMU_OPER_INIT); 25861816cb70SBarry Harding CSR_WRITE_4(dev, Q_ADDR(rxq, Q_CSR), BMU_FIFO_OP_ON); 25871816cb70SBarry Harding if (dev->d_bustype == PEX_BUS) { 25881816cb70SBarry Harding CSR_WRITE_2(dev, Q_ADDR(rxq, Q_WM), 0x80); 25891816cb70SBarry Harding } else { 25901816cb70SBarry Harding CSR_WRITE_2(dev, Q_ADDR(rxq, Q_WM), MSK_BMU_RX_WM); 25911816cb70SBarry Harding } 25921816cb70SBarry Harding if (dev->d_hw_id == CHIP_ID_YUKON_EC_U && 25931816cb70SBarry Harding dev->d_hw_rev >= CHIP_REV_YU_EC_U_A1) { 25941816cb70SBarry Harding /* MAC Rx RAM Read is controlled by hardware. */ 25951816cb70SBarry Harding CSR_WRITE_4(dev, Q_ADDR(rxq, Q_F), F_M_RX_RAM_DIS); 25961816cb70SBarry Harding } 25971816cb70SBarry Harding 25981816cb70SBarry Harding yge_init_tx_ring(port); 25991816cb70SBarry Harding 26001816cb70SBarry Harding /* Disable Rx checksum offload and RSS hash. */ 26011816cb70SBarry Harding CSR_WRITE_4(dev, Q_ADDR(rxq, Q_CSR), 26021816cb70SBarry Harding BMU_DIS_RX_CHKSUM | BMU_DIS_RX_RSS_HASH); 26031816cb70SBarry Harding 26041816cb70SBarry Harding yge_init_rx_ring(port); 26051816cb70SBarry Harding 26061816cb70SBarry Harding /* Configure interrupt handling. */ 26071816cb70SBarry Harding if (port == dev->d_port[YGE_PORT_A]) { 26081816cb70SBarry Harding dev->d_intrmask |= Y2_IS_PORT_A; 26091816cb70SBarry Harding dev->d_intrhwemask |= Y2_HWE_L1_MASK; 26101816cb70SBarry Harding } else if (port == dev->d_port[YGE_PORT_B]) { 26111816cb70SBarry Harding dev->d_intrmask |= Y2_IS_PORT_B; 26121816cb70SBarry Harding dev->d_intrhwemask |= Y2_HWE_L2_MASK; 26131816cb70SBarry Harding } 26141816cb70SBarry Harding CSR_WRITE_4(dev, B0_HWE_IMSK, dev->d_intrhwemask); 26151816cb70SBarry Harding (void) CSR_READ_4(dev, B0_HWE_IMSK); 26161816cb70SBarry Harding CSR_WRITE_4(dev, B0_IMSK, dev->d_intrmask); 26171816cb70SBarry Harding (void) CSR_READ_4(dev, B0_IMSK); 26181816cb70SBarry Harding 26191816cb70SBarry Harding /* Enable RX/TX GMAC */ 26201816cb70SBarry Harding gmac = GMAC_READ_2(dev, pnum, GM_GP_CTRL); 26211816cb70SBarry Harding gmac |= (GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); 26221816cb70SBarry Harding GMAC_WRITE_2(port->p_dev, port->p_port, GM_GP_CTRL, gmac); 26231816cb70SBarry Harding /* Read again to ensure writing. */ 26241816cb70SBarry Harding (void) GMAC_READ_2(dev, pnum, GM_GP_CTRL); 26251816cb70SBarry Harding 26261816cb70SBarry Harding /* Reset TX timer */ 26271816cb70SBarry Harding port->p_tx_wdog = 0; 26281816cb70SBarry Harding } 26291816cb70SBarry Harding 26301816cb70SBarry Harding static void 26311816cb70SBarry Harding yge_set_rambuffer(yge_port_t *port) 26321816cb70SBarry Harding { 26331816cb70SBarry Harding yge_dev_t *dev; 26341816cb70SBarry Harding int ltpp, utpp; 26351816cb70SBarry Harding int pnum; 26361816cb70SBarry Harding uint32_t rxq; 26371816cb70SBarry Harding uint32_t txq; 26381816cb70SBarry Harding 26391816cb70SBarry Harding dev = port->p_dev; 26401816cb70SBarry Harding pnum = port->p_port; 26411816cb70SBarry Harding rxq = port->p_rxq; 26421816cb70SBarry Harding txq = port->p_txq; 26431816cb70SBarry Harding 26441816cb70SBarry Harding if ((port->p_flags & PORT_FLAG_RAMBUF) == 0) 26451816cb70SBarry Harding return; 26461816cb70SBarry Harding 26471816cb70SBarry Harding /* Setup Rx Queue. */ 26481816cb70SBarry Harding CSR_WRITE_1(dev, RB_ADDR(rxq, RB_CTRL), RB_RST_CLR); 26491816cb70SBarry Harding CSR_WRITE_4(dev, RB_ADDR(rxq, RB_START), dev->d_rxqstart[pnum] / 8); 26501816cb70SBarry Harding CSR_WRITE_4(dev, RB_ADDR(rxq, RB_END), dev->d_rxqend[pnum] / 8); 26511816cb70SBarry Harding CSR_WRITE_4(dev, RB_ADDR(rxq, RB_WP), dev->d_rxqstart[pnum] / 8); 26521816cb70SBarry Harding CSR_WRITE_4(dev, RB_ADDR(rxq, RB_RP), dev->d_rxqstart[pnum] / 8); 26531816cb70SBarry Harding 26541816cb70SBarry Harding utpp = 26551816cb70SBarry Harding (dev->d_rxqend[pnum] + 1 - dev->d_rxqstart[pnum] - RB_ULPP) / 8; 26561816cb70SBarry Harding ltpp = 26571816cb70SBarry Harding (dev->d_rxqend[pnum] + 1 - dev->d_rxqstart[pnum] - RB_LLPP_B) / 8; 26581816cb70SBarry Harding 26591816cb70SBarry Harding if (dev->d_rxqsize < MSK_MIN_RXQ_SIZE) 26601816cb70SBarry Harding ltpp += (RB_LLPP_B - RB_LLPP_S) / 8; 26611816cb70SBarry Harding 26621816cb70SBarry Harding CSR_WRITE_4(dev, RB_ADDR(rxq, RB_RX_UTPP), utpp); 26631816cb70SBarry Harding CSR_WRITE_4(dev, RB_ADDR(rxq, RB_RX_LTPP), ltpp); 26641816cb70SBarry Harding /* Set Rx priority(RB_RX_UTHP/RB_RX_LTHP) thresholds? */ 26651816cb70SBarry Harding 26661816cb70SBarry Harding CSR_WRITE_1(dev, RB_ADDR(rxq, RB_CTRL), RB_ENA_OP_MD); 26671816cb70SBarry Harding (void) CSR_READ_1(dev, RB_ADDR(rxq, RB_CTRL)); 26681816cb70SBarry Harding 26691816cb70SBarry Harding /* Setup Tx Queue. */ 26701816cb70SBarry Harding CSR_WRITE_1(dev, RB_ADDR(txq, RB_CTRL), RB_RST_CLR); 26711816cb70SBarry Harding CSR_WRITE_4(dev, RB_ADDR(txq, RB_START), dev->d_txqstart[pnum] / 8); 26721816cb70SBarry Harding CSR_WRITE_4(dev, RB_ADDR(txq, RB_END), dev->d_txqend[pnum] / 8); 26731816cb70SBarry Harding CSR_WRITE_4(dev, RB_ADDR(txq, RB_WP), dev->d_txqstart[pnum] / 8); 26741816cb70SBarry Harding CSR_WRITE_4(dev, RB_ADDR(txq, RB_RP), dev->d_txqstart[pnum] / 8); 26751816cb70SBarry Harding /* Enable Store & Forward for Tx side. */ 26761816cb70SBarry Harding CSR_WRITE_1(dev, RB_ADDR(txq, RB_CTRL), RB_ENA_STFWD); 26771816cb70SBarry Harding CSR_WRITE_1(dev, RB_ADDR(txq, RB_CTRL), RB_ENA_OP_MD); 26781816cb70SBarry Harding (void) CSR_READ_1(dev, RB_ADDR(txq, RB_CTRL)); 26791816cb70SBarry Harding } 26801816cb70SBarry Harding 26811816cb70SBarry Harding static void 26821816cb70SBarry Harding yge_set_prefetch(yge_dev_t *dev, int qaddr, yge_ring_t *ring) 26831816cb70SBarry Harding { 26841816cb70SBarry Harding /* Reset the prefetch unit. */ 26851816cb70SBarry Harding CSR_WRITE_4(dev, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_CTRL_REG), 26861816cb70SBarry Harding PREF_UNIT_RST_SET); 26871816cb70SBarry Harding CSR_WRITE_4(dev, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_CTRL_REG), 26881816cb70SBarry Harding PREF_UNIT_RST_CLR); 26891816cb70SBarry Harding /* Set LE base address. */ 26901816cb70SBarry Harding CSR_WRITE_4(dev, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_ADDR_LOW_REG), 26911816cb70SBarry Harding YGE_ADDR_LO(ring->r_paddr)); 26921816cb70SBarry Harding CSR_WRITE_4(dev, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_ADDR_HI_REG), 26931816cb70SBarry Harding YGE_ADDR_HI(ring->r_paddr)); 26941816cb70SBarry Harding /* Set the list last index. */ 26951816cb70SBarry Harding CSR_WRITE_2(dev, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_LAST_IDX_REG), 26961816cb70SBarry Harding ring->r_num - 1); 26971816cb70SBarry Harding /* Turn on prefetch unit. */ 26981816cb70SBarry Harding CSR_WRITE_4(dev, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_CTRL_REG), 26991816cb70SBarry Harding PREF_UNIT_OP_ON); 27001816cb70SBarry Harding /* Dummy read to ensure write. */ 27011816cb70SBarry Harding (void) CSR_READ_4(dev, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_CTRL_REG)); 27021816cb70SBarry Harding } 27031816cb70SBarry Harding 27041816cb70SBarry Harding static void 27051816cb70SBarry Harding yge_stop_port(yge_port_t *port) 27061816cb70SBarry Harding { 27071816cb70SBarry Harding yge_dev_t *dev = port->p_dev; 27081816cb70SBarry Harding int pnum = port->p_port; 27091816cb70SBarry Harding uint32_t txq = port->p_txq; 27101816cb70SBarry Harding uint32_t rxq = port->p_rxq; 27111816cb70SBarry Harding uint32_t val; 27121816cb70SBarry Harding int i; 27131816cb70SBarry Harding 27141816cb70SBarry Harding dev = port->p_dev; 27151816cb70SBarry Harding 27161816cb70SBarry Harding /* 27171816cb70SBarry Harding * shutdown timeout 27181816cb70SBarry Harding */ 27191816cb70SBarry Harding port->p_tx_wdog = 0; 27201816cb70SBarry Harding 27211816cb70SBarry Harding /* Disable interrupts. */ 27221816cb70SBarry Harding if (pnum == YGE_PORT_A) { 27231816cb70SBarry Harding dev->d_intrmask &= ~Y2_IS_PORT_A; 27241816cb70SBarry Harding dev->d_intrhwemask &= ~Y2_HWE_L1_MASK; 27251816cb70SBarry Harding } else { 27261816cb70SBarry Harding dev->d_intrmask &= ~Y2_IS_PORT_B; 27271816cb70SBarry Harding dev->d_intrhwemask &= ~Y2_HWE_L2_MASK; 27281816cb70SBarry Harding } 27291816cb70SBarry Harding CSR_WRITE_4(dev, B0_HWE_IMSK, dev->d_intrhwemask); 27301816cb70SBarry Harding (void) CSR_READ_4(dev, B0_HWE_IMSK); 27311816cb70SBarry Harding CSR_WRITE_4(dev, B0_IMSK, dev->d_intrmask); 27321816cb70SBarry Harding (void) CSR_READ_4(dev, B0_IMSK); 27331816cb70SBarry Harding 27341816cb70SBarry Harding /* Disable Tx/Rx MAC. */ 27351816cb70SBarry Harding val = GMAC_READ_2(dev, pnum, GM_GP_CTRL); 27361816cb70SBarry Harding val &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); 27371816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_GP_CTRL, val); 27381816cb70SBarry Harding /* Read again to ensure writing. */ 27391816cb70SBarry Harding (void) GMAC_READ_2(dev, pnum, GM_GP_CTRL); 27401816cb70SBarry Harding 27411816cb70SBarry Harding /* Update stats and clear counters. */ 27421816cb70SBarry Harding yge_stats_update(port); 27431816cb70SBarry Harding 27441816cb70SBarry Harding /* Stop Tx BMU. */ 27451816cb70SBarry Harding CSR_WRITE_4(dev, Q_ADDR(txq, Q_CSR), BMU_STOP); 27461816cb70SBarry Harding val = CSR_READ_4(dev, Q_ADDR(txq, Q_CSR)); 27471816cb70SBarry Harding for (i = 0; i < YGE_TIMEOUT; i += 10) { 27481816cb70SBarry Harding if ((val & (BMU_STOP | BMU_IDLE)) == 0) { 27491816cb70SBarry Harding CSR_WRITE_4(dev, Q_ADDR(txq, Q_CSR), BMU_STOP); 27501816cb70SBarry Harding val = CSR_READ_4(dev, Q_ADDR(txq, Q_CSR)); 27511816cb70SBarry Harding } else 27521816cb70SBarry Harding break; 27531816cb70SBarry Harding drv_usecwait(10); 27541816cb70SBarry Harding } 27551816cb70SBarry Harding /* This is probably fairly catastrophic. */ 27561816cb70SBarry Harding if ((val & (BMU_STOP | BMU_IDLE)) == 0) 27571816cb70SBarry Harding yge_error(NULL, port, "Tx BMU stop failed"); 27581816cb70SBarry Harding 27591816cb70SBarry Harding CSR_WRITE_1(dev, RB_ADDR(txq, RB_CTRL), RB_RST_SET | RB_DIS_OP_MD); 27601816cb70SBarry Harding 27611816cb70SBarry Harding /* Disable all GMAC interrupt. */ 27621816cb70SBarry Harding CSR_WRITE_1(dev, MR_ADDR(pnum, GMAC_IRQ_MSK), 0); 27631816cb70SBarry Harding 27641816cb70SBarry Harding /* Disable the RAM Interface Arbiter. */ 27651816cb70SBarry Harding CSR_WRITE_1(dev, MR_ADDR(pnum, TXA_CTRL), TXA_DIS_ARB); 27661816cb70SBarry Harding 27671816cb70SBarry Harding /* Reset the PCI FIFO of the async Tx queue */ 27681816cb70SBarry Harding CSR_WRITE_4(dev, Q_ADDR(txq, Q_CSR), BMU_RST_SET | BMU_FIFO_RST); 27691816cb70SBarry Harding 27701816cb70SBarry Harding /* Reset the Tx prefetch units. */ 27711816cb70SBarry Harding CSR_WRITE_4(dev, Y2_PREF_Q_ADDR(txq, PREF_UNIT_CTRL_REG), 27721816cb70SBarry Harding PREF_UNIT_RST_SET); 27731816cb70SBarry Harding 27741816cb70SBarry Harding /* Reset the RAM Buffer async Tx queue. */ 27751816cb70SBarry Harding CSR_WRITE_1(dev, RB_ADDR(txq, RB_CTRL), RB_RST_SET); 27761816cb70SBarry Harding 27771816cb70SBarry Harding /* Reset Tx MAC FIFO. */ 27781816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), GMF_RST_SET); 27791816cb70SBarry Harding /* Set Pause Off. */ 27801816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, GMAC_CTRL), GMC_PAUSE_OFF); 27811816cb70SBarry Harding 27821816cb70SBarry Harding /* 27831816cb70SBarry Harding * The Rx Stop command will not work for Yukon-2 if the BMU does not 27841816cb70SBarry Harding * reach the end of packet and since we can't make sure that we have 27851816cb70SBarry Harding * incoming data, we must reset the BMU while it is not during a DMA 27861816cb70SBarry Harding * transfer. Since it is possible that the Rx path is still active, 27871816cb70SBarry Harding * the Rx RAM buffer will be stopped first, so any possible incoming 27881816cb70SBarry Harding * data will not trigger a DMA. After the RAM buffer is stopped, the 27891816cb70SBarry Harding * BMU is polled until any DMA in progress is ended and only then it 27901816cb70SBarry Harding * will be reset. 27911816cb70SBarry Harding */ 27921816cb70SBarry Harding 27931816cb70SBarry Harding /* Disable the RAM Buffer receive queue. */ 27941816cb70SBarry Harding CSR_WRITE_1(dev, RB_ADDR(rxq, RB_CTRL), RB_DIS_OP_MD); 27951816cb70SBarry Harding for (i = 0; i < YGE_TIMEOUT; i += 10) { 27961816cb70SBarry Harding if (CSR_READ_1(dev, RB_ADDR(rxq, Q_RSL)) == 27971816cb70SBarry Harding CSR_READ_1(dev, RB_ADDR(rxq, Q_RL))) 27981816cb70SBarry Harding break; 27991816cb70SBarry Harding drv_usecwait(10); 28001816cb70SBarry Harding } 28011816cb70SBarry Harding /* This is probably nearly a fatal error. */ 28021816cb70SBarry Harding if (i == YGE_TIMEOUT) 28031816cb70SBarry Harding yge_error(NULL, port, "Rx BMU stop failed"); 28041816cb70SBarry Harding 28051816cb70SBarry Harding CSR_WRITE_4(dev, Q_ADDR(rxq, Q_CSR), BMU_RST_SET | BMU_FIFO_RST); 28061816cb70SBarry Harding /* Reset the Rx prefetch unit. */ 28071816cb70SBarry Harding CSR_WRITE_4(dev, Y2_PREF_Q_ADDR(rxq, PREF_UNIT_CTRL_REG), 28081816cb70SBarry Harding PREF_UNIT_RST_SET); 28091816cb70SBarry Harding /* Reset the RAM Buffer receive queue. */ 28101816cb70SBarry Harding CSR_WRITE_1(dev, RB_ADDR(rxq, RB_CTRL), RB_RST_SET); 28111816cb70SBarry Harding /* Reset Rx MAC FIFO. */ 28121816cb70SBarry Harding CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_CTRL_T), GMF_RST_SET); 28131816cb70SBarry Harding } 28141816cb70SBarry Harding 28151816cb70SBarry Harding /* 28161816cb70SBarry Harding * When GM_PAR_MIB_CLR bit of GM_PHY_ADDR is set, reading lower 28171816cb70SBarry Harding * counter clears high 16 bits of the counter such that accessing 28181816cb70SBarry Harding * lower 16 bits should be the last operation. 28191816cb70SBarry Harding */ 28201816cb70SBarry Harding #define YGE_READ_MIB32(x, y) \ 28211816cb70SBarry Harding GMAC_READ_4(dev, x, y) 28221816cb70SBarry Harding 28231816cb70SBarry Harding #define YGE_READ_MIB64(x, y) \ 28241816cb70SBarry Harding ((((uint64_t)YGE_READ_MIB32(x, (y) + 8)) << 32) + \ 28251816cb70SBarry Harding (uint64_t)YGE_READ_MIB32(x, y)) 28261816cb70SBarry Harding 28271816cb70SBarry Harding static void 28281816cb70SBarry Harding yge_stats_clear(yge_port_t *port) 28291816cb70SBarry Harding { 28301816cb70SBarry Harding yge_dev_t *dev; 28311816cb70SBarry Harding uint16_t gmac; 28321816cb70SBarry Harding int32_t pnum; 28331816cb70SBarry Harding 28341816cb70SBarry Harding pnum = port->p_port; 28351816cb70SBarry Harding dev = port->p_dev; 28361816cb70SBarry Harding 28371816cb70SBarry Harding /* Set MIB Clear Counter Mode. */ 28381816cb70SBarry Harding gmac = GMAC_READ_2(dev, pnum, GM_PHY_ADDR); 28391816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_PHY_ADDR, gmac | GM_PAR_MIB_CLR); 28401816cb70SBarry Harding /* Read all MIB Counters with Clear Mode set. */ 28411816cb70SBarry Harding for (int i = GM_RXF_UC_OK; i <= GM_TXE_FIFO_UR; i += 4) 28421816cb70SBarry Harding (void) YGE_READ_MIB32(pnum, i); 28431816cb70SBarry Harding /* Clear MIB Clear Counter Mode. */ 28441816cb70SBarry Harding gmac &= ~GM_PAR_MIB_CLR; 28451816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_PHY_ADDR, gmac); 28461816cb70SBarry Harding } 28471816cb70SBarry Harding 28481816cb70SBarry Harding static void 28491816cb70SBarry Harding yge_stats_update(yge_port_t *port) 28501816cb70SBarry Harding { 28511816cb70SBarry Harding yge_dev_t *dev; 28521816cb70SBarry Harding struct yge_hw_stats *stats; 28531816cb70SBarry Harding uint16_t gmac; 28541816cb70SBarry Harding int32_t pnum; 28551816cb70SBarry Harding 28561816cb70SBarry Harding dev = port->p_dev; 28571816cb70SBarry Harding pnum = port->p_port; 28581816cb70SBarry Harding 28591816cb70SBarry Harding if (dev->d_suspended || !port->p_running) { 28601816cb70SBarry Harding return; 28611816cb70SBarry Harding } 28621816cb70SBarry Harding stats = &port->p_stats; 28631816cb70SBarry Harding /* Set MIB Clear Counter Mode. */ 28641816cb70SBarry Harding gmac = GMAC_READ_2(dev, pnum, GM_PHY_ADDR); 28651816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_PHY_ADDR, gmac | GM_PAR_MIB_CLR); 28661816cb70SBarry Harding 28671816cb70SBarry Harding /* Rx stats. */ 28681816cb70SBarry Harding stats->rx_ucast_frames += YGE_READ_MIB32(pnum, GM_RXF_UC_OK); 28691816cb70SBarry Harding stats->rx_bcast_frames += YGE_READ_MIB32(pnum, GM_RXF_BC_OK); 28701816cb70SBarry Harding stats->rx_pause_frames += YGE_READ_MIB32(pnum, GM_RXF_MPAUSE); 28711816cb70SBarry Harding stats->rx_mcast_frames += YGE_READ_MIB32(pnum, GM_RXF_MC_OK); 28721816cb70SBarry Harding stats->rx_crc_errs += YGE_READ_MIB32(pnum, GM_RXF_FCS_ERR); 28731816cb70SBarry Harding (void) YGE_READ_MIB32(pnum, GM_RXF_SPARE1); 28741816cb70SBarry Harding stats->rx_good_octets += YGE_READ_MIB64(pnum, GM_RXO_OK_LO); 28751816cb70SBarry Harding stats->rx_bad_octets += YGE_READ_MIB64(pnum, GM_RXO_ERR_LO); 28761816cb70SBarry Harding stats->rx_runts += YGE_READ_MIB32(pnum, GM_RXF_SHT); 28771816cb70SBarry Harding stats->rx_runt_errs += YGE_READ_MIB32(pnum, GM_RXE_FRAG); 28781816cb70SBarry Harding stats->rx_pkts_64 += YGE_READ_MIB32(pnum, GM_RXF_64B); 28791816cb70SBarry Harding stats->rx_pkts_65_127 += YGE_READ_MIB32(pnum, GM_RXF_127B); 28801816cb70SBarry Harding stats->rx_pkts_128_255 += YGE_READ_MIB32(pnum, GM_RXF_255B); 28811816cb70SBarry Harding stats->rx_pkts_256_511 += YGE_READ_MIB32(pnum, GM_RXF_511B); 28821816cb70SBarry Harding stats->rx_pkts_512_1023 += YGE_READ_MIB32(pnum, GM_RXF_1023B); 28831816cb70SBarry Harding stats->rx_pkts_1024_1518 += YGE_READ_MIB32(pnum, GM_RXF_1518B); 28841816cb70SBarry Harding stats->rx_pkts_1519_max += YGE_READ_MIB32(pnum, GM_RXF_MAX_SZ); 28851816cb70SBarry Harding stats->rx_pkts_too_long += YGE_READ_MIB32(pnum, GM_RXF_LNG_ERR); 28861816cb70SBarry Harding stats->rx_pkts_jabbers += YGE_READ_MIB32(pnum, GM_RXF_JAB_PKT); 28871816cb70SBarry Harding (void) YGE_READ_MIB32(pnum, GM_RXF_SPARE2); 28881816cb70SBarry Harding stats->rx_fifo_oflows += YGE_READ_MIB32(pnum, GM_RXE_FIFO_OV); 28891816cb70SBarry Harding (void) YGE_READ_MIB32(pnum, GM_RXF_SPARE3); 28901816cb70SBarry Harding 28911816cb70SBarry Harding /* Tx stats. */ 28921816cb70SBarry Harding stats->tx_ucast_frames += YGE_READ_MIB32(pnum, GM_TXF_UC_OK); 28931816cb70SBarry Harding stats->tx_bcast_frames += YGE_READ_MIB32(pnum, GM_TXF_BC_OK); 28941816cb70SBarry Harding stats->tx_pause_frames += YGE_READ_MIB32(pnum, GM_TXF_MPAUSE); 28951816cb70SBarry Harding stats->tx_mcast_frames += YGE_READ_MIB32(pnum, GM_TXF_MC_OK); 28961816cb70SBarry Harding stats->tx_octets += YGE_READ_MIB64(pnum, GM_TXO_OK_LO); 28971816cb70SBarry Harding stats->tx_pkts_64 += YGE_READ_MIB32(pnum, GM_TXF_64B); 28981816cb70SBarry Harding stats->tx_pkts_65_127 += YGE_READ_MIB32(pnum, GM_TXF_127B); 28991816cb70SBarry Harding stats->tx_pkts_128_255 += YGE_READ_MIB32(pnum, GM_TXF_255B); 29001816cb70SBarry Harding stats->tx_pkts_256_511 += YGE_READ_MIB32(pnum, GM_TXF_511B); 29011816cb70SBarry Harding stats->tx_pkts_512_1023 += YGE_READ_MIB32(pnum, GM_TXF_1023B); 29021816cb70SBarry Harding stats->tx_pkts_1024_1518 += YGE_READ_MIB32(pnum, GM_TXF_1518B); 29031816cb70SBarry Harding stats->tx_pkts_1519_max += YGE_READ_MIB32(pnum, GM_TXF_MAX_SZ); 29041816cb70SBarry Harding (void) YGE_READ_MIB32(pnum, GM_TXF_SPARE1); 29051816cb70SBarry Harding stats->tx_colls += YGE_READ_MIB32(pnum, GM_TXF_COL); 29061816cb70SBarry Harding stats->tx_late_colls += YGE_READ_MIB32(pnum, GM_TXF_LAT_COL); 29071816cb70SBarry Harding stats->tx_excess_colls += YGE_READ_MIB32(pnum, GM_TXF_ABO_COL); 29081816cb70SBarry Harding stats->tx_multi_colls += YGE_READ_MIB32(pnum, GM_TXF_MUL_COL); 29091816cb70SBarry Harding stats->tx_single_colls += YGE_READ_MIB32(pnum, GM_TXF_SNG_COL); 29101816cb70SBarry Harding stats->tx_underflows += YGE_READ_MIB32(pnum, GM_TXE_FIFO_UR); 29111816cb70SBarry Harding /* Clear MIB Clear Counter Mode. */ 29121816cb70SBarry Harding gmac &= ~GM_PAR_MIB_CLR; 29131816cb70SBarry Harding GMAC_WRITE_2(dev, pnum, GM_PHY_ADDR, gmac); 29141816cb70SBarry Harding } 29151816cb70SBarry Harding 29161816cb70SBarry Harding #undef YGE_READ_MIB32 29171816cb70SBarry Harding #undef YGE_READ_MIB64 29181816cb70SBarry Harding 29191816cb70SBarry Harding uint32_t 29201816cb70SBarry Harding yge_hashbit(const uint8_t *addr) 29211816cb70SBarry Harding { 29221816cb70SBarry Harding int idx; 29231816cb70SBarry Harding int bit; 29241816cb70SBarry Harding uint_t data; 29251816cb70SBarry Harding uint32_t crc; 29261816cb70SBarry Harding #define POLY_BE 0x04c11db7 29271816cb70SBarry Harding 29281816cb70SBarry Harding crc = 0xffffffff; 29291816cb70SBarry Harding for (idx = 0; idx < 6; idx++) { 29301816cb70SBarry Harding for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) { 29311816cb70SBarry Harding crc = (crc << 1) 29321816cb70SBarry Harding ^ ((((crc >> 31) ^ data) & 1) ? POLY_BE : 0); 29331816cb70SBarry Harding } 29341816cb70SBarry Harding } 29351816cb70SBarry Harding #undef POLY_BE 29361816cb70SBarry Harding 29371816cb70SBarry Harding return (crc % 64); 29381816cb70SBarry Harding } 29391816cb70SBarry Harding 29401816cb70SBarry Harding int 29411816cb70SBarry Harding yge_m_stat(void *arg, uint_t stat, uint64_t *val) 29421816cb70SBarry Harding { 29431816cb70SBarry Harding yge_port_t *port = arg; 29441816cb70SBarry Harding struct yge_hw_stats *stats = &port->p_stats; 29451816cb70SBarry Harding 29461816cb70SBarry Harding if (stat == MAC_STAT_IFSPEED) { 29471816cb70SBarry Harding /* 29481816cb70SBarry Harding * This is the first stat we are asked about. We update only 29491816cb70SBarry Harding * for this stat, to avoid paying the hefty cost of the update 29501816cb70SBarry Harding * once for each stat. 29511816cb70SBarry Harding */ 29521816cb70SBarry Harding DEV_LOCK(port->p_dev); 29531816cb70SBarry Harding yge_stats_update(port); 29541816cb70SBarry Harding DEV_UNLOCK(port->p_dev); 29551816cb70SBarry Harding } 29561816cb70SBarry Harding 29571816cb70SBarry Harding if (mii_m_getstat(port->p_mii, stat, val) == 0) { 29581816cb70SBarry Harding return (0); 29591816cb70SBarry Harding } 29601816cb70SBarry Harding 29611816cb70SBarry Harding switch (stat) { 29621816cb70SBarry Harding case MAC_STAT_MULTIRCV: 29631816cb70SBarry Harding *val = stats->rx_mcast_frames; 29641816cb70SBarry Harding break; 29651816cb70SBarry Harding 29661816cb70SBarry Harding case MAC_STAT_BRDCSTRCV: 29671816cb70SBarry Harding *val = stats->rx_bcast_frames; 29681816cb70SBarry Harding break; 29691816cb70SBarry Harding 29701816cb70SBarry Harding case MAC_STAT_MULTIXMT: 29711816cb70SBarry Harding *val = stats->tx_mcast_frames; 29721816cb70SBarry Harding break; 29731816cb70SBarry Harding 29741816cb70SBarry Harding case MAC_STAT_BRDCSTXMT: 29751816cb70SBarry Harding *val = stats->tx_bcast_frames; 29761816cb70SBarry Harding break; 29771816cb70SBarry Harding 29781816cb70SBarry Harding case MAC_STAT_IPACKETS: 29791816cb70SBarry Harding *val = stats->rx_ucast_frames; 29801816cb70SBarry Harding break; 29811816cb70SBarry Harding 29821816cb70SBarry Harding case MAC_STAT_RBYTES: 29831816cb70SBarry Harding *val = stats->rx_good_octets; 29841816cb70SBarry Harding break; 29851816cb70SBarry Harding 29861816cb70SBarry Harding case MAC_STAT_OPACKETS: 29871816cb70SBarry Harding *val = stats->tx_ucast_frames; 29881816cb70SBarry Harding break; 29891816cb70SBarry Harding 29901816cb70SBarry Harding case MAC_STAT_OBYTES: 29911816cb70SBarry Harding *val = stats->tx_octets; 29921816cb70SBarry Harding break; 29931816cb70SBarry Harding 29941816cb70SBarry Harding case MAC_STAT_NORCVBUF: 29951816cb70SBarry Harding *val = stats->rx_nobuf; 29961816cb70SBarry Harding break; 29971816cb70SBarry Harding 29981816cb70SBarry Harding case MAC_STAT_COLLISIONS: 29991816cb70SBarry Harding *val = stats->tx_colls; 30001816cb70SBarry Harding break; 30011816cb70SBarry Harding 30021816cb70SBarry Harding case ETHER_STAT_ALIGN_ERRORS: 30031816cb70SBarry Harding *val = stats->rx_runt_errs; 30041816cb70SBarry Harding break; 30051816cb70SBarry Harding 30061816cb70SBarry Harding case ETHER_STAT_FCS_ERRORS: 30071816cb70SBarry Harding *val = stats->rx_crc_errs; 30081816cb70SBarry Harding break; 30091816cb70SBarry Harding 30101816cb70SBarry Harding case ETHER_STAT_FIRST_COLLISIONS: 30111816cb70SBarry Harding *val = stats->tx_single_colls; 30121816cb70SBarry Harding break; 30131816cb70SBarry Harding 30141816cb70SBarry Harding case ETHER_STAT_MULTI_COLLISIONS: 30151816cb70SBarry Harding *val = stats->tx_multi_colls; 30161816cb70SBarry Harding break; 30171816cb70SBarry Harding 30181816cb70SBarry Harding case ETHER_STAT_TX_LATE_COLLISIONS: 30191816cb70SBarry Harding *val = stats->tx_late_colls; 30201816cb70SBarry Harding break; 30211816cb70SBarry Harding 30221816cb70SBarry Harding case ETHER_STAT_EX_COLLISIONS: 30231816cb70SBarry Harding *val = stats->tx_excess_colls; 30241816cb70SBarry Harding break; 30251816cb70SBarry Harding 30261816cb70SBarry Harding case ETHER_STAT_TOOLONG_ERRORS: 30271816cb70SBarry Harding *val = stats->rx_pkts_too_long; 30281816cb70SBarry Harding break; 30291816cb70SBarry Harding 30301816cb70SBarry Harding case MAC_STAT_OVERFLOWS: 30311816cb70SBarry Harding *val = stats->rx_fifo_oflows; 30321816cb70SBarry Harding break; 30331816cb70SBarry Harding 30341816cb70SBarry Harding case MAC_STAT_UNDERFLOWS: 30351816cb70SBarry Harding *val = stats->tx_underflows; 30361816cb70SBarry Harding break; 30371816cb70SBarry Harding 30381816cb70SBarry Harding case ETHER_STAT_TOOSHORT_ERRORS: 30391816cb70SBarry Harding *val = stats->rx_runts; 30401816cb70SBarry Harding break; 30411816cb70SBarry Harding 30421816cb70SBarry Harding case ETHER_STAT_JABBER_ERRORS: 30431816cb70SBarry Harding *val = stats->rx_pkts_jabbers; 30441816cb70SBarry Harding break; 30451816cb70SBarry Harding 30461816cb70SBarry Harding default: 30471816cb70SBarry Harding return (ENOTSUP); 30481816cb70SBarry Harding } 30491816cb70SBarry Harding return (0); 30501816cb70SBarry Harding } 30511816cb70SBarry Harding 30521816cb70SBarry Harding int 30531816cb70SBarry Harding yge_m_start(void *arg) 30541816cb70SBarry Harding { 30551816cb70SBarry Harding yge_port_t *port = arg; 30561816cb70SBarry Harding 30571816cb70SBarry Harding DEV_LOCK(port->p_dev); 30581816cb70SBarry Harding 30591816cb70SBarry Harding /* 30601816cb70SBarry Harding * We defer resource allocation to this point, because we 30611816cb70SBarry Harding * don't want to waste DMA resources that might better be used 30621816cb70SBarry Harding * elsewhere, if the port is not actually being used. 30631816cb70SBarry Harding * 30641816cb70SBarry Harding * Furthermore, this gives us a more graceful handling of dynamic 30651816cb70SBarry Harding * MTU modification. 30661816cb70SBarry Harding */ 30671816cb70SBarry Harding if (yge_txrx_dma_alloc(port) != DDI_SUCCESS) { 30681816cb70SBarry Harding /* Make sure we free up partially allocated resources. */ 30691816cb70SBarry Harding yge_txrx_dma_free(port); 30701816cb70SBarry Harding DEV_UNLOCK(port->p_dev); 30711816cb70SBarry Harding return (ENOMEM); 30721816cb70SBarry Harding } 30731816cb70SBarry Harding 30741816cb70SBarry Harding if (!port->p_dev->d_suspended) 30751816cb70SBarry Harding yge_start_port(port); 30761816cb70SBarry Harding port->p_running = B_TRUE; 30771816cb70SBarry Harding DEV_UNLOCK(port->p_dev); 30781816cb70SBarry Harding 30791816cb70SBarry Harding mii_start(port->p_mii); 30801816cb70SBarry Harding 30811816cb70SBarry Harding return (0); 30821816cb70SBarry Harding } 30831816cb70SBarry Harding 30841816cb70SBarry Harding void 30851816cb70SBarry Harding yge_m_stop(void *arg) 30861816cb70SBarry Harding { 30871816cb70SBarry Harding yge_port_t *port = arg; 30881816cb70SBarry Harding yge_dev_t *dev = port->p_dev; 30891816cb70SBarry Harding 30901816cb70SBarry Harding DEV_LOCK(dev); 30911816cb70SBarry Harding if (!dev->d_suspended) 30921816cb70SBarry Harding yge_stop_port(port); 30931816cb70SBarry Harding 30941816cb70SBarry Harding port->p_running = B_FALSE; 30951816cb70SBarry Harding 30961816cb70SBarry Harding /* Release resources we don't need */ 30971816cb70SBarry Harding yge_txrx_dma_free(port); 30981816cb70SBarry Harding DEV_UNLOCK(dev); 30991816cb70SBarry Harding } 31001816cb70SBarry Harding 31011816cb70SBarry Harding int 31021816cb70SBarry Harding yge_m_promisc(void *arg, boolean_t on) 31031816cb70SBarry Harding { 31041816cb70SBarry Harding yge_port_t *port = arg; 31051816cb70SBarry Harding 31061816cb70SBarry Harding DEV_LOCK(port->p_dev); 31071816cb70SBarry Harding 31081816cb70SBarry Harding /* Save current promiscuous mode. */ 31091816cb70SBarry Harding port->p_promisc = on; 31101816cb70SBarry Harding yge_setrxfilt(port); 31111816cb70SBarry Harding 31121816cb70SBarry Harding DEV_UNLOCK(port->p_dev); 31131816cb70SBarry Harding 31141816cb70SBarry Harding return (0); 31151816cb70SBarry Harding } 31161816cb70SBarry Harding 31171816cb70SBarry Harding int 31181816cb70SBarry Harding yge_m_multicst(void *arg, boolean_t add, const uint8_t *addr) 31191816cb70SBarry Harding { 31201816cb70SBarry Harding yge_port_t *port = arg; 31211816cb70SBarry Harding int bit; 31221816cb70SBarry Harding boolean_t update; 31231816cb70SBarry Harding 31241816cb70SBarry Harding bit = yge_hashbit(addr); 31251816cb70SBarry Harding ASSERT(bit < 64); 31261816cb70SBarry Harding 31271816cb70SBarry Harding DEV_LOCK(port->p_dev); 31281816cb70SBarry Harding if (add) { 31291816cb70SBarry Harding if (port->p_mccount[bit] == 0) { 31301816cb70SBarry Harding /* Set the corresponding bit in the hash table. */ 31311816cb70SBarry Harding port->p_mchash[bit / 32] |= (1 << (bit % 32)); 31321816cb70SBarry Harding update = B_TRUE; 31331816cb70SBarry Harding } 31341816cb70SBarry Harding port->p_mccount[bit]++; 31351816cb70SBarry Harding } else { 31361816cb70SBarry Harding ASSERT(port->p_mccount[bit] > 0); 31371816cb70SBarry Harding port->p_mccount[bit]--; 31381816cb70SBarry Harding if (port->p_mccount[bit] == 0) { 31391816cb70SBarry Harding port->p_mchash[bit / 32] &= ~(1 << (bit % 32)); 31401816cb70SBarry Harding update = B_TRUE; 31411816cb70SBarry Harding } 31421816cb70SBarry Harding } 31431816cb70SBarry Harding 31441816cb70SBarry Harding if (update) { 31451816cb70SBarry Harding yge_setrxfilt(port); 31461816cb70SBarry Harding } 31471816cb70SBarry Harding DEV_UNLOCK(port->p_dev); 31481816cb70SBarry Harding return (0); 31491816cb70SBarry Harding } 31501816cb70SBarry Harding 31511816cb70SBarry Harding int 31521816cb70SBarry Harding yge_m_unicst(void *arg, const uint8_t *macaddr) 31531816cb70SBarry Harding { 31541816cb70SBarry Harding yge_port_t *port = arg; 31551816cb70SBarry Harding 31561816cb70SBarry Harding DEV_LOCK(port->p_dev); 31571816cb70SBarry Harding 31581816cb70SBarry Harding bcopy(macaddr, port->p_curraddr, ETHERADDRL); 31591816cb70SBarry Harding yge_setrxfilt(port); 31601816cb70SBarry Harding 31611816cb70SBarry Harding DEV_UNLOCK(port->p_dev); 31621816cb70SBarry Harding 31631816cb70SBarry Harding return (0); 31641816cb70SBarry Harding } 31651816cb70SBarry Harding 31661816cb70SBarry Harding mblk_t * 31671816cb70SBarry Harding yge_m_tx(void *arg, mblk_t *mp) 31681816cb70SBarry Harding { 31691816cb70SBarry Harding yge_port_t *port = arg; 31701816cb70SBarry Harding mblk_t *nmp; 31711816cb70SBarry Harding int enq = 0; 31721816cb70SBarry Harding uint32_t ridx; 31731816cb70SBarry Harding int idx; 31741816cb70SBarry Harding boolean_t resched = B_FALSE; 31751816cb70SBarry Harding 31761816cb70SBarry Harding TX_LOCK(port->p_dev); 31771816cb70SBarry Harding 31781816cb70SBarry Harding if (port->p_dev->d_suspended) { 31791816cb70SBarry Harding 31801816cb70SBarry Harding TX_UNLOCK(port->p_dev); 31811816cb70SBarry Harding 31821816cb70SBarry Harding while ((nmp = mp) != NULL) { 31831816cb70SBarry Harding /* carrier_errors++; */ 31841816cb70SBarry Harding mp = mp->b_next; 31851816cb70SBarry Harding freemsg(nmp); 31861816cb70SBarry Harding } 31871816cb70SBarry Harding return (NULL); 31881816cb70SBarry Harding } 31891816cb70SBarry Harding 31901816cb70SBarry Harding /* attempt a reclaim */ 31911816cb70SBarry Harding ridx = port->p_port == YGE_PORT_A ? 31921816cb70SBarry Harding STAT_TXA1_RIDX : STAT_TXA2_RIDX; 31931816cb70SBarry Harding idx = CSR_READ_2(port->p_dev, ridx); 31941816cb70SBarry Harding if (port->p_tx_cons != idx) 31951816cb70SBarry Harding resched = yge_txeof_locked(port, idx); 31961816cb70SBarry Harding 31971816cb70SBarry Harding while (mp != NULL) { 31981816cb70SBarry Harding nmp = mp->b_next; 31991816cb70SBarry Harding mp->b_next = NULL; 32001816cb70SBarry Harding 32011816cb70SBarry Harding if (!yge_send(port, mp)) { 32021816cb70SBarry Harding mp->b_next = nmp; 32031816cb70SBarry Harding break; 32041816cb70SBarry Harding } 32051816cb70SBarry Harding enq++; 32061816cb70SBarry Harding mp = nmp; 32071816cb70SBarry Harding 32081816cb70SBarry Harding } 32091816cb70SBarry Harding if (enq > 0) { 32101816cb70SBarry Harding /* Transmit */ 32111816cb70SBarry Harding CSR_WRITE_2(port->p_dev, 32121816cb70SBarry Harding Y2_PREF_Q_ADDR(port->p_txq, PREF_UNIT_PUT_IDX_REG), 32131816cb70SBarry Harding port->p_tx_prod); 32141816cb70SBarry Harding } 32151816cb70SBarry Harding 32161816cb70SBarry Harding TX_UNLOCK(port->p_dev); 32171816cb70SBarry Harding 32181816cb70SBarry Harding if (resched) 32191816cb70SBarry Harding mac_tx_update(port->p_mh); 32201816cb70SBarry Harding 32211816cb70SBarry Harding return (mp); 32221816cb70SBarry Harding } 32231816cb70SBarry Harding 32241816cb70SBarry Harding void 32251816cb70SBarry Harding yge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 32261816cb70SBarry Harding { 32271816cb70SBarry Harding #ifdef YGE_MII_LOOPBACK 32281816cb70SBarry Harding /* LINTED E_FUNC_SET_NOT_USED */ 32291816cb70SBarry Harding yge_port_t *port = arg; 32301816cb70SBarry Harding 32311816cb70SBarry Harding /* 32321816cb70SBarry Harding * Right now, the MII common layer does not properly handle 32331816cb70SBarry Harding * loopback on these PHYs. Fixing this should be done at some 32341816cb70SBarry Harding * point in the future. 32351816cb70SBarry Harding */ 32361816cb70SBarry Harding if (mii_m_loop_ioctl(port->p_mii, wq, mp)) 32371816cb70SBarry Harding return; 32381816cb70SBarry Harding #else 32391816cb70SBarry Harding _NOTE(ARGUNUSED(arg)); 32401816cb70SBarry Harding #endif 32411816cb70SBarry Harding 32421816cb70SBarry Harding miocnak(wq, mp, 0, EINVAL); 32431816cb70SBarry Harding } 32441816cb70SBarry Harding 32451816cb70SBarry Harding int 32461816cb70SBarry Harding yge_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 32471816cb70SBarry Harding uint_t pr_valsize, const void *pr_val) 32481816cb70SBarry Harding { 32491816cb70SBarry Harding yge_port_t *port = arg; 32501816cb70SBarry Harding uint32_t new_mtu; 32511816cb70SBarry Harding int err = 0; 32521816cb70SBarry Harding 32531816cb70SBarry Harding err = mii_m_setprop(port->p_mii, pr_name, pr_num, pr_valsize, pr_val); 32541816cb70SBarry Harding if (err != ENOTSUP) { 32551816cb70SBarry Harding return (err); 32561816cb70SBarry Harding } 32571816cb70SBarry Harding 32581816cb70SBarry Harding DEV_LOCK(port->p_dev); 32591816cb70SBarry Harding 32601816cb70SBarry Harding switch (pr_num) { 32611816cb70SBarry Harding case MAC_PROP_MTU: 32621816cb70SBarry Harding if (pr_valsize < sizeof (new_mtu)) { 32631816cb70SBarry Harding err = EINVAL; 32641816cb70SBarry Harding break; 32651816cb70SBarry Harding } 32661816cb70SBarry Harding bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 32671816cb70SBarry Harding if (new_mtu == port->p_mtu) { 32681816cb70SBarry Harding /* no change */ 32691816cb70SBarry Harding err = 0; 32701816cb70SBarry Harding break; 32711816cb70SBarry Harding } 32721816cb70SBarry Harding if (new_mtu < ETHERMTU) { 32731816cb70SBarry Harding yge_error(NULL, port, 32741816cb70SBarry Harding "Maximum MTU size too small: %d", new_mtu); 32751816cb70SBarry Harding err = EINVAL; 32761816cb70SBarry Harding break; 32771816cb70SBarry Harding } 32781816cb70SBarry Harding if (new_mtu > (port->p_flags & PORT_FLAG_NOJUMBO ? 32791816cb70SBarry Harding ETHERMTU : YGE_JUMBO_MTU)) { 32801816cb70SBarry Harding yge_error(NULL, port, 32811816cb70SBarry Harding "Maximum MTU size too big: %d", new_mtu); 32821816cb70SBarry Harding err = EINVAL; 32831816cb70SBarry Harding break; 32841816cb70SBarry Harding } 32851816cb70SBarry Harding if (port->p_running) { 32861816cb70SBarry Harding yge_error(NULL, port, 32871816cb70SBarry Harding "Unable to change maximum MTU while running"); 32881816cb70SBarry Harding err = EBUSY; 32891816cb70SBarry Harding break; 32901816cb70SBarry Harding } 32911816cb70SBarry Harding 32921816cb70SBarry Harding 32931816cb70SBarry Harding /* 32941816cb70SBarry Harding * NB: It would probably be better not to hold the 32951816cb70SBarry Harding * DEVLOCK, but releasing it creates a potential race 32961816cb70SBarry Harding * if m_start is called concurrently. 32971816cb70SBarry Harding * 32981816cb70SBarry Harding * It turns out that the MAC layer guarantees safety 32991816cb70SBarry Harding * for us here by using a cut out for this kind of 33001816cb70SBarry Harding * notification call back anyway. 33011816cb70SBarry Harding * 33021816cb70SBarry Harding * See R8. and R14. in mac.c locking comments, which read 33031816cb70SBarry Harding * as follows: 33041816cb70SBarry Harding * 33051816cb70SBarry Harding * R8. Since it is not guaranteed (see R14) that 33061816cb70SBarry Harding * drivers won't hold locks across mac driver 33071816cb70SBarry Harding * interfaces, the MAC layer must provide a cut out 33081816cb70SBarry Harding * for control interfaces like upcall notifications 33091816cb70SBarry Harding * and start them in a separate thread. 33101816cb70SBarry Harding * 33111816cb70SBarry Harding * R14. It would be preferable if MAC drivers don't 33121816cb70SBarry Harding * hold any locks across any mac call. However at a 33131816cb70SBarry Harding * minimum they must not hold any locks across data 33141816cb70SBarry Harding * upcalls. They must also make sure that all 33151816cb70SBarry Harding * references to mac data structures are cleaned up 33161816cb70SBarry Harding * and that it is single threaded at mac_unregister 33171816cb70SBarry Harding * time. 33181816cb70SBarry Harding */ 33191816cb70SBarry Harding err = mac_maxsdu_update(port->p_mh, new_mtu); 33201816cb70SBarry Harding if (err != 0) { 33211816cb70SBarry Harding /* This should never occur! */ 33221816cb70SBarry Harding yge_error(NULL, port, 33231816cb70SBarry Harding "Failed notifying GLDv3 of new maximum MTU"); 33241816cb70SBarry Harding } else { 33251816cb70SBarry Harding port->p_mtu = new_mtu; 33261816cb70SBarry Harding } 33271816cb70SBarry Harding break; 33281816cb70SBarry Harding 33291816cb70SBarry Harding default: 33301816cb70SBarry Harding err = ENOTSUP; 33311816cb70SBarry Harding break; 33321816cb70SBarry Harding } 33331816cb70SBarry Harding 33341816cb70SBarry Harding err: 33351816cb70SBarry Harding DEV_UNLOCK(port->p_dev); 33361816cb70SBarry Harding 33371816cb70SBarry Harding return (err); 33381816cb70SBarry Harding } 33391816cb70SBarry Harding 33401816cb70SBarry Harding int 33411816cb70SBarry Harding yge_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 33420dc2366fSVenugopal Iyer uint_t pr_valsize, void *pr_val) 33431816cb70SBarry Harding { 33441816cb70SBarry Harding yge_port_t *port = arg; 33451816cb70SBarry Harding 33460dc2366fSVenugopal Iyer return (mii_m_getprop(port->p_mii, pr_name, pr_num, pr_valsize, 33470dc2366fSVenugopal Iyer pr_val)); 33481816cb70SBarry Harding } 33491816cb70SBarry Harding 33500dc2366fSVenugopal Iyer static void 33510dc2366fSVenugopal Iyer yge_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num, 33520dc2366fSVenugopal Iyer mac_prop_info_handle_t prh) 33530dc2366fSVenugopal Iyer { 33540dc2366fSVenugopal Iyer yge_port_t *port = arg; 33551816cb70SBarry Harding 33561816cb70SBarry Harding switch (pr_num) { 33571816cb70SBarry Harding case MAC_PROP_MTU: 33580dc2366fSVenugopal Iyer mac_prop_info_set_range_uint32(prh, ETHERMTU, 33591816cb70SBarry Harding port->p_flags & PORT_FLAG_NOJUMBO ? 33600dc2366fSVenugopal Iyer ETHERMTU : YGE_JUMBO_MTU); 33611816cb70SBarry Harding break; 33621816cb70SBarry Harding default: 33630dc2366fSVenugopal Iyer mii_m_propinfo(port->p_mii, pr_name, pr_num, prh); 33641816cb70SBarry Harding break; 33651816cb70SBarry Harding } 33661816cb70SBarry Harding } 33671816cb70SBarry Harding 33681816cb70SBarry Harding void 33691816cb70SBarry Harding yge_dispatch(yge_dev_t *dev, int flag) 33701816cb70SBarry Harding { 33711816cb70SBarry Harding TASK_LOCK(dev); 33721816cb70SBarry Harding dev->d_task_flags |= flag; 33731816cb70SBarry Harding TASK_SIGNAL(dev); 33741816cb70SBarry Harding TASK_UNLOCK(dev); 33751816cb70SBarry Harding } 33761816cb70SBarry Harding 33771816cb70SBarry Harding void 33781816cb70SBarry Harding yge_task(void *arg) 33791816cb70SBarry Harding { 33801816cb70SBarry Harding yge_dev_t *dev = arg; 33811816cb70SBarry Harding int flags; 33821816cb70SBarry Harding 33831816cb70SBarry Harding for (;;) { 33841816cb70SBarry Harding 33851816cb70SBarry Harding TASK_LOCK(dev); 33861816cb70SBarry Harding while ((flags = dev->d_task_flags) == 0) 33871816cb70SBarry Harding TASK_WAIT(dev); 33881816cb70SBarry Harding 33891816cb70SBarry Harding dev->d_task_flags = 0; 33901816cb70SBarry Harding TASK_UNLOCK(dev); 33911816cb70SBarry Harding 33921816cb70SBarry Harding /* 33931816cb70SBarry Harding * This should be the first thing after the sleep so if we are 33941816cb70SBarry Harding * requested to exit we do that and not waste time doing work 33951816cb70SBarry Harding * we will then abandone. 33961816cb70SBarry Harding */ 33971816cb70SBarry Harding if (flags & YGE_TASK_EXIT) 33981816cb70SBarry Harding break; 33991816cb70SBarry Harding 34001816cb70SBarry Harding /* all processing done without holding locks */ 34011816cb70SBarry Harding if (flags & YGE_TASK_RESTART) 34021816cb70SBarry Harding yge_restart_task(dev); 34031816cb70SBarry Harding } 34041816cb70SBarry Harding } 34051816cb70SBarry Harding 34061816cb70SBarry Harding void 34071816cb70SBarry Harding yge_error(yge_dev_t *dev, yge_port_t *port, char *fmt, ...) 34081816cb70SBarry Harding { 34091816cb70SBarry Harding va_list ap; 34101816cb70SBarry Harding char buf[256]; 3411388fc72dSvitezslav batrla - Sun Microsystems - Prague Czech Republic int ppa; 34121816cb70SBarry Harding 34131816cb70SBarry Harding va_start(ap, fmt); 34141816cb70SBarry Harding (void) vsnprintf(buf, sizeof (buf), fmt, ap); 34151816cb70SBarry Harding va_end(ap); 34161816cb70SBarry Harding 3417388fc72dSvitezslav batrla - Sun Microsystems - Prague Czech Republic if (dev == NULL && port == NULL) { 3418388fc72dSvitezslav batrla - Sun Microsystems - Prague Czech Republic cmn_err(CE_WARN, "yge: %s", buf); 3419388fc72dSvitezslav batrla - Sun Microsystems - Prague Czech Republic } else { 3420388fc72dSvitezslav batrla - Sun Microsystems - Prague Czech Republic if (port != NULL) 3421388fc72dSvitezslav batrla - Sun Microsystems - Prague Czech Republic ppa = port->p_ppa; 3422388fc72dSvitezslav batrla - Sun Microsystems - Prague Czech Republic else 3423388fc72dSvitezslav batrla - Sun Microsystems - Prague Czech Republic ppa = ddi_get_instance(dev->d_dip); 3424388fc72dSvitezslav batrla - Sun Microsystems - Prague Czech Republic cmn_err(CE_WARN, "yge%d: %s", ppa, buf); 3425388fc72dSvitezslav batrla - Sun Microsystems - Prague Czech Republic } 34261816cb70SBarry Harding } 34271816cb70SBarry Harding 34281816cb70SBarry Harding static int 34291816cb70SBarry Harding yge_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 34301816cb70SBarry Harding { 34311816cb70SBarry Harding yge_dev_t *dev; 34321816cb70SBarry Harding int rv; 34331816cb70SBarry Harding 34341816cb70SBarry Harding switch (cmd) { 34351816cb70SBarry Harding case DDI_ATTACH: 34361816cb70SBarry Harding dev = kmem_zalloc(sizeof (*dev), KM_SLEEP); 34371816cb70SBarry Harding dev->d_port[0] = kmem_zalloc(sizeof (yge_port_t), KM_SLEEP); 34381816cb70SBarry Harding dev->d_port[1] = kmem_zalloc(sizeof (yge_port_t), KM_SLEEP); 34391816cb70SBarry Harding dev->d_dip = dip; 34401816cb70SBarry Harding ddi_set_driver_private(dip, dev); 34411816cb70SBarry Harding 34421816cb70SBarry Harding dev->d_port[0]->p_port = 0; 34431816cb70SBarry Harding dev->d_port[0]->p_dev = dev; 34441816cb70SBarry Harding dev->d_port[1]->p_port = 0; 34451816cb70SBarry Harding dev->d_port[1]->p_dev = dev; 34461816cb70SBarry Harding 34471816cb70SBarry Harding rv = yge_attach(dev); 34481816cb70SBarry Harding if (rv != DDI_SUCCESS) { 34491816cb70SBarry Harding ddi_set_driver_private(dip, 0); 34501816cb70SBarry Harding kmem_free(dev->d_port[1], sizeof (yge_port_t)); 34511816cb70SBarry Harding kmem_free(dev->d_port[0], sizeof (yge_port_t)); 34521816cb70SBarry Harding kmem_free(dev, sizeof (*dev)); 34531816cb70SBarry Harding } 34541816cb70SBarry Harding return (rv); 34551816cb70SBarry Harding 34561816cb70SBarry Harding case DDI_RESUME: 34571816cb70SBarry Harding dev = ddi_get_driver_private(dip); 34581816cb70SBarry Harding ASSERT(dev != NULL); 34591816cb70SBarry Harding return (yge_resume(dev)); 34601816cb70SBarry Harding 34611816cb70SBarry Harding default: 34621816cb70SBarry Harding return (DDI_FAILURE); 34631816cb70SBarry Harding } 34641816cb70SBarry Harding } 34651816cb70SBarry Harding 34661816cb70SBarry Harding static int 34671816cb70SBarry Harding yge_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 34681816cb70SBarry Harding { 34691816cb70SBarry Harding yge_dev_t *dev; 3470*3661c01dSGarrett D'Amore mac_handle_t mh; 34711816cb70SBarry Harding 34721816cb70SBarry Harding switch (cmd) { 34731816cb70SBarry Harding case DDI_DETACH: 34741816cb70SBarry Harding 34751816cb70SBarry Harding dev = ddi_get_driver_private(dip); 34761816cb70SBarry Harding 34771816cb70SBarry Harding /* attempt to unregister MACs from Nemo */ 34781816cb70SBarry Harding for (int i = 0; i < dev->d_num_port; i++) { 3479*3661c01dSGarrett D'Amore 3480*3661c01dSGarrett D'Amore if (((mh = dev->d_port[i]->p_mh) != NULL) && 3481*3661c01dSGarrett D'Amore (mac_disable(mh) != 0)) { 3482*3661c01dSGarrett D'Amore /* 3483*3661c01dSGarrett D'Amore * We'd really like a mac_enable to reenable 3484*3661c01dSGarrett D'Amore * any MACs that we previously disabled. Too 3485*3661c01dSGarrett D'Amore * bad GLDv3 doesn't have one. 3486*3661c01dSGarrett D'Amore */ 34871816cb70SBarry Harding return (DDI_FAILURE); 34881816cb70SBarry Harding } 34891816cb70SBarry Harding } 34901816cb70SBarry Harding 34911816cb70SBarry Harding ASSERT(dip == dev->d_dip); 34921816cb70SBarry Harding yge_detach(dev); 34931816cb70SBarry Harding ddi_set_driver_private(dip, 0); 3494*3661c01dSGarrett D'Amore for (int i = 0; i < dev->d_num_port; i++) { 3495*3661c01dSGarrett D'Amore if ((mh = dev->d_port[i]->p_mh) != NULL) { 3496*3661c01dSGarrett D'Amore /* This can't fail after mac_disable above. */ 3497*3661c01dSGarrett D'Amore (void) mac_unregister(mh); 3498*3661c01dSGarrett D'Amore } 3499*3661c01dSGarrett D'Amore } 35001816cb70SBarry Harding kmem_free(dev->d_port[1], sizeof (yge_port_t)); 35011816cb70SBarry Harding kmem_free(dev->d_port[0], sizeof (yge_port_t)); 35021816cb70SBarry Harding kmem_free(dev, sizeof (*dev)); 35031816cb70SBarry Harding return (DDI_SUCCESS); 35041816cb70SBarry Harding 35051816cb70SBarry Harding case DDI_SUSPEND: 35061816cb70SBarry Harding dev = ddi_get_driver_private(dip); 35071816cb70SBarry Harding ASSERT(dev != NULL); 35081816cb70SBarry Harding return (yge_suspend(dev)); 35091816cb70SBarry Harding 35101816cb70SBarry Harding default: 35111816cb70SBarry Harding return (DDI_FAILURE); 35121816cb70SBarry Harding } 35131816cb70SBarry Harding } 35141816cb70SBarry Harding 35151816cb70SBarry Harding static int 35161816cb70SBarry Harding yge_quiesce(dev_info_t *dip) 35171816cb70SBarry Harding { 35181816cb70SBarry Harding yge_dev_t *dev; 35191816cb70SBarry Harding 35201816cb70SBarry Harding dev = ddi_get_driver_private(dip); 35211816cb70SBarry Harding ASSERT(dev != NULL); 35221816cb70SBarry Harding 35231816cb70SBarry Harding /* NB: No locking! We are called in single threaded context */ 35241816cb70SBarry Harding for (int i = 0; i < dev->d_num_port; i++) { 35251816cb70SBarry Harding yge_port_t *port = dev->d_port[i]; 35261816cb70SBarry Harding if (port->p_running) 35271816cb70SBarry Harding yge_stop_port(port); 35281816cb70SBarry Harding } 35291816cb70SBarry Harding 35301816cb70SBarry Harding /* Disable all interrupts. */ 35311816cb70SBarry Harding CSR_WRITE_4(dev, B0_IMSK, 0); 35321816cb70SBarry Harding (void) CSR_READ_4(dev, B0_IMSK); 35331816cb70SBarry Harding CSR_WRITE_4(dev, B0_HWE_IMSK, 0); 35341816cb70SBarry Harding (void) CSR_READ_4(dev, B0_HWE_IMSK); 35351816cb70SBarry Harding 35361816cb70SBarry Harding /* Put hardware into reset. */ 35371816cb70SBarry Harding CSR_WRITE_2(dev, B0_CTST, CS_RST_SET); 35381816cb70SBarry Harding 35391816cb70SBarry Harding return (DDI_SUCCESS); 35401816cb70SBarry Harding } 35411816cb70SBarry Harding 35421816cb70SBarry Harding /* 35431816cb70SBarry Harding * Stream information 35441816cb70SBarry Harding */ 35451816cb70SBarry Harding DDI_DEFINE_STREAM_OPS(yge_devops, nulldev, nulldev, yge_ddi_attach, 35461816cb70SBarry Harding yge_ddi_detach, nodev, NULL, D_MP, NULL, yge_quiesce); 35471816cb70SBarry Harding 35481816cb70SBarry Harding /* 35491816cb70SBarry Harding * Module linkage information. 35501816cb70SBarry Harding */ 35511816cb70SBarry Harding 35521816cb70SBarry Harding static struct modldrv yge_modldrv = { 35531816cb70SBarry Harding &mod_driverops, /* drv_modops */ 35541816cb70SBarry Harding "Yukon 2 Ethernet", /* drv_linkinfo */ 35551816cb70SBarry Harding &yge_devops /* drv_dev_ops */ 35561816cb70SBarry Harding }; 35571816cb70SBarry Harding 35581816cb70SBarry Harding static struct modlinkage yge_modlinkage = { 35591816cb70SBarry Harding MODREV_1, /* ml_rev */ 35601816cb70SBarry Harding &yge_modldrv, /* ml_linkage */ 35611816cb70SBarry Harding NULL 35621816cb70SBarry Harding }; 35631816cb70SBarry Harding 35641816cb70SBarry Harding /* 35651816cb70SBarry Harding * DDI entry points. 35661816cb70SBarry Harding */ 35671816cb70SBarry Harding int 35681816cb70SBarry Harding _init(void) 35691816cb70SBarry Harding { 35701816cb70SBarry Harding int rv; 35711816cb70SBarry Harding mac_init_ops(&yge_devops, "yge"); 35721816cb70SBarry Harding if ((rv = mod_install(&yge_modlinkage)) != DDI_SUCCESS) { 35731816cb70SBarry Harding mac_fini_ops(&yge_devops); 35741816cb70SBarry Harding } 35751816cb70SBarry Harding return (rv); 35761816cb70SBarry Harding } 35771816cb70SBarry Harding 35781816cb70SBarry Harding int 35791816cb70SBarry Harding _fini(void) 35801816cb70SBarry Harding { 35811816cb70SBarry Harding int rv; 35821816cb70SBarry Harding if ((rv = mod_remove(&yge_modlinkage)) == DDI_SUCCESS) { 35831816cb70SBarry Harding mac_fini_ops(&yge_devops); 35841816cb70SBarry Harding } 35851816cb70SBarry Harding return (rv); 35861816cb70SBarry Harding } 35871816cb70SBarry Harding 35881816cb70SBarry Harding int 35891816cb70SBarry Harding _info(struct modinfo *modinfop) 35901816cb70SBarry Harding { 35911816cb70SBarry Harding return (mod_info(&yge_modlinkage, modinfop)); 35921816cb70SBarry Harding } 3593