110506SBarry.Harding@Sun.COM /* 211869SVitezslav.Batrla@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 310506SBarry.Harding@Sun.COM * Use is subject to license terms. 410506SBarry.Harding@Sun.COM */ 510506SBarry.Harding@Sun.COM 610506SBarry.Harding@Sun.COM /* 710506SBarry.Harding@Sun.COM * This driver was derived from the FreeBSD if_msk.c driver, which 810506SBarry.Harding@Sun.COM * bears the following copyright attributions and licenses. 910506SBarry.Harding@Sun.COM */ 1010506SBarry.Harding@Sun.COM 1110506SBarry.Harding@Sun.COM /* 1210506SBarry.Harding@Sun.COM * 1310506SBarry.Harding@Sun.COM * LICENSE: 1410506SBarry.Harding@Sun.COM * Copyright (C) Marvell International Ltd. and/or its affiliates 1510506SBarry.Harding@Sun.COM * 1610506SBarry.Harding@Sun.COM * The computer program files contained in this folder ("Files") 1710506SBarry.Harding@Sun.COM * are provided to you under the BSD-type license terms provided 1810506SBarry.Harding@Sun.COM * below, and any use of such Files and any derivative works 1910506SBarry.Harding@Sun.COM * thereof created by you shall be governed by the following terms 2010506SBarry.Harding@Sun.COM * and conditions: 2110506SBarry.Harding@Sun.COM * 2210506SBarry.Harding@Sun.COM * - Redistributions of source code must retain the above copyright 2310506SBarry.Harding@Sun.COM * notice, this list of conditions and the following disclaimer. 2410506SBarry.Harding@Sun.COM * - Redistributions in binary form must reproduce the above 2510506SBarry.Harding@Sun.COM * copyright notice, this list of conditions and the following 2610506SBarry.Harding@Sun.COM * disclaimer in the documentation and/or other materials provided 2710506SBarry.Harding@Sun.COM * with the distribution. 2810506SBarry.Harding@Sun.COM * - Neither the name of Marvell nor the names of its contributors 2910506SBarry.Harding@Sun.COM * may be used to endorse or promote products derived from this 3010506SBarry.Harding@Sun.COM * software without specific prior written permission. 3110506SBarry.Harding@Sun.COM * 3210506SBarry.Harding@Sun.COM * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3310506SBarry.Harding@Sun.COM * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3410506SBarry.Harding@Sun.COM * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 3510506SBarry.Harding@Sun.COM * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 3610506SBarry.Harding@Sun.COM * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 3710506SBarry.Harding@Sun.COM * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 3810506SBarry.Harding@Sun.COM * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 3910506SBarry.Harding@Sun.COM * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4010506SBarry.Harding@Sun.COM * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 4110506SBarry.Harding@Sun.COM * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 4210506SBarry.Harding@Sun.COM * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 4310506SBarry.Harding@Sun.COM * OF THE POSSIBILITY OF SUCH DAMAGE. 4410506SBarry.Harding@Sun.COM * /LICENSE 4510506SBarry.Harding@Sun.COM * 4610506SBarry.Harding@Sun.COM */ 4710506SBarry.Harding@Sun.COM /* 4810506SBarry.Harding@Sun.COM * Copyright (c) 1997, 1998, 1999, 2000 4910506SBarry.Harding@Sun.COM * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. 5010506SBarry.Harding@Sun.COM * 5110506SBarry.Harding@Sun.COM * Redistribution and use in source and binary forms, with or without 5210506SBarry.Harding@Sun.COM * modification, are permitted provided that the following conditions 5310506SBarry.Harding@Sun.COM * are met: 5410506SBarry.Harding@Sun.COM * 1. Redistributions of source code must retain the above copyright 5510506SBarry.Harding@Sun.COM * notice, this list of conditions and the following disclaimer. 5610506SBarry.Harding@Sun.COM * 2. Redistributions in binary form must reproduce the above copyright 5710506SBarry.Harding@Sun.COM * notice, this list of conditions and the following disclaimer in the 5810506SBarry.Harding@Sun.COM * documentation and/or other materials provided with the distribution. 5910506SBarry.Harding@Sun.COM * 3. All advertising materials mentioning features or use of this software 6010506SBarry.Harding@Sun.COM * must display the following acknowledgement: 6110506SBarry.Harding@Sun.COM * This product includes software developed by Bill Paul. 6210506SBarry.Harding@Sun.COM * 4. Neither the name of the author nor the names of any co-contributors 6310506SBarry.Harding@Sun.COM * may be used to endorse or promote products derived from this software 6410506SBarry.Harding@Sun.COM * without specific prior written permission. 6510506SBarry.Harding@Sun.COM * 6610506SBarry.Harding@Sun.COM * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 6710506SBarry.Harding@Sun.COM * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 6810506SBarry.Harding@Sun.COM * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 6910506SBarry.Harding@Sun.COM * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 7010506SBarry.Harding@Sun.COM * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 7110506SBarry.Harding@Sun.COM * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 7210506SBarry.Harding@Sun.COM * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 7310506SBarry.Harding@Sun.COM * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 7410506SBarry.Harding@Sun.COM * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 7510506SBarry.Harding@Sun.COM * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 7610506SBarry.Harding@Sun.COM * THE POSSIBILITY OF SUCH DAMAGE. 7710506SBarry.Harding@Sun.COM */ 7810506SBarry.Harding@Sun.COM /* 7910506SBarry.Harding@Sun.COM * Copyright (c) 2003 Nathan L. Binkert <binkertn@umich.edu> 8010506SBarry.Harding@Sun.COM * 8110506SBarry.Harding@Sun.COM * Permission to use, copy, modify, and distribute this software for any 8210506SBarry.Harding@Sun.COM * purpose with or without fee is hereby granted, provided that the above 8310506SBarry.Harding@Sun.COM * copyright notice and this permission notice appear in all copies. 8410506SBarry.Harding@Sun.COM * 8510506SBarry.Harding@Sun.COM * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8610506SBarry.Harding@Sun.COM * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 8710506SBarry.Harding@Sun.COM * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 8810506SBarry.Harding@Sun.COM * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 8910506SBarry.Harding@Sun.COM * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 9010506SBarry.Harding@Sun.COM * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 9110506SBarry.Harding@Sun.COM * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 9210506SBarry.Harding@Sun.COM */ 9310506SBarry.Harding@Sun.COM 9410506SBarry.Harding@Sun.COM #include <sys/varargs.h> 9510506SBarry.Harding@Sun.COM #include <sys/types.h> 9610506SBarry.Harding@Sun.COM #include <sys/modctl.h> 9710506SBarry.Harding@Sun.COM #include <sys/conf.h> 9810506SBarry.Harding@Sun.COM #include <sys/devops.h> 9910506SBarry.Harding@Sun.COM #include <sys/stream.h> 10010506SBarry.Harding@Sun.COM #include <sys/strsun.h> 10110506SBarry.Harding@Sun.COM #include <sys/cmn_err.h> 10210506SBarry.Harding@Sun.COM #include <sys/ethernet.h> 10310506SBarry.Harding@Sun.COM #include <sys/kmem.h> 10410506SBarry.Harding@Sun.COM #include <sys/time.h> 10510506SBarry.Harding@Sun.COM #include <sys/pci.h> 10610506SBarry.Harding@Sun.COM #include <sys/mii.h> 10710506SBarry.Harding@Sun.COM #include <sys/miiregs.h> 10810506SBarry.Harding@Sun.COM #include <sys/mac.h> 10910506SBarry.Harding@Sun.COM #include <sys/mac_ether.h> 11010506SBarry.Harding@Sun.COM #include <sys/mac_provider.h> 11110506SBarry.Harding@Sun.COM #include <sys/debug.h> 11210506SBarry.Harding@Sun.COM #include <sys/note.h> 11310506SBarry.Harding@Sun.COM #include <sys/ddi.h> 11410506SBarry.Harding@Sun.COM #include <sys/sunddi.h> 11510506SBarry.Harding@Sun.COM #include <sys/vlan.h> 11610506SBarry.Harding@Sun.COM 11710506SBarry.Harding@Sun.COM #include "yge.h" 11810506SBarry.Harding@Sun.COM 11910506SBarry.Harding@Sun.COM static struct ddi_device_acc_attr yge_regs_attr = { 12010506SBarry.Harding@Sun.COM DDI_DEVICE_ATTR_V0, 12110506SBarry.Harding@Sun.COM DDI_STRUCTURE_LE_ACC, 12211236SStephen.Hanson@Sun.COM DDI_STRICTORDER_ACC 12310506SBarry.Harding@Sun.COM }; 12410506SBarry.Harding@Sun.COM 12510506SBarry.Harding@Sun.COM static struct ddi_device_acc_attr yge_ring_attr = { 12610506SBarry.Harding@Sun.COM DDI_DEVICE_ATTR_V0, 12710506SBarry.Harding@Sun.COM DDI_STRUCTURE_LE_ACC, 12810506SBarry.Harding@Sun.COM DDI_STRICTORDER_ACC 12910506SBarry.Harding@Sun.COM }; 13010506SBarry.Harding@Sun.COM 13110506SBarry.Harding@Sun.COM static struct ddi_device_acc_attr yge_buf_attr = { 13210506SBarry.Harding@Sun.COM DDI_DEVICE_ATTR_V0, 13310506SBarry.Harding@Sun.COM DDI_NEVERSWAP_ACC, 13410506SBarry.Harding@Sun.COM DDI_STRICTORDER_ACC 13510506SBarry.Harding@Sun.COM }; 13610506SBarry.Harding@Sun.COM 13710506SBarry.Harding@Sun.COM #define DESC_ALIGN 0x1000 13810506SBarry.Harding@Sun.COM 13910506SBarry.Harding@Sun.COM static ddi_dma_attr_t yge_ring_dma_attr = { 14010506SBarry.Harding@Sun.COM DMA_ATTR_V0, /* dma_attr_version */ 14110506SBarry.Harding@Sun.COM 0, /* dma_attr_addr_lo */ 14210506SBarry.Harding@Sun.COM 0x00000000ffffffffull, /* dma_attr_addr_hi */ 14310506SBarry.Harding@Sun.COM 0x00000000ffffffffull, /* dma_attr_count_max */ 14410506SBarry.Harding@Sun.COM DESC_ALIGN, /* dma_attr_align */ 14510506SBarry.Harding@Sun.COM 0x000007fc, /* dma_attr_burstsizes */ 14610506SBarry.Harding@Sun.COM 1, /* dma_attr_minxfer */ 14710506SBarry.Harding@Sun.COM 0x00000000ffffffffull, /* dma_attr_maxxfer */ 14810506SBarry.Harding@Sun.COM 0x00000000ffffffffull, /* dma_attr_seg */ 14910506SBarry.Harding@Sun.COM 1, /* dma_attr_sgllen */ 15010506SBarry.Harding@Sun.COM 1, /* dma_attr_granular */ 15110506SBarry.Harding@Sun.COM 0 /* dma_attr_flags */ 15210506SBarry.Harding@Sun.COM }; 15310506SBarry.Harding@Sun.COM 15410506SBarry.Harding@Sun.COM static ddi_dma_attr_t yge_buf_dma_attr = { 15510506SBarry.Harding@Sun.COM DMA_ATTR_V0, /* dma_attr_version */ 15610506SBarry.Harding@Sun.COM 0, /* dma_attr_addr_lo */ 15710506SBarry.Harding@Sun.COM 0x00000000ffffffffull, /* dma_attr_addr_hi */ 15810506SBarry.Harding@Sun.COM 0x00000000ffffffffull, /* dma_attr_count_max */ 15910506SBarry.Harding@Sun.COM 1, /* dma_attr_align */ 16010506SBarry.Harding@Sun.COM 0x0000fffc, /* dma_attr_burstsizes */ 16110506SBarry.Harding@Sun.COM 1, /* dma_attr_minxfer */ 16210506SBarry.Harding@Sun.COM 0x000000000000ffffull, /* dma_attr_maxxfer */ 16310506SBarry.Harding@Sun.COM 0x00000000ffffffffull, /* dma_attr_seg */ 16410506SBarry.Harding@Sun.COM 8, /* dma_attr_sgllen */ 16510506SBarry.Harding@Sun.COM 1, /* dma_attr_granular */ 16610506SBarry.Harding@Sun.COM 0 /* dma_attr_flags */ 16710506SBarry.Harding@Sun.COM }; 16810506SBarry.Harding@Sun.COM 16910506SBarry.Harding@Sun.COM 17010506SBarry.Harding@Sun.COM static int yge_attach(yge_dev_t *); 17110506SBarry.Harding@Sun.COM static void yge_detach(yge_dev_t *); 17210506SBarry.Harding@Sun.COM static int yge_suspend(yge_dev_t *); 17310506SBarry.Harding@Sun.COM static int yge_resume(yge_dev_t *); 17410506SBarry.Harding@Sun.COM 17510506SBarry.Harding@Sun.COM static void yge_reset(yge_dev_t *); 17610506SBarry.Harding@Sun.COM static void yge_setup_rambuffer(yge_dev_t *); 17710506SBarry.Harding@Sun.COM 17810506SBarry.Harding@Sun.COM static int yge_init_port(yge_port_t *); 17910506SBarry.Harding@Sun.COM static void yge_uninit_port(yge_port_t *); 18010506SBarry.Harding@Sun.COM static int yge_register_port(yge_port_t *); 18110506SBarry.Harding@Sun.COM static int yge_unregister_port(yge_port_t *); 18210506SBarry.Harding@Sun.COM 18310506SBarry.Harding@Sun.COM static void yge_tick(void *); 18410506SBarry.Harding@Sun.COM static uint_t yge_intr(caddr_t, caddr_t); 18510506SBarry.Harding@Sun.COM static int yge_intr_gmac(yge_port_t *); 18610506SBarry.Harding@Sun.COM static void yge_intr_enable(yge_dev_t *); 18710506SBarry.Harding@Sun.COM static void yge_intr_disable(yge_dev_t *); 18810506SBarry.Harding@Sun.COM static boolean_t yge_handle_events(yge_dev_t *, mblk_t **, mblk_t **, int *); 18910506SBarry.Harding@Sun.COM static void yge_handle_hwerr(yge_port_t *, uint32_t); 19010506SBarry.Harding@Sun.COM static void yge_intr_hwerr(yge_dev_t *); 19110506SBarry.Harding@Sun.COM static mblk_t *yge_rxeof(yge_port_t *, uint32_t, int); 19210506SBarry.Harding@Sun.COM static void yge_txeof(yge_port_t *, int); 19310506SBarry.Harding@Sun.COM static boolean_t yge_send(yge_port_t *, mblk_t *); 19410506SBarry.Harding@Sun.COM static void yge_set_prefetch(yge_dev_t *, int, yge_ring_t *); 19510506SBarry.Harding@Sun.COM static void yge_set_rambuffer(yge_port_t *); 19610506SBarry.Harding@Sun.COM static void yge_start_port(yge_port_t *); 19710506SBarry.Harding@Sun.COM static void yge_stop_port(yge_port_t *); 19810506SBarry.Harding@Sun.COM static void yge_phy_power(yge_dev_t *, boolean_t); 19910506SBarry.Harding@Sun.COM static int yge_alloc_ring(yge_port_t *, yge_dev_t *, yge_ring_t *, uint32_t); 20010506SBarry.Harding@Sun.COM static void yge_free_ring(yge_ring_t *); 20110506SBarry.Harding@Sun.COM static uint8_t yge_find_capability(yge_dev_t *, uint8_t); 20210506SBarry.Harding@Sun.COM 20310506SBarry.Harding@Sun.COM static int yge_txrx_dma_alloc(yge_port_t *); 20410506SBarry.Harding@Sun.COM static void yge_txrx_dma_free(yge_port_t *); 20510506SBarry.Harding@Sun.COM static void yge_init_rx_ring(yge_port_t *); 20610506SBarry.Harding@Sun.COM static void yge_init_tx_ring(yge_port_t *); 20710506SBarry.Harding@Sun.COM 20810506SBarry.Harding@Sun.COM static uint16_t yge_mii_readreg(yge_port_t *, uint8_t, uint8_t); 20910506SBarry.Harding@Sun.COM static void yge_mii_writereg(yge_port_t *, uint8_t, uint8_t, uint16_t); 21010506SBarry.Harding@Sun.COM 21110506SBarry.Harding@Sun.COM static uint16_t yge_mii_read(void *, uint8_t, uint8_t); 21210506SBarry.Harding@Sun.COM static void yge_mii_write(void *, uint8_t, uint8_t, uint16_t); 21310506SBarry.Harding@Sun.COM static void yge_mii_notify(void *, link_state_t); 21410506SBarry.Harding@Sun.COM 21510506SBarry.Harding@Sun.COM static void yge_setrxfilt(yge_port_t *); 21610506SBarry.Harding@Sun.COM static void yge_restart_task(yge_dev_t *); 21710506SBarry.Harding@Sun.COM static void yge_task(void *); 21810506SBarry.Harding@Sun.COM static void yge_dispatch(yge_dev_t *, int); 21910506SBarry.Harding@Sun.COM 22010506SBarry.Harding@Sun.COM static void yge_stats_clear(yge_port_t *); 22110506SBarry.Harding@Sun.COM static void yge_stats_update(yge_port_t *); 22210506SBarry.Harding@Sun.COM static uint32_t yge_hashbit(const uint8_t *); 22310506SBarry.Harding@Sun.COM 22410506SBarry.Harding@Sun.COM static int yge_m_unicst(void *, const uint8_t *); 22510506SBarry.Harding@Sun.COM static int yge_m_multicst(void *, boolean_t, const uint8_t *); 22610506SBarry.Harding@Sun.COM static int yge_m_promisc(void *, boolean_t); 22710506SBarry.Harding@Sun.COM static mblk_t *yge_m_tx(void *, mblk_t *); 22810506SBarry.Harding@Sun.COM static int yge_m_stat(void *, uint_t, uint64_t *); 22910506SBarry.Harding@Sun.COM static int yge_m_start(void *); 23010506SBarry.Harding@Sun.COM static void yge_m_stop(void *); 231*11878SVenu.Iyer@Sun.COM static int yge_m_getprop(void *, const char *, mac_prop_id_t, uint_t, void *); 232*11878SVenu.Iyer@Sun.COM static void yge_m_propinfo(void *, const char *, mac_prop_id_t, 233*11878SVenu.Iyer@Sun.COM mac_prop_info_handle_t); 23410506SBarry.Harding@Sun.COM static int yge_m_setprop(void *, const char *, mac_prop_id_t, uint_t, 23510506SBarry.Harding@Sun.COM const void *); 23610506SBarry.Harding@Sun.COM static void yge_m_ioctl(void *, queue_t *, mblk_t *); 23710506SBarry.Harding@Sun.COM 23810506SBarry.Harding@Sun.COM void yge_error(yge_dev_t *, yge_port_t *, char *, ...); 23910506SBarry.Harding@Sun.COM extern void yge_phys_update(yge_port_t *); 24010506SBarry.Harding@Sun.COM extern int yge_phys_restart(yge_port_t *, boolean_t); 24110506SBarry.Harding@Sun.COM extern int yge_phys_init(yge_port_t *, phy_readreg_t, phy_writereg_t); 24210506SBarry.Harding@Sun.COM 24310506SBarry.Harding@Sun.COM static mac_callbacks_t yge_m_callbacks = { 244*11878SVenu.Iyer@Sun.COM MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO, 24510506SBarry.Harding@Sun.COM yge_m_stat, 24610506SBarry.Harding@Sun.COM yge_m_start, 24710506SBarry.Harding@Sun.COM yge_m_stop, 24810506SBarry.Harding@Sun.COM yge_m_promisc, 24910506SBarry.Harding@Sun.COM yge_m_multicst, 25010506SBarry.Harding@Sun.COM yge_m_unicst, 25110506SBarry.Harding@Sun.COM yge_m_tx, 252*11878SVenu.Iyer@Sun.COM NULL, 25310506SBarry.Harding@Sun.COM yge_m_ioctl, 25410506SBarry.Harding@Sun.COM NULL, /* mc_getcapab */ 25510506SBarry.Harding@Sun.COM NULL, /* mc_open */ 25610506SBarry.Harding@Sun.COM NULL, /* mc_close */ 25710506SBarry.Harding@Sun.COM yge_m_setprop, 25810506SBarry.Harding@Sun.COM yge_m_getprop, 259*11878SVenu.Iyer@Sun.COM yge_m_propinfo 26010506SBarry.Harding@Sun.COM }; 26110506SBarry.Harding@Sun.COM 26210506SBarry.Harding@Sun.COM static mii_ops_t yge_mii_ops = { 26310506SBarry.Harding@Sun.COM MII_OPS_VERSION, 26410506SBarry.Harding@Sun.COM yge_mii_read, 26510506SBarry.Harding@Sun.COM yge_mii_write, 26610506SBarry.Harding@Sun.COM yge_mii_notify, 26710506SBarry.Harding@Sun.COM NULL /* reset */ 26810506SBarry.Harding@Sun.COM }; 26910506SBarry.Harding@Sun.COM 27010506SBarry.Harding@Sun.COM /* 27110506SBarry.Harding@Sun.COM * This is the low level interface routine to read from the PHY 27210506SBarry.Harding@Sun.COM * MII registers. There is multiple steps to these accesses. First 27310506SBarry.Harding@Sun.COM * the register number is written to an address register. Then after 27410506SBarry.Harding@Sun.COM * a specified delay status is checked until the data is present. 27510506SBarry.Harding@Sun.COM */ 27610506SBarry.Harding@Sun.COM static uint16_t 27710506SBarry.Harding@Sun.COM yge_mii_readreg(yge_port_t *port, uint8_t phy, uint8_t reg) 27810506SBarry.Harding@Sun.COM { 27910506SBarry.Harding@Sun.COM yge_dev_t *dev = port->p_dev; 28010506SBarry.Harding@Sun.COM int pnum = port->p_port; 28110506SBarry.Harding@Sun.COM uint16_t val; 28210506SBarry.Harding@Sun.COM 28310506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_SMI_CTRL, 28410506SBarry.Harding@Sun.COM GM_SMI_CT_PHY_AD(phy) | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD); 28510506SBarry.Harding@Sun.COM 28610506SBarry.Harding@Sun.COM for (int i = 0; i < YGE_TIMEOUT; i += 10) { 28710506SBarry.Harding@Sun.COM drv_usecwait(10); 28810506SBarry.Harding@Sun.COM val = GMAC_READ_2(dev, pnum, GM_SMI_CTRL); 28910506SBarry.Harding@Sun.COM if ((val & GM_SMI_CT_RD_VAL) != 0) { 29010506SBarry.Harding@Sun.COM val = GMAC_READ_2(dev, pnum, GM_SMI_DATA); 29110506SBarry.Harding@Sun.COM return (val); 29210506SBarry.Harding@Sun.COM } 29310506SBarry.Harding@Sun.COM } 29410506SBarry.Harding@Sun.COM 29510506SBarry.Harding@Sun.COM return (0xffff); 29610506SBarry.Harding@Sun.COM } 29710506SBarry.Harding@Sun.COM 29810506SBarry.Harding@Sun.COM /* 29910506SBarry.Harding@Sun.COM * This is the low level interface routine to write to the PHY 30010506SBarry.Harding@Sun.COM * MII registers. There is multiple steps to these accesses. The 30110506SBarry.Harding@Sun.COM * data and the target registers address are written to the PHY. 30210506SBarry.Harding@Sun.COM * Then the PHY is polled until it is done with the write. Note 30310506SBarry.Harding@Sun.COM * that the delays are specified and required! 30410506SBarry.Harding@Sun.COM */ 30510506SBarry.Harding@Sun.COM static void 30610506SBarry.Harding@Sun.COM yge_mii_writereg(yge_port_t *port, uint8_t phy, uint8_t reg, uint16_t val) 30710506SBarry.Harding@Sun.COM { 30810506SBarry.Harding@Sun.COM yge_dev_t *dev = port->p_dev; 30910506SBarry.Harding@Sun.COM int pnum = port->p_port; 31010506SBarry.Harding@Sun.COM 31110506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_SMI_DATA, val); 31210506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_SMI_CTRL, 31310506SBarry.Harding@Sun.COM GM_SMI_CT_PHY_AD(phy) | GM_SMI_CT_REG_AD(reg)); 31410506SBarry.Harding@Sun.COM 31510506SBarry.Harding@Sun.COM for (int i = 0; i < YGE_TIMEOUT; i += 10) { 31610506SBarry.Harding@Sun.COM drv_usecwait(10); 31710506SBarry.Harding@Sun.COM if ((GMAC_READ_2(dev, pnum, GM_SMI_CTRL) & GM_SMI_CT_BUSY) == 0) 31810506SBarry.Harding@Sun.COM return; 31910506SBarry.Harding@Sun.COM } 32010506SBarry.Harding@Sun.COM 32110506SBarry.Harding@Sun.COM yge_error(NULL, port, "phy write timeout"); 32210506SBarry.Harding@Sun.COM } 32310506SBarry.Harding@Sun.COM 32410506SBarry.Harding@Sun.COM static uint16_t 32510506SBarry.Harding@Sun.COM yge_mii_read(void *arg, uint8_t phy, uint8_t reg) 32610506SBarry.Harding@Sun.COM { 32710506SBarry.Harding@Sun.COM yge_port_t *port = arg; 32810506SBarry.Harding@Sun.COM uint16_t rv; 32910506SBarry.Harding@Sun.COM 33010506SBarry.Harding@Sun.COM PHY_LOCK(port->p_dev); 33110506SBarry.Harding@Sun.COM rv = yge_mii_readreg(port, phy, reg); 33210506SBarry.Harding@Sun.COM PHY_UNLOCK(port->p_dev); 33310506SBarry.Harding@Sun.COM return (rv); 33410506SBarry.Harding@Sun.COM } 33510506SBarry.Harding@Sun.COM 33610506SBarry.Harding@Sun.COM static void 33710506SBarry.Harding@Sun.COM yge_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t val) 33810506SBarry.Harding@Sun.COM { 33910506SBarry.Harding@Sun.COM yge_port_t *port = arg; 34010506SBarry.Harding@Sun.COM 34110506SBarry.Harding@Sun.COM PHY_LOCK(port->p_dev); 34210506SBarry.Harding@Sun.COM yge_mii_writereg(port, phy, reg, val); 34310506SBarry.Harding@Sun.COM PHY_UNLOCK(port->p_dev); 34410506SBarry.Harding@Sun.COM } 34510506SBarry.Harding@Sun.COM 34610506SBarry.Harding@Sun.COM /* 34710506SBarry.Harding@Sun.COM * The MII common code calls this function to let the MAC driver 34810506SBarry.Harding@Sun.COM * know when there has been a change in status. 34910506SBarry.Harding@Sun.COM */ 35010506SBarry.Harding@Sun.COM void 35110506SBarry.Harding@Sun.COM yge_mii_notify(void *arg, link_state_t link) 35210506SBarry.Harding@Sun.COM { 35310506SBarry.Harding@Sun.COM yge_port_t *port = arg; 35410506SBarry.Harding@Sun.COM yge_dev_t *dev = port->p_dev; 35510506SBarry.Harding@Sun.COM uint32_t gmac; 35610506SBarry.Harding@Sun.COM uint32_t gpcr; 35710506SBarry.Harding@Sun.COM link_flowctrl_t fc; 35810506SBarry.Harding@Sun.COM link_duplex_t duplex; 35910506SBarry.Harding@Sun.COM int speed; 36010506SBarry.Harding@Sun.COM 36110506SBarry.Harding@Sun.COM fc = mii_get_flowctrl(port->p_mii); 36210506SBarry.Harding@Sun.COM duplex = mii_get_duplex(port->p_mii); 36310506SBarry.Harding@Sun.COM speed = mii_get_speed(port->p_mii); 36410506SBarry.Harding@Sun.COM 36510506SBarry.Harding@Sun.COM DEV_LOCK(dev); 36610506SBarry.Harding@Sun.COM 36710506SBarry.Harding@Sun.COM if (link == LINK_STATE_UP) { 36810506SBarry.Harding@Sun.COM 36910506SBarry.Harding@Sun.COM /* Enable Tx FIFO Underrun. */ 37010506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, MR_ADDR(port->p_port, GMAC_IRQ_MSK), 37110506SBarry.Harding@Sun.COM GM_IS_TX_FF_UR | /* TX FIFO underflow */ 37210506SBarry.Harding@Sun.COM GM_IS_RX_FF_OR); /* RX FIFO overflow */ 37310506SBarry.Harding@Sun.COM 37410506SBarry.Harding@Sun.COM gpcr = GM_GPCR_AU_ALL_DIS; 37510506SBarry.Harding@Sun.COM 37610506SBarry.Harding@Sun.COM switch (fc) { 37710506SBarry.Harding@Sun.COM case LINK_FLOWCTRL_BI: 37810506SBarry.Harding@Sun.COM gmac = GMC_PAUSE_ON; 37910506SBarry.Harding@Sun.COM gpcr &= ~(GM_GPCR_FC_RX_DIS | GM_GPCR_FC_TX_DIS); 38010506SBarry.Harding@Sun.COM break; 38110506SBarry.Harding@Sun.COM case LINK_FLOWCTRL_TX: 38210506SBarry.Harding@Sun.COM gmac = GMC_PAUSE_ON; 38310506SBarry.Harding@Sun.COM gpcr |= GM_GPCR_FC_RX_DIS; 38410506SBarry.Harding@Sun.COM break; 38510506SBarry.Harding@Sun.COM case LINK_FLOWCTRL_RX: 38610506SBarry.Harding@Sun.COM gmac = GMC_PAUSE_ON; 38710506SBarry.Harding@Sun.COM gpcr |= GM_GPCR_FC_TX_DIS; 38810506SBarry.Harding@Sun.COM break; 38910506SBarry.Harding@Sun.COM case LINK_FLOWCTRL_NONE: 39010506SBarry.Harding@Sun.COM default: 39110506SBarry.Harding@Sun.COM gmac = GMC_PAUSE_OFF; 39210506SBarry.Harding@Sun.COM gpcr |= GM_GPCR_FC_RX_DIS; 39310506SBarry.Harding@Sun.COM gpcr |= GM_GPCR_FC_TX_DIS; 39410506SBarry.Harding@Sun.COM break; 39510506SBarry.Harding@Sun.COM } 39610506SBarry.Harding@Sun.COM 39710506SBarry.Harding@Sun.COM gpcr &= ~((GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100)); 39810506SBarry.Harding@Sun.COM switch (speed) { 39910506SBarry.Harding@Sun.COM case 1000: 40010506SBarry.Harding@Sun.COM gpcr |= GM_GPCR_SPEED_1000; 40110506SBarry.Harding@Sun.COM break; 40210506SBarry.Harding@Sun.COM case 100: 40310506SBarry.Harding@Sun.COM gpcr |= GM_GPCR_SPEED_100; 40410506SBarry.Harding@Sun.COM break; 40510506SBarry.Harding@Sun.COM case 10: 40610506SBarry.Harding@Sun.COM default: 40710506SBarry.Harding@Sun.COM break; 40810506SBarry.Harding@Sun.COM } 40910506SBarry.Harding@Sun.COM 41010506SBarry.Harding@Sun.COM if (duplex == LINK_DUPLEX_FULL) { 41110506SBarry.Harding@Sun.COM gpcr |= GM_GPCR_DUP_FULL; 41210506SBarry.Harding@Sun.COM } else { 41310506SBarry.Harding@Sun.COM gpcr &= ~(GM_GPCR_DUP_FULL); 41410506SBarry.Harding@Sun.COM gmac = GMC_PAUSE_OFF; 41510506SBarry.Harding@Sun.COM gpcr |= GM_GPCR_FC_RX_DIS; 41610506SBarry.Harding@Sun.COM gpcr |= GM_GPCR_FC_TX_DIS; 41710506SBarry.Harding@Sun.COM } 41810506SBarry.Harding@Sun.COM 41910506SBarry.Harding@Sun.COM gpcr |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA; 42010506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, port->p_port, GM_GP_CTRL, gpcr); 42110506SBarry.Harding@Sun.COM 42210506SBarry.Harding@Sun.COM /* Read again to ensure writing. */ 42310506SBarry.Harding@Sun.COM (void) GMAC_READ_2(dev, port->p_port, GM_GP_CTRL); 42410506SBarry.Harding@Sun.COM 42510506SBarry.Harding@Sun.COM /* write out the flow control gmac setting */ 42610506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(port->p_port, GMAC_CTRL), gmac); 42710506SBarry.Harding@Sun.COM 42810506SBarry.Harding@Sun.COM } else { 42910506SBarry.Harding@Sun.COM /* Disable Rx/Tx MAC. */ 43010506SBarry.Harding@Sun.COM gpcr = GMAC_READ_2(dev, port->p_port, GM_GP_CTRL); 43110506SBarry.Harding@Sun.COM gpcr &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); 43210506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, port->p_port, GM_GP_CTRL, gpcr); 43310506SBarry.Harding@Sun.COM 43410506SBarry.Harding@Sun.COM /* Read again to ensure writing. */ 43510506SBarry.Harding@Sun.COM (void) GMAC_READ_2(dev, port->p_port, GM_GP_CTRL); 43610506SBarry.Harding@Sun.COM } 43710506SBarry.Harding@Sun.COM 43810506SBarry.Harding@Sun.COM DEV_UNLOCK(dev); 43910506SBarry.Harding@Sun.COM 44010506SBarry.Harding@Sun.COM mac_link_update(port->p_mh, link); 44110506SBarry.Harding@Sun.COM 44210506SBarry.Harding@Sun.COM if (port->p_running && (link == LINK_STATE_UP)) { 44310506SBarry.Harding@Sun.COM mac_tx_update(port->p_mh); 44410506SBarry.Harding@Sun.COM } 44510506SBarry.Harding@Sun.COM } 44610506SBarry.Harding@Sun.COM 44710506SBarry.Harding@Sun.COM static void 44810506SBarry.Harding@Sun.COM yge_setrxfilt(yge_port_t *port) 44910506SBarry.Harding@Sun.COM { 45010506SBarry.Harding@Sun.COM yge_dev_t *dev; 45110506SBarry.Harding@Sun.COM uint16_t mode; 45210506SBarry.Harding@Sun.COM uint8_t *ea; 45310506SBarry.Harding@Sun.COM uint32_t *mchash; 45410506SBarry.Harding@Sun.COM int pnum; 45510506SBarry.Harding@Sun.COM 45610506SBarry.Harding@Sun.COM dev = port->p_dev; 45710506SBarry.Harding@Sun.COM pnum = port->p_port; 45810506SBarry.Harding@Sun.COM ea = port->p_curraddr; 45910506SBarry.Harding@Sun.COM mchash = port->p_mchash; 46010506SBarry.Harding@Sun.COM 46110506SBarry.Harding@Sun.COM if (dev->d_suspended) 46210506SBarry.Harding@Sun.COM return; 46310506SBarry.Harding@Sun.COM 46410506SBarry.Harding@Sun.COM /* Set station address. */ 46510506SBarry.Harding@Sun.COM for (int i = 0; i < (ETHERADDRL / 2); i++) { 46610506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_SRC_ADDR_1L + i * 4, 46710506SBarry.Harding@Sun.COM ((uint16_t)ea[i * 2] | ((uint16_t)ea[(i * 2) + 1] << 8))); 46810506SBarry.Harding@Sun.COM } 46910506SBarry.Harding@Sun.COM for (int i = 0; i < (ETHERADDRL / 2); i++) { 47010506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_SRC_ADDR_2L + i * 4, 47110506SBarry.Harding@Sun.COM ((uint16_t)ea[i * 2] | ((uint16_t)ea[(i * 2) + 1] << 8))); 47210506SBarry.Harding@Sun.COM } 47310506SBarry.Harding@Sun.COM 47410506SBarry.Harding@Sun.COM /* Figure out receive filtering mode. */ 47510506SBarry.Harding@Sun.COM mode = GMAC_READ_2(dev, pnum, GM_RX_CTRL); 47610506SBarry.Harding@Sun.COM if (port->p_promisc) { 47710506SBarry.Harding@Sun.COM mode &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); 47810506SBarry.Harding@Sun.COM } else { 47910506SBarry.Harding@Sun.COM mode |= (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); 48010506SBarry.Harding@Sun.COM } 48110506SBarry.Harding@Sun.COM /* Write the multicast filter. */ 48210506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_MC_ADDR_H1, mchash[0] & 0xffff); 48310506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_MC_ADDR_H2, (mchash[0] >> 16) & 0xffff); 48410506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_MC_ADDR_H3, mchash[1] & 0xffff); 48510506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_MC_ADDR_H4, (mchash[1] >> 16) & 0xffff); 48610506SBarry.Harding@Sun.COM /* Write the receive filtering mode. */ 48710506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_RX_CTRL, mode); 48810506SBarry.Harding@Sun.COM } 48910506SBarry.Harding@Sun.COM 49010506SBarry.Harding@Sun.COM static void 49110506SBarry.Harding@Sun.COM yge_init_rx_ring(yge_port_t *port) 49210506SBarry.Harding@Sun.COM { 49310506SBarry.Harding@Sun.COM yge_buf_t *rxb; 49410506SBarry.Harding@Sun.COM yge_ring_t *ring; 49510506SBarry.Harding@Sun.COM int prod; 49610506SBarry.Harding@Sun.COM 49710506SBarry.Harding@Sun.COM port->p_rx_cons = 0; 49810506SBarry.Harding@Sun.COM port->p_rx_putwm = YGE_PUT_WM; 49910506SBarry.Harding@Sun.COM ring = &port->p_rx_ring; 50010506SBarry.Harding@Sun.COM 50110506SBarry.Harding@Sun.COM /* ala bzero, but uses safer acch access */ 50210506SBarry.Harding@Sun.COM CLEARRING(ring); 50310506SBarry.Harding@Sun.COM 50410506SBarry.Harding@Sun.COM for (prod = 0; prod < YGE_RX_RING_CNT; prod++) { 50510506SBarry.Harding@Sun.COM /* Hang out receive buffers. */ 50610506SBarry.Harding@Sun.COM rxb = &port->p_rx_buf[prod]; 50710506SBarry.Harding@Sun.COM 50810506SBarry.Harding@Sun.COM PUTADDR(ring, prod, rxb->b_paddr); 50910506SBarry.Harding@Sun.COM PUTCTRL(ring, prod, port->p_framesize | OP_PACKET | HW_OWNER); 51010506SBarry.Harding@Sun.COM } 51110506SBarry.Harding@Sun.COM 51210506SBarry.Harding@Sun.COM SYNCRING(ring, DDI_DMA_SYNC_FORDEV); 51310506SBarry.Harding@Sun.COM 51410506SBarry.Harding@Sun.COM yge_set_prefetch(port->p_dev, port->p_rxq, ring); 51510506SBarry.Harding@Sun.COM 51610506SBarry.Harding@Sun.COM /* Update prefetch unit. */ 51710506SBarry.Harding@Sun.COM CSR_WRITE_2(port->p_dev, 51810506SBarry.Harding@Sun.COM Y2_PREF_Q_ADDR(port->p_rxq, PREF_UNIT_PUT_IDX_REG), 51910506SBarry.Harding@Sun.COM YGE_RX_RING_CNT - 1); 52010506SBarry.Harding@Sun.COM } 52110506SBarry.Harding@Sun.COM 52210506SBarry.Harding@Sun.COM static void 52310506SBarry.Harding@Sun.COM yge_init_tx_ring(yge_port_t *port) 52410506SBarry.Harding@Sun.COM { 52510506SBarry.Harding@Sun.COM yge_ring_t *ring = &port->p_tx_ring; 52610506SBarry.Harding@Sun.COM 52710506SBarry.Harding@Sun.COM port->p_tx_prod = 0; 52810506SBarry.Harding@Sun.COM port->p_tx_cons = 0; 52910506SBarry.Harding@Sun.COM port->p_tx_cnt = 0; 53010506SBarry.Harding@Sun.COM 53110506SBarry.Harding@Sun.COM CLEARRING(ring); 53210506SBarry.Harding@Sun.COM SYNCRING(ring, DDI_DMA_SYNC_FORDEV); 53310506SBarry.Harding@Sun.COM 53410506SBarry.Harding@Sun.COM yge_set_prefetch(port->p_dev, port->p_txq, ring); 53510506SBarry.Harding@Sun.COM } 53610506SBarry.Harding@Sun.COM 53710506SBarry.Harding@Sun.COM static void 53810506SBarry.Harding@Sun.COM yge_setup_rambuffer(yge_dev_t *dev) 53910506SBarry.Harding@Sun.COM { 54010506SBarry.Harding@Sun.COM int next; 54110506SBarry.Harding@Sun.COM int i; 54210506SBarry.Harding@Sun.COM 54310506SBarry.Harding@Sun.COM /* Get adapter SRAM size. */ 54410506SBarry.Harding@Sun.COM dev->d_ramsize = CSR_READ_1(dev, B2_E_0) * 4; 54510506SBarry.Harding@Sun.COM if (dev->d_ramsize == 0) 54610506SBarry.Harding@Sun.COM return; 54710506SBarry.Harding@Sun.COM 54810506SBarry.Harding@Sun.COM dev->d_pflags |= PORT_FLAG_RAMBUF; 54910506SBarry.Harding@Sun.COM /* 55010506SBarry.Harding@Sun.COM * Give receiver 2/3 of memory and round down to the multiple 55110506SBarry.Harding@Sun.COM * of 1024. Tx/Rx RAM buffer size of Yukon 2 should be multiple 55210506SBarry.Harding@Sun.COM * of 1024. 55310506SBarry.Harding@Sun.COM */ 55410506SBarry.Harding@Sun.COM dev->d_rxqsize = (((dev->d_ramsize * 1024 * 2) / 3) & ~(1024 - 1)); 55510506SBarry.Harding@Sun.COM dev->d_txqsize = (dev->d_ramsize * 1024) - dev->d_rxqsize; 55610506SBarry.Harding@Sun.COM 55710506SBarry.Harding@Sun.COM for (i = 0, next = 0; i < dev->d_num_port; i++) { 55810506SBarry.Harding@Sun.COM dev->d_rxqstart[i] = next; 55910506SBarry.Harding@Sun.COM dev->d_rxqend[i] = next + dev->d_rxqsize - 1; 56010506SBarry.Harding@Sun.COM next = dev->d_rxqend[i] + 1; 56110506SBarry.Harding@Sun.COM dev->d_txqstart[i] = next; 56210506SBarry.Harding@Sun.COM dev->d_txqend[i] = next + dev->d_txqsize - 1; 56310506SBarry.Harding@Sun.COM next = dev->d_txqend[i] + 1; 56410506SBarry.Harding@Sun.COM } 56510506SBarry.Harding@Sun.COM } 56610506SBarry.Harding@Sun.COM 56710506SBarry.Harding@Sun.COM static void 56810506SBarry.Harding@Sun.COM yge_phy_power(yge_dev_t *dev, boolean_t powerup) 56910506SBarry.Harding@Sun.COM { 57010506SBarry.Harding@Sun.COM uint32_t val; 57110506SBarry.Harding@Sun.COM int i; 57210506SBarry.Harding@Sun.COM 57310506SBarry.Harding@Sun.COM if (powerup) { 57410506SBarry.Harding@Sun.COM /* Switch power to VCC (WA for VAUX problem). */ 57510506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B0_POWER_CTRL, 57610506SBarry.Harding@Sun.COM PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON); 57710506SBarry.Harding@Sun.COM /* Disable Core Clock Division, set Clock Select to 0. */ 57810506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS); 57910506SBarry.Harding@Sun.COM 58010506SBarry.Harding@Sun.COM val = 0; 58110506SBarry.Harding@Sun.COM if (dev->d_hw_id == CHIP_ID_YUKON_XL && 58210506SBarry.Harding@Sun.COM dev->d_hw_rev > CHIP_REV_YU_XL_A1) { 58310506SBarry.Harding@Sun.COM /* Enable bits are inverted. */ 58410506SBarry.Harding@Sun.COM val = Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS | 58510506SBarry.Harding@Sun.COM Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS | 58610506SBarry.Harding@Sun.COM Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS; 58710506SBarry.Harding@Sun.COM } 58810506SBarry.Harding@Sun.COM /* 58910506SBarry.Harding@Sun.COM * Enable PCI & Core Clock, enable clock gating for both Links. 59010506SBarry.Harding@Sun.COM */ 59110506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_Y2_CLK_GATE, val); 59210506SBarry.Harding@Sun.COM 59310506SBarry.Harding@Sun.COM val = pci_config_get32(dev->d_pcih, PCI_OUR_REG_1); 59410506SBarry.Harding@Sun.COM val &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); 59510506SBarry.Harding@Sun.COM if (dev->d_hw_id == CHIP_ID_YUKON_XL && 59610506SBarry.Harding@Sun.COM dev->d_hw_rev > CHIP_REV_YU_XL_A1) { 59710506SBarry.Harding@Sun.COM /* Deassert Low Power for 1st PHY. */ 59810506SBarry.Harding@Sun.COM val |= PCI_Y2_PHY1_COMA; 59910506SBarry.Harding@Sun.COM if (dev->d_num_port > 1) 60010506SBarry.Harding@Sun.COM val |= PCI_Y2_PHY2_COMA; 60110506SBarry.Harding@Sun.COM } 60210506SBarry.Harding@Sun.COM 60310506SBarry.Harding@Sun.COM /* Release PHY from PowerDown/COMA mode. */ 60410506SBarry.Harding@Sun.COM pci_config_put32(dev->d_pcih, PCI_OUR_REG_1, val); 60510506SBarry.Harding@Sun.COM 60610506SBarry.Harding@Sun.COM switch (dev->d_hw_id) { 60710506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_EC_U: 60810506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_EX: 60910506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_FE_P: { 61010506SBarry.Harding@Sun.COM uint32_t our; 61110506SBarry.Harding@Sun.COM 61210506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, B0_CTST, Y2_HW_WOL_OFF); 61310506SBarry.Harding@Sun.COM 61410506SBarry.Harding@Sun.COM /* Enable all clocks. */ 61510506SBarry.Harding@Sun.COM pci_config_put32(dev->d_pcih, PCI_OUR_REG_3, 0); 61610506SBarry.Harding@Sun.COM 61710506SBarry.Harding@Sun.COM our = pci_config_get32(dev->d_pcih, PCI_OUR_REG_4); 61810506SBarry.Harding@Sun.COM our &= (PCI_FORCE_ASPM_REQUEST|PCI_ASPM_GPHY_LINK_DOWN| 61910506SBarry.Harding@Sun.COM PCI_ASPM_INT_FIFO_EMPTY|PCI_ASPM_CLKRUN_REQUEST); 62010506SBarry.Harding@Sun.COM /* Set all bits to 0 except bits 15..12. */ 62110506SBarry.Harding@Sun.COM pci_config_put32(dev->d_pcih, PCI_OUR_REG_4, our); 62210506SBarry.Harding@Sun.COM 62310506SBarry.Harding@Sun.COM /* Set to default value. */ 62410506SBarry.Harding@Sun.COM our = pci_config_get32(dev->d_pcih, PCI_OUR_REG_5); 62510506SBarry.Harding@Sun.COM our &= P_CTL_TIM_VMAIN_AV_MSK; 62610506SBarry.Harding@Sun.COM pci_config_put32(dev->d_pcih, PCI_OUR_REG_5, our); 62710506SBarry.Harding@Sun.COM 62810506SBarry.Harding@Sun.COM pci_config_put32(dev->d_pcih, PCI_OUR_REG_1, 0); 62910506SBarry.Harding@Sun.COM 63010506SBarry.Harding@Sun.COM /* 63110506SBarry.Harding@Sun.COM * Enable workaround for dev 4.107 on Yukon-Ultra 63210506SBarry.Harding@Sun.COM * and Extreme 63310506SBarry.Harding@Sun.COM */ 63410506SBarry.Harding@Sun.COM our = CSR_READ_4(dev, B2_GP_IO); 63510506SBarry.Harding@Sun.COM our |= GLB_GPIO_STAT_RACE_DIS; 63610506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B2_GP_IO, our); 63710506SBarry.Harding@Sun.COM 63810506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B2_GP_IO); 63910506SBarry.Harding@Sun.COM break; 64010506SBarry.Harding@Sun.COM } 64110506SBarry.Harding@Sun.COM default: 64210506SBarry.Harding@Sun.COM break; 64310506SBarry.Harding@Sun.COM } 64410506SBarry.Harding@Sun.COM 64510506SBarry.Harding@Sun.COM for (i = 0; i < dev->d_num_port; i++) { 64610506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, MR_ADDR(i, GMAC_LINK_CTRL), 64710506SBarry.Harding@Sun.COM GMLC_RST_SET); 64810506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, MR_ADDR(i, GMAC_LINK_CTRL), 64910506SBarry.Harding@Sun.COM GMLC_RST_CLR); 65010506SBarry.Harding@Sun.COM } 65110506SBarry.Harding@Sun.COM } else { 65210506SBarry.Harding@Sun.COM val = pci_config_get32(dev->d_pcih, PCI_OUR_REG_1); 65310506SBarry.Harding@Sun.COM if (dev->d_hw_id == CHIP_ID_YUKON_XL && 65410506SBarry.Harding@Sun.COM dev->d_hw_rev > CHIP_REV_YU_XL_A1) { 65510506SBarry.Harding@Sun.COM val &= ~PCI_Y2_PHY1_COMA; 65610506SBarry.Harding@Sun.COM if (dev->d_num_port > 1) 65710506SBarry.Harding@Sun.COM val &= ~PCI_Y2_PHY2_COMA; 65810506SBarry.Harding@Sun.COM val &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); 65910506SBarry.Harding@Sun.COM } else { 66010506SBarry.Harding@Sun.COM val |= (PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD); 66110506SBarry.Harding@Sun.COM } 66210506SBarry.Harding@Sun.COM pci_config_put32(dev->d_pcih, PCI_OUR_REG_1, val); 66310506SBarry.Harding@Sun.COM 66410506SBarry.Harding@Sun.COM val = Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS | 66510506SBarry.Harding@Sun.COM Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS | 66610506SBarry.Harding@Sun.COM Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS; 66710506SBarry.Harding@Sun.COM if (dev->d_hw_id == CHIP_ID_YUKON_XL && 66810506SBarry.Harding@Sun.COM dev->d_hw_rev > CHIP_REV_YU_XL_A1) { 66910506SBarry.Harding@Sun.COM /* Enable bits are inverted. */ 67010506SBarry.Harding@Sun.COM val = 0; 67110506SBarry.Harding@Sun.COM } 67210506SBarry.Harding@Sun.COM /* 67310506SBarry.Harding@Sun.COM * Disable PCI & Core Clock, disable clock gating for 67410506SBarry.Harding@Sun.COM * both Links. 67510506SBarry.Harding@Sun.COM */ 67610506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_Y2_CLK_GATE, val); 67710506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B0_POWER_CTRL, 67810506SBarry.Harding@Sun.COM PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF); 67910506SBarry.Harding@Sun.COM } 68010506SBarry.Harding@Sun.COM } 68110506SBarry.Harding@Sun.COM 68210506SBarry.Harding@Sun.COM static void 68310506SBarry.Harding@Sun.COM yge_reset(yge_dev_t *dev) 68410506SBarry.Harding@Sun.COM { 68510506SBarry.Harding@Sun.COM uint64_t addr; 68610506SBarry.Harding@Sun.COM uint16_t status; 68710506SBarry.Harding@Sun.COM uint32_t val; 68810506SBarry.Harding@Sun.COM int i; 68910506SBarry.Harding@Sun.COM ddi_acc_handle_t pcih = dev->d_pcih; 69010506SBarry.Harding@Sun.COM 69110506SBarry.Harding@Sun.COM /* Turn off ASF */ 69210506SBarry.Harding@Sun.COM if (dev->d_hw_id == CHIP_ID_YUKON_EX) { 69310506SBarry.Harding@Sun.COM status = CSR_READ_2(dev, B28_Y2_ASF_STAT_CMD); 69410506SBarry.Harding@Sun.COM /* Clear AHB bridge & microcontroller reset */ 69510506SBarry.Harding@Sun.COM status &= ~Y2_ASF_CPU_MODE; 69610506SBarry.Harding@Sun.COM status &= ~Y2_ASF_AHB_RST; 69710506SBarry.Harding@Sun.COM /* Clear ASF microcontroller state */ 69810506SBarry.Harding@Sun.COM status &= ~Y2_ASF_STAT_MSK; 69910506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, B28_Y2_ASF_STAT_CMD, status); 70010506SBarry.Harding@Sun.COM } else { 70110506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); 70210506SBarry.Harding@Sun.COM } 70310506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, B0_CTST, Y2_ASF_DISABLE); 70410506SBarry.Harding@Sun.COM 70510506SBarry.Harding@Sun.COM /* 70610506SBarry.Harding@Sun.COM * Since we disabled ASF, S/W reset is required for Power Management. 70710506SBarry.Harding@Sun.COM */ 70810506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B0_CTST, CS_RST_SET); 70910506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B0_CTST, CS_RST_CLR); 71010506SBarry.Harding@Sun.COM 71110506SBarry.Harding@Sun.COM /* Allow writes to PCI config space */ 71210506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_ON); 71310506SBarry.Harding@Sun.COM 71410506SBarry.Harding@Sun.COM /* Clear all error bits in the PCI status register. */ 71510506SBarry.Harding@Sun.COM status = pci_config_get16(pcih, PCI_CONF_STAT); 71610506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_ON); 71710506SBarry.Harding@Sun.COM 71810506SBarry.Harding@Sun.COM status |= (PCI_STAT_S_PERROR | PCI_STAT_S_SYSERR | PCI_STAT_R_MAST_AB | 71910506SBarry.Harding@Sun.COM PCI_STAT_R_TARG_AB | PCI_STAT_PERROR); 72010506SBarry.Harding@Sun.COM pci_config_put16(pcih, PCI_CONF_STAT, status); 72110506SBarry.Harding@Sun.COM 72210506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B0_CTST, CS_MRST_CLR); 72310506SBarry.Harding@Sun.COM 72410506SBarry.Harding@Sun.COM switch (dev->d_bustype) { 72510506SBarry.Harding@Sun.COM case PEX_BUS: 72610506SBarry.Harding@Sun.COM /* Clear all PEX errors. */ 72710506SBarry.Harding@Sun.COM CSR_PCI_WRITE_4(dev, Y2_CFG_AER + AER_UNCOR_ERR, 0xffffffff); 72810506SBarry.Harding@Sun.COM 72910506SBarry.Harding@Sun.COM /* is error bit status stuck? */ 73010506SBarry.Harding@Sun.COM val = CSR_PCI_READ_4(dev, PEX_UNC_ERR_STAT); 73110506SBarry.Harding@Sun.COM if ((val & PEX_RX_OV) != 0) { 73210506SBarry.Harding@Sun.COM dev->d_intrmask &= ~Y2_IS_HW_ERR; 73310506SBarry.Harding@Sun.COM dev->d_intrhwemask &= ~Y2_IS_PCI_EXP; 73410506SBarry.Harding@Sun.COM } 73510506SBarry.Harding@Sun.COM break; 73610506SBarry.Harding@Sun.COM case PCI_BUS: 73710506SBarry.Harding@Sun.COM /* Set Cache Line Size to 2 (8 bytes) if configured to 0. */ 73810506SBarry.Harding@Sun.COM if (pci_config_get8(pcih, PCI_CONF_CACHE_LINESZ) == 0) 73910506SBarry.Harding@Sun.COM pci_config_put16(pcih, PCI_CONF_CACHE_LINESZ, 2); 74010506SBarry.Harding@Sun.COM break; 74110506SBarry.Harding@Sun.COM case PCIX_BUS: 74210506SBarry.Harding@Sun.COM /* Set Cache Line Size to 2 (8 bytes) if configured to 0. */ 74310506SBarry.Harding@Sun.COM if (pci_config_get8(pcih, PCI_CONF_CACHE_LINESZ) == 0) 74410506SBarry.Harding@Sun.COM pci_config_put16(pcih, PCI_CONF_CACHE_LINESZ, 2); 74510506SBarry.Harding@Sun.COM 74610506SBarry.Harding@Sun.COM /* Set Cache Line Size opt. */ 74710506SBarry.Harding@Sun.COM val = pci_config_get32(pcih, PCI_OUR_REG_1); 74810506SBarry.Harding@Sun.COM val |= PCI_CLS_OPT; 74910506SBarry.Harding@Sun.COM pci_config_put32(pcih, PCI_OUR_REG_1, val); 75010506SBarry.Harding@Sun.COM break; 75110506SBarry.Harding@Sun.COM } 75210506SBarry.Harding@Sun.COM 75310506SBarry.Harding@Sun.COM /* Set PHY power state. */ 75410506SBarry.Harding@Sun.COM yge_phy_power(dev, B_TRUE); 75510506SBarry.Harding@Sun.COM 75610506SBarry.Harding@Sun.COM /* Reset GPHY/GMAC Control */ 75710506SBarry.Harding@Sun.COM for (i = 0; i < dev->d_num_port; i++) { 75810506SBarry.Harding@Sun.COM /* GPHY Control reset. */ 75910506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(i, GPHY_CTRL), GPC_RST_SET); 76010506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(i, GPHY_CTRL), GPC_RST_CLR); 76110506SBarry.Harding@Sun.COM /* GMAC Control reset. */ 76210506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(i, GMAC_CTRL), GMC_RST_SET); 76310506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(i, GMAC_CTRL), GMC_RST_CLR); 76410506SBarry.Harding@Sun.COM if (dev->d_hw_id == CHIP_ID_YUKON_EX || 76510506SBarry.Harding@Sun.COM dev->d_hw_id == CHIP_ID_YUKON_SUPR) { 76610506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, MR_ADDR(i, GMAC_CTRL), 76710506SBarry.Harding@Sun.COM (GMC_BYP_RETR_ON | GMC_BYP_MACSECRX_ON | 76810506SBarry.Harding@Sun.COM GMC_BYP_MACSECTX_ON)); 76910506SBarry.Harding@Sun.COM } 77010506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, MR_ADDR(i, GMAC_CTRL), GMC_F_LOOPB_OFF); 77110506SBarry.Harding@Sun.COM 77210506SBarry.Harding@Sun.COM } 77310506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 77410506SBarry.Harding@Sun.COM 77510506SBarry.Harding@Sun.COM /* LED On. */ 77610506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, B0_CTST, Y2_LED_STAT_ON); 77710506SBarry.Harding@Sun.COM 77810506SBarry.Harding@Sun.COM /* Clear TWSI IRQ. */ 77910506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B2_I2C_IRQ, I2C_CLR_IRQ); 78010506SBarry.Harding@Sun.COM 78110506SBarry.Harding@Sun.COM /* Turn off hardware timer. */ 78210506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TI_CTRL, TIM_STOP); 78310506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TI_CTRL, TIM_CLR_IRQ); 78410506SBarry.Harding@Sun.COM 78510506SBarry.Harding@Sun.COM /* Turn off descriptor polling. */ 78610506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B28_DPT_CTRL, DPT_STOP); 78710506SBarry.Harding@Sun.COM 78810506SBarry.Harding@Sun.COM /* Turn off time stamps. */ 78910506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, GMAC_TI_ST_CTRL, GMT_ST_STOP); 79010506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ); 79110506SBarry.Harding@Sun.COM 79210506SBarry.Harding@Sun.COM /* Don't permit config space writing */ 79310506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 79410506SBarry.Harding@Sun.COM 79510506SBarry.Harding@Sun.COM /* enable TX Arbiters */ 79610506SBarry.Harding@Sun.COM for (i = 0; i < dev->d_num_port; i++) 79710506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, MR_ADDR(i, TXA_CTRL), TXA_ENA_ARB); 79810506SBarry.Harding@Sun.COM 79910506SBarry.Harding@Sun.COM /* Configure timeout values. */ 80010506SBarry.Harding@Sun.COM for (i = 0; i < dev->d_num_port; i++) { 80110506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_CTRL), RI_RST_CLR); 80210506SBarry.Harding@Sun.COM 80310506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_WTO_R1), RI_TO_53); 80410506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_WTO_XA1), RI_TO_53); 80510506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_WTO_XS1), RI_TO_53); 80610506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_RTO_R1), RI_TO_53); 80710506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_RTO_XA1), RI_TO_53); 80810506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_RTO_XS1), RI_TO_53); 80910506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_WTO_R2), RI_TO_53); 81010506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_WTO_XA2), RI_TO_53); 81110506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_WTO_XS2), RI_TO_53); 81210506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_RTO_R2), RI_TO_53); 81310506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_RTO_XA2), RI_TO_53); 81410506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, SELECT_RAM_BUFFER(i, B3_RI_RTO_XS2), RI_TO_53); 81510506SBarry.Harding@Sun.COM } 81610506SBarry.Harding@Sun.COM 81710506SBarry.Harding@Sun.COM /* Disable all interrupts. */ 81810506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_HWE_IMSK, 0); 81910506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B0_HWE_IMSK); 82010506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_IMSK, 0); 82110506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B0_IMSK); 82210506SBarry.Harding@Sun.COM 82310506SBarry.Harding@Sun.COM /* 82410506SBarry.Harding@Sun.COM * On dual port PCI-X card, there is an problem where status 82510506SBarry.Harding@Sun.COM * can be received out of order due to split transactions. 82610506SBarry.Harding@Sun.COM */ 82710506SBarry.Harding@Sun.COM if (dev->d_bustype == PCIX_BUS && dev->d_num_port > 1) { 82810506SBarry.Harding@Sun.COM int pcix; 82910506SBarry.Harding@Sun.COM uint16_t pcix_cmd; 83010506SBarry.Harding@Sun.COM 83110506SBarry.Harding@Sun.COM if ((pcix = yge_find_capability(dev, PCI_CAP_ID_PCIX)) != 0) { 83210506SBarry.Harding@Sun.COM pcix_cmd = pci_config_get16(pcih, pcix + 2); 83310506SBarry.Harding@Sun.COM /* Clear Max Outstanding Split Transactions. */ 83410506SBarry.Harding@Sun.COM pcix_cmd &= ~0x70; 83510506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_ON); 83610506SBarry.Harding@Sun.COM pci_config_put16(pcih, pcix + 2, pcix_cmd); 83710506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 83810506SBarry.Harding@Sun.COM } 83910506SBarry.Harding@Sun.COM } 84010506SBarry.Harding@Sun.COM if (dev->d_bustype == PEX_BUS) { 84110506SBarry.Harding@Sun.COM uint16_t v, width; 84210506SBarry.Harding@Sun.COM 84310506SBarry.Harding@Sun.COM v = pci_config_get16(pcih, PEX_DEV_CTRL); 84410506SBarry.Harding@Sun.COM /* Change Max. Read Request Size to 4096 bytes. */ 84510506SBarry.Harding@Sun.COM v &= ~PEX_DC_MAX_RRS_MSK; 84610506SBarry.Harding@Sun.COM v |= PEX_DC_MAX_RD_RQ_SIZE(5); 84710506SBarry.Harding@Sun.COM pci_config_put16(pcih, PEX_DEV_CTRL, v); 84810506SBarry.Harding@Sun.COM width = pci_config_get16(pcih, PEX_LNK_STAT); 84910506SBarry.Harding@Sun.COM width = (width & PEX_LS_LINK_WI_MSK) >> 4; 85010506SBarry.Harding@Sun.COM v = pci_config_get16(pcih, PEX_LNK_CAP); 85110506SBarry.Harding@Sun.COM v = (v & PEX_LS_LINK_WI_MSK) >> 4; 85210506SBarry.Harding@Sun.COM if (v != width) 85310506SBarry.Harding@Sun.COM yge_error(dev, NULL, 85410506SBarry.Harding@Sun.COM "Negotiated width of PCIe link(x%d) != " 85510506SBarry.Harding@Sun.COM "max. width of link(x%d)\n", width, v); 85610506SBarry.Harding@Sun.COM } 85710506SBarry.Harding@Sun.COM 85810506SBarry.Harding@Sun.COM /* Clear status list. */ 85910506SBarry.Harding@Sun.COM CLEARRING(&dev->d_status_ring); 86010506SBarry.Harding@Sun.COM SYNCRING(&dev->d_status_ring, DDI_DMA_SYNC_FORDEV); 86110506SBarry.Harding@Sun.COM 86210506SBarry.Harding@Sun.COM dev->d_stat_cons = 0; 86310506SBarry.Harding@Sun.COM 86410506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, STAT_CTRL, SC_STAT_RST_SET); 86510506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, STAT_CTRL, SC_STAT_RST_CLR); 86610506SBarry.Harding@Sun.COM 86710506SBarry.Harding@Sun.COM /* Set the status list base address. */ 86810506SBarry.Harding@Sun.COM addr = dev->d_status_ring.r_paddr; 86910506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, STAT_LIST_ADDR_LO, YGE_ADDR_LO(addr)); 87010506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, STAT_LIST_ADDR_HI, YGE_ADDR_HI(addr)); 87110506SBarry.Harding@Sun.COM 87210506SBarry.Harding@Sun.COM /* Set the status list last index. */ 87310506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, STAT_LAST_IDX, YGE_STAT_RING_CNT - 1); 87410506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, STAT_PUT_IDX, 0); 87510506SBarry.Harding@Sun.COM 87610506SBarry.Harding@Sun.COM if (dev->d_hw_id == CHIP_ID_YUKON_EC && 87710506SBarry.Harding@Sun.COM dev->d_hw_rev == CHIP_REV_YU_EC_A1) { 87810506SBarry.Harding@Sun.COM /* WA for dev. #4.3 */ 87910506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, STAT_TX_IDX_TH, ST_TXTH_IDX_MASK); 88010506SBarry.Harding@Sun.COM /* WA for dev #4.18 */ 88110506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, STAT_FIFO_WM, 0x21); 88210506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, STAT_FIFO_ISR_WM, 7); 88310506SBarry.Harding@Sun.COM } else { 88410506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, STAT_TX_IDX_TH, 10); 88510506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, STAT_FIFO_WM, 16); 88610506SBarry.Harding@Sun.COM 88710506SBarry.Harding@Sun.COM /* ISR status FIFO watermark */ 88810506SBarry.Harding@Sun.COM if (dev->d_hw_id == CHIP_ID_YUKON_XL && 88910506SBarry.Harding@Sun.COM dev->d_hw_rev == CHIP_REV_YU_XL_A0) 89010506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, STAT_FIFO_ISR_WM, 4); 89110506SBarry.Harding@Sun.COM else 89210506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, STAT_FIFO_ISR_WM, 16); 89310506SBarry.Harding@Sun.COM 89410506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, STAT_ISR_TIMER_INI, 0x0190); 89510506SBarry.Harding@Sun.COM } 89610506SBarry.Harding@Sun.COM 89710506SBarry.Harding@Sun.COM /* 89810506SBarry.Harding@Sun.COM * Use default value for STAT_ISR_TIMER_INI, STAT_LEV_TIMER_INI. 89910506SBarry.Harding@Sun.COM */ 90010506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, STAT_TX_TIMER_INI, YGE_USECS(dev, 1000)); 90110506SBarry.Harding@Sun.COM 90210506SBarry.Harding@Sun.COM /* Enable status unit. */ 90310506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, STAT_CTRL, SC_STAT_OP_ON); 90410506SBarry.Harding@Sun.COM 90510506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, STAT_TX_TIMER_CTRL, TIM_START); 90610506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, STAT_LEV_TIMER_CTRL, TIM_START); 90710506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, STAT_ISR_TIMER_CTRL, TIM_START); 90810506SBarry.Harding@Sun.COM } 90910506SBarry.Harding@Sun.COM 91010506SBarry.Harding@Sun.COM static int 91110506SBarry.Harding@Sun.COM yge_init_port(yge_port_t *port) 91210506SBarry.Harding@Sun.COM { 91310506SBarry.Harding@Sun.COM yge_dev_t *dev = port->p_dev; 91410506SBarry.Harding@Sun.COM int i; 91510506SBarry.Harding@Sun.COM mac_register_t *macp; 91610506SBarry.Harding@Sun.COM 91710506SBarry.Harding@Sun.COM port->p_flags = dev->d_pflags; 91810506SBarry.Harding@Sun.COM port->p_ppa = ddi_get_instance(dev->d_dip) + (port->p_port * 100); 91910506SBarry.Harding@Sun.COM 92010506SBarry.Harding@Sun.COM port->p_tx_buf = kmem_zalloc(sizeof (yge_buf_t) * YGE_TX_RING_CNT, 92110506SBarry.Harding@Sun.COM KM_SLEEP); 92210506SBarry.Harding@Sun.COM port->p_rx_buf = kmem_zalloc(sizeof (yge_buf_t) * YGE_RX_RING_CNT, 92310506SBarry.Harding@Sun.COM KM_SLEEP); 92410506SBarry.Harding@Sun.COM 92510506SBarry.Harding@Sun.COM /* Setup Tx/Rx queue register offsets. */ 92610506SBarry.Harding@Sun.COM if (port->p_port == YGE_PORT_A) { 92710506SBarry.Harding@Sun.COM port->p_txq = Q_XA1; 92810506SBarry.Harding@Sun.COM port->p_txsq = Q_XS1; 92910506SBarry.Harding@Sun.COM port->p_rxq = Q_R1; 93010506SBarry.Harding@Sun.COM } else { 93110506SBarry.Harding@Sun.COM port->p_txq = Q_XA2; 93210506SBarry.Harding@Sun.COM port->p_txsq = Q_XS2; 93310506SBarry.Harding@Sun.COM port->p_rxq = Q_R2; 93410506SBarry.Harding@Sun.COM } 93510506SBarry.Harding@Sun.COM 93610506SBarry.Harding@Sun.COM /* Disable jumbo frame for Yukon FE. */ 93710506SBarry.Harding@Sun.COM if (dev->d_hw_id == CHIP_ID_YUKON_FE) 93810506SBarry.Harding@Sun.COM port->p_flags |= PORT_FLAG_NOJUMBO; 93910506SBarry.Harding@Sun.COM 94010506SBarry.Harding@Sun.COM /* 94110506SBarry.Harding@Sun.COM * Start out assuming a regular MTU. Users can change this 94210506SBarry.Harding@Sun.COM * with dladm. The dladm daemon is supposed to issue commands 94310506SBarry.Harding@Sun.COM * to change the default MTU using m_setprop during early boot 94410506SBarry.Harding@Sun.COM * (before the interface is plumbed) if the user has so 94510506SBarry.Harding@Sun.COM * requested. 94610506SBarry.Harding@Sun.COM */ 94710506SBarry.Harding@Sun.COM port->p_mtu = ETHERMTU; 94810506SBarry.Harding@Sun.COM 94910506SBarry.Harding@Sun.COM port->p_mii = mii_alloc(port, dev->d_dip, &yge_mii_ops); 95010506SBarry.Harding@Sun.COM if (port->p_mii == NULL) { 95110506SBarry.Harding@Sun.COM yge_error(NULL, port, "MII handle allocation failed"); 95210506SBarry.Harding@Sun.COM return (DDI_FAILURE); 95310506SBarry.Harding@Sun.COM } 95410506SBarry.Harding@Sun.COM /* We assume all parts support asymmetric pause */ 95510506SBarry.Harding@Sun.COM mii_set_pauseable(port->p_mii, B_TRUE, B_TRUE); 95610506SBarry.Harding@Sun.COM 95710506SBarry.Harding@Sun.COM /* 95810506SBarry.Harding@Sun.COM * Get station address for this interface. Note that 95910506SBarry.Harding@Sun.COM * dual port cards actually come with three station 96010506SBarry.Harding@Sun.COM * addresses: one for each port, plus an extra. The 96110506SBarry.Harding@Sun.COM * extra one is used by the SysKonnect driver software 96210506SBarry.Harding@Sun.COM * as a 'virtual' station address for when both ports 96310506SBarry.Harding@Sun.COM * are operating in failover mode. Currently we don't 96410506SBarry.Harding@Sun.COM * use this extra address. 96510506SBarry.Harding@Sun.COM */ 96610506SBarry.Harding@Sun.COM for (i = 0; i < ETHERADDRL; i++) { 96710506SBarry.Harding@Sun.COM port->p_curraddr[i] = 96810506SBarry.Harding@Sun.COM CSR_READ_1(dev, B2_MAC_1 + (port->p_port * 8) + i); 96910506SBarry.Harding@Sun.COM } 97010506SBarry.Harding@Sun.COM 97110506SBarry.Harding@Sun.COM /* Register with Nemo. */ 97210506SBarry.Harding@Sun.COM if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 97310506SBarry.Harding@Sun.COM yge_error(NULL, port, "MAC handle allocation failed"); 97410506SBarry.Harding@Sun.COM return (DDI_FAILURE); 97510506SBarry.Harding@Sun.COM } 97610506SBarry.Harding@Sun.COM macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 97710506SBarry.Harding@Sun.COM macp->m_driver = port; 97810506SBarry.Harding@Sun.COM macp->m_dip = dev->d_dip; 97910506SBarry.Harding@Sun.COM macp->m_src_addr = port->p_curraddr; 98010506SBarry.Harding@Sun.COM macp->m_callbacks = &yge_m_callbacks; 98110506SBarry.Harding@Sun.COM macp->m_min_sdu = 0; 98210506SBarry.Harding@Sun.COM macp->m_max_sdu = port->p_mtu; 98310506SBarry.Harding@Sun.COM macp->m_instance = port->p_ppa; 98410506SBarry.Harding@Sun.COM macp->m_margin = VLAN_TAGSZ; 98510506SBarry.Harding@Sun.COM 98610506SBarry.Harding@Sun.COM port->p_mreg = macp; 98710506SBarry.Harding@Sun.COM 98810506SBarry.Harding@Sun.COM return (DDI_SUCCESS); 98910506SBarry.Harding@Sun.COM } 99010506SBarry.Harding@Sun.COM 99110506SBarry.Harding@Sun.COM static int 99210506SBarry.Harding@Sun.COM yge_add_intr(yge_dev_t *dev, int intr_type) 99310506SBarry.Harding@Sun.COM { 99410506SBarry.Harding@Sun.COM dev_info_t *dip; 99510506SBarry.Harding@Sun.COM int count; 99610506SBarry.Harding@Sun.COM int actual; 99710506SBarry.Harding@Sun.COM int rv; 99810506SBarry.Harding@Sun.COM int i, j; 99910506SBarry.Harding@Sun.COM 100010506SBarry.Harding@Sun.COM dip = dev->d_dip; 100110506SBarry.Harding@Sun.COM 100210506SBarry.Harding@Sun.COM rv = ddi_intr_get_nintrs(dip, intr_type, &count); 100310506SBarry.Harding@Sun.COM if ((rv != DDI_SUCCESS) || (count == 0)) { 100410506SBarry.Harding@Sun.COM yge_error(dev, NULL, 100510506SBarry.Harding@Sun.COM "ddi_intr_get_nintrs failed, rv %d, count %d", rv, count); 100610506SBarry.Harding@Sun.COM return (DDI_FAILURE); 100710506SBarry.Harding@Sun.COM } 100810506SBarry.Harding@Sun.COM 100910506SBarry.Harding@Sun.COM /* 101010506SBarry.Harding@Sun.COM * Allocate the interrupt. Note that we only bother with a single 101110506SBarry.Harding@Sun.COM * interrupt. One could argue that for MSI devices with dual ports, 101210506SBarry.Harding@Sun.COM * it would be nice to have a separate interrupt per port. But right 101310506SBarry.Harding@Sun.COM * now I don't know how to configure that, so we'll just settle for 101410506SBarry.Harding@Sun.COM * a single interrupt. 101510506SBarry.Harding@Sun.COM */ 101610506SBarry.Harding@Sun.COM dev->d_intrcnt = 1; 101710506SBarry.Harding@Sun.COM 101810506SBarry.Harding@Sun.COM dev->d_intrsize = count * sizeof (ddi_intr_handle_t); 101910506SBarry.Harding@Sun.COM dev->d_intrh = kmem_zalloc(dev->d_intrsize, KM_SLEEP); 102010506SBarry.Harding@Sun.COM if (dev->d_intrh == NULL) { 102110506SBarry.Harding@Sun.COM yge_error(dev, NULL, "Unable to allocate interrupt handle"); 102210506SBarry.Harding@Sun.COM return (DDI_FAILURE); 102310506SBarry.Harding@Sun.COM } 102410506SBarry.Harding@Sun.COM 102510506SBarry.Harding@Sun.COM rv = ddi_intr_alloc(dip, dev->d_intrh, intr_type, 0, dev->d_intrcnt, 102610506SBarry.Harding@Sun.COM &actual, DDI_INTR_ALLOC_STRICT); 102710506SBarry.Harding@Sun.COM if ((rv != DDI_SUCCESS) || (actual == 0)) { 102810506SBarry.Harding@Sun.COM yge_error(dev, NULL, 102910506SBarry.Harding@Sun.COM "Unable to allocate interrupt, %d, count %d", 103010506SBarry.Harding@Sun.COM rv, actual); 103110506SBarry.Harding@Sun.COM kmem_free(dev->d_intrh, dev->d_intrsize); 103210506SBarry.Harding@Sun.COM return (DDI_FAILURE); 103310506SBarry.Harding@Sun.COM } 103410506SBarry.Harding@Sun.COM 103510506SBarry.Harding@Sun.COM if ((rv = ddi_intr_get_pri(dev->d_intrh[0], &dev->d_intrpri)) != 103610506SBarry.Harding@Sun.COM DDI_SUCCESS) { 103710506SBarry.Harding@Sun.COM for (i = 0; i < dev->d_intrcnt; i++) 103810506SBarry.Harding@Sun.COM (void) ddi_intr_free(dev->d_intrh[i]); 103910506SBarry.Harding@Sun.COM yge_error(dev, NULL, 104010506SBarry.Harding@Sun.COM "Unable to get interrupt priority, %d", rv); 104110506SBarry.Harding@Sun.COM kmem_free(dev->d_intrh, dev->d_intrsize); 104210506SBarry.Harding@Sun.COM return (DDI_FAILURE); 104310506SBarry.Harding@Sun.COM } 104410506SBarry.Harding@Sun.COM 104510506SBarry.Harding@Sun.COM if ((rv = ddi_intr_get_cap(dev->d_intrh[0], &dev->d_intrcap)) != 104610506SBarry.Harding@Sun.COM DDI_SUCCESS) { 104710506SBarry.Harding@Sun.COM yge_error(dev, NULL, 104810506SBarry.Harding@Sun.COM "Unable to get interrupt capabilities, %d", rv); 104910506SBarry.Harding@Sun.COM for (i = 0; i < dev->d_intrcnt; i++) 105010506SBarry.Harding@Sun.COM (void) ddi_intr_free(dev->d_intrh[i]); 105110506SBarry.Harding@Sun.COM kmem_free(dev->d_intrh, dev->d_intrsize); 105210506SBarry.Harding@Sun.COM return (DDI_FAILURE); 105310506SBarry.Harding@Sun.COM } 105410506SBarry.Harding@Sun.COM 105510506SBarry.Harding@Sun.COM /* register interrupt handler to kernel */ 105610506SBarry.Harding@Sun.COM for (i = 0; i < dev->d_intrcnt; i++) { 105710506SBarry.Harding@Sun.COM if ((rv = ddi_intr_add_handler(dev->d_intrh[i], yge_intr, 105810506SBarry.Harding@Sun.COM dev, NULL)) != DDI_SUCCESS) { 105910506SBarry.Harding@Sun.COM yge_error(dev, NULL, 106010506SBarry.Harding@Sun.COM "Unable to add interrupt handler, %d", rv); 106110506SBarry.Harding@Sun.COM for (j = 0; j < i; j++) 106210506SBarry.Harding@Sun.COM (void) ddi_intr_remove_handler(dev->d_intrh[j]); 106310506SBarry.Harding@Sun.COM for (i = 0; i < dev->d_intrcnt; i++) 106410506SBarry.Harding@Sun.COM (void) ddi_intr_free(dev->d_intrh[i]); 106510506SBarry.Harding@Sun.COM kmem_free(dev->d_intrh, dev->d_intrsize); 106610506SBarry.Harding@Sun.COM return (DDI_FAILURE); 106710506SBarry.Harding@Sun.COM } 106810506SBarry.Harding@Sun.COM } 106910506SBarry.Harding@Sun.COM 107010506SBarry.Harding@Sun.COM mutex_init(&dev->d_rxlock, NULL, MUTEX_DRIVER, 107110506SBarry.Harding@Sun.COM DDI_INTR_PRI(dev->d_intrpri)); 107210506SBarry.Harding@Sun.COM mutex_init(&dev->d_txlock, NULL, MUTEX_DRIVER, 107310506SBarry.Harding@Sun.COM DDI_INTR_PRI(dev->d_intrpri)); 107410506SBarry.Harding@Sun.COM mutex_init(&dev->d_phylock, NULL, MUTEX_DRIVER, 107510506SBarry.Harding@Sun.COM DDI_INTR_PRI(dev->d_intrpri)); 107610506SBarry.Harding@Sun.COM mutex_init(&dev->d_task_mtx, NULL, MUTEX_DRIVER, 107710506SBarry.Harding@Sun.COM DDI_INTR_PRI(dev->d_intrpri)); 107810506SBarry.Harding@Sun.COM 107910506SBarry.Harding@Sun.COM return (DDI_SUCCESS); 108010506SBarry.Harding@Sun.COM } 108110506SBarry.Harding@Sun.COM 108210506SBarry.Harding@Sun.COM static int 108310506SBarry.Harding@Sun.COM yge_attach_intr(yge_dev_t *dev) 108410506SBarry.Harding@Sun.COM { 108510506SBarry.Harding@Sun.COM dev_info_t *dip = dev->d_dip; 108610506SBarry.Harding@Sun.COM int intr_types; 108710506SBarry.Harding@Sun.COM int rv; 108810506SBarry.Harding@Sun.COM 108910506SBarry.Harding@Sun.COM /* Allocate IRQ resources. */ 109010506SBarry.Harding@Sun.COM rv = ddi_intr_get_supported_types(dip, &intr_types); 109110506SBarry.Harding@Sun.COM if (rv != DDI_SUCCESS) { 109210506SBarry.Harding@Sun.COM yge_error(dev, NULL, 109310506SBarry.Harding@Sun.COM "Unable to determine supported interrupt types, %d", rv); 109410506SBarry.Harding@Sun.COM return (DDI_FAILURE); 109510506SBarry.Harding@Sun.COM } 109610506SBarry.Harding@Sun.COM 109710506SBarry.Harding@Sun.COM /* 109810506SBarry.Harding@Sun.COM * We default to not supporting MSI. We've found some device 109910506SBarry.Harding@Sun.COM * and motherboard combinations don't always work well with 110010506SBarry.Harding@Sun.COM * MSI interrupts. Users may override this if they choose. 110110506SBarry.Harding@Sun.COM */ 110210506SBarry.Harding@Sun.COM if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "msi_enable", 0) == 0) { 110310506SBarry.Harding@Sun.COM /* If msi disable property present, disable both msix/msi. */ 110410506SBarry.Harding@Sun.COM if (intr_types & DDI_INTR_TYPE_FIXED) { 110510506SBarry.Harding@Sun.COM intr_types &= ~(DDI_INTR_TYPE_MSI | DDI_INTR_TYPE_MSIX); 110610506SBarry.Harding@Sun.COM } 110710506SBarry.Harding@Sun.COM } 110810506SBarry.Harding@Sun.COM 110910506SBarry.Harding@Sun.COM if (intr_types & DDI_INTR_TYPE_MSIX) { 111010506SBarry.Harding@Sun.COM if ((rv = yge_add_intr(dev, DDI_INTR_TYPE_MSIX)) == 111110506SBarry.Harding@Sun.COM DDI_SUCCESS) 111210506SBarry.Harding@Sun.COM return (DDI_SUCCESS); 111310506SBarry.Harding@Sun.COM } 111410506SBarry.Harding@Sun.COM 111510506SBarry.Harding@Sun.COM if (intr_types & DDI_INTR_TYPE_MSI) { 111610506SBarry.Harding@Sun.COM if ((rv = yge_add_intr(dev, DDI_INTR_TYPE_MSI)) == 111710506SBarry.Harding@Sun.COM DDI_SUCCESS) 111810506SBarry.Harding@Sun.COM return (DDI_SUCCESS); 111910506SBarry.Harding@Sun.COM } 112010506SBarry.Harding@Sun.COM 112110506SBarry.Harding@Sun.COM if (intr_types & DDI_INTR_TYPE_FIXED) { 112210506SBarry.Harding@Sun.COM if ((rv = yge_add_intr(dev, DDI_INTR_TYPE_FIXED)) == 112310506SBarry.Harding@Sun.COM DDI_SUCCESS) 112410506SBarry.Harding@Sun.COM return (DDI_SUCCESS); 112510506SBarry.Harding@Sun.COM } 112610506SBarry.Harding@Sun.COM 112710506SBarry.Harding@Sun.COM yge_error(dev, NULL, "Unable to configure any interrupts"); 112810506SBarry.Harding@Sun.COM return (DDI_FAILURE); 112910506SBarry.Harding@Sun.COM } 113010506SBarry.Harding@Sun.COM 113110506SBarry.Harding@Sun.COM static void 113210506SBarry.Harding@Sun.COM yge_intr_enable(yge_dev_t *dev) 113310506SBarry.Harding@Sun.COM { 113410506SBarry.Harding@Sun.COM int i; 113510506SBarry.Harding@Sun.COM if (dev->d_intrcap & DDI_INTR_FLAG_BLOCK) { 113610506SBarry.Harding@Sun.COM /* Call ddi_intr_block_enable() for MSI interrupts */ 113710506SBarry.Harding@Sun.COM (void) ddi_intr_block_enable(dev->d_intrh, dev->d_intrcnt); 113810506SBarry.Harding@Sun.COM } else { 113910506SBarry.Harding@Sun.COM /* Call ddi_intr_enable for FIXED interrupts */ 114010506SBarry.Harding@Sun.COM for (i = 0; i < dev->d_intrcnt; i++) 114110506SBarry.Harding@Sun.COM (void) ddi_intr_enable(dev->d_intrh[i]); 114210506SBarry.Harding@Sun.COM } 114310506SBarry.Harding@Sun.COM } 114410506SBarry.Harding@Sun.COM 114510506SBarry.Harding@Sun.COM void 114610506SBarry.Harding@Sun.COM yge_intr_disable(yge_dev_t *dev) 114710506SBarry.Harding@Sun.COM { 114810506SBarry.Harding@Sun.COM int i; 114910506SBarry.Harding@Sun.COM 115010506SBarry.Harding@Sun.COM if (dev->d_intrcap & DDI_INTR_FLAG_BLOCK) { 115110506SBarry.Harding@Sun.COM (void) ddi_intr_block_disable(dev->d_intrh, dev->d_intrcnt); 115210506SBarry.Harding@Sun.COM } else { 115310506SBarry.Harding@Sun.COM for (i = 0; i < dev->d_intrcnt; i++) 115410506SBarry.Harding@Sun.COM (void) ddi_intr_disable(dev->d_intrh[i]); 115510506SBarry.Harding@Sun.COM } 115610506SBarry.Harding@Sun.COM } 115710506SBarry.Harding@Sun.COM 115810506SBarry.Harding@Sun.COM static uint8_t 115910506SBarry.Harding@Sun.COM yge_find_capability(yge_dev_t *dev, uint8_t cap) 116010506SBarry.Harding@Sun.COM { 116110506SBarry.Harding@Sun.COM uint8_t ptr; 116210506SBarry.Harding@Sun.COM uint16_t capit; 116310506SBarry.Harding@Sun.COM ddi_acc_handle_t pcih = dev->d_pcih; 116410506SBarry.Harding@Sun.COM 116510506SBarry.Harding@Sun.COM if ((pci_config_get16(pcih, PCI_CONF_STAT) & PCI_STAT_CAP) == 0) { 116610506SBarry.Harding@Sun.COM return (0); 116710506SBarry.Harding@Sun.COM } 116810506SBarry.Harding@Sun.COM /* This assumes PCI, and not CardBus. */ 116910506SBarry.Harding@Sun.COM ptr = pci_config_get8(pcih, PCI_CONF_CAP_PTR); 117010506SBarry.Harding@Sun.COM while (ptr != 0) { 117110506SBarry.Harding@Sun.COM capit = pci_config_get8(pcih, ptr + PCI_CAP_ID); 117210506SBarry.Harding@Sun.COM if (capit == cap) { 117310506SBarry.Harding@Sun.COM return (ptr); 117410506SBarry.Harding@Sun.COM } 117510506SBarry.Harding@Sun.COM ptr = pci_config_get8(pcih, ptr + PCI_CAP_NEXT_PTR); 117610506SBarry.Harding@Sun.COM } 117710506SBarry.Harding@Sun.COM return (0); 117810506SBarry.Harding@Sun.COM } 117910506SBarry.Harding@Sun.COM 118010506SBarry.Harding@Sun.COM static int 118110506SBarry.Harding@Sun.COM yge_attach(yge_dev_t *dev) 118210506SBarry.Harding@Sun.COM { 118310506SBarry.Harding@Sun.COM dev_info_t *dip = dev->d_dip; 118410506SBarry.Harding@Sun.COM int rv; 118510506SBarry.Harding@Sun.COM int nattached; 118610506SBarry.Harding@Sun.COM uint8_t pm_cap; 118710506SBarry.Harding@Sun.COM 118810506SBarry.Harding@Sun.COM if (pci_config_setup(dip, &dev->d_pcih) != DDI_SUCCESS) { 118910506SBarry.Harding@Sun.COM yge_error(dev, NULL, "Unable to map PCI configuration space"); 119010506SBarry.Harding@Sun.COM goto fail; 119110506SBarry.Harding@Sun.COM } 119210506SBarry.Harding@Sun.COM 119310506SBarry.Harding@Sun.COM /* 119410506SBarry.Harding@Sun.COM * Map control/status registers. 119510506SBarry.Harding@Sun.COM */ 119610506SBarry.Harding@Sun.COM 119710506SBarry.Harding@Sun.COM /* ensure the pmcsr status is D0 state */ 119810506SBarry.Harding@Sun.COM pm_cap = yge_find_capability(dev, PCI_CAP_ID_PM); 119910506SBarry.Harding@Sun.COM if (pm_cap != 0) { 120010506SBarry.Harding@Sun.COM uint16_t pmcsr; 120110506SBarry.Harding@Sun.COM pmcsr = pci_config_get16(dev->d_pcih, pm_cap + PCI_PMCSR); 120210506SBarry.Harding@Sun.COM pmcsr &= ~PCI_PMCSR_STATE_MASK; 120310506SBarry.Harding@Sun.COM pci_config_put16(dev->d_pcih, pm_cap + PCI_PMCSR, 120410506SBarry.Harding@Sun.COM pmcsr | PCI_PMCSR_D0); 120510506SBarry.Harding@Sun.COM } 120610506SBarry.Harding@Sun.COM 120710506SBarry.Harding@Sun.COM /* Enable PCI access and bus master. */ 120810506SBarry.Harding@Sun.COM pci_config_put16(dev->d_pcih, PCI_CONF_COMM, 120910506SBarry.Harding@Sun.COM pci_config_get16(dev->d_pcih, PCI_CONF_COMM) | 121010506SBarry.Harding@Sun.COM PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME); 121110506SBarry.Harding@Sun.COM 121210506SBarry.Harding@Sun.COM 121310506SBarry.Harding@Sun.COM /* Allocate I/O resource */ 121410506SBarry.Harding@Sun.COM rv = ddi_regs_map_setup(dip, 1, &dev->d_regs, 0, 0, &yge_regs_attr, 121510506SBarry.Harding@Sun.COM &dev->d_regsh); 121610506SBarry.Harding@Sun.COM if (rv != DDI_SUCCESS) { 121710506SBarry.Harding@Sun.COM yge_error(dev, NULL, "Unable to map device registers"); 121810506SBarry.Harding@Sun.COM goto fail; 121910506SBarry.Harding@Sun.COM } 122010506SBarry.Harding@Sun.COM 122110506SBarry.Harding@Sun.COM 122210506SBarry.Harding@Sun.COM /* Enable all clocks. */ 122310506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_ON); 122410506SBarry.Harding@Sun.COM pci_config_put32(dev->d_pcih, PCI_OUR_REG_3, 0); 122510506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 122610506SBarry.Harding@Sun.COM 122710506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, B0_CTST, CS_RST_CLR); 122810506SBarry.Harding@Sun.COM dev->d_hw_id = CSR_READ_1(dev, B2_CHIP_ID); 122910506SBarry.Harding@Sun.COM dev->d_hw_rev = (CSR_READ_1(dev, B2_MAC_CFG) >> 4) & 0x0f; 123010506SBarry.Harding@Sun.COM 123110506SBarry.Harding@Sun.COM 123210506SBarry.Harding@Sun.COM /* 123310506SBarry.Harding@Sun.COM * Bail out if chip is not recognized. Note that we only enforce 123410506SBarry.Harding@Sun.COM * this in production builds. The Ultra-2 (88e8057) has a problem 123510506SBarry.Harding@Sun.COM * right now where TX works fine, but RX seems not to. So we've 123610506SBarry.Harding@Sun.COM * disabled that for now. 123710506SBarry.Harding@Sun.COM */ 123810506SBarry.Harding@Sun.COM if (dev->d_hw_id < CHIP_ID_YUKON_XL || 123910506SBarry.Harding@Sun.COM dev->d_hw_id >= CHIP_ID_YUKON_UL_2) { 124010506SBarry.Harding@Sun.COM yge_error(dev, NULL, "Unknown device: id=0x%02x, rev=0x%02x", 124110506SBarry.Harding@Sun.COM dev->d_hw_id, dev->d_hw_rev); 124210506SBarry.Harding@Sun.COM #ifndef DEBUG 124310506SBarry.Harding@Sun.COM goto fail; 124410506SBarry.Harding@Sun.COM #endif 124510506SBarry.Harding@Sun.COM } 124610506SBarry.Harding@Sun.COM 124710506SBarry.Harding@Sun.COM /* Soft reset. */ 124810506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, B0_CTST, CS_RST_SET); 124910506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, B0_CTST, CS_RST_CLR); 125010506SBarry.Harding@Sun.COM dev->d_pmd = CSR_READ_1(dev, B2_PMD_TYP); 125110506SBarry.Harding@Sun.COM if (dev->d_pmd == 'L' || dev->d_pmd == 'S' || dev->d_pmd == 'P') 125210506SBarry.Harding@Sun.COM dev->d_coppertype = 0; 125310506SBarry.Harding@Sun.COM else 125410506SBarry.Harding@Sun.COM dev->d_coppertype = 1; 125510506SBarry.Harding@Sun.COM /* Check number of MACs. */ 125610506SBarry.Harding@Sun.COM dev->d_num_port = 1; 125710506SBarry.Harding@Sun.COM if ((CSR_READ_1(dev, B2_Y2_HW_RES) & CFG_DUAL_MAC_MSK) == 125810506SBarry.Harding@Sun.COM CFG_DUAL_MAC_MSK) { 125910506SBarry.Harding@Sun.COM if (!(CSR_READ_1(dev, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC)) 126010506SBarry.Harding@Sun.COM dev->d_num_port++; 126110506SBarry.Harding@Sun.COM } 126210506SBarry.Harding@Sun.COM 126310506SBarry.Harding@Sun.COM /* Check bus type. */ 126410506SBarry.Harding@Sun.COM if (yge_find_capability(dev, PCI_CAP_ID_PCI_E) != 0) { 126510506SBarry.Harding@Sun.COM dev->d_bustype = PEX_BUS; 126610506SBarry.Harding@Sun.COM } else if (yge_find_capability(dev, PCI_CAP_ID_PCIX) != 0) { 126710506SBarry.Harding@Sun.COM dev->d_bustype = PCIX_BUS; 126810506SBarry.Harding@Sun.COM } else { 126910506SBarry.Harding@Sun.COM dev->d_bustype = PCI_BUS; 127010506SBarry.Harding@Sun.COM } 127110506SBarry.Harding@Sun.COM 127210506SBarry.Harding@Sun.COM switch (dev->d_hw_id) { 127310506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_EC: 127410506SBarry.Harding@Sun.COM dev->d_clock = 125; /* 125 Mhz */ 127510506SBarry.Harding@Sun.COM break; 127610506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_UL_2: 127710506SBarry.Harding@Sun.COM dev->d_clock = 125; /* 125 Mhz */ 127810506SBarry.Harding@Sun.COM break; 127910506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_SUPR: 128010506SBarry.Harding@Sun.COM dev->d_clock = 125; /* 125 Mhz */ 128110506SBarry.Harding@Sun.COM break; 128210506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_EC_U: 128310506SBarry.Harding@Sun.COM dev->d_clock = 125; /* 125 Mhz */ 128410506SBarry.Harding@Sun.COM break; 128510506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_EX: 128610506SBarry.Harding@Sun.COM dev->d_clock = 125; /* 125 Mhz */ 128710506SBarry.Harding@Sun.COM break; 128810506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_FE: 128910506SBarry.Harding@Sun.COM dev->d_clock = 100; /* 100 Mhz */ 129010506SBarry.Harding@Sun.COM break; 129110506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_FE_P: 129210506SBarry.Harding@Sun.COM dev->d_clock = 50; /* 50 Mhz */ 129310506SBarry.Harding@Sun.COM break; 129410506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_XL: 129510506SBarry.Harding@Sun.COM dev->d_clock = 156; /* 156 Mhz */ 129610506SBarry.Harding@Sun.COM break; 129710506SBarry.Harding@Sun.COM default: 129810506SBarry.Harding@Sun.COM dev->d_clock = 156; /* 156 Mhz */ 129910506SBarry.Harding@Sun.COM break; 130010506SBarry.Harding@Sun.COM } 130110506SBarry.Harding@Sun.COM 130210506SBarry.Harding@Sun.COM dev->d_process_limit = YGE_RX_RING_CNT/2; 130310506SBarry.Harding@Sun.COM 130410506SBarry.Harding@Sun.COM rv = yge_alloc_ring(NULL, dev, &dev->d_status_ring, YGE_STAT_RING_CNT); 130510506SBarry.Harding@Sun.COM if (rv != DDI_SUCCESS) 130610506SBarry.Harding@Sun.COM goto fail; 130710506SBarry.Harding@Sun.COM 130810506SBarry.Harding@Sun.COM /* Setup event taskq. */ 130910506SBarry.Harding@Sun.COM dev->d_task_q = ddi_taskq_create(dip, "tq", 1, TASKQ_DEFAULTPRI, 0); 131010506SBarry.Harding@Sun.COM if (dev->d_task_q == NULL) { 131110506SBarry.Harding@Sun.COM yge_error(dev, NULL, "failed to create taskq"); 131210506SBarry.Harding@Sun.COM goto fail; 131310506SBarry.Harding@Sun.COM } 131410506SBarry.Harding@Sun.COM 131510506SBarry.Harding@Sun.COM /* Init the condition variable */ 131610506SBarry.Harding@Sun.COM cv_init(&dev->d_task_cv, NULL, CV_DRIVER, NULL); 131710506SBarry.Harding@Sun.COM 131810506SBarry.Harding@Sun.COM /* Allocate IRQ resources. */ 131910506SBarry.Harding@Sun.COM if ((rv = yge_attach_intr(dev)) != DDI_SUCCESS) { 132010506SBarry.Harding@Sun.COM goto fail; 132110506SBarry.Harding@Sun.COM } 132210506SBarry.Harding@Sun.COM 132310506SBarry.Harding@Sun.COM /* Set base interrupt mask. */ 132410506SBarry.Harding@Sun.COM dev->d_intrmask = Y2_IS_HW_ERR | Y2_IS_STAT_BMU; 132510506SBarry.Harding@Sun.COM dev->d_intrhwemask = Y2_IS_TIST_OV | Y2_IS_MST_ERR | 132610506SBarry.Harding@Sun.COM Y2_IS_IRQ_STAT | Y2_IS_PCI_EXP | Y2_IS_PCI_NEXP; 132710506SBarry.Harding@Sun.COM 132810506SBarry.Harding@Sun.COM /* Reset the adapter. */ 132910506SBarry.Harding@Sun.COM yge_reset(dev); 133010506SBarry.Harding@Sun.COM 133110506SBarry.Harding@Sun.COM yge_setup_rambuffer(dev); 133210506SBarry.Harding@Sun.COM 133310506SBarry.Harding@Sun.COM nattached = 0; 133410506SBarry.Harding@Sun.COM for (int i = 0; i < dev->d_num_port; i++) { 133510506SBarry.Harding@Sun.COM yge_port_t *port = dev->d_port[i]; 133610506SBarry.Harding@Sun.COM if (yge_init_port(port) != DDI_SUCCESS) { 133710506SBarry.Harding@Sun.COM goto fail; 133810506SBarry.Harding@Sun.COM } 133910506SBarry.Harding@Sun.COM } 134010506SBarry.Harding@Sun.COM 134110506SBarry.Harding@Sun.COM yge_intr_enable(dev); 134210506SBarry.Harding@Sun.COM 134310506SBarry.Harding@Sun.COM /* set up the periodic to run once per second */ 134410506SBarry.Harding@Sun.COM dev->d_periodic = ddi_periodic_add(yge_tick, dev, 1000000000, 0); 134510506SBarry.Harding@Sun.COM 134610506SBarry.Harding@Sun.COM for (int i = 0; i < dev->d_num_port; i++) { 134710506SBarry.Harding@Sun.COM yge_port_t *port = dev->d_port[i]; 134810506SBarry.Harding@Sun.COM if (yge_register_port(port) == DDI_SUCCESS) { 134910506SBarry.Harding@Sun.COM nattached++; 135010506SBarry.Harding@Sun.COM } 135110506SBarry.Harding@Sun.COM } 135210506SBarry.Harding@Sun.COM 135310506SBarry.Harding@Sun.COM if (nattached == 0) { 135410506SBarry.Harding@Sun.COM goto fail; 135510506SBarry.Harding@Sun.COM } 135610506SBarry.Harding@Sun.COM 135710506SBarry.Harding@Sun.COM /* Dispatch the taskq */ 135810506SBarry.Harding@Sun.COM if (ddi_taskq_dispatch(dev->d_task_q, yge_task, dev, DDI_SLEEP) != 135910506SBarry.Harding@Sun.COM DDI_SUCCESS) { 136010506SBarry.Harding@Sun.COM yge_error(dev, NULL, "failed to start taskq"); 136110506SBarry.Harding@Sun.COM goto fail; 136210506SBarry.Harding@Sun.COM } 136310506SBarry.Harding@Sun.COM 136410506SBarry.Harding@Sun.COM ddi_report_dev(dip); 136510506SBarry.Harding@Sun.COM 136610506SBarry.Harding@Sun.COM return (DDI_SUCCESS); 136710506SBarry.Harding@Sun.COM 136810506SBarry.Harding@Sun.COM fail: 136910506SBarry.Harding@Sun.COM yge_detach(dev); 137010506SBarry.Harding@Sun.COM return (DDI_FAILURE); 137110506SBarry.Harding@Sun.COM } 137210506SBarry.Harding@Sun.COM 137310506SBarry.Harding@Sun.COM static int 137410506SBarry.Harding@Sun.COM yge_register_port(yge_port_t *port) 137510506SBarry.Harding@Sun.COM { 137610506SBarry.Harding@Sun.COM if (mac_register(port->p_mreg, &port->p_mh) != DDI_SUCCESS) { 137710506SBarry.Harding@Sun.COM yge_error(NULL, port, "MAC registration failed"); 137810506SBarry.Harding@Sun.COM return (DDI_FAILURE); 137910506SBarry.Harding@Sun.COM } 138010506SBarry.Harding@Sun.COM 138110506SBarry.Harding@Sun.COM return (DDI_SUCCESS); 138210506SBarry.Harding@Sun.COM } 138310506SBarry.Harding@Sun.COM 138410506SBarry.Harding@Sun.COM static int 138510506SBarry.Harding@Sun.COM yge_unregister_port(yge_port_t *port) 138610506SBarry.Harding@Sun.COM { 138710506SBarry.Harding@Sun.COM if ((port->p_mh) && (mac_unregister(port->p_mh) != 0)) { 138810506SBarry.Harding@Sun.COM return (DDI_FAILURE); 138910506SBarry.Harding@Sun.COM } 139010506SBarry.Harding@Sun.COM port->p_mh = NULL; 139110506SBarry.Harding@Sun.COM return (DDI_SUCCESS); 139210506SBarry.Harding@Sun.COM } 139310506SBarry.Harding@Sun.COM 139410506SBarry.Harding@Sun.COM /* 139510506SBarry.Harding@Sun.COM * Free up port specific resources. This is called only when the 139610506SBarry.Harding@Sun.COM * port is not registered (and hence not running). 139710506SBarry.Harding@Sun.COM */ 139810506SBarry.Harding@Sun.COM static void 139910506SBarry.Harding@Sun.COM yge_uninit_port(yge_port_t *port) 140010506SBarry.Harding@Sun.COM { 140110506SBarry.Harding@Sun.COM ASSERT(!port->p_running); 140210506SBarry.Harding@Sun.COM 140310506SBarry.Harding@Sun.COM if (port->p_mreg) 140410506SBarry.Harding@Sun.COM mac_free(port->p_mreg); 140510506SBarry.Harding@Sun.COM 140610506SBarry.Harding@Sun.COM if (port->p_mii) 140710506SBarry.Harding@Sun.COM mii_free(port->p_mii); 140810506SBarry.Harding@Sun.COM 140910506SBarry.Harding@Sun.COM yge_txrx_dma_free(port); 141010506SBarry.Harding@Sun.COM 141110506SBarry.Harding@Sun.COM if (port->p_tx_buf) 141210506SBarry.Harding@Sun.COM kmem_free(port->p_tx_buf, 141310506SBarry.Harding@Sun.COM sizeof (yge_buf_t) * YGE_TX_RING_CNT); 141410506SBarry.Harding@Sun.COM if (port->p_rx_buf) 141510506SBarry.Harding@Sun.COM kmem_free(port->p_rx_buf, 141610506SBarry.Harding@Sun.COM sizeof (yge_buf_t) * YGE_RX_RING_CNT); 141710506SBarry.Harding@Sun.COM } 141810506SBarry.Harding@Sun.COM 141910506SBarry.Harding@Sun.COM static void 142010506SBarry.Harding@Sun.COM yge_detach(yge_dev_t *dev) 142110506SBarry.Harding@Sun.COM { 142210506SBarry.Harding@Sun.COM /* 142310506SBarry.Harding@Sun.COM * Turn off the periodic. 142410506SBarry.Harding@Sun.COM */ 142510506SBarry.Harding@Sun.COM if (dev->d_periodic) 142610506SBarry.Harding@Sun.COM ddi_periodic_delete(dev->d_periodic); 142710506SBarry.Harding@Sun.COM 142810506SBarry.Harding@Sun.COM for (int i = 0; i < dev->d_num_port; i++) { 142910506SBarry.Harding@Sun.COM yge_uninit_port(dev->d_port[i]); 143010506SBarry.Harding@Sun.COM } 143110506SBarry.Harding@Sun.COM 143210506SBarry.Harding@Sun.COM /* 143310506SBarry.Harding@Sun.COM * Make sure all interrupts are disabled. 143410506SBarry.Harding@Sun.COM */ 143510506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_IMSK, 0); 143610506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B0_IMSK); 143710506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_HWE_IMSK, 0); 143810506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B0_HWE_IMSK); 143910506SBarry.Harding@Sun.COM 144010506SBarry.Harding@Sun.COM /* LED Off. */ 144110506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, B0_CTST, Y2_LED_STAT_OFF); 144210506SBarry.Harding@Sun.COM 144310506SBarry.Harding@Sun.COM /* Put hardware reset. */ 144410506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, B0_CTST, CS_RST_SET); 144510506SBarry.Harding@Sun.COM 144610506SBarry.Harding@Sun.COM yge_free_ring(&dev->d_status_ring); 144710506SBarry.Harding@Sun.COM 144810506SBarry.Harding@Sun.COM if (dev->d_task_q != NULL) { 144910506SBarry.Harding@Sun.COM yge_dispatch(dev, YGE_TASK_EXIT); 145010506SBarry.Harding@Sun.COM ddi_taskq_destroy(dev->d_task_q); 145110506SBarry.Harding@Sun.COM dev->d_task_q = NULL; 145210506SBarry.Harding@Sun.COM } 145310506SBarry.Harding@Sun.COM 145410506SBarry.Harding@Sun.COM cv_destroy(&dev->d_task_cv); 145510506SBarry.Harding@Sun.COM 145610506SBarry.Harding@Sun.COM yge_intr_disable(dev); 145710506SBarry.Harding@Sun.COM 145810506SBarry.Harding@Sun.COM if (dev->d_intrh != NULL) { 145910506SBarry.Harding@Sun.COM for (int i = 0; i < dev->d_intrcnt; i++) { 146010506SBarry.Harding@Sun.COM (void) ddi_intr_remove_handler(dev->d_intrh[i]); 146110506SBarry.Harding@Sun.COM (void) ddi_intr_free(dev->d_intrh[i]); 146210506SBarry.Harding@Sun.COM } 146310506SBarry.Harding@Sun.COM kmem_free(dev->d_intrh, dev->d_intrsize); 146410506SBarry.Harding@Sun.COM mutex_destroy(&dev->d_phylock); 146510506SBarry.Harding@Sun.COM mutex_destroy(&dev->d_txlock); 146610506SBarry.Harding@Sun.COM mutex_destroy(&dev->d_rxlock); 146710506SBarry.Harding@Sun.COM mutex_destroy(&dev->d_task_mtx); 146810506SBarry.Harding@Sun.COM } 146910506SBarry.Harding@Sun.COM if (dev->d_regsh != NULL) 147010506SBarry.Harding@Sun.COM ddi_regs_map_free(&dev->d_regsh); 147110506SBarry.Harding@Sun.COM 147210506SBarry.Harding@Sun.COM if (dev->d_pcih != NULL) 147310506SBarry.Harding@Sun.COM pci_config_teardown(&dev->d_pcih); 147410506SBarry.Harding@Sun.COM } 147510506SBarry.Harding@Sun.COM 147610506SBarry.Harding@Sun.COM static int 147710506SBarry.Harding@Sun.COM yge_alloc_ring(yge_port_t *port, yge_dev_t *dev, yge_ring_t *ring, uint32_t num) 147810506SBarry.Harding@Sun.COM { 147910506SBarry.Harding@Sun.COM dev_info_t *dip; 148010506SBarry.Harding@Sun.COM caddr_t kaddr; 148110506SBarry.Harding@Sun.COM size_t len; 148210506SBarry.Harding@Sun.COM int rv; 148310506SBarry.Harding@Sun.COM ddi_dma_cookie_t dmac; 148410506SBarry.Harding@Sun.COM unsigned ndmac; 148510506SBarry.Harding@Sun.COM 148610506SBarry.Harding@Sun.COM if (port && !dev) 148710506SBarry.Harding@Sun.COM dev = port->p_dev; 148810506SBarry.Harding@Sun.COM dip = dev->d_dip; 148910506SBarry.Harding@Sun.COM 149010506SBarry.Harding@Sun.COM ring->r_num = num; 149110506SBarry.Harding@Sun.COM 149210506SBarry.Harding@Sun.COM rv = ddi_dma_alloc_handle(dip, &yge_ring_dma_attr, DDI_DMA_DONTWAIT, 149310506SBarry.Harding@Sun.COM NULL, &ring->r_dmah); 149410506SBarry.Harding@Sun.COM if (rv != DDI_SUCCESS) { 149510506SBarry.Harding@Sun.COM yge_error(dev, port, "Unable to allocate ring DMA handle"); 149610506SBarry.Harding@Sun.COM return (DDI_FAILURE); 149710506SBarry.Harding@Sun.COM } 149810506SBarry.Harding@Sun.COM 149910506SBarry.Harding@Sun.COM rv = ddi_dma_mem_alloc(ring->r_dmah, num * sizeof (yge_desc_t), 150010506SBarry.Harding@Sun.COM &yge_ring_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, 150110506SBarry.Harding@Sun.COM &kaddr, &len, &ring->r_acch); 150210506SBarry.Harding@Sun.COM if (rv != DDI_SUCCESS) { 150310506SBarry.Harding@Sun.COM yge_error(dev, port, "Unable to allocate ring DMA memory"); 150410506SBarry.Harding@Sun.COM return (DDI_FAILURE); 150510506SBarry.Harding@Sun.COM } 150610506SBarry.Harding@Sun.COM ring->r_size = len; 150710506SBarry.Harding@Sun.COM ring->r_kaddr = (void *)kaddr; 150810506SBarry.Harding@Sun.COM 150910506SBarry.Harding@Sun.COM bzero(kaddr, len); 151010506SBarry.Harding@Sun.COM 151110506SBarry.Harding@Sun.COM rv = ddi_dma_addr_bind_handle(ring->r_dmah, NULL, kaddr, 151210506SBarry.Harding@Sun.COM len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 151310506SBarry.Harding@Sun.COM &dmac, &ndmac); 151410506SBarry.Harding@Sun.COM if (rv != DDI_DMA_MAPPED) { 151510506SBarry.Harding@Sun.COM yge_error(dev, port, "Unable to bind ring DMA handle"); 151610506SBarry.Harding@Sun.COM return (DDI_FAILURE); 151710506SBarry.Harding@Sun.COM } 151810506SBarry.Harding@Sun.COM ASSERT(ndmac == 1); 151910506SBarry.Harding@Sun.COM ring->r_paddr = dmac.dmac_address; 152010506SBarry.Harding@Sun.COM 152110506SBarry.Harding@Sun.COM return (DDI_SUCCESS); 152210506SBarry.Harding@Sun.COM } 152310506SBarry.Harding@Sun.COM 152410506SBarry.Harding@Sun.COM static void 152510506SBarry.Harding@Sun.COM yge_free_ring(yge_ring_t *ring) 152610506SBarry.Harding@Sun.COM { 152710506SBarry.Harding@Sun.COM if (ring->r_paddr) 152810506SBarry.Harding@Sun.COM (void) ddi_dma_unbind_handle(ring->r_dmah); 152910506SBarry.Harding@Sun.COM ring->r_paddr = 0; 153010506SBarry.Harding@Sun.COM if (ring->r_acch) 153110506SBarry.Harding@Sun.COM ddi_dma_mem_free(&ring->r_acch); 153210506SBarry.Harding@Sun.COM ring->r_kaddr = NULL; 153310506SBarry.Harding@Sun.COM ring->r_acch = NULL; 153410506SBarry.Harding@Sun.COM if (ring->r_dmah) 153510506SBarry.Harding@Sun.COM ddi_dma_free_handle(&ring->r_dmah); 153610506SBarry.Harding@Sun.COM ring->r_dmah = NULL; 153710506SBarry.Harding@Sun.COM } 153810506SBarry.Harding@Sun.COM 153910506SBarry.Harding@Sun.COM static int 154010506SBarry.Harding@Sun.COM yge_alloc_buf(yge_port_t *port, yge_buf_t *b, size_t bufsz, int flag) 154110506SBarry.Harding@Sun.COM { 154210506SBarry.Harding@Sun.COM yge_dev_t *dev = port->p_dev; 154310506SBarry.Harding@Sun.COM size_t l; 154410506SBarry.Harding@Sun.COM int sflag; 154510506SBarry.Harding@Sun.COM int rv; 154610506SBarry.Harding@Sun.COM ddi_dma_cookie_t dmac; 154710506SBarry.Harding@Sun.COM unsigned ndmac; 154810506SBarry.Harding@Sun.COM 154910506SBarry.Harding@Sun.COM sflag = flag & (DDI_DMA_STREAMING | DDI_DMA_CONSISTENT); 155010506SBarry.Harding@Sun.COM 155110506SBarry.Harding@Sun.COM /* Now allocate Tx buffers. */ 155210506SBarry.Harding@Sun.COM rv = ddi_dma_alloc_handle(dev->d_dip, &yge_buf_dma_attr, 155310506SBarry.Harding@Sun.COM DDI_DMA_DONTWAIT, NULL, &b->b_dmah); 155410506SBarry.Harding@Sun.COM if (rv != DDI_SUCCESS) { 155510506SBarry.Harding@Sun.COM yge_error(NULL, port, "Unable to alloc DMA handle for buffer"); 155610506SBarry.Harding@Sun.COM return (DDI_FAILURE); 155710506SBarry.Harding@Sun.COM } 155810506SBarry.Harding@Sun.COM 155910506SBarry.Harding@Sun.COM rv = ddi_dma_mem_alloc(b->b_dmah, bufsz, &yge_buf_attr, 156010506SBarry.Harding@Sun.COM sflag, DDI_DMA_DONTWAIT, NULL, &b->b_buf, &l, &b->b_acch); 156110506SBarry.Harding@Sun.COM if (rv != DDI_SUCCESS) { 156210506SBarry.Harding@Sun.COM yge_error(NULL, port, "Unable to alloc DMA memory for buffer"); 156310506SBarry.Harding@Sun.COM return (DDI_FAILURE); 156410506SBarry.Harding@Sun.COM } 156510506SBarry.Harding@Sun.COM 156610506SBarry.Harding@Sun.COM rv = ddi_dma_addr_bind_handle(b->b_dmah, NULL, b->b_buf, l, flag, 156710506SBarry.Harding@Sun.COM DDI_DMA_DONTWAIT, NULL, &dmac, &ndmac); 156810506SBarry.Harding@Sun.COM if (rv != DDI_DMA_MAPPED) { 156910506SBarry.Harding@Sun.COM yge_error(NULL, port, "Unable to bind DMA handle for buffer"); 157010506SBarry.Harding@Sun.COM return (DDI_FAILURE); 157110506SBarry.Harding@Sun.COM } 157210506SBarry.Harding@Sun.COM ASSERT(ndmac == 1); 157310506SBarry.Harding@Sun.COM b->b_paddr = dmac.dmac_address; 157410506SBarry.Harding@Sun.COM return (DDI_SUCCESS); 157510506SBarry.Harding@Sun.COM } 157610506SBarry.Harding@Sun.COM 157710506SBarry.Harding@Sun.COM static void 157810506SBarry.Harding@Sun.COM yge_free_buf(yge_buf_t *b) 157910506SBarry.Harding@Sun.COM { 158010506SBarry.Harding@Sun.COM if (b->b_paddr) 158110506SBarry.Harding@Sun.COM (void) ddi_dma_unbind_handle(b->b_dmah); 158210506SBarry.Harding@Sun.COM b->b_paddr = 0; 158310506SBarry.Harding@Sun.COM if (b->b_acch) 158410506SBarry.Harding@Sun.COM ddi_dma_mem_free(&b->b_acch); 158510506SBarry.Harding@Sun.COM b->b_buf = NULL; 158610506SBarry.Harding@Sun.COM b->b_acch = NULL; 158710506SBarry.Harding@Sun.COM if (b->b_dmah) 158810506SBarry.Harding@Sun.COM ddi_dma_free_handle(&b->b_dmah); 158910506SBarry.Harding@Sun.COM b->b_dmah = NULL; 159010506SBarry.Harding@Sun.COM } 159110506SBarry.Harding@Sun.COM 159210506SBarry.Harding@Sun.COM static int 159310506SBarry.Harding@Sun.COM yge_txrx_dma_alloc(yge_port_t *port) 159410506SBarry.Harding@Sun.COM { 159510506SBarry.Harding@Sun.COM uint32_t bufsz; 159610506SBarry.Harding@Sun.COM int rv; 159710506SBarry.Harding@Sun.COM int i; 159810506SBarry.Harding@Sun.COM yge_buf_t *b; 159910506SBarry.Harding@Sun.COM 160010506SBarry.Harding@Sun.COM /* 160110506SBarry.Harding@Sun.COM * It seems that Yukon II supports full 64 bit DMA operations. 160210506SBarry.Harding@Sun.COM * But we limit it to 32 bits only for now. The 64 bit 160310506SBarry.Harding@Sun.COM * operation would require substantially more complex 160410506SBarry.Harding@Sun.COM * descriptor handling, since in such a case we would need two 160510506SBarry.Harding@Sun.COM * LEs to represent a single physical address. 160610506SBarry.Harding@Sun.COM * 160710506SBarry.Harding@Sun.COM * If we find that this is limiting us, then we should go back 160810506SBarry.Harding@Sun.COM * and re-examine it. 160910506SBarry.Harding@Sun.COM */ 161010506SBarry.Harding@Sun.COM 161110506SBarry.Harding@Sun.COM /* Note our preferred buffer size. */ 161210506SBarry.Harding@Sun.COM bufsz = port->p_mtu; 161310506SBarry.Harding@Sun.COM 161410506SBarry.Harding@Sun.COM /* Allocate Tx ring. */ 161510506SBarry.Harding@Sun.COM rv = yge_alloc_ring(port, NULL, &port->p_tx_ring, YGE_TX_RING_CNT); 161610506SBarry.Harding@Sun.COM if (rv != DDI_SUCCESS) { 161710506SBarry.Harding@Sun.COM return (DDI_FAILURE); 161810506SBarry.Harding@Sun.COM } 161910506SBarry.Harding@Sun.COM 162010506SBarry.Harding@Sun.COM /* Now allocate Tx buffers. */ 162110506SBarry.Harding@Sun.COM b = port->p_tx_buf; 162210506SBarry.Harding@Sun.COM for (i = 0; i < YGE_TX_RING_CNT; i++) { 162310506SBarry.Harding@Sun.COM rv = yge_alloc_buf(port, b, bufsz, 162410506SBarry.Harding@Sun.COM DDI_DMA_STREAMING | DDI_DMA_WRITE); 162510506SBarry.Harding@Sun.COM if (rv != DDI_SUCCESS) { 162610506SBarry.Harding@Sun.COM return (DDI_FAILURE); 162710506SBarry.Harding@Sun.COM } 162810506SBarry.Harding@Sun.COM b++; 162910506SBarry.Harding@Sun.COM } 163010506SBarry.Harding@Sun.COM 163110506SBarry.Harding@Sun.COM /* Allocate Rx ring. */ 163210506SBarry.Harding@Sun.COM rv = yge_alloc_ring(port, NULL, &port->p_rx_ring, YGE_RX_RING_CNT); 163310506SBarry.Harding@Sun.COM if (rv != DDI_SUCCESS) { 163410506SBarry.Harding@Sun.COM return (DDI_FAILURE); 163510506SBarry.Harding@Sun.COM } 163610506SBarry.Harding@Sun.COM 163710506SBarry.Harding@Sun.COM /* Now allocate Rx buffers. */ 163810506SBarry.Harding@Sun.COM b = port->p_rx_buf; 163910506SBarry.Harding@Sun.COM for (i = 0; i < YGE_RX_RING_CNT; i++) { 164010506SBarry.Harding@Sun.COM rv = yge_alloc_buf(port, b, bufsz, 164110506SBarry.Harding@Sun.COM DDI_DMA_STREAMING | DDI_DMA_READ); 164210506SBarry.Harding@Sun.COM if (rv != DDI_SUCCESS) { 164310506SBarry.Harding@Sun.COM return (DDI_FAILURE); 164410506SBarry.Harding@Sun.COM } 164510506SBarry.Harding@Sun.COM b++; 164610506SBarry.Harding@Sun.COM } 164710506SBarry.Harding@Sun.COM 164810506SBarry.Harding@Sun.COM return (DDI_SUCCESS); 164910506SBarry.Harding@Sun.COM } 165010506SBarry.Harding@Sun.COM 165110506SBarry.Harding@Sun.COM static void 165210506SBarry.Harding@Sun.COM yge_txrx_dma_free(yge_port_t *port) 165310506SBarry.Harding@Sun.COM { 165410506SBarry.Harding@Sun.COM yge_buf_t *b; 165510506SBarry.Harding@Sun.COM 165610506SBarry.Harding@Sun.COM /* Tx ring. */ 165710506SBarry.Harding@Sun.COM yge_free_ring(&port->p_tx_ring); 165810506SBarry.Harding@Sun.COM 165910506SBarry.Harding@Sun.COM /* Rx ring. */ 166010506SBarry.Harding@Sun.COM yge_free_ring(&port->p_rx_ring); 166110506SBarry.Harding@Sun.COM 166210506SBarry.Harding@Sun.COM /* Tx buffers. */ 166310506SBarry.Harding@Sun.COM b = port->p_tx_buf; 166410506SBarry.Harding@Sun.COM for (int i = 0; i < YGE_TX_RING_CNT; i++, b++) { 166510506SBarry.Harding@Sun.COM yge_free_buf(b); 166610506SBarry.Harding@Sun.COM } 166710506SBarry.Harding@Sun.COM /* Rx buffers. */ 166810506SBarry.Harding@Sun.COM b = port->p_rx_buf; 166910506SBarry.Harding@Sun.COM for (int i = 0; i < YGE_RX_RING_CNT; i++, b++) { 167010506SBarry.Harding@Sun.COM yge_free_buf(b); 167110506SBarry.Harding@Sun.COM } 167210506SBarry.Harding@Sun.COM } 167310506SBarry.Harding@Sun.COM 167410506SBarry.Harding@Sun.COM boolean_t 167510506SBarry.Harding@Sun.COM yge_send(yge_port_t *port, mblk_t *mp) 167610506SBarry.Harding@Sun.COM { 167710506SBarry.Harding@Sun.COM yge_ring_t *ring = &port->p_tx_ring; 167810506SBarry.Harding@Sun.COM yge_buf_t *txb; 167910506SBarry.Harding@Sun.COM int16_t prod; 168010506SBarry.Harding@Sun.COM size_t len; 168110506SBarry.Harding@Sun.COM 168210506SBarry.Harding@Sun.COM /* 168310506SBarry.Harding@Sun.COM * For now we're not going to support checksum offload or LSO. 168410506SBarry.Harding@Sun.COM */ 168510506SBarry.Harding@Sun.COM 168610506SBarry.Harding@Sun.COM len = msgsize(mp); 168710506SBarry.Harding@Sun.COM if (len > port->p_framesize) { 168810506SBarry.Harding@Sun.COM /* too big! */ 168910506SBarry.Harding@Sun.COM freemsg(mp); 169010506SBarry.Harding@Sun.COM return (B_TRUE); 169110506SBarry.Harding@Sun.COM } 169210506SBarry.Harding@Sun.COM 169310506SBarry.Harding@Sun.COM /* Check number of available descriptors. */ 169410506SBarry.Harding@Sun.COM if (port->p_tx_cnt + 1 >= 169510506SBarry.Harding@Sun.COM (YGE_TX_RING_CNT - YGE_RESERVED_TX_DESC_CNT)) { 169610506SBarry.Harding@Sun.COM port->p_wantw = B_TRUE; 169710506SBarry.Harding@Sun.COM return (B_FALSE); 169810506SBarry.Harding@Sun.COM } 169910506SBarry.Harding@Sun.COM 170010506SBarry.Harding@Sun.COM prod = port->p_tx_prod; 170110506SBarry.Harding@Sun.COM 170210506SBarry.Harding@Sun.COM txb = &port->p_tx_buf[prod]; 170310506SBarry.Harding@Sun.COM mcopymsg(mp, txb->b_buf); 170410506SBarry.Harding@Sun.COM SYNCBUF(txb, DDI_DMA_SYNC_FORDEV); 170510506SBarry.Harding@Sun.COM 170610506SBarry.Harding@Sun.COM PUTADDR(ring, prod, txb->b_paddr); 170710506SBarry.Harding@Sun.COM PUTCTRL(ring, prod, len | OP_PACKET | HW_OWNER | EOP); 170810506SBarry.Harding@Sun.COM SYNCENTRY(ring, prod, DDI_DMA_SYNC_FORDEV); 170910506SBarry.Harding@Sun.COM port->p_tx_cnt++; 171010506SBarry.Harding@Sun.COM 171110506SBarry.Harding@Sun.COM YGE_INC(prod, YGE_TX_RING_CNT); 171210506SBarry.Harding@Sun.COM 171310506SBarry.Harding@Sun.COM /* Update producer index. */ 171410506SBarry.Harding@Sun.COM port->p_tx_prod = prod; 171510506SBarry.Harding@Sun.COM 171610506SBarry.Harding@Sun.COM return (B_TRUE); 171710506SBarry.Harding@Sun.COM } 171810506SBarry.Harding@Sun.COM 171910506SBarry.Harding@Sun.COM static int 172010506SBarry.Harding@Sun.COM yge_suspend(yge_dev_t *dev) 172110506SBarry.Harding@Sun.COM { 172210506SBarry.Harding@Sun.COM for (int i = 0; i < dev->d_num_port; i++) { 172310506SBarry.Harding@Sun.COM yge_port_t *port = dev->d_port[i]; 172410506SBarry.Harding@Sun.COM mii_suspend(port->p_mii); 172510506SBarry.Harding@Sun.COM } 172610506SBarry.Harding@Sun.COM 172710506SBarry.Harding@Sun.COM 172810506SBarry.Harding@Sun.COM DEV_LOCK(dev); 172910506SBarry.Harding@Sun.COM 173010506SBarry.Harding@Sun.COM for (int i = 0; i < dev->d_num_port; i++) { 173110506SBarry.Harding@Sun.COM yge_port_t *port = dev->d_port[i]; 173210506SBarry.Harding@Sun.COM 173310506SBarry.Harding@Sun.COM if (port->p_running) { 173410506SBarry.Harding@Sun.COM yge_stop_port(port); 173510506SBarry.Harding@Sun.COM } 173610506SBarry.Harding@Sun.COM } 173710506SBarry.Harding@Sun.COM 173810506SBarry.Harding@Sun.COM /* Disable all interrupts. */ 173910506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_IMSK, 0); 174010506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B0_IMSK); 174110506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_HWE_IMSK, 0); 174210506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B0_HWE_IMSK); 174310506SBarry.Harding@Sun.COM 174410506SBarry.Harding@Sun.COM yge_phy_power(dev, B_FALSE); 174510506SBarry.Harding@Sun.COM 174610506SBarry.Harding@Sun.COM /* Put hardware reset. */ 174710506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, B0_CTST, CS_RST_SET); 174810506SBarry.Harding@Sun.COM dev->d_suspended = B_TRUE; 174910506SBarry.Harding@Sun.COM 175010506SBarry.Harding@Sun.COM DEV_UNLOCK(dev); 175110506SBarry.Harding@Sun.COM 175210506SBarry.Harding@Sun.COM return (DDI_SUCCESS); 175310506SBarry.Harding@Sun.COM } 175410506SBarry.Harding@Sun.COM 175510506SBarry.Harding@Sun.COM static int 175610506SBarry.Harding@Sun.COM yge_resume(yge_dev_t *dev) 175710506SBarry.Harding@Sun.COM { 175810506SBarry.Harding@Sun.COM uint8_t pm_cap; 175910506SBarry.Harding@Sun.COM 176010506SBarry.Harding@Sun.COM DEV_LOCK(dev); 176110506SBarry.Harding@Sun.COM 176210506SBarry.Harding@Sun.COM /* ensure the pmcsr status is D0 state */ 176310506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_ON); 176410506SBarry.Harding@Sun.COM 176510506SBarry.Harding@Sun.COM if ((pm_cap = yge_find_capability(dev, PCI_CAP_ID_PM)) != 0) { 176610506SBarry.Harding@Sun.COM uint16_t pmcsr; 176710506SBarry.Harding@Sun.COM pmcsr = pci_config_get16(dev->d_pcih, pm_cap + PCI_PMCSR); 176810506SBarry.Harding@Sun.COM pmcsr &= ~PCI_PMCSR_STATE_MASK; 176910506SBarry.Harding@Sun.COM pci_config_put16(dev->d_pcih, pm_cap + PCI_PMCSR, 177010506SBarry.Harding@Sun.COM pmcsr | PCI_PMCSR_D0); 177110506SBarry.Harding@Sun.COM } 177210506SBarry.Harding@Sun.COM 177310506SBarry.Harding@Sun.COM /* Enable PCI access and bus master. */ 177410506SBarry.Harding@Sun.COM pci_config_put16(dev->d_pcih, PCI_CONF_COMM, 177510506SBarry.Harding@Sun.COM pci_config_get16(dev->d_pcih, PCI_CONF_COMM) | 177610506SBarry.Harding@Sun.COM PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME); 177710506SBarry.Harding@Sun.COM 177810506SBarry.Harding@Sun.COM /* Enable all clocks. */ 177910506SBarry.Harding@Sun.COM switch (dev->d_hw_id) { 178010506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_EX: 178110506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_EC_U: 178210506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_FE_P: 178310506SBarry.Harding@Sun.COM pci_config_put32(dev->d_pcih, PCI_OUR_REG_3, 0); 178410506SBarry.Harding@Sun.COM break; 178510506SBarry.Harding@Sun.COM } 178610506SBarry.Harding@Sun.COM 178710506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 178810506SBarry.Harding@Sun.COM 178910506SBarry.Harding@Sun.COM yge_reset(dev); 179010506SBarry.Harding@Sun.COM 179110506SBarry.Harding@Sun.COM /* Make sure interrupts are reenabled */ 179210506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_IMSK, 0); 179310506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_IMSK, Y2_IS_HW_ERR | Y2_IS_STAT_BMU); 179410506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_HWE_IMSK, 179510506SBarry.Harding@Sun.COM Y2_IS_TIST_OV | Y2_IS_MST_ERR | 179610506SBarry.Harding@Sun.COM Y2_IS_IRQ_STAT | Y2_IS_PCI_EXP | Y2_IS_PCI_NEXP); 179710506SBarry.Harding@Sun.COM 179810506SBarry.Harding@Sun.COM for (int i = 0; i < dev->d_num_port; i++) { 179910506SBarry.Harding@Sun.COM yge_port_t *port = dev->d_port[i]; 180010506SBarry.Harding@Sun.COM 180110506SBarry.Harding@Sun.COM if (port != NULL && port->p_running) { 180210506SBarry.Harding@Sun.COM yge_start_port(port); 180310506SBarry.Harding@Sun.COM } 180410506SBarry.Harding@Sun.COM } 180510506SBarry.Harding@Sun.COM dev->d_suspended = B_FALSE; 180610506SBarry.Harding@Sun.COM 180710506SBarry.Harding@Sun.COM DEV_UNLOCK(dev); 180810506SBarry.Harding@Sun.COM 180910506SBarry.Harding@Sun.COM /* Reset MII layer */ 181010506SBarry.Harding@Sun.COM for (int i = 0; i < dev->d_num_port; i++) { 181110506SBarry.Harding@Sun.COM yge_port_t *port = dev->d_port[i]; 181210506SBarry.Harding@Sun.COM 181310506SBarry.Harding@Sun.COM if (port->p_running) { 181410506SBarry.Harding@Sun.COM mii_resume(port->p_mii); 181510506SBarry.Harding@Sun.COM mac_tx_update(port->p_mh); 181610506SBarry.Harding@Sun.COM } 181710506SBarry.Harding@Sun.COM } 181810506SBarry.Harding@Sun.COM 181910506SBarry.Harding@Sun.COM return (DDI_SUCCESS); 182010506SBarry.Harding@Sun.COM } 182110506SBarry.Harding@Sun.COM 182210506SBarry.Harding@Sun.COM static mblk_t * 182310506SBarry.Harding@Sun.COM yge_rxeof(yge_port_t *port, uint32_t status, int len) 182410506SBarry.Harding@Sun.COM { 182510506SBarry.Harding@Sun.COM yge_dev_t *dev = port->p_dev; 182610506SBarry.Harding@Sun.COM mblk_t *mp; 182710506SBarry.Harding@Sun.COM int cons, rxlen; 182810506SBarry.Harding@Sun.COM yge_buf_t *rxb; 182910506SBarry.Harding@Sun.COM yge_ring_t *ring; 183010506SBarry.Harding@Sun.COM 183110506SBarry.Harding@Sun.COM ASSERT(mutex_owned(&dev->d_rxlock)); 183210506SBarry.Harding@Sun.COM 183310506SBarry.Harding@Sun.COM if (!port->p_running) 183410506SBarry.Harding@Sun.COM return (NULL); 183510506SBarry.Harding@Sun.COM 183610506SBarry.Harding@Sun.COM ring = &port->p_rx_ring; 183710506SBarry.Harding@Sun.COM cons = port->p_rx_cons; 183810506SBarry.Harding@Sun.COM rxlen = status >> 16; 183910506SBarry.Harding@Sun.COM rxb = &port->p_rx_buf[cons]; 184010506SBarry.Harding@Sun.COM mp = NULL; 184110506SBarry.Harding@Sun.COM 184210506SBarry.Harding@Sun.COM 184310506SBarry.Harding@Sun.COM if ((dev->d_hw_id == CHIP_ID_YUKON_FE_P) && 184410506SBarry.Harding@Sun.COM (dev->d_hw_rev == CHIP_REV_YU_FE2_A0)) { 184510506SBarry.Harding@Sun.COM /* 184610506SBarry.Harding@Sun.COM * Apparently the status for this chip is not reliable. 184710506SBarry.Harding@Sun.COM * Only perform minimal consistency checking; the MAC 184810506SBarry.Harding@Sun.COM * and upper protocols will have to filter any garbage. 184910506SBarry.Harding@Sun.COM */ 185010506SBarry.Harding@Sun.COM if ((len > port->p_framesize) || (rxlen != len)) { 185110506SBarry.Harding@Sun.COM goto bad; 185210506SBarry.Harding@Sun.COM } 185310506SBarry.Harding@Sun.COM } else { 185410506SBarry.Harding@Sun.COM if ((len > port->p_framesize) || (rxlen != len) || 185510506SBarry.Harding@Sun.COM ((status & GMR_FS_ANY_ERR) != 0) || 185610506SBarry.Harding@Sun.COM ((status & GMR_FS_RX_OK) == 0)) { 185710506SBarry.Harding@Sun.COM goto bad; 185810506SBarry.Harding@Sun.COM } 185910506SBarry.Harding@Sun.COM } 186010506SBarry.Harding@Sun.COM 186110506SBarry.Harding@Sun.COM if ((mp = allocb(len + YGE_HEADROOM, BPRI_HI)) != NULL) { 186210506SBarry.Harding@Sun.COM 186310506SBarry.Harding@Sun.COM /* good packet - yay */ 186410506SBarry.Harding@Sun.COM mp->b_rptr += YGE_HEADROOM; 186510506SBarry.Harding@Sun.COM SYNCBUF(rxb, DDI_DMA_SYNC_FORKERNEL); 186610506SBarry.Harding@Sun.COM bcopy(rxb->b_buf, mp->b_rptr, len); 186710506SBarry.Harding@Sun.COM mp->b_wptr = mp->b_rptr + len; 186810506SBarry.Harding@Sun.COM } else { 186910506SBarry.Harding@Sun.COM port->p_stats.rx_nobuf++; 187010506SBarry.Harding@Sun.COM } 187110506SBarry.Harding@Sun.COM 187210506SBarry.Harding@Sun.COM bad: 187310506SBarry.Harding@Sun.COM 187410506SBarry.Harding@Sun.COM PUTCTRL(ring, cons, port->p_framesize | OP_PACKET | HW_OWNER); 187510506SBarry.Harding@Sun.COM SYNCENTRY(ring, cons, DDI_DMA_SYNC_FORDEV); 187610506SBarry.Harding@Sun.COM 187710506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, 187810506SBarry.Harding@Sun.COM Y2_PREF_Q_ADDR(port->p_rxq, PREF_UNIT_PUT_IDX_REG), 187910506SBarry.Harding@Sun.COM cons); 188010506SBarry.Harding@Sun.COM 188110506SBarry.Harding@Sun.COM YGE_INC(port->p_rx_cons, YGE_RX_RING_CNT); 188210506SBarry.Harding@Sun.COM 188310506SBarry.Harding@Sun.COM return (mp); 188410506SBarry.Harding@Sun.COM } 188510506SBarry.Harding@Sun.COM 188610506SBarry.Harding@Sun.COM static boolean_t 188710506SBarry.Harding@Sun.COM yge_txeof_locked(yge_port_t *port, int idx) 188810506SBarry.Harding@Sun.COM { 188910506SBarry.Harding@Sun.COM int prog; 189010506SBarry.Harding@Sun.COM int16_t cons; 189110506SBarry.Harding@Sun.COM boolean_t resched; 189210506SBarry.Harding@Sun.COM 189310506SBarry.Harding@Sun.COM if (!port->p_running) { 189410506SBarry.Harding@Sun.COM return (B_FALSE); 189510506SBarry.Harding@Sun.COM } 189610506SBarry.Harding@Sun.COM 189710506SBarry.Harding@Sun.COM cons = port->p_tx_cons; 189810506SBarry.Harding@Sun.COM prog = 0; 189910506SBarry.Harding@Sun.COM for (; cons != idx; YGE_INC(cons, YGE_TX_RING_CNT)) { 190010506SBarry.Harding@Sun.COM if (port->p_tx_cnt <= 0) 190110506SBarry.Harding@Sun.COM break; 190210506SBarry.Harding@Sun.COM prog++; 190310506SBarry.Harding@Sun.COM port->p_tx_cnt--; 190410506SBarry.Harding@Sun.COM /* No need to sync LEs as we didn't update LEs. */ 190510506SBarry.Harding@Sun.COM } 190610506SBarry.Harding@Sun.COM 190710506SBarry.Harding@Sun.COM port->p_tx_cons = cons; 190810506SBarry.Harding@Sun.COM 190910506SBarry.Harding@Sun.COM if (prog > 0) { 191010506SBarry.Harding@Sun.COM resched = port->p_wantw; 191110506SBarry.Harding@Sun.COM port->p_tx_wdog = 0; 191210506SBarry.Harding@Sun.COM port->p_wantw = B_FALSE; 191310506SBarry.Harding@Sun.COM return (resched); 191410506SBarry.Harding@Sun.COM } else { 191510506SBarry.Harding@Sun.COM return (B_FALSE); 191610506SBarry.Harding@Sun.COM } 191710506SBarry.Harding@Sun.COM } 191810506SBarry.Harding@Sun.COM 191910506SBarry.Harding@Sun.COM static void 192010506SBarry.Harding@Sun.COM yge_txeof(yge_port_t *port, int idx) 192110506SBarry.Harding@Sun.COM { 192210506SBarry.Harding@Sun.COM boolean_t resched; 192310506SBarry.Harding@Sun.COM 192410506SBarry.Harding@Sun.COM TX_LOCK(port->p_dev); 192510506SBarry.Harding@Sun.COM 192610506SBarry.Harding@Sun.COM resched = yge_txeof_locked(port, idx); 192710506SBarry.Harding@Sun.COM 192810506SBarry.Harding@Sun.COM TX_UNLOCK(port->p_dev); 192910506SBarry.Harding@Sun.COM 193010506SBarry.Harding@Sun.COM if (resched && port->p_running) { 193110506SBarry.Harding@Sun.COM mac_tx_update(port->p_mh); 193210506SBarry.Harding@Sun.COM } 193310506SBarry.Harding@Sun.COM } 193410506SBarry.Harding@Sun.COM 193510506SBarry.Harding@Sun.COM static void 193610506SBarry.Harding@Sun.COM yge_restart_task(yge_dev_t *dev) 193710506SBarry.Harding@Sun.COM { 193810506SBarry.Harding@Sun.COM yge_port_t *port; 193910506SBarry.Harding@Sun.COM 194010506SBarry.Harding@Sun.COM DEV_LOCK(dev); 194110506SBarry.Harding@Sun.COM 194210506SBarry.Harding@Sun.COM /* Cancel pending I/O and free all Rx/Tx buffers. */ 194310506SBarry.Harding@Sun.COM for (int i = 0; i < dev->d_num_port; i++) { 194410506SBarry.Harding@Sun.COM port = dev->d_port[i]; 194510506SBarry.Harding@Sun.COM if (port->p_running) 194610506SBarry.Harding@Sun.COM yge_stop_port(dev->d_port[i]); 194710506SBarry.Harding@Sun.COM } 194810506SBarry.Harding@Sun.COM yge_reset(dev); 194910506SBarry.Harding@Sun.COM for (int i = 0; i < dev->d_num_port; i++) { 195010506SBarry.Harding@Sun.COM port = dev->d_port[i]; 195110506SBarry.Harding@Sun.COM 195210506SBarry.Harding@Sun.COM if (port->p_running) 195310506SBarry.Harding@Sun.COM yge_start_port(port); 195410506SBarry.Harding@Sun.COM } 195510506SBarry.Harding@Sun.COM 195610506SBarry.Harding@Sun.COM DEV_UNLOCK(dev); 195710506SBarry.Harding@Sun.COM 195810506SBarry.Harding@Sun.COM for (int i = 0; i < dev->d_num_port; i++) { 195910506SBarry.Harding@Sun.COM port = dev->d_port[i]; 196010506SBarry.Harding@Sun.COM 196110506SBarry.Harding@Sun.COM mii_reset(port->p_mii); 196210506SBarry.Harding@Sun.COM if (port->p_running) 196310506SBarry.Harding@Sun.COM mac_tx_update(port->p_mh); 196410506SBarry.Harding@Sun.COM } 196510506SBarry.Harding@Sun.COM } 196610506SBarry.Harding@Sun.COM 196710506SBarry.Harding@Sun.COM static void 196810506SBarry.Harding@Sun.COM yge_tick(void *arg) 196910506SBarry.Harding@Sun.COM { 197010506SBarry.Harding@Sun.COM yge_dev_t *dev = arg; 197110506SBarry.Harding@Sun.COM yge_port_t *port; 197210506SBarry.Harding@Sun.COM boolean_t restart = B_FALSE; 197310506SBarry.Harding@Sun.COM boolean_t resched = B_FALSE; 197410506SBarry.Harding@Sun.COM int idx; 197510506SBarry.Harding@Sun.COM 197610506SBarry.Harding@Sun.COM DEV_LOCK(dev); 197710506SBarry.Harding@Sun.COM 197810506SBarry.Harding@Sun.COM if (dev->d_suspended) { 197910506SBarry.Harding@Sun.COM DEV_UNLOCK(dev); 198010506SBarry.Harding@Sun.COM return; 198110506SBarry.Harding@Sun.COM } 198210506SBarry.Harding@Sun.COM 198310506SBarry.Harding@Sun.COM for (int i = 0; i < dev->d_num_port; i++) { 198410506SBarry.Harding@Sun.COM port = dev->d_port[i]; 198510506SBarry.Harding@Sun.COM 198610506SBarry.Harding@Sun.COM if (!port->p_running) 198710506SBarry.Harding@Sun.COM continue; 198810506SBarry.Harding@Sun.COM 198910506SBarry.Harding@Sun.COM if (port->p_tx_cnt) { 199010506SBarry.Harding@Sun.COM uint32_t ridx; 199110506SBarry.Harding@Sun.COM 199210506SBarry.Harding@Sun.COM /* 199310506SBarry.Harding@Sun.COM * Reclaim first as there is a possibility of losing 199410506SBarry.Harding@Sun.COM * Tx completion interrupts. 199510506SBarry.Harding@Sun.COM */ 199610506SBarry.Harding@Sun.COM ridx = port->p_port == YGE_PORT_A ? 199710506SBarry.Harding@Sun.COM STAT_TXA1_RIDX : STAT_TXA2_RIDX; 199810506SBarry.Harding@Sun.COM idx = CSR_READ_2(dev, ridx); 199910506SBarry.Harding@Sun.COM if (port->p_tx_cons != idx) { 200010506SBarry.Harding@Sun.COM resched = yge_txeof_locked(port, idx); 200110506SBarry.Harding@Sun.COM 200210506SBarry.Harding@Sun.COM } else { 200310506SBarry.Harding@Sun.COM 200410506SBarry.Harding@Sun.COM /* detect TX hang */ 200510506SBarry.Harding@Sun.COM port->p_tx_wdog++; 200610506SBarry.Harding@Sun.COM if (port->p_tx_wdog > YGE_TX_TIMEOUT) { 200710506SBarry.Harding@Sun.COM port->p_tx_wdog = 0; 200810506SBarry.Harding@Sun.COM yge_error(NULL, port, 200910506SBarry.Harding@Sun.COM "TX hang detected!"); 201010506SBarry.Harding@Sun.COM restart = B_TRUE; 201110506SBarry.Harding@Sun.COM } 201210506SBarry.Harding@Sun.COM } 201310506SBarry.Harding@Sun.COM } 201410506SBarry.Harding@Sun.COM } 201510506SBarry.Harding@Sun.COM 201610506SBarry.Harding@Sun.COM DEV_UNLOCK(dev); 201710506SBarry.Harding@Sun.COM if (restart) { 201810506SBarry.Harding@Sun.COM yge_dispatch(dev, YGE_TASK_RESTART); 201910506SBarry.Harding@Sun.COM } else { 202010506SBarry.Harding@Sun.COM if (resched) { 202110506SBarry.Harding@Sun.COM for (int i = 0; i < dev->d_num_port; i++) { 202210506SBarry.Harding@Sun.COM port = dev->d_port[i]; 202310506SBarry.Harding@Sun.COM 202410506SBarry.Harding@Sun.COM if (port->p_running) 202510506SBarry.Harding@Sun.COM mac_tx_update(port->p_mh); 202610506SBarry.Harding@Sun.COM } 202710506SBarry.Harding@Sun.COM } 202810506SBarry.Harding@Sun.COM } 202910506SBarry.Harding@Sun.COM } 203010506SBarry.Harding@Sun.COM 203110506SBarry.Harding@Sun.COM static int 203210506SBarry.Harding@Sun.COM yge_intr_gmac(yge_port_t *port) 203310506SBarry.Harding@Sun.COM { 203410506SBarry.Harding@Sun.COM yge_dev_t *dev = port->p_dev; 203510506SBarry.Harding@Sun.COM int pnum = port->p_port; 203610506SBarry.Harding@Sun.COM uint8_t status; 203710506SBarry.Harding@Sun.COM int dispatch_wrk = 0; 203810506SBarry.Harding@Sun.COM 203910506SBarry.Harding@Sun.COM status = CSR_READ_1(dev, MR_ADDR(pnum, GMAC_IRQ_SRC)); 204010506SBarry.Harding@Sun.COM 204110506SBarry.Harding@Sun.COM /* GMAC Rx FIFO overrun. */ 204210506SBarry.Harding@Sun.COM if ((status & GM_IS_RX_FF_OR) != 0) { 204310506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_CTRL_T), GMF_CLI_RX_FO); 204410506SBarry.Harding@Sun.COM yge_error(NULL, port, "Rx FIFO overrun!"); 204510506SBarry.Harding@Sun.COM dispatch_wrk |= YGE_TASK_RESTART; 204610506SBarry.Harding@Sun.COM } 204710506SBarry.Harding@Sun.COM /* GMAC Tx FIFO underrun. */ 204810506SBarry.Harding@Sun.COM if ((status & GM_IS_TX_FF_UR) != 0) { 204910506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), GMF_CLI_TX_FU); 205010506SBarry.Harding@Sun.COM yge_error(NULL, port, "Tx FIFO underrun!"); 205110506SBarry.Harding@Sun.COM /* 205210506SBarry.Harding@Sun.COM * In case of Tx underrun, we may need to flush/reset 205310506SBarry.Harding@Sun.COM * Tx MAC but that would also require 205410506SBarry.Harding@Sun.COM * resynchronization with status LEs. Reinitializing 205510506SBarry.Harding@Sun.COM * status LEs would affect the other port in dual MAC 205610506SBarry.Harding@Sun.COM * configuration so it should be avoided if we can. 205710506SBarry.Harding@Sun.COM * Due to lack of documentation it's all vague guess 205810506SBarry.Harding@Sun.COM * but it needs more investigation. 205910506SBarry.Harding@Sun.COM */ 206010506SBarry.Harding@Sun.COM } 206110506SBarry.Harding@Sun.COM return (dispatch_wrk); 206210506SBarry.Harding@Sun.COM } 206310506SBarry.Harding@Sun.COM 206410506SBarry.Harding@Sun.COM static void 206510506SBarry.Harding@Sun.COM yge_handle_hwerr(yge_port_t *port, uint32_t status) 206610506SBarry.Harding@Sun.COM { 206710506SBarry.Harding@Sun.COM yge_dev_t *dev = port->p_dev; 206810506SBarry.Harding@Sun.COM 206910506SBarry.Harding@Sun.COM if ((status & Y2_IS_PAR_RD1) != 0) { 207010506SBarry.Harding@Sun.COM yge_error(NULL, port, "RAM buffer read parity error"); 207110506SBarry.Harding@Sun.COM /* Clear IRQ. */ 207210506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, SELECT_RAM_BUFFER(port->p_port, B3_RI_CTRL), 207310506SBarry.Harding@Sun.COM RI_CLR_RD_PERR); 207410506SBarry.Harding@Sun.COM } 207510506SBarry.Harding@Sun.COM if ((status & Y2_IS_PAR_WR1) != 0) { 207610506SBarry.Harding@Sun.COM yge_error(NULL, port, "RAM buffer write parity error"); 207710506SBarry.Harding@Sun.COM /* Clear IRQ. */ 207810506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, SELECT_RAM_BUFFER(port->p_port, B3_RI_CTRL), 207910506SBarry.Harding@Sun.COM RI_CLR_WR_PERR); 208010506SBarry.Harding@Sun.COM } 208110506SBarry.Harding@Sun.COM if ((status & Y2_IS_PAR_MAC1) != 0) { 208210506SBarry.Harding@Sun.COM yge_error(NULL, port, "Tx MAC parity error"); 208310506SBarry.Harding@Sun.COM /* Clear IRQ. */ 208410506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(port->p_port, TX_GMF_CTRL_T), 208510506SBarry.Harding@Sun.COM GMF_CLI_TX_PE); 208610506SBarry.Harding@Sun.COM } 208710506SBarry.Harding@Sun.COM if ((status & Y2_IS_PAR_RX1) != 0) { 208810506SBarry.Harding@Sun.COM yge_error(NULL, port, "Rx parity error"); 208910506SBarry.Harding@Sun.COM /* Clear IRQ. */ 209010506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Q_ADDR(port->p_rxq, Q_CSR), BMU_CLR_IRQ_PAR); 209110506SBarry.Harding@Sun.COM } 209210506SBarry.Harding@Sun.COM if ((status & (Y2_IS_TCP_TXS1 | Y2_IS_TCP_TXA1)) != 0) { 209310506SBarry.Harding@Sun.COM yge_error(NULL, port, "TCP segmentation error"); 209410506SBarry.Harding@Sun.COM /* Clear IRQ. */ 209510506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Q_ADDR(port->p_txq, Q_CSR), BMU_CLR_IRQ_TCP); 209610506SBarry.Harding@Sun.COM } 209710506SBarry.Harding@Sun.COM } 209810506SBarry.Harding@Sun.COM 209910506SBarry.Harding@Sun.COM static void 210010506SBarry.Harding@Sun.COM yge_intr_hwerr(yge_dev_t *dev) 210110506SBarry.Harding@Sun.COM { 210210506SBarry.Harding@Sun.COM uint32_t status; 210310506SBarry.Harding@Sun.COM uint32_t tlphead[4]; 210410506SBarry.Harding@Sun.COM 210510506SBarry.Harding@Sun.COM status = CSR_READ_4(dev, B0_HWE_ISRC); 210610506SBarry.Harding@Sun.COM /* Time Stamp timer overflow. */ 210710506SBarry.Harding@Sun.COM if ((status & Y2_IS_TIST_OV) != 0) 210810506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ); 210910506SBarry.Harding@Sun.COM if ((status & Y2_IS_PCI_NEXP) != 0) { 211010506SBarry.Harding@Sun.COM /* 211110506SBarry.Harding@Sun.COM * PCI Express Error occurred which is not described in PEX 211210506SBarry.Harding@Sun.COM * spec. 211310506SBarry.Harding@Sun.COM * This error is also mapped either to Master Abort( 211410506SBarry.Harding@Sun.COM * Y2_IS_MST_ERR) or Target Abort (Y2_IS_IRQ_STAT) bit and 211510506SBarry.Harding@Sun.COM * can only be cleared there. 211610506SBarry.Harding@Sun.COM */ 211710506SBarry.Harding@Sun.COM yge_error(dev, NULL, "PCI Express protocol violation error"); 211810506SBarry.Harding@Sun.COM } 211910506SBarry.Harding@Sun.COM 212010506SBarry.Harding@Sun.COM if ((status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) != 0) { 212110506SBarry.Harding@Sun.COM uint16_t v16; 212210506SBarry.Harding@Sun.COM 212310506SBarry.Harding@Sun.COM if ((status & Y2_IS_IRQ_STAT) != 0) 212410506SBarry.Harding@Sun.COM yge_error(dev, NULL, "Unexpected IRQ Status error"); 212510506SBarry.Harding@Sun.COM if ((status & Y2_IS_MST_ERR) != 0) 212610506SBarry.Harding@Sun.COM yge_error(dev, NULL, "Unexpected IRQ Master error"); 212710506SBarry.Harding@Sun.COM /* Reset all bits in the PCI status register. */ 212810506SBarry.Harding@Sun.COM v16 = pci_config_get16(dev->d_pcih, PCI_CONF_STAT); 212910506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_ON); 213010506SBarry.Harding@Sun.COM pci_config_put16(dev->d_pcih, PCI_CONF_STAT, v16 | 213110506SBarry.Harding@Sun.COM PCI_STAT_S_PERROR | PCI_STAT_S_SYSERR | PCI_STAT_R_MAST_AB | 213210506SBarry.Harding@Sun.COM PCI_STAT_R_TARG_AB | PCI_STAT_PERROR); 213310506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 213410506SBarry.Harding@Sun.COM } 213510506SBarry.Harding@Sun.COM 213610506SBarry.Harding@Sun.COM /* Check for PCI Express Uncorrectable Error. */ 213710506SBarry.Harding@Sun.COM if ((status & Y2_IS_PCI_EXP) != 0) { 213810506SBarry.Harding@Sun.COM uint32_t v32; 213910506SBarry.Harding@Sun.COM 214010506SBarry.Harding@Sun.COM /* 214110506SBarry.Harding@Sun.COM * On PCI Express bus bridges are called root complexes (RC). 214210506SBarry.Harding@Sun.COM * PCI Express errors are recognized by the root complex too, 214310506SBarry.Harding@Sun.COM * which requests the system to handle the problem. After 214410506SBarry.Harding@Sun.COM * error occurrence it may be that no access to the adapter 214510506SBarry.Harding@Sun.COM * may be performed any longer. 214610506SBarry.Harding@Sun.COM */ 214710506SBarry.Harding@Sun.COM 214810506SBarry.Harding@Sun.COM v32 = CSR_PCI_READ_4(dev, PEX_UNC_ERR_STAT); 214910506SBarry.Harding@Sun.COM if ((v32 & PEX_UNSUP_REQ) != 0) { 215010506SBarry.Harding@Sun.COM /* Ignore unsupported request error. */ 215110506SBarry.Harding@Sun.COM yge_error(dev, NULL, 215210506SBarry.Harding@Sun.COM "Uncorrectable PCI Express error"); 215310506SBarry.Harding@Sun.COM } 215410506SBarry.Harding@Sun.COM if ((v32 & (PEX_FATAL_ERRORS | PEX_POIS_TLP)) != 0) { 215510506SBarry.Harding@Sun.COM int i; 215610506SBarry.Harding@Sun.COM 215710506SBarry.Harding@Sun.COM /* Get TLP header form Log Registers. */ 215810506SBarry.Harding@Sun.COM for (i = 0; i < 4; i++) 215910506SBarry.Harding@Sun.COM tlphead[i] = CSR_PCI_READ_4(dev, 216010506SBarry.Harding@Sun.COM PEX_HEADER_LOG + i * 4); 216110506SBarry.Harding@Sun.COM /* Check for vendor defined broadcast message. */ 216210506SBarry.Harding@Sun.COM if (!(tlphead[0] == 0x73004001 && tlphead[1] == 0x7f)) { 216310506SBarry.Harding@Sun.COM dev->d_intrhwemask &= ~Y2_IS_PCI_EXP; 216410506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_HWE_IMSK, 216510506SBarry.Harding@Sun.COM dev->d_intrhwemask); 216610506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B0_HWE_IMSK); 216710506SBarry.Harding@Sun.COM } 216810506SBarry.Harding@Sun.COM } 216910506SBarry.Harding@Sun.COM /* Clear the interrupt. */ 217010506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_ON); 217110506SBarry.Harding@Sun.COM CSR_PCI_WRITE_4(dev, PEX_UNC_ERR_STAT, 0xffffffff); 217210506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 217310506SBarry.Harding@Sun.COM } 217410506SBarry.Harding@Sun.COM 217510506SBarry.Harding@Sun.COM if ((status & Y2_HWE_L1_MASK) != 0 && dev->d_port[YGE_PORT_A] != NULL) 217610506SBarry.Harding@Sun.COM yge_handle_hwerr(dev->d_port[YGE_PORT_A], status); 217710506SBarry.Harding@Sun.COM if ((status & Y2_HWE_L2_MASK) != 0 && dev->d_port[YGE_PORT_B] != NULL) 217810506SBarry.Harding@Sun.COM yge_handle_hwerr(dev->d_port[YGE_PORT_B], status >> 8); 217910506SBarry.Harding@Sun.COM } 218010506SBarry.Harding@Sun.COM 218110506SBarry.Harding@Sun.COM /* 218210506SBarry.Harding@Sun.COM * Returns B_TRUE if there is potentially more work to do. 218310506SBarry.Harding@Sun.COM */ 218410506SBarry.Harding@Sun.COM static boolean_t 218510506SBarry.Harding@Sun.COM yge_handle_events(yge_dev_t *dev, mblk_t **heads, mblk_t **tails, int *txindex) 218610506SBarry.Harding@Sun.COM { 218710506SBarry.Harding@Sun.COM yge_port_t *port; 218810506SBarry.Harding@Sun.COM yge_ring_t *ring; 218910506SBarry.Harding@Sun.COM uint32_t control, status; 219010506SBarry.Harding@Sun.COM int cons, idx, len, pnum; 219110506SBarry.Harding@Sun.COM mblk_t *mp; 219210506SBarry.Harding@Sun.COM uint32_t rxprogs[2]; 219310506SBarry.Harding@Sun.COM 219410506SBarry.Harding@Sun.COM rxprogs[0] = rxprogs[1] = 0; 219510506SBarry.Harding@Sun.COM 219610506SBarry.Harding@Sun.COM idx = CSR_READ_2(dev, STAT_PUT_IDX); 219710506SBarry.Harding@Sun.COM if (idx == dev->d_stat_cons) { 219810506SBarry.Harding@Sun.COM return (B_FALSE); 219910506SBarry.Harding@Sun.COM } 220010506SBarry.Harding@Sun.COM 220110506SBarry.Harding@Sun.COM ring = &dev->d_status_ring; 220210506SBarry.Harding@Sun.COM 220310506SBarry.Harding@Sun.COM for (cons = dev->d_stat_cons; cons != idx; ) { 220410506SBarry.Harding@Sun.COM /* Sync status LE. */ 220510506SBarry.Harding@Sun.COM SYNCENTRY(ring, cons, DDI_DMA_SYNC_FORKERNEL); 220610506SBarry.Harding@Sun.COM control = GETCTRL(ring, cons); 220710506SBarry.Harding@Sun.COM if ((control & HW_OWNER) == 0) { 220810506SBarry.Harding@Sun.COM yge_error(dev, NULL, "Status descriptor error: " 220910506SBarry.Harding@Sun.COM "index %d, control %x", cons, control); 221010506SBarry.Harding@Sun.COM break; 221110506SBarry.Harding@Sun.COM } 221210506SBarry.Harding@Sun.COM 221310506SBarry.Harding@Sun.COM status = GETSTAT(ring, cons); 221410506SBarry.Harding@Sun.COM 221510506SBarry.Harding@Sun.COM control &= ~HW_OWNER; 221610506SBarry.Harding@Sun.COM len = control & STLE_LEN_MASK; 221710506SBarry.Harding@Sun.COM pnum = ((control >> 16) & 0x01); 221810506SBarry.Harding@Sun.COM port = dev->d_port[pnum]; 221910506SBarry.Harding@Sun.COM if (port == NULL) { 222010506SBarry.Harding@Sun.COM yge_error(dev, NULL, "Invalid port opcode: 0x%08x", 222110506SBarry.Harding@Sun.COM control & STLE_OP_MASK); 222210506SBarry.Harding@Sun.COM goto finish; 222310506SBarry.Harding@Sun.COM } 222410506SBarry.Harding@Sun.COM 222510506SBarry.Harding@Sun.COM switch (control & STLE_OP_MASK) { 222610506SBarry.Harding@Sun.COM case OP_RXSTAT: 222710506SBarry.Harding@Sun.COM mp = yge_rxeof(port, status, len); 222810506SBarry.Harding@Sun.COM if (mp != NULL) { 222910506SBarry.Harding@Sun.COM if (heads[pnum] == NULL) 223010506SBarry.Harding@Sun.COM heads[pnum] = mp; 223110506SBarry.Harding@Sun.COM else 223210506SBarry.Harding@Sun.COM tails[pnum]->b_next = mp; 223310506SBarry.Harding@Sun.COM tails[pnum] = mp; 223410506SBarry.Harding@Sun.COM } 223510506SBarry.Harding@Sun.COM 223610506SBarry.Harding@Sun.COM rxprogs[pnum]++; 223710506SBarry.Harding@Sun.COM break; 223810506SBarry.Harding@Sun.COM 223910506SBarry.Harding@Sun.COM case OP_TXINDEXLE: 224010506SBarry.Harding@Sun.COM txindex[0] = status & STLE_TXA1_MSKL; 224110506SBarry.Harding@Sun.COM txindex[1] = 224210506SBarry.Harding@Sun.COM ((status & STLE_TXA2_MSKL) >> STLE_TXA2_SHIFTL) | 224310506SBarry.Harding@Sun.COM ((len & STLE_TXA2_MSKH) << STLE_TXA2_SHIFTH); 224410506SBarry.Harding@Sun.COM break; 224510506SBarry.Harding@Sun.COM default: 224610506SBarry.Harding@Sun.COM yge_error(dev, NULL, "Unhandled opcode: 0x%08x", 224710506SBarry.Harding@Sun.COM control & STLE_OP_MASK); 224810506SBarry.Harding@Sun.COM break; 224910506SBarry.Harding@Sun.COM } 225010506SBarry.Harding@Sun.COM finish: 225110506SBarry.Harding@Sun.COM 225210506SBarry.Harding@Sun.COM /* Give it back to HW. */ 225310506SBarry.Harding@Sun.COM PUTCTRL(ring, cons, control); 225410506SBarry.Harding@Sun.COM SYNCENTRY(ring, cons, DDI_DMA_SYNC_FORDEV); 225510506SBarry.Harding@Sun.COM 225610506SBarry.Harding@Sun.COM YGE_INC(cons, YGE_STAT_RING_CNT); 225710506SBarry.Harding@Sun.COM if (rxprogs[pnum] > dev->d_process_limit) { 225810506SBarry.Harding@Sun.COM break; 225910506SBarry.Harding@Sun.COM } 226010506SBarry.Harding@Sun.COM } 226110506SBarry.Harding@Sun.COM 226210506SBarry.Harding@Sun.COM dev->d_stat_cons = cons; 226310506SBarry.Harding@Sun.COM if (dev->d_stat_cons != CSR_READ_2(dev, STAT_PUT_IDX)) 226410506SBarry.Harding@Sun.COM return (B_TRUE); 226510506SBarry.Harding@Sun.COM else 226610506SBarry.Harding@Sun.COM return (B_FALSE); 226710506SBarry.Harding@Sun.COM } 226810506SBarry.Harding@Sun.COM 226910506SBarry.Harding@Sun.COM /*ARGSUSED1*/ 227010506SBarry.Harding@Sun.COM static uint_t 227110506SBarry.Harding@Sun.COM yge_intr(caddr_t arg1, caddr_t arg2) 227210506SBarry.Harding@Sun.COM { 227310506SBarry.Harding@Sun.COM yge_dev_t *dev; 227410506SBarry.Harding@Sun.COM yge_port_t *port1; 227510506SBarry.Harding@Sun.COM yge_port_t *port2; 227610506SBarry.Harding@Sun.COM uint32_t status; 227710506SBarry.Harding@Sun.COM mblk_t *heads[2], *tails[2]; 227810506SBarry.Harding@Sun.COM int txindex[2]; 227910506SBarry.Harding@Sun.COM int dispatch_wrk; 228010506SBarry.Harding@Sun.COM 228110506SBarry.Harding@Sun.COM dev = (void *)arg1; 228210506SBarry.Harding@Sun.COM 228310506SBarry.Harding@Sun.COM heads[0] = heads[1] = NULL; 228410506SBarry.Harding@Sun.COM tails[0] = tails[1] = NULL; 228510506SBarry.Harding@Sun.COM txindex[0] = txindex[1] = -1; 228610506SBarry.Harding@Sun.COM dispatch_wrk = 0; 228710506SBarry.Harding@Sun.COM 228810506SBarry.Harding@Sun.COM port1 = dev->d_port[YGE_PORT_A]; 228910506SBarry.Harding@Sun.COM port2 = dev->d_port[YGE_PORT_B]; 229010506SBarry.Harding@Sun.COM 229110506SBarry.Harding@Sun.COM RX_LOCK(dev); 229210506SBarry.Harding@Sun.COM 229310506SBarry.Harding@Sun.COM if (dev->d_suspended) { 229410506SBarry.Harding@Sun.COM RX_UNLOCK(dev); 229510506SBarry.Harding@Sun.COM return (DDI_INTR_UNCLAIMED); 229610506SBarry.Harding@Sun.COM } 229710506SBarry.Harding@Sun.COM 229810506SBarry.Harding@Sun.COM /* Get interrupt source. */ 229910506SBarry.Harding@Sun.COM status = CSR_READ_4(dev, B0_Y2_SP_ISRC2); 230010506SBarry.Harding@Sun.COM if (status == 0 || status == 0xffffffff || 230110506SBarry.Harding@Sun.COM (status & dev->d_intrmask) == 0) { /* Stray interrupt ? */ 230210506SBarry.Harding@Sun.COM /* Reenable interrupts. */ 230310506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_Y2_SP_ICR, 2); 230410506SBarry.Harding@Sun.COM RX_UNLOCK(dev); 230510506SBarry.Harding@Sun.COM return (DDI_INTR_UNCLAIMED); 230610506SBarry.Harding@Sun.COM } 230710506SBarry.Harding@Sun.COM 230810506SBarry.Harding@Sun.COM if ((status & Y2_IS_HW_ERR) != 0) { 230910506SBarry.Harding@Sun.COM yge_intr_hwerr(dev); 231010506SBarry.Harding@Sun.COM } 231110506SBarry.Harding@Sun.COM 231210506SBarry.Harding@Sun.COM if (status & Y2_IS_IRQ_MAC1) { 231310506SBarry.Harding@Sun.COM dispatch_wrk |= yge_intr_gmac(port1); 231410506SBarry.Harding@Sun.COM } 231510506SBarry.Harding@Sun.COM if (status & Y2_IS_IRQ_MAC2) { 231610506SBarry.Harding@Sun.COM dispatch_wrk |= yge_intr_gmac(port2); 231710506SBarry.Harding@Sun.COM } 231810506SBarry.Harding@Sun.COM 231910506SBarry.Harding@Sun.COM if ((status & (Y2_IS_CHK_RX1 | Y2_IS_CHK_RX2)) != 0) { 232010506SBarry.Harding@Sun.COM yge_error(NULL, status & Y2_IS_CHK_RX1 ? port1 : port2, 232110506SBarry.Harding@Sun.COM "Rx descriptor error"); 232210506SBarry.Harding@Sun.COM dev->d_intrmask &= ~(Y2_IS_CHK_RX1 | Y2_IS_CHK_RX2); 232310506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_IMSK, dev->d_intrmask); 232410506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B0_IMSK); 232510506SBarry.Harding@Sun.COM } 232610506SBarry.Harding@Sun.COM if ((status & (Y2_IS_CHK_TXA1 | Y2_IS_CHK_TXA2)) != 0) { 232710506SBarry.Harding@Sun.COM yge_error(NULL, status & Y2_IS_CHK_TXA1 ? port1 : port2, 232810506SBarry.Harding@Sun.COM "Tx descriptor error"); 232910506SBarry.Harding@Sun.COM dev->d_intrmask &= ~(Y2_IS_CHK_TXA1 | Y2_IS_CHK_TXA2); 233010506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_IMSK, dev->d_intrmask); 233110506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B0_IMSK); 233210506SBarry.Harding@Sun.COM } 233310506SBarry.Harding@Sun.COM 233410506SBarry.Harding@Sun.COM /* handle events until it returns false */ 233510506SBarry.Harding@Sun.COM while (yge_handle_events(dev, heads, tails, txindex)) 233610506SBarry.Harding@Sun.COM /* NOP */; 233710506SBarry.Harding@Sun.COM 233810506SBarry.Harding@Sun.COM /* Do receive/transmit events */ 233910506SBarry.Harding@Sun.COM if ((status & Y2_IS_STAT_BMU)) { 234010506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, STAT_CTRL, SC_STAT_CLR_IRQ); 234110506SBarry.Harding@Sun.COM } 234210506SBarry.Harding@Sun.COM 234310506SBarry.Harding@Sun.COM /* Reenable interrupts. */ 234410506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_Y2_SP_ICR, 2); 234510506SBarry.Harding@Sun.COM 234610506SBarry.Harding@Sun.COM RX_UNLOCK(dev); 234710506SBarry.Harding@Sun.COM 234810506SBarry.Harding@Sun.COM if (dispatch_wrk) { 234910506SBarry.Harding@Sun.COM yge_dispatch(dev, dispatch_wrk); 235010506SBarry.Harding@Sun.COM } 235110506SBarry.Harding@Sun.COM 235210506SBarry.Harding@Sun.COM if (port1->p_running) { 235310506SBarry.Harding@Sun.COM if (txindex[0] >= 0) { 235410506SBarry.Harding@Sun.COM yge_txeof(port1, txindex[0]); 235510506SBarry.Harding@Sun.COM } 235610506SBarry.Harding@Sun.COM if (heads[0]) 235710506SBarry.Harding@Sun.COM mac_rx(port1->p_mh, NULL, heads[0]); 235810506SBarry.Harding@Sun.COM } else { 235910506SBarry.Harding@Sun.COM if (heads[0]) { 236010506SBarry.Harding@Sun.COM mblk_t *mp; 236110506SBarry.Harding@Sun.COM while ((mp = heads[0]) != NULL) { 236210506SBarry.Harding@Sun.COM heads[0] = mp->b_next; 236310506SBarry.Harding@Sun.COM freemsg(mp); 236410506SBarry.Harding@Sun.COM } 236510506SBarry.Harding@Sun.COM } 236610506SBarry.Harding@Sun.COM } 236710506SBarry.Harding@Sun.COM 236810506SBarry.Harding@Sun.COM if (port2->p_running) { 236910506SBarry.Harding@Sun.COM if (txindex[1] >= 0) { 237010506SBarry.Harding@Sun.COM yge_txeof(port2, txindex[1]); 237110506SBarry.Harding@Sun.COM } 237210506SBarry.Harding@Sun.COM if (heads[1]) 237310506SBarry.Harding@Sun.COM mac_rx(port2->p_mh, NULL, heads[1]); 237410506SBarry.Harding@Sun.COM } else { 237510506SBarry.Harding@Sun.COM if (heads[1]) { 237610506SBarry.Harding@Sun.COM mblk_t *mp; 237710506SBarry.Harding@Sun.COM while ((mp = heads[1]) != NULL) { 237810506SBarry.Harding@Sun.COM heads[1] = mp->b_next; 237910506SBarry.Harding@Sun.COM freemsg(mp); 238010506SBarry.Harding@Sun.COM } 238110506SBarry.Harding@Sun.COM } 238210506SBarry.Harding@Sun.COM } 238310506SBarry.Harding@Sun.COM 238410506SBarry.Harding@Sun.COM return (DDI_INTR_CLAIMED); 238510506SBarry.Harding@Sun.COM } 238610506SBarry.Harding@Sun.COM 238710506SBarry.Harding@Sun.COM static void 238810506SBarry.Harding@Sun.COM yge_set_tx_stfwd(yge_port_t *port) 238910506SBarry.Harding@Sun.COM { 239010506SBarry.Harding@Sun.COM yge_dev_t *dev = port->p_dev; 239110506SBarry.Harding@Sun.COM int pnum = port->p_port; 239210506SBarry.Harding@Sun.COM 239310506SBarry.Harding@Sun.COM switch (dev->d_hw_id) { 239410506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_EX: 239510506SBarry.Harding@Sun.COM if (dev->d_hw_rev == CHIP_REV_YU_EX_A0) 239610506SBarry.Harding@Sun.COM goto yukon_ex_workaround; 239710506SBarry.Harding@Sun.COM 239810506SBarry.Harding@Sun.COM if (port->p_mtu > ETHERMTU) 239910506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), 240010506SBarry.Harding@Sun.COM TX_JUMBO_ENA | TX_STFW_ENA); 240110506SBarry.Harding@Sun.COM else 240210506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), 240310506SBarry.Harding@Sun.COM TX_JUMBO_DIS | TX_STFW_ENA); 240410506SBarry.Harding@Sun.COM break; 240510506SBarry.Harding@Sun.COM default: 240610506SBarry.Harding@Sun.COM yukon_ex_workaround: 240710506SBarry.Harding@Sun.COM if (port->p_mtu > ETHERMTU) { 240810506SBarry.Harding@Sun.COM /* Set Tx GMAC FIFO Almost Empty Threshold. */ 240910506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_AE_THR), 241010506SBarry.Harding@Sun.COM MSK_ECU_JUMBO_WM << 16 | MSK_ECU_AE_THR); 241110506SBarry.Harding@Sun.COM /* Disable Store & Forward mode for Tx. */ 241210506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), 241310506SBarry.Harding@Sun.COM TX_JUMBO_ENA | TX_STFW_DIS); 241410506SBarry.Harding@Sun.COM } else { 241510506SBarry.Harding@Sun.COM /* Enable Store & Forward mode for Tx. */ 241610506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), 241710506SBarry.Harding@Sun.COM TX_JUMBO_DIS | TX_STFW_ENA); 241810506SBarry.Harding@Sun.COM } 241910506SBarry.Harding@Sun.COM break; 242010506SBarry.Harding@Sun.COM } 242110506SBarry.Harding@Sun.COM } 242210506SBarry.Harding@Sun.COM 242310506SBarry.Harding@Sun.COM static void 242410506SBarry.Harding@Sun.COM yge_start_port(yge_port_t *port) 242510506SBarry.Harding@Sun.COM { 242610506SBarry.Harding@Sun.COM yge_dev_t *dev = port->p_dev; 242710506SBarry.Harding@Sun.COM uint16_t gmac; 242810506SBarry.Harding@Sun.COM int32_t pnum; 242910506SBarry.Harding@Sun.COM int32_t rxq; 243010506SBarry.Harding@Sun.COM int32_t txq; 243110506SBarry.Harding@Sun.COM uint32_t reg; 243210506SBarry.Harding@Sun.COM 243310506SBarry.Harding@Sun.COM pnum = port->p_port; 243410506SBarry.Harding@Sun.COM txq = port->p_txq; 243510506SBarry.Harding@Sun.COM rxq = port->p_rxq; 243610506SBarry.Harding@Sun.COM 243710506SBarry.Harding@Sun.COM if (port->p_mtu < ETHERMTU) 243810506SBarry.Harding@Sun.COM port->p_framesize = ETHERMTU; 243910506SBarry.Harding@Sun.COM else 244010506SBarry.Harding@Sun.COM port->p_framesize = port->p_mtu; 244110506SBarry.Harding@Sun.COM port->p_framesize += sizeof (struct ether_vlan_header); 244210506SBarry.Harding@Sun.COM 244310506SBarry.Harding@Sun.COM /* 244410506SBarry.Harding@Sun.COM * Note for the future, if we enable offloads: 244510506SBarry.Harding@Sun.COM * In Yukon EC Ultra, TSO & checksum offload is not 244610506SBarry.Harding@Sun.COM * supported for jumbo frame. 244710506SBarry.Harding@Sun.COM */ 244810506SBarry.Harding@Sun.COM 244910506SBarry.Harding@Sun.COM /* GMAC Control reset */ 245010506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, GMAC_CTRL), GMC_RST_SET); 245110506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, GMAC_CTRL), GMC_RST_CLR); 245210506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, GMAC_CTRL), GMC_F_LOOPB_OFF); 245310506SBarry.Harding@Sun.COM if (dev->d_hw_id == CHIP_ID_YUKON_EX) 245410506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, GMAC_CTRL), 245510506SBarry.Harding@Sun.COM GMC_BYP_MACSECRX_ON | GMC_BYP_MACSECTX_ON | 245610506SBarry.Harding@Sun.COM GMC_BYP_RETR_ON); 245710506SBarry.Harding@Sun.COM /* 245810506SBarry.Harding@Sun.COM * Initialize GMAC first such that speed/duplex/flow-control 245910506SBarry.Harding@Sun.COM * parameters are renegotiated with the interface is brought up. 246010506SBarry.Harding@Sun.COM */ 246110506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_GP_CTRL, 0); 246210506SBarry.Harding@Sun.COM 246310506SBarry.Harding@Sun.COM /* Dummy read the Interrupt Source Register. */ 246410506SBarry.Harding@Sun.COM (void) CSR_READ_1(dev, MR_ADDR(pnum, GMAC_IRQ_SRC)); 246510506SBarry.Harding@Sun.COM 246610506SBarry.Harding@Sun.COM /* Clear MIB stats. */ 246710506SBarry.Harding@Sun.COM yge_stats_clear(port); 246810506SBarry.Harding@Sun.COM 246910506SBarry.Harding@Sun.COM /* Disable FCS. */ 247010506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_RX_CTRL, GM_RXCR_CRC_DIS); 247110506SBarry.Harding@Sun.COM 247210506SBarry.Harding@Sun.COM /* Setup Transmit Control Register. */ 247310506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF)); 247410506SBarry.Harding@Sun.COM 247510506SBarry.Harding@Sun.COM /* Setup Transmit Flow Control Register. */ 247610506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_TX_FLOW_CTRL, 0xffff); 247710506SBarry.Harding@Sun.COM 247810506SBarry.Harding@Sun.COM /* Setup Transmit Parameter Register. */ 247910506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_TX_PARAM, 248010506SBarry.Harding@Sun.COM TX_JAM_LEN_VAL(TX_JAM_LEN_DEF) | TX_JAM_IPG_VAL(TX_JAM_IPG_DEF) | 248110506SBarry.Harding@Sun.COM TX_IPG_JAM_DATA(TX_IPG_JAM_DEF) | TX_BACK_OFF_LIM(TX_BOF_LIM_DEF)); 248210506SBarry.Harding@Sun.COM 248310506SBarry.Harding@Sun.COM gmac = DATA_BLIND_VAL(DATA_BLIND_DEF) | 248410506SBarry.Harding@Sun.COM GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF); 248510506SBarry.Harding@Sun.COM 248610506SBarry.Harding@Sun.COM if (port->p_mtu > ETHERMTU) 248710506SBarry.Harding@Sun.COM gmac |= GM_SMOD_JUMBO_ENA; 248810506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_SERIAL_MODE, gmac); 248910506SBarry.Harding@Sun.COM 249010506SBarry.Harding@Sun.COM /* Disable interrupts for counter overflows. */ 249110506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_TX_IRQ_MSK, 0); 249210506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_RX_IRQ_MSK, 0); 249310506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_TR_IRQ_MSK, 0); 249410506SBarry.Harding@Sun.COM 249510506SBarry.Harding@Sun.COM /* Configure Rx MAC FIFO. */ 249610506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_CTRL_T), GMF_RST_SET); 249710506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_CTRL_T), GMF_RST_CLR); 249810506SBarry.Harding@Sun.COM reg = GMF_OPER_ON | GMF_RX_F_FL_ON; 249910506SBarry.Harding@Sun.COM if (dev->d_hw_id == CHIP_ID_YUKON_FE_P || 250010506SBarry.Harding@Sun.COM dev->d_hw_id == CHIP_ID_YUKON_EX) 250110506SBarry.Harding@Sun.COM reg |= GMF_RX_OVER_ON; 250210506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_CTRL_T), reg); 250310506SBarry.Harding@Sun.COM 250410506SBarry.Harding@Sun.COM /* Set receive filter. */ 250510506SBarry.Harding@Sun.COM yge_setrxfilt(port); 250610506SBarry.Harding@Sun.COM 250710506SBarry.Harding@Sun.COM /* Flush Rx MAC FIFO on any flow control or error. */ 250810506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_FL_MSK), GMR_FS_ANY_ERR); 250910506SBarry.Harding@Sun.COM 251010506SBarry.Harding@Sun.COM /* 251110506SBarry.Harding@Sun.COM * Set Rx FIFO flush threshold to 64 bytes + 1 FIFO word 251210506SBarry.Harding@Sun.COM * due to hardware hang on receipt of pause frames. 251310506SBarry.Harding@Sun.COM */ 251410506SBarry.Harding@Sun.COM reg = RX_GMF_FL_THR_DEF + 1; 251510506SBarry.Harding@Sun.COM /* FE+ magic */ 251610506SBarry.Harding@Sun.COM if ((dev->d_hw_id == CHIP_ID_YUKON_FE_P) && 251710506SBarry.Harding@Sun.COM (dev->d_hw_rev == CHIP_REV_YU_FE2_A0)) 251810506SBarry.Harding@Sun.COM reg = 0x178; 251910506SBarry.Harding@Sun.COM 252010506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_FL_THR), reg); 252110506SBarry.Harding@Sun.COM 252210506SBarry.Harding@Sun.COM /* Configure Tx MAC FIFO. */ 252310506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), GMF_RST_SET); 252410506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), GMF_RST_CLR); 252510506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), GMF_OPER_ON); 252610506SBarry.Harding@Sun.COM 252710506SBarry.Harding@Sun.COM /* Disable hardware VLAN tag insertion/stripping. */ 252810506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_CTRL_T), RX_VLAN_STRIP_OFF); 252910506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), TX_VLAN_TAG_OFF); 253010506SBarry.Harding@Sun.COM 253110506SBarry.Harding@Sun.COM if ((port->p_flags & PORT_FLAG_RAMBUF) == 0) { 253210506SBarry.Harding@Sun.COM /* Set Rx Pause threshold. */ 253310506SBarry.Harding@Sun.COM if ((dev->d_hw_id == CHIP_ID_YUKON_FE_P) && 253410506SBarry.Harding@Sun.COM (dev->d_hw_rev == CHIP_REV_YU_FE2_A0)) { 253510506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, MR_ADDR(pnum, RX_GMF_LP_THR), 253610506SBarry.Harding@Sun.COM MSK_ECU_LLPP); 253710506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, MR_ADDR(pnum, RX_GMF_UP_THR), 253810506SBarry.Harding@Sun.COM MSK_FEP_ULPP); 253910506SBarry.Harding@Sun.COM } else { 254010506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, MR_ADDR(pnum, RX_GMF_LP_THR), 254110506SBarry.Harding@Sun.COM MSK_ECU_LLPP); 254210506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, MR_ADDR(pnum, RX_GMF_UP_THR), 254310506SBarry.Harding@Sun.COM MSK_ECU_ULPP); 254410506SBarry.Harding@Sun.COM } 254510506SBarry.Harding@Sun.COM /* Configure store-and-forward for TX */ 254610506SBarry.Harding@Sun.COM yge_set_tx_stfwd(port); 254710506SBarry.Harding@Sun.COM } 254810506SBarry.Harding@Sun.COM 254910506SBarry.Harding@Sun.COM if ((dev->d_hw_id == CHIP_ID_YUKON_FE_P) && 255010506SBarry.Harding@Sun.COM (dev->d_hw_rev == CHIP_REV_YU_FE2_A0)) { 255110506SBarry.Harding@Sun.COM /* Disable dynamic watermark */ 255210506SBarry.Harding@Sun.COM reg = CSR_READ_4(dev, MR_ADDR(pnum, TX_GMF_EA)); 255310506SBarry.Harding@Sun.COM reg &= ~TX_DYN_WM_ENA; 255410506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_EA), reg); 255510506SBarry.Harding@Sun.COM } 255610506SBarry.Harding@Sun.COM 255710506SBarry.Harding@Sun.COM /* 255810506SBarry.Harding@Sun.COM * Disable Force Sync bit and Alloc bit in Tx RAM interface 255910506SBarry.Harding@Sun.COM * arbiter as we don't use Sync Tx queue. 256010506SBarry.Harding@Sun.COM */ 256110506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, MR_ADDR(pnum, TXA_CTRL), 256210506SBarry.Harding@Sun.COM TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC); 256310506SBarry.Harding@Sun.COM /* Enable the RAM Interface Arbiter. */ 256410506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, MR_ADDR(pnum, TXA_CTRL), TXA_ENA_ARB); 256510506SBarry.Harding@Sun.COM 256610506SBarry.Harding@Sun.COM /* Setup RAM buffer. */ 256710506SBarry.Harding@Sun.COM yge_set_rambuffer(port); 256810506SBarry.Harding@Sun.COM 256910506SBarry.Harding@Sun.COM /* Disable Tx sync Queue. */ 257010506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, RB_ADDR(port->p_txsq, RB_CTRL), RB_RST_SET); 257110506SBarry.Harding@Sun.COM 257210506SBarry.Harding@Sun.COM /* Setup Tx Queue Bus Memory Interface. */ 257310506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Q_ADDR(txq, Q_CSR), BMU_CLR_RESET); 257410506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Q_ADDR(txq, Q_CSR), BMU_OPER_INIT); 257510506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Q_ADDR(txq, Q_CSR), BMU_FIFO_OP_ON); 257610506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, Q_ADDR(txq, Q_WM), MSK_BMU_TX_WM); 257710506SBarry.Harding@Sun.COM 257810506SBarry.Harding@Sun.COM switch (dev->d_hw_id) { 257910506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_EC_U: 258010506SBarry.Harding@Sun.COM if (dev->d_hw_rev == CHIP_REV_YU_EC_U_A0) { 258110506SBarry.Harding@Sun.COM /* Fix for Yukon-EC Ultra: set BMU FIFO level */ 258210506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, Q_ADDR(txq, Q_AL), MSK_ECU_TXFF_LEV); 258310506SBarry.Harding@Sun.COM } 258410506SBarry.Harding@Sun.COM break; 258510506SBarry.Harding@Sun.COM case CHIP_ID_YUKON_EX: 258610506SBarry.Harding@Sun.COM /* 258710506SBarry.Harding@Sun.COM * Yukon Extreme seems to have silicon bug for 258810506SBarry.Harding@Sun.COM * automatic Tx checksum calculation capability. 258910506SBarry.Harding@Sun.COM */ 259010506SBarry.Harding@Sun.COM if (dev->d_hw_rev == CHIP_REV_YU_EX_B0) 259110506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Q_ADDR(txq, Q_F), F_TX_CHK_AUTO_OFF); 259210506SBarry.Harding@Sun.COM break; 259310506SBarry.Harding@Sun.COM } 259410506SBarry.Harding@Sun.COM 259510506SBarry.Harding@Sun.COM /* Setup Rx Queue Bus Memory Interface. */ 259610506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Q_ADDR(rxq, Q_CSR), BMU_CLR_RESET); 259710506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Q_ADDR(rxq, Q_CSR), BMU_OPER_INIT); 259810506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Q_ADDR(rxq, Q_CSR), BMU_FIFO_OP_ON); 259910506SBarry.Harding@Sun.COM if (dev->d_bustype == PEX_BUS) { 260010506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, Q_ADDR(rxq, Q_WM), 0x80); 260110506SBarry.Harding@Sun.COM } else { 260210506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, Q_ADDR(rxq, Q_WM), MSK_BMU_RX_WM); 260310506SBarry.Harding@Sun.COM } 260410506SBarry.Harding@Sun.COM if (dev->d_hw_id == CHIP_ID_YUKON_EC_U && 260510506SBarry.Harding@Sun.COM dev->d_hw_rev >= CHIP_REV_YU_EC_U_A1) { 260610506SBarry.Harding@Sun.COM /* MAC Rx RAM Read is controlled by hardware. */ 260710506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Q_ADDR(rxq, Q_F), F_M_RX_RAM_DIS); 260810506SBarry.Harding@Sun.COM } 260910506SBarry.Harding@Sun.COM 261010506SBarry.Harding@Sun.COM yge_init_tx_ring(port); 261110506SBarry.Harding@Sun.COM 261210506SBarry.Harding@Sun.COM /* Disable Rx checksum offload and RSS hash. */ 261310506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Q_ADDR(rxq, Q_CSR), 261410506SBarry.Harding@Sun.COM BMU_DIS_RX_CHKSUM | BMU_DIS_RX_RSS_HASH); 261510506SBarry.Harding@Sun.COM 261610506SBarry.Harding@Sun.COM yge_init_rx_ring(port); 261710506SBarry.Harding@Sun.COM 261810506SBarry.Harding@Sun.COM /* Configure interrupt handling. */ 261910506SBarry.Harding@Sun.COM if (port == dev->d_port[YGE_PORT_A]) { 262010506SBarry.Harding@Sun.COM dev->d_intrmask |= Y2_IS_PORT_A; 262110506SBarry.Harding@Sun.COM dev->d_intrhwemask |= Y2_HWE_L1_MASK; 262210506SBarry.Harding@Sun.COM } else if (port == dev->d_port[YGE_PORT_B]) { 262310506SBarry.Harding@Sun.COM dev->d_intrmask |= Y2_IS_PORT_B; 262410506SBarry.Harding@Sun.COM dev->d_intrhwemask |= Y2_HWE_L2_MASK; 262510506SBarry.Harding@Sun.COM } 262610506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_HWE_IMSK, dev->d_intrhwemask); 262710506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B0_HWE_IMSK); 262810506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_IMSK, dev->d_intrmask); 262910506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B0_IMSK); 263010506SBarry.Harding@Sun.COM 263110506SBarry.Harding@Sun.COM /* Enable RX/TX GMAC */ 263210506SBarry.Harding@Sun.COM gmac = GMAC_READ_2(dev, pnum, GM_GP_CTRL); 263310506SBarry.Harding@Sun.COM gmac |= (GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); 263410506SBarry.Harding@Sun.COM GMAC_WRITE_2(port->p_dev, port->p_port, GM_GP_CTRL, gmac); 263510506SBarry.Harding@Sun.COM /* Read again to ensure writing. */ 263610506SBarry.Harding@Sun.COM (void) GMAC_READ_2(dev, pnum, GM_GP_CTRL); 263710506SBarry.Harding@Sun.COM 263810506SBarry.Harding@Sun.COM /* Reset TX timer */ 263910506SBarry.Harding@Sun.COM port->p_tx_wdog = 0; 264010506SBarry.Harding@Sun.COM } 264110506SBarry.Harding@Sun.COM 264210506SBarry.Harding@Sun.COM static void 264310506SBarry.Harding@Sun.COM yge_set_rambuffer(yge_port_t *port) 264410506SBarry.Harding@Sun.COM { 264510506SBarry.Harding@Sun.COM yge_dev_t *dev; 264610506SBarry.Harding@Sun.COM int ltpp, utpp; 264710506SBarry.Harding@Sun.COM int pnum; 264810506SBarry.Harding@Sun.COM uint32_t rxq; 264910506SBarry.Harding@Sun.COM uint32_t txq; 265010506SBarry.Harding@Sun.COM 265110506SBarry.Harding@Sun.COM dev = port->p_dev; 265210506SBarry.Harding@Sun.COM pnum = port->p_port; 265310506SBarry.Harding@Sun.COM rxq = port->p_rxq; 265410506SBarry.Harding@Sun.COM txq = port->p_txq; 265510506SBarry.Harding@Sun.COM 265610506SBarry.Harding@Sun.COM if ((port->p_flags & PORT_FLAG_RAMBUF) == 0) 265710506SBarry.Harding@Sun.COM return; 265810506SBarry.Harding@Sun.COM 265910506SBarry.Harding@Sun.COM /* Setup Rx Queue. */ 266010506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, RB_ADDR(rxq, RB_CTRL), RB_RST_CLR); 266110506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, RB_ADDR(rxq, RB_START), dev->d_rxqstart[pnum] / 8); 266210506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, RB_ADDR(rxq, RB_END), dev->d_rxqend[pnum] / 8); 266310506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, RB_ADDR(rxq, RB_WP), dev->d_rxqstart[pnum] / 8); 266410506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, RB_ADDR(rxq, RB_RP), dev->d_rxqstart[pnum] / 8); 266510506SBarry.Harding@Sun.COM 266610506SBarry.Harding@Sun.COM utpp = 266710506SBarry.Harding@Sun.COM (dev->d_rxqend[pnum] + 1 - dev->d_rxqstart[pnum] - RB_ULPP) / 8; 266810506SBarry.Harding@Sun.COM ltpp = 266910506SBarry.Harding@Sun.COM (dev->d_rxqend[pnum] + 1 - dev->d_rxqstart[pnum] - RB_LLPP_B) / 8; 267010506SBarry.Harding@Sun.COM 267110506SBarry.Harding@Sun.COM if (dev->d_rxqsize < MSK_MIN_RXQ_SIZE) 267210506SBarry.Harding@Sun.COM ltpp += (RB_LLPP_B - RB_LLPP_S) / 8; 267310506SBarry.Harding@Sun.COM 267410506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, RB_ADDR(rxq, RB_RX_UTPP), utpp); 267510506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, RB_ADDR(rxq, RB_RX_LTPP), ltpp); 267610506SBarry.Harding@Sun.COM /* Set Rx priority(RB_RX_UTHP/RB_RX_LTHP) thresholds? */ 267710506SBarry.Harding@Sun.COM 267810506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, RB_ADDR(rxq, RB_CTRL), RB_ENA_OP_MD); 267910506SBarry.Harding@Sun.COM (void) CSR_READ_1(dev, RB_ADDR(rxq, RB_CTRL)); 268010506SBarry.Harding@Sun.COM 268110506SBarry.Harding@Sun.COM /* Setup Tx Queue. */ 268210506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, RB_ADDR(txq, RB_CTRL), RB_RST_CLR); 268310506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, RB_ADDR(txq, RB_START), dev->d_txqstart[pnum] / 8); 268410506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, RB_ADDR(txq, RB_END), dev->d_txqend[pnum] / 8); 268510506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, RB_ADDR(txq, RB_WP), dev->d_txqstart[pnum] / 8); 268610506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, RB_ADDR(txq, RB_RP), dev->d_txqstart[pnum] / 8); 268710506SBarry.Harding@Sun.COM /* Enable Store & Forward for Tx side. */ 268810506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, RB_ADDR(txq, RB_CTRL), RB_ENA_STFWD); 268910506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, RB_ADDR(txq, RB_CTRL), RB_ENA_OP_MD); 269010506SBarry.Harding@Sun.COM (void) CSR_READ_1(dev, RB_ADDR(txq, RB_CTRL)); 269110506SBarry.Harding@Sun.COM } 269210506SBarry.Harding@Sun.COM 269310506SBarry.Harding@Sun.COM static void 269410506SBarry.Harding@Sun.COM yge_set_prefetch(yge_dev_t *dev, int qaddr, yge_ring_t *ring) 269510506SBarry.Harding@Sun.COM { 269610506SBarry.Harding@Sun.COM /* Reset the prefetch unit. */ 269710506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_CTRL_REG), 269810506SBarry.Harding@Sun.COM PREF_UNIT_RST_SET); 269910506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_CTRL_REG), 270010506SBarry.Harding@Sun.COM PREF_UNIT_RST_CLR); 270110506SBarry.Harding@Sun.COM /* Set LE base address. */ 270210506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_ADDR_LOW_REG), 270310506SBarry.Harding@Sun.COM YGE_ADDR_LO(ring->r_paddr)); 270410506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_ADDR_HI_REG), 270510506SBarry.Harding@Sun.COM YGE_ADDR_HI(ring->r_paddr)); 270610506SBarry.Harding@Sun.COM /* Set the list last index. */ 270710506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_LAST_IDX_REG), 270810506SBarry.Harding@Sun.COM ring->r_num - 1); 270910506SBarry.Harding@Sun.COM /* Turn on prefetch unit. */ 271010506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_CTRL_REG), 271110506SBarry.Harding@Sun.COM PREF_UNIT_OP_ON); 271210506SBarry.Harding@Sun.COM /* Dummy read to ensure write. */ 271310506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, Y2_PREF_Q_ADDR(qaddr, PREF_UNIT_CTRL_REG)); 271410506SBarry.Harding@Sun.COM } 271510506SBarry.Harding@Sun.COM 271610506SBarry.Harding@Sun.COM static void 271710506SBarry.Harding@Sun.COM yge_stop_port(yge_port_t *port) 271810506SBarry.Harding@Sun.COM { 271910506SBarry.Harding@Sun.COM yge_dev_t *dev = port->p_dev; 272010506SBarry.Harding@Sun.COM int pnum = port->p_port; 272110506SBarry.Harding@Sun.COM uint32_t txq = port->p_txq; 272210506SBarry.Harding@Sun.COM uint32_t rxq = port->p_rxq; 272310506SBarry.Harding@Sun.COM uint32_t val; 272410506SBarry.Harding@Sun.COM int i; 272510506SBarry.Harding@Sun.COM 272610506SBarry.Harding@Sun.COM dev = port->p_dev; 272710506SBarry.Harding@Sun.COM 272810506SBarry.Harding@Sun.COM /* 272910506SBarry.Harding@Sun.COM * shutdown timeout 273010506SBarry.Harding@Sun.COM */ 273110506SBarry.Harding@Sun.COM port->p_tx_wdog = 0; 273210506SBarry.Harding@Sun.COM 273310506SBarry.Harding@Sun.COM /* Disable interrupts. */ 273410506SBarry.Harding@Sun.COM if (pnum == YGE_PORT_A) { 273510506SBarry.Harding@Sun.COM dev->d_intrmask &= ~Y2_IS_PORT_A; 273610506SBarry.Harding@Sun.COM dev->d_intrhwemask &= ~Y2_HWE_L1_MASK; 273710506SBarry.Harding@Sun.COM } else { 273810506SBarry.Harding@Sun.COM dev->d_intrmask &= ~Y2_IS_PORT_B; 273910506SBarry.Harding@Sun.COM dev->d_intrhwemask &= ~Y2_HWE_L2_MASK; 274010506SBarry.Harding@Sun.COM } 274110506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_HWE_IMSK, dev->d_intrhwemask); 274210506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B0_HWE_IMSK); 274310506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_IMSK, dev->d_intrmask); 274410506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B0_IMSK); 274510506SBarry.Harding@Sun.COM 274610506SBarry.Harding@Sun.COM /* Disable Tx/Rx MAC. */ 274710506SBarry.Harding@Sun.COM val = GMAC_READ_2(dev, pnum, GM_GP_CTRL); 274810506SBarry.Harding@Sun.COM val &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); 274910506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_GP_CTRL, val); 275010506SBarry.Harding@Sun.COM /* Read again to ensure writing. */ 275110506SBarry.Harding@Sun.COM (void) GMAC_READ_2(dev, pnum, GM_GP_CTRL); 275210506SBarry.Harding@Sun.COM 275310506SBarry.Harding@Sun.COM /* Update stats and clear counters. */ 275410506SBarry.Harding@Sun.COM yge_stats_update(port); 275510506SBarry.Harding@Sun.COM 275610506SBarry.Harding@Sun.COM /* Stop Tx BMU. */ 275710506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Q_ADDR(txq, Q_CSR), BMU_STOP); 275810506SBarry.Harding@Sun.COM val = CSR_READ_4(dev, Q_ADDR(txq, Q_CSR)); 275910506SBarry.Harding@Sun.COM for (i = 0; i < YGE_TIMEOUT; i += 10) { 276010506SBarry.Harding@Sun.COM if ((val & (BMU_STOP | BMU_IDLE)) == 0) { 276110506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Q_ADDR(txq, Q_CSR), BMU_STOP); 276210506SBarry.Harding@Sun.COM val = CSR_READ_4(dev, Q_ADDR(txq, Q_CSR)); 276310506SBarry.Harding@Sun.COM } else 276410506SBarry.Harding@Sun.COM break; 276510506SBarry.Harding@Sun.COM drv_usecwait(10); 276610506SBarry.Harding@Sun.COM } 276710506SBarry.Harding@Sun.COM /* This is probably fairly catastrophic. */ 276810506SBarry.Harding@Sun.COM if ((val & (BMU_STOP | BMU_IDLE)) == 0) 276910506SBarry.Harding@Sun.COM yge_error(NULL, port, "Tx BMU stop failed"); 277010506SBarry.Harding@Sun.COM 277110506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, RB_ADDR(txq, RB_CTRL), RB_RST_SET | RB_DIS_OP_MD); 277210506SBarry.Harding@Sun.COM 277310506SBarry.Harding@Sun.COM /* Disable all GMAC interrupt. */ 277410506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, MR_ADDR(pnum, GMAC_IRQ_MSK), 0); 277510506SBarry.Harding@Sun.COM 277610506SBarry.Harding@Sun.COM /* Disable the RAM Interface Arbiter. */ 277710506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, MR_ADDR(pnum, TXA_CTRL), TXA_DIS_ARB); 277810506SBarry.Harding@Sun.COM 277910506SBarry.Harding@Sun.COM /* Reset the PCI FIFO of the async Tx queue */ 278010506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Q_ADDR(txq, Q_CSR), BMU_RST_SET | BMU_FIFO_RST); 278110506SBarry.Harding@Sun.COM 278210506SBarry.Harding@Sun.COM /* Reset the Tx prefetch units. */ 278310506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Y2_PREF_Q_ADDR(txq, PREF_UNIT_CTRL_REG), 278410506SBarry.Harding@Sun.COM PREF_UNIT_RST_SET); 278510506SBarry.Harding@Sun.COM 278610506SBarry.Harding@Sun.COM /* Reset the RAM Buffer async Tx queue. */ 278710506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, RB_ADDR(txq, RB_CTRL), RB_RST_SET); 278810506SBarry.Harding@Sun.COM 278910506SBarry.Harding@Sun.COM /* Reset Tx MAC FIFO. */ 279010506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, TX_GMF_CTRL_T), GMF_RST_SET); 279110506SBarry.Harding@Sun.COM /* Set Pause Off. */ 279210506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, GMAC_CTRL), GMC_PAUSE_OFF); 279310506SBarry.Harding@Sun.COM 279410506SBarry.Harding@Sun.COM /* 279510506SBarry.Harding@Sun.COM * The Rx Stop command will not work for Yukon-2 if the BMU does not 279610506SBarry.Harding@Sun.COM * reach the end of packet and since we can't make sure that we have 279710506SBarry.Harding@Sun.COM * incoming data, we must reset the BMU while it is not during a DMA 279810506SBarry.Harding@Sun.COM * transfer. Since it is possible that the Rx path is still active, 279910506SBarry.Harding@Sun.COM * the Rx RAM buffer will be stopped first, so any possible incoming 280010506SBarry.Harding@Sun.COM * data will not trigger a DMA. After the RAM buffer is stopped, the 280110506SBarry.Harding@Sun.COM * BMU is polled until any DMA in progress is ended and only then it 280210506SBarry.Harding@Sun.COM * will be reset. 280310506SBarry.Harding@Sun.COM */ 280410506SBarry.Harding@Sun.COM 280510506SBarry.Harding@Sun.COM /* Disable the RAM Buffer receive queue. */ 280610506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, RB_ADDR(rxq, RB_CTRL), RB_DIS_OP_MD); 280710506SBarry.Harding@Sun.COM for (i = 0; i < YGE_TIMEOUT; i += 10) { 280810506SBarry.Harding@Sun.COM if (CSR_READ_1(dev, RB_ADDR(rxq, Q_RSL)) == 280910506SBarry.Harding@Sun.COM CSR_READ_1(dev, RB_ADDR(rxq, Q_RL))) 281010506SBarry.Harding@Sun.COM break; 281110506SBarry.Harding@Sun.COM drv_usecwait(10); 281210506SBarry.Harding@Sun.COM } 281310506SBarry.Harding@Sun.COM /* This is probably nearly a fatal error. */ 281410506SBarry.Harding@Sun.COM if (i == YGE_TIMEOUT) 281510506SBarry.Harding@Sun.COM yge_error(NULL, port, "Rx BMU stop failed"); 281610506SBarry.Harding@Sun.COM 281710506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Q_ADDR(rxq, Q_CSR), BMU_RST_SET | BMU_FIFO_RST); 281810506SBarry.Harding@Sun.COM /* Reset the Rx prefetch unit. */ 281910506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, Y2_PREF_Q_ADDR(rxq, PREF_UNIT_CTRL_REG), 282010506SBarry.Harding@Sun.COM PREF_UNIT_RST_SET); 282110506SBarry.Harding@Sun.COM /* Reset the RAM Buffer receive queue. */ 282210506SBarry.Harding@Sun.COM CSR_WRITE_1(dev, RB_ADDR(rxq, RB_CTRL), RB_RST_SET); 282310506SBarry.Harding@Sun.COM /* Reset Rx MAC FIFO. */ 282410506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, MR_ADDR(pnum, RX_GMF_CTRL_T), GMF_RST_SET); 282510506SBarry.Harding@Sun.COM } 282610506SBarry.Harding@Sun.COM 282710506SBarry.Harding@Sun.COM /* 282810506SBarry.Harding@Sun.COM * When GM_PAR_MIB_CLR bit of GM_PHY_ADDR is set, reading lower 282910506SBarry.Harding@Sun.COM * counter clears high 16 bits of the counter such that accessing 283010506SBarry.Harding@Sun.COM * lower 16 bits should be the last operation. 283110506SBarry.Harding@Sun.COM */ 283210506SBarry.Harding@Sun.COM #define YGE_READ_MIB32(x, y) \ 283310506SBarry.Harding@Sun.COM GMAC_READ_4(dev, x, y) 283410506SBarry.Harding@Sun.COM 283510506SBarry.Harding@Sun.COM #define YGE_READ_MIB64(x, y) \ 283610506SBarry.Harding@Sun.COM ((((uint64_t)YGE_READ_MIB32(x, (y) + 8)) << 32) + \ 283710506SBarry.Harding@Sun.COM (uint64_t)YGE_READ_MIB32(x, y)) 283810506SBarry.Harding@Sun.COM 283910506SBarry.Harding@Sun.COM static void 284010506SBarry.Harding@Sun.COM yge_stats_clear(yge_port_t *port) 284110506SBarry.Harding@Sun.COM { 284210506SBarry.Harding@Sun.COM yge_dev_t *dev; 284310506SBarry.Harding@Sun.COM uint16_t gmac; 284410506SBarry.Harding@Sun.COM int32_t pnum; 284510506SBarry.Harding@Sun.COM 284610506SBarry.Harding@Sun.COM pnum = port->p_port; 284710506SBarry.Harding@Sun.COM dev = port->p_dev; 284810506SBarry.Harding@Sun.COM 284910506SBarry.Harding@Sun.COM /* Set MIB Clear Counter Mode. */ 285010506SBarry.Harding@Sun.COM gmac = GMAC_READ_2(dev, pnum, GM_PHY_ADDR); 285110506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_PHY_ADDR, gmac | GM_PAR_MIB_CLR); 285210506SBarry.Harding@Sun.COM /* Read all MIB Counters with Clear Mode set. */ 285310506SBarry.Harding@Sun.COM for (int i = GM_RXF_UC_OK; i <= GM_TXE_FIFO_UR; i += 4) 285410506SBarry.Harding@Sun.COM (void) YGE_READ_MIB32(pnum, i); 285510506SBarry.Harding@Sun.COM /* Clear MIB Clear Counter Mode. */ 285610506SBarry.Harding@Sun.COM gmac &= ~GM_PAR_MIB_CLR; 285710506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_PHY_ADDR, gmac); 285810506SBarry.Harding@Sun.COM } 285910506SBarry.Harding@Sun.COM 286010506SBarry.Harding@Sun.COM static void 286110506SBarry.Harding@Sun.COM yge_stats_update(yge_port_t *port) 286210506SBarry.Harding@Sun.COM { 286310506SBarry.Harding@Sun.COM yge_dev_t *dev; 286410506SBarry.Harding@Sun.COM struct yge_hw_stats *stats; 286510506SBarry.Harding@Sun.COM uint16_t gmac; 286610506SBarry.Harding@Sun.COM int32_t pnum; 286710506SBarry.Harding@Sun.COM 286810506SBarry.Harding@Sun.COM dev = port->p_dev; 286910506SBarry.Harding@Sun.COM pnum = port->p_port; 287010506SBarry.Harding@Sun.COM 287110506SBarry.Harding@Sun.COM if (dev->d_suspended || !port->p_running) { 287210506SBarry.Harding@Sun.COM return; 287310506SBarry.Harding@Sun.COM } 287410506SBarry.Harding@Sun.COM stats = &port->p_stats; 287510506SBarry.Harding@Sun.COM /* Set MIB Clear Counter Mode. */ 287610506SBarry.Harding@Sun.COM gmac = GMAC_READ_2(dev, pnum, GM_PHY_ADDR); 287710506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_PHY_ADDR, gmac | GM_PAR_MIB_CLR); 287810506SBarry.Harding@Sun.COM 287910506SBarry.Harding@Sun.COM /* Rx stats. */ 288010506SBarry.Harding@Sun.COM stats->rx_ucast_frames += YGE_READ_MIB32(pnum, GM_RXF_UC_OK); 288110506SBarry.Harding@Sun.COM stats->rx_bcast_frames += YGE_READ_MIB32(pnum, GM_RXF_BC_OK); 288210506SBarry.Harding@Sun.COM stats->rx_pause_frames += YGE_READ_MIB32(pnum, GM_RXF_MPAUSE); 288310506SBarry.Harding@Sun.COM stats->rx_mcast_frames += YGE_READ_MIB32(pnum, GM_RXF_MC_OK); 288410506SBarry.Harding@Sun.COM stats->rx_crc_errs += YGE_READ_MIB32(pnum, GM_RXF_FCS_ERR); 288510506SBarry.Harding@Sun.COM (void) YGE_READ_MIB32(pnum, GM_RXF_SPARE1); 288610506SBarry.Harding@Sun.COM stats->rx_good_octets += YGE_READ_MIB64(pnum, GM_RXO_OK_LO); 288710506SBarry.Harding@Sun.COM stats->rx_bad_octets += YGE_READ_MIB64(pnum, GM_RXO_ERR_LO); 288810506SBarry.Harding@Sun.COM stats->rx_runts += YGE_READ_MIB32(pnum, GM_RXF_SHT); 288910506SBarry.Harding@Sun.COM stats->rx_runt_errs += YGE_READ_MIB32(pnum, GM_RXE_FRAG); 289010506SBarry.Harding@Sun.COM stats->rx_pkts_64 += YGE_READ_MIB32(pnum, GM_RXF_64B); 289110506SBarry.Harding@Sun.COM stats->rx_pkts_65_127 += YGE_READ_MIB32(pnum, GM_RXF_127B); 289210506SBarry.Harding@Sun.COM stats->rx_pkts_128_255 += YGE_READ_MIB32(pnum, GM_RXF_255B); 289310506SBarry.Harding@Sun.COM stats->rx_pkts_256_511 += YGE_READ_MIB32(pnum, GM_RXF_511B); 289410506SBarry.Harding@Sun.COM stats->rx_pkts_512_1023 += YGE_READ_MIB32(pnum, GM_RXF_1023B); 289510506SBarry.Harding@Sun.COM stats->rx_pkts_1024_1518 += YGE_READ_MIB32(pnum, GM_RXF_1518B); 289610506SBarry.Harding@Sun.COM stats->rx_pkts_1519_max += YGE_READ_MIB32(pnum, GM_RXF_MAX_SZ); 289710506SBarry.Harding@Sun.COM stats->rx_pkts_too_long += YGE_READ_MIB32(pnum, GM_RXF_LNG_ERR); 289810506SBarry.Harding@Sun.COM stats->rx_pkts_jabbers += YGE_READ_MIB32(pnum, GM_RXF_JAB_PKT); 289910506SBarry.Harding@Sun.COM (void) YGE_READ_MIB32(pnum, GM_RXF_SPARE2); 290010506SBarry.Harding@Sun.COM stats->rx_fifo_oflows += YGE_READ_MIB32(pnum, GM_RXE_FIFO_OV); 290110506SBarry.Harding@Sun.COM (void) YGE_READ_MIB32(pnum, GM_RXF_SPARE3); 290210506SBarry.Harding@Sun.COM 290310506SBarry.Harding@Sun.COM /* Tx stats. */ 290410506SBarry.Harding@Sun.COM stats->tx_ucast_frames += YGE_READ_MIB32(pnum, GM_TXF_UC_OK); 290510506SBarry.Harding@Sun.COM stats->tx_bcast_frames += YGE_READ_MIB32(pnum, GM_TXF_BC_OK); 290610506SBarry.Harding@Sun.COM stats->tx_pause_frames += YGE_READ_MIB32(pnum, GM_TXF_MPAUSE); 290710506SBarry.Harding@Sun.COM stats->tx_mcast_frames += YGE_READ_MIB32(pnum, GM_TXF_MC_OK); 290810506SBarry.Harding@Sun.COM stats->tx_octets += YGE_READ_MIB64(pnum, GM_TXO_OK_LO); 290910506SBarry.Harding@Sun.COM stats->tx_pkts_64 += YGE_READ_MIB32(pnum, GM_TXF_64B); 291010506SBarry.Harding@Sun.COM stats->tx_pkts_65_127 += YGE_READ_MIB32(pnum, GM_TXF_127B); 291110506SBarry.Harding@Sun.COM stats->tx_pkts_128_255 += YGE_READ_MIB32(pnum, GM_TXF_255B); 291210506SBarry.Harding@Sun.COM stats->tx_pkts_256_511 += YGE_READ_MIB32(pnum, GM_TXF_511B); 291310506SBarry.Harding@Sun.COM stats->tx_pkts_512_1023 += YGE_READ_MIB32(pnum, GM_TXF_1023B); 291410506SBarry.Harding@Sun.COM stats->tx_pkts_1024_1518 += YGE_READ_MIB32(pnum, GM_TXF_1518B); 291510506SBarry.Harding@Sun.COM stats->tx_pkts_1519_max += YGE_READ_MIB32(pnum, GM_TXF_MAX_SZ); 291610506SBarry.Harding@Sun.COM (void) YGE_READ_MIB32(pnum, GM_TXF_SPARE1); 291710506SBarry.Harding@Sun.COM stats->tx_colls += YGE_READ_MIB32(pnum, GM_TXF_COL); 291810506SBarry.Harding@Sun.COM stats->tx_late_colls += YGE_READ_MIB32(pnum, GM_TXF_LAT_COL); 291910506SBarry.Harding@Sun.COM stats->tx_excess_colls += YGE_READ_MIB32(pnum, GM_TXF_ABO_COL); 292010506SBarry.Harding@Sun.COM stats->tx_multi_colls += YGE_READ_MIB32(pnum, GM_TXF_MUL_COL); 292110506SBarry.Harding@Sun.COM stats->tx_single_colls += YGE_READ_MIB32(pnum, GM_TXF_SNG_COL); 292210506SBarry.Harding@Sun.COM stats->tx_underflows += YGE_READ_MIB32(pnum, GM_TXE_FIFO_UR); 292310506SBarry.Harding@Sun.COM /* Clear MIB Clear Counter Mode. */ 292410506SBarry.Harding@Sun.COM gmac &= ~GM_PAR_MIB_CLR; 292510506SBarry.Harding@Sun.COM GMAC_WRITE_2(dev, pnum, GM_PHY_ADDR, gmac); 292610506SBarry.Harding@Sun.COM } 292710506SBarry.Harding@Sun.COM 292810506SBarry.Harding@Sun.COM #undef YGE_READ_MIB32 292910506SBarry.Harding@Sun.COM #undef YGE_READ_MIB64 293010506SBarry.Harding@Sun.COM 293110506SBarry.Harding@Sun.COM uint32_t 293210506SBarry.Harding@Sun.COM yge_hashbit(const uint8_t *addr) 293310506SBarry.Harding@Sun.COM { 293410506SBarry.Harding@Sun.COM int idx; 293510506SBarry.Harding@Sun.COM int bit; 293610506SBarry.Harding@Sun.COM uint_t data; 293710506SBarry.Harding@Sun.COM uint32_t crc; 293810506SBarry.Harding@Sun.COM #define POLY_BE 0x04c11db7 293910506SBarry.Harding@Sun.COM 294010506SBarry.Harding@Sun.COM crc = 0xffffffff; 294110506SBarry.Harding@Sun.COM for (idx = 0; idx < 6; idx++) { 294210506SBarry.Harding@Sun.COM for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) { 294310506SBarry.Harding@Sun.COM crc = (crc << 1) 294410506SBarry.Harding@Sun.COM ^ ((((crc >> 31) ^ data) & 1) ? POLY_BE : 0); 294510506SBarry.Harding@Sun.COM } 294610506SBarry.Harding@Sun.COM } 294710506SBarry.Harding@Sun.COM #undef POLY_BE 294810506SBarry.Harding@Sun.COM 294910506SBarry.Harding@Sun.COM return (crc % 64); 295010506SBarry.Harding@Sun.COM } 295110506SBarry.Harding@Sun.COM 295210506SBarry.Harding@Sun.COM int 295310506SBarry.Harding@Sun.COM yge_m_stat(void *arg, uint_t stat, uint64_t *val) 295410506SBarry.Harding@Sun.COM { 295510506SBarry.Harding@Sun.COM yge_port_t *port = arg; 295610506SBarry.Harding@Sun.COM struct yge_hw_stats *stats = &port->p_stats; 295710506SBarry.Harding@Sun.COM 295810506SBarry.Harding@Sun.COM if (stat == MAC_STAT_IFSPEED) { 295910506SBarry.Harding@Sun.COM /* 296010506SBarry.Harding@Sun.COM * This is the first stat we are asked about. We update only 296110506SBarry.Harding@Sun.COM * for this stat, to avoid paying the hefty cost of the update 296210506SBarry.Harding@Sun.COM * once for each stat. 296310506SBarry.Harding@Sun.COM */ 296410506SBarry.Harding@Sun.COM DEV_LOCK(port->p_dev); 296510506SBarry.Harding@Sun.COM yge_stats_update(port); 296610506SBarry.Harding@Sun.COM DEV_UNLOCK(port->p_dev); 296710506SBarry.Harding@Sun.COM } 296810506SBarry.Harding@Sun.COM 296910506SBarry.Harding@Sun.COM if (mii_m_getstat(port->p_mii, stat, val) == 0) { 297010506SBarry.Harding@Sun.COM return (0); 297110506SBarry.Harding@Sun.COM } 297210506SBarry.Harding@Sun.COM 297310506SBarry.Harding@Sun.COM switch (stat) { 297410506SBarry.Harding@Sun.COM case MAC_STAT_MULTIRCV: 297510506SBarry.Harding@Sun.COM *val = stats->rx_mcast_frames; 297610506SBarry.Harding@Sun.COM break; 297710506SBarry.Harding@Sun.COM 297810506SBarry.Harding@Sun.COM case MAC_STAT_BRDCSTRCV: 297910506SBarry.Harding@Sun.COM *val = stats->rx_bcast_frames; 298010506SBarry.Harding@Sun.COM break; 298110506SBarry.Harding@Sun.COM 298210506SBarry.Harding@Sun.COM case MAC_STAT_MULTIXMT: 298310506SBarry.Harding@Sun.COM *val = stats->tx_mcast_frames; 298410506SBarry.Harding@Sun.COM break; 298510506SBarry.Harding@Sun.COM 298610506SBarry.Harding@Sun.COM case MAC_STAT_BRDCSTXMT: 298710506SBarry.Harding@Sun.COM *val = stats->tx_bcast_frames; 298810506SBarry.Harding@Sun.COM break; 298910506SBarry.Harding@Sun.COM 299010506SBarry.Harding@Sun.COM case MAC_STAT_IPACKETS: 299110506SBarry.Harding@Sun.COM *val = stats->rx_ucast_frames; 299210506SBarry.Harding@Sun.COM break; 299310506SBarry.Harding@Sun.COM 299410506SBarry.Harding@Sun.COM case MAC_STAT_RBYTES: 299510506SBarry.Harding@Sun.COM *val = stats->rx_good_octets; 299610506SBarry.Harding@Sun.COM break; 299710506SBarry.Harding@Sun.COM 299810506SBarry.Harding@Sun.COM case MAC_STAT_OPACKETS: 299910506SBarry.Harding@Sun.COM *val = stats->tx_ucast_frames; 300010506SBarry.Harding@Sun.COM break; 300110506SBarry.Harding@Sun.COM 300210506SBarry.Harding@Sun.COM case MAC_STAT_OBYTES: 300310506SBarry.Harding@Sun.COM *val = stats->tx_octets; 300410506SBarry.Harding@Sun.COM break; 300510506SBarry.Harding@Sun.COM 300610506SBarry.Harding@Sun.COM case MAC_STAT_NORCVBUF: 300710506SBarry.Harding@Sun.COM *val = stats->rx_nobuf; 300810506SBarry.Harding@Sun.COM break; 300910506SBarry.Harding@Sun.COM 301010506SBarry.Harding@Sun.COM case MAC_STAT_COLLISIONS: 301110506SBarry.Harding@Sun.COM *val = stats->tx_colls; 301210506SBarry.Harding@Sun.COM break; 301310506SBarry.Harding@Sun.COM 301410506SBarry.Harding@Sun.COM case ETHER_STAT_ALIGN_ERRORS: 301510506SBarry.Harding@Sun.COM *val = stats->rx_runt_errs; 301610506SBarry.Harding@Sun.COM break; 301710506SBarry.Harding@Sun.COM 301810506SBarry.Harding@Sun.COM case ETHER_STAT_FCS_ERRORS: 301910506SBarry.Harding@Sun.COM *val = stats->rx_crc_errs; 302010506SBarry.Harding@Sun.COM break; 302110506SBarry.Harding@Sun.COM 302210506SBarry.Harding@Sun.COM case ETHER_STAT_FIRST_COLLISIONS: 302310506SBarry.Harding@Sun.COM *val = stats->tx_single_colls; 302410506SBarry.Harding@Sun.COM break; 302510506SBarry.Harding@Sun.COM 302610506SBarry.Harding@Sun.COM case ETHER_STAT_MULTI_COLLISIONS: 302710506SBarry.Harding@Sun.COM *val = stats->tx_multi_colls; 302810506SBarry.Harding@Sun.COM break; 302910506SBarry.Harding@Sun.COM 303010506SBarry.Harding@Sun.COM case ETHER_STAT_TX_LATE_COLLISIONS: 303110506SBarry.Harding@Sun.COM *val = stats->tx_late_colls; 303210506SBarry.Harding@Sun.COM break; 303310506SBarry.Harding@Sun.COM 303410506SBarry.Harding@Sun.COM case ETHER_STAT_EX_COLLISIONS: 303510506SBarry.Harding@Sun.COM *val = stats->tx_excess_colls; 303610506SBarry.Harding@Sun.COM break; 303710506SBarry.Harding@Sun.COM 303810506SBarry.Harding@Sun.COM case ETHER_STAT_TOOLONG_ERRORS: 303910506SBarry.Harding@Sun.COM *val = stats->rx_pkts_too_long; 304010506SBarry.Harding@Sun.COM break; 304110506SBarry.Harding@Sun.COM 304210506SBarry.Harding@Sun.COM case MAC_STAT_OVERFLOWS: 304310506SBarry.Harding@Sun.COM *val = stats->rx_fifo_oflows; 304410506SBarry.Harding@Sun.COM break; 304510506SBarry.Harding@Sun.COM 304610506SBarry.Harding@Sun.COM case MAC_STAT_UNDERFLOWS: 304710506SBarry.Harding@Sun.COM *val = stats->tx_underflows; 304810506SBarry.Harding@Sun.COM break; 304910506SBarry.Harding@Sun.COM 305010506SBarry.Harding@Sun.COM case ETHER_STAT_TOOSHORT_ERRORS: 305110506SBarry.Harding@Sun.COM *val = stats->rx_runts; 305210506SBarry.Harding@Sun.COM break; 305310506SBarry.Harding@Sun.COM 305410506SBarry.Harding@Sun.COM case ETHER_STAT_JABBER_ERRORS: 305510506SBarry.Harding@Sun.COM *val = stats->rx_pkts_jabbers; 305610506SBarry.Harding@Sun.COM break; 305710506SBarry.Harding@Sun.COM 305810506SBarry.Harding@Sun.COM default: 305910506SBarry.Harding@Sun.COM return (ENOTSUP); 306010506SBarry.Harding@Sun.COM } 306110506SBarry.Harding@Sun.COM return (0); 306210506SBarry.Harding@Sun.COM } 306310506SBarry.Harding@Sun.COM 306410506SBarry.Harding@Sun.COM int 306510506SBarry.Harding@Sun.COM yge_m_start(void *arg) 306610506SBarry.Harding@Sun.COM { 306710506SBarry.Harding@Sun.COM yge_port_t *port = arg; 306810506SBarry.Harding@Sun.COM 306910506SBarry.Harding@Sun.COM DEV_LOCK(port->p_dev); 307010506SBarry.Harding@Sun.COM 307110506SBarry.Harding@Sun.COM /* 307210506SBarry.Harding@Sun.COM * We defer resource allocation to this point, because we 307310506SBarry.Harding@Sun.COM * don't want to waste DMA resources that might better be used 307410506SBarry.Harding@Sun.COM * elsewhere, if the port is not actually being used. 307510506SBarry.Harding@Sun.COM * 307610506SBarry.Harding@Sun.COM * Furthermore, this gives us a more graceful handling of dynamic 307710506SBarry.Harding@Sun.COM * MTU modification. 307810506SBarry.Harding@Sun.COM */ 307910506SBarry.Harding@Sun.COM if (yge_txrx_dma_alloc(port) != DDI_SUCCESS) { 308010506SBarry.Harding@Sun.COM /* Make sure we free up partially allocated resources. */ 308110506SBarry.Harding@Sun.COM yge_txrx_dma_free(port); 308210506SBarry.Harding@Sun.COM DEV_UNLOCK(port->p_dev); 308310506SBarry.Harding@Sun.COM return (ENOMEM); 308410506SBarry.Harding@Sun.COM } 308510506SBarry.Harding@Sun.COM 308610506SBarry.Harding@Sun.COM if (!port->p_dev->d_suspended) 308710506SBarry.Harding@Sun.COM yge_start_port(port); 308810506SBarry.Harding@Sun.COM port->p_running = B_TRUE; 308910506SBarry.Harding@Sun.COM DEV_UNLOCK(port->p_dev); 309010506SBarry.Harding@Sun.COM 309110506SBarry.Harding@Sun.COM mii_start(port->p_mii); 309210506SBarry.Harding@Sun.COM 309310506SBarry.Harding@Sun.COM return (0); 309410506SBarry.Harding@Sun.COM } 309510506SBarry.Harding@Sun.COM 309610506SBarry.Harding@Sun.COM void 309710506SBarry.Harding@Sun.COM yge_m_stop(void *arg) 309810506SBarry.Harding@Sun.COM { 309910506SBarry.Harding@Sun.COM yge_port_t *port = arg; 310010506SBarry.Harding@Sun.COM yge_dev_t *dev = port->p_dev; 310110506SBarry.Harding@Sun.COM 310210506SBarry.Harding@Sun.COM DEV_LOCK(dev); 310310506SBarry.Harding@Sun.COM if (!dev->d_suspended) 310410506SBarry.Harding@Sun.COM yge_stop_port(port); 310510506SBarry.Harding@Sun.COM 310610506SBarry.Harding@Sun.COM port->p_running = B_FALSE; 310710506SBarry.Harding@Sun.COM 310810506SBarry.Harding@Sun.COM /* Release resources we don't need */ 310910506SBarry.Harding@Sun.COM yge_txrx_dma_free(port); 311010506SBarry.Harding@Sun.COM DEV_UNLOCK(dev); 311110506SBarry.Harding@Sun.COM } 311210506SBarry.Harding@Sun.COM 311310506SBarry.Harding@Sun.COM int 311410506SBarry.Harding@Sun.COM yge_m_promisc(void *arg, boolean_t on) 311510506SBarry.Harding@Sun.COM { 311610506SBarry.Harding@Sun.COM yge_port_t *port = arg; 311710506SBarry.Harding@Sun.COM 311810506SBarry.Harding@Sun.COM DEV_LOCK(port->p_dev); 311910506SBarry.Harding@Sun.COM 312010506SBarry.Harding@Sun.COM /* Save current promiscuous mode. */ 312110506SBarry.Harding@Sun.COM port->p_promisc = on; 312210506SBarry.Harding@Sun.COM yge_setrxfilt(port); 312310506SBarry.Harding@Sun.COM 312410506SBarry.Harding@Sun.COM DEV_UNLOCK(port->p_dev); 312510506SBarry.Harding@Sun.COM 312610506SBarry.Harding@Sun.COM return (0); 312710506SBarry.Harding@Sun.COM } 312810506SBarry.Harding@Sun.COM 312910506SBarry.Harding@Sun.COM int 313010506SBarry.Harding@Sun.COM yge_m_multicst(void *arg, boolean_t add, const uint8_t *addr) 313110506SBarry.Harding@Sun.COM { 313210506SBarry.Harding@Sun.COM yge_port_t *port = arg; 313310506SBarry.Harding@Sun.COM int bit; 313410506SBarry.Harding@Sun.COM boolean_t update; 313510506SBarry.Harding@Sun.COM 313610506SBarry.Harding@Sun.COM bit = yge_hashbit(addr); 313710506SBarry.Harding@Sun.COM ASSERT(bit < 64); 313810506SBarry.Harding@Sun.COM 313910506SBarry.Harding@Sun.COM DEV_LOCK(port->p_dev); 314010506SBarry.Harding@Sun.COM if (add) { 314110506SBarry.Harding@Sun.COM if (port->p_mccount[bit] == 0) { 314210506SBarry.Harding@Sun.COM /* Set the corresponding bit in the hash table. */ 314310506SBarry.Harding@Sun.COM port->p_mchash[bit / 32] |= (1 << (bit % 32)); 314410506SBarry.Harding@Sun.COM update = B_TRUE; 314510506SBarry.Harding@Sun.COM } 314610506SBarry.Harding@Sun.COM port->p_mccount[bit]++; 314710506SBarry.Harding@Sun.COM } else { 314810506SBarry.Harding@Sun.COM ASSERT(port->p_mccount[bit] > 0); 314910506SBarry.Harding@Sun.COM port->p_mccount[bit]--; 315010506SBarry.Harding@Sun.COM if (port->p_mccount[bit] == 0) { 315110506SBarry.Harding@Sun.COM port->p_mchash[bit / 32] &= ~(1 << (bit % 32)); 315210506SBarry.Harding@Sun.COM update = B_TRUE; 315310506SBarry.Harding@Sun.COM } 315410506SBarry.Harding@Sun.COM } 315510506SBarry.Harding@Sun.COM 315610506SBarry.Harding@Sun.COM if (update) { 315710506SBarry.Harding@Sun.COM yge_setrxfilt(port); 315810506SBarry.Harding@Sun.COM } 315910506SBarry.Harding@Sun.COM DEV_UNLOCK(port->p_dev); 316010506SBarry.Harding@Sun.COM return (0); 316110506SBarry.Harding@Sun.COM } 316210506SBarry.Harding@Sun.COM 316310506SBarry.Harding@Sun.COM int 316410506SBarry.Harding@Sun.COM yge_m_unicst(void *arg, const uint8_t *macaddr) 316510506SBarry.Harding@Sun.COM { 316610506SBarry.Harding@Sun.COM yge_port_t *port = arg; 316710506SBarry.Harding@Sun.COM 316810506SBarry.Harding@Sun.COM DEV_LOCK(port->p_dev); 316910506SBarry.Harding@Sun.COM 317010506SBarry.Harding@Sun.COM bcopy(macaddr, port->p_curraddr, ETHERADDRL); 317110506SBarry.Harding@Sun.COM yge_setrxfilt(port); 317210506SBarry.Harding@Sun.COM 317310506SBarry.Harding@Sun.COM DEV_UNLOCK(port->p_dev); 317410506SBarry.Harding@Sun.COM 317510506SBarry.Harding@Sun.COM return (0); 317610506SBarry.Harding@Sun.COM } 317710506SBarry.Harding@Sun.COM 317810506SBarry.Harding@Sun.COM mblk_t * 317910506SBarry.Harding@Sun.COM yge_m_tx(void *arg, mblk_t *mp) 318010506SBarry.Harding@Sun.COM { 318110506SBarry.Harding@Sun.COM yge_port_t *port = arg; 318210506SBarry.Harding@Sun.COM mblk_t *nmp; 318310506SBarry.Harding@Sun.COM int enq = 0; 318410506SBarry.Harding@Sun.COM uint32_t ridx; 318510506SBarry.Harding@Sun.COM int idx; 318610506SBarry.Harding@Sun.COM boolean_t resched = B_FALSE; 318710506SBarry.Harding@Sun.COM 318810506SBarry.Harding@Sun.COM TX_LOCK(port->p_dev); 318910506SBarry.Harding@Sun.COM 319010506SBarry.Harding@Sun.COM if (port->p_dev->d_suspended) { 319110506SBarry.Harding@Sun.COM 319210506SBarry.Harding@Sun.COM TX_UNLOCK(port->p_dev); 319310506SBarry.Harding@Sun.COM 319410506SBarry.Harding@Sun.COM while ((nmp = mp) != NULL) { 319510506SBarry.Harding@Sun.COM /* carrier_errors++; */ 319610506SBarry.Harding@Sun.COM mp = mp->b_next; 319710506SBarry.Harding@Sun.COM freemsg(nmp); 319810506SBarry.Harding@Sun.COM } 319910506SBarry.Harding@Sun.COM return (NULL); 320010506SBarry.Harding@Sun.COM } 320110506SBarry.Harding@Sun.COM 320210506SBarry.Harding@Sun.COM /* attempt a reclaim */ 320310506SBarry.Harding@Sun.COM ridx = port->p_port == YGE_PORT_A ? 320410506SBarry.Harding@Sun.COM STAT_TXA1_RIDX : STAT_TXA2_RIDX; 320510506SBarry.Harding@Sun.COM idx = CSR_READ_2(port->p_dev, ridx); 320610506SBarry.Harding@Sun.COM if (port->p_tx_cons != idx) 320710506SBarry.Harding@Sun.COM resched = yge_txeof_locked(port, idx); 320810506SBarry.Harding@Sun.COM 320910506SBarry.Harding@Sun.COM while (mp != NULL) { 321010506SBarry.Harding@Sun.COM nmp = mp->b_next; 321110506SBarry.Harding@Sun.COM mp->b_next = NULL; 321210506SBarry.Harding@Sun.COM 321310506SBarry.Harding@Sun.COM if (!yge_send(port, mp)) { 321410506SBarry.Harding@Sun.COM mp->b_next = nmp; 321510506SBarry.Harding@Sun.COM break; 321610506SBarry.Harding@Sun.COM } 321710506SBarry.Harding@Sun.COM enq++; 321810506SBarry.Harding@Sun.COM mp = nmp; 321910506SBarry.Harding@Sun.COM 322010506SBarry.Harding@Sun.COM } 322110506SBarry.Harding@Sun.COM if (enq > 0) { 322210506SBarry.Harding@Sun.COM /* Transmit */ 322310506SBarry.Harding@Sun.COM CSR_WRITE_2(port->p_dev, 322410506SBarry.Harding@Sun.COM Y2_PREF_Q_ADDR(port->p_txq, PREF_UNIT_PUT_IDX_REG), 322510506SBarry.Harding@Sun.COM port->p_tx_prod); 322610506SBarry.Harding@Sun.COM } 322710506SBarry.Harding@Sun.COM 322810506SBarry.Harding@Sun.COM TX_UNLOCK(port->p_dev); 322910506SBarry.Harding@Sun.COM 323010506SBarry.Harding@Sun.COM if (resched) 323110506SBarry.Harding@Sun.COM mac_tx_update(port->p_mh); 323210506SBarry.Harding@Sun.COM 323310506SBarry.Harding@Sun.COM return (mp); 323410506SBarry.Harding@Sun.COM } 323510506SBarry.Harding@Sun.COM 323610506SBarry.Harding@Sun.COM void 323710506SBarry.Harding@Sun.COM yge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp) 323810506SBarry.Harding@Sun.COM { 323910506SBarry.Harding@Sun.COM #ifdef YGE_MII_LOOPBACK 324010506SBarry.Harding@Sun.COM /* LINTED E_FUNC_SET_NOT_USED */ 324110506SBarry.Harding@Sun.COM yge_port_t *port = arg; 324210506SBarry.Harding@Sun.COM 324310506SBarry.Harding@Sun.COM /* 324410506SBarry.Harding@Sun.COM * Right now, the MII common layer does not properly handle 324510506SBarry.Harding@Sun.COM * loopback on these PHYs. Fixing this should be done at some 324610506SBarry.Harding@Sun.COM * point in the future. 324710506SBarry.Harding@Sun.COM */ 324810506SBarry.Harding@Sun.COM if (mii_m_loop_ioctl(port->p_mii, wq, mp)) 324910506SBarry.Harding@Sun.COM return; 325010506SBarry.Harding@Sun.COM #else 325110506SBarry.Harding@Sun.COM _NOTE(ARGUNUSED(arg)); 325210506SBarry.Harding@Sun.COM #endif 325310506SBarry.Harding@Sun.COM 325410506SBarry.Harding@Sun.COM miocnak(wq, mp, 0, EINVAL); 325510506SBarry.Harding@Sun.COM } 325610506SBarry.Harding@Sun.COM 325710506SBarry.Harding@Sun.COM int 325810506SBarry.Harding@Sun.COM yge_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 325910506SBarry.Harding@Sun.COM uint_t pr_valsize, const void *pr_val) 326010506SBarry.Harding@Sun.COM { 326110506SBarry.Harding@Sun.COM yge_port_t *port = arg; 326210506SBarry.Harding@Sun.COM uint32_t new_mtu; 326310506SBarry.Harding@Sun.COM int err = 0; 326410506SBarry.Harding@Sun.COM 326510506SBarry.Harding@Sun.COM err = mii_m_setprop(port->p_mii, pr_name, pr_num, pr_valsize, pr_val); 326610506SBarry.Harding@Sun.COM if (err != ENOTSUP) { 326710506SBarry.Harding@Sun.COM return (err); 326810506SBarry.Harding@Sun.COM } 326910506SBarry.Harding@Sun.COM 327010506SBarry.Harding@Sun.COM DEV_LOCK(port->p_dev); 327110506SBarry.Harding@Sun.COM 327210506SBarry.Harding@Sun.COM switch (pr_num) { 327310506SBarry.Harding@Sun.COM case MAC_PROP_MTU: 327410506SBarry.Harding@Sun.COM if (pr_valsize < sizeof (new_mtu)) { 327510506SBarry.Harding@Sun.COM err = EINVAL; 327610506SBarry.Harding@Sun.COM break; 327710506SBarry.Harding@Sun.COM } 327810506SBarry.Harding@Sun.COM bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 327910506SBarry.Harding@Sun.COM if (new_mtu == port->p_mtu) { 328010506SBarry.Harding@Sun.COM /* no change */ 328110506SBarry.Harding@Sun.COM err = 0; 328210506SBarry.Harding@Sun.COM break; 328310506SBarry.Harding@Sun.COM } 328410506SBarry.Harding@Sun.COM if (new_mtu < ETHERMTU) { 328510506SBarry.Harding@Sun.COM yge_error(NULL, port, 328610506SBarry.Harding@Sun.COM "Maximum MTU size too small: %d", new_mtu); 328710506SBarry.Harding@Sun.COM err = EINVAL; 328810506SBarry.Harding@Sun.COM break; 328910506SBarry.Harding@Sun.COM } 329010506SBarry.Harding@Sun.COM if (new_mtu > (port->p_flags & PORT_FLAG_NOJUMBO ? 329110506SBarry.Harding@Sun.COM ETHERMTU : YGE_JUMBO_MTU)) { 329210506SBarry.Harding@Sun.COM yge_error(NULL, port, 329310506SBarry.Harding@Sun.COM "Maximum MTU size too big: %d", new_mtu); 329410506SBarry.Harding@Sun.COM err = EINVAL; 329510506SBarry.Harding@Sun.COM break; 329610506SBarry.Harding@Sun.COM } 329710506SBarry.Harding@Sun.COM if (port->p_running) { 329810506SBarry.Harding@Sun.COM yge_error(NULL, port, 329910506SBarry.Harding@Sun.COM "Unable to change maximum MTU while running"); 330010506SBarry.Harding@Sun.COM err = EBUSY; 330110506SBarry.Harding@Sun.COM break; 330210506SBarry.Harding@Sun.COM } 330310506SBarry.Harding@Sun.COM 330410506SBarry.Harding@Sun.COM 330510506SBarry.Harding@Sun.COM /* 330610506SBarry.Harding@Sun.COM * NB: It would probably be better not to hold the 330710506SBarry.Harding@Sun.COM * DEVLOCK, but releasing it creates a potential race 330810506SBarry.Harding@Sun.COM * if m_start is called concurrently. 330910506SBarry.Harding@Sun.COM * 331010506SBarry.Harding@Sun.COM * It turns out that the MAC layer guarantees safety 331110506SBarry.Harding@Sun.COM * for us here by using a cut out for this kind of 331210506SBarry.Harding@Sun.COM * notification call back anyway. 331310506SBarry.Harding@Sun.COM * 331410506SBarry.Harding@Sun.COM * See R8. and R14. in mac.c locking comments, which read 331510506SBarry.Harding@Sun.COM * as follows: 331610506SBarry.Harding@Sun.COM * 331710506SBarry.Harding@Sun.COM * R8. Since it is not guaranteed (see R14) that 331810506SBarry.Harding@Sun.COM * drivers won't hold locks across mac driver 331910506SBarry.Harding@Sun.COM * interfaces, the MAC layer must provide a cut out 332010506SBarry.Harding@Sun.COM * for control interfaces like upcall notifications 332110506SBarry.Harding@Sun.COM * and start them in a separate thread. 332210506SBarry.Harding@Sun.COM * 332310506SBarry.Harding@Sun.COM * R14. It would be preferable if MAC drivers don't 332410506SBarry.Harding@Sun.COM * hold any locks across any mac call. However at a 332510506SBarry.Harding@Sun.COM * minimum they must not hold any locks across data 332610506SBarry.Harding@Sun.COM * upcalls. They must also make sure that all 332710506SBarry.Harding@Sun.COM * references to mac data structures are cleaned up 332810506SBarry.Harding@Sun.COM * and that it is single threaded at mac_unregister 332910506SBarry.Harding@Sun.COM * time. 333010506SBarry.Harding@Sun.COM */ 333110506SBarry.Harding@Sun.COM err = mac_maxsdu_update(port->p_mh, new_mtu); 333210506SBarry.Harding@Sun.COM if (err != 0) { 333310506SBarry.Harding@Sun.COM /* This should never occur! */ 333410506SBarry.Harding@Sun.COM yge_error(NULL, port, 333510506SBarry.Harding@Sun.COM "Failed notifying GLDv3 of new maximum MTU"); 333610506SBarry.Harding@Sun.COM } else { 333710506SBarry.Harding@Sun.COM port->p_mtu = new_mtu; 333810506SBarry.Harding@Sun.COM } 333910506SBarry.Harding@Sun.COM break; 334010506SBarry.Harding@Sun.COM 334110506SBarry.Harding@Sun.COM default: 334210506SBarry.Harding@Sun.COM err = ENOTSUP; 334310506SBarry.Harding@Sun.COM break; 334410506SBarry.Harding@Sun.COM } 334510506SBarry.Harding@Sun.COM 334610506SBarry.Harding@Sun.COM err: 334710506SBarry.Harding@Sun.COM DEV_UNLOCK(port->p_dev); 334810506SBarry.Harding@Sun.COM 334910506SBarry.Harding@Sun.COM return (err); 335010506SBarry.Harding@Sun.COM } 335110506SBarry.Harding@Sun.COM 335210506SBarry.Harding@Sun.COM int 335310506SBarry.Harding@Sun.COM yge_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 3354*11878SVenu.Iyer@Sun.COM uint_t pr_valsize, void *pr_val) 335510506SBarry.Harding@Sun.COM { 335610506SBarry.Harding@Sun.COM yge_port_t *port = arg; 3357*11878SVenu.Iyer@Sun.COM 3358*11878SVenu.Iyer@Sun.COM return (mii_m_getprop(port->p_mii, pr_name, pr_num, pr_valsize, 3359*11878SVenu.Iyer@Sun.COM pr_val)); 3360*11878SVenu.Iyer@Sun.COM } 3361*11878SVenu.Iyer@Sun.COM 3362*11878SVenu.Iyer@Sun.COM static void 3363*11878SVenu.Iyer@Sun.COM yge_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num, 3364*11878SVenu.Iyer@Sun.COM mac_prop_info_handle_t prh) 3365*11878SVenu.Iyer@Sun.COM { 3366*11878SVenu.Iyer@Sun.COM yge_port_t *port = arg; 336710506SBarry.Harding@Sun.COM 336810506SBarry.Harding@Sun.COM switch (pr_num) { 336910506SBarry.Harding@Sun.COM case MAC_PROP_MTU: 3370*11878SVenu.Iyer@Sun.COM mac_prop_info_set_range_uint32(prh, ETHERMTU, 337110506SBarry.Harding@Sun.COM port->p_flags & PORT_FLAG_NOJUMBO ? 3372*11878SVenu.Iyer@Sun.COM ETHERMTU : YGE_JUMBO_MTU); 337310506SBarry.Harding@Sun.COM break; 337410506SBarry.Harding@Sun.COM default: 3375*11878SVenu.Iyer@Sun.COM mii_m_propinfo(port->p_mii, pr_name, pr_num, prh); 337610506SBarry.Harding@Sun.COM break; 337710506SBarry.Harding@Sun.COM } 337810506SBarry.Harding@Sun.COM } 337910506SBarry.Harding@Sun.COM 338010506SBarry.Harding@Sun.COM void 338110506SBarry.Harding@Sun.COM yge_dispatch(yge_dev_t *dev, int flag) 338210506SBarry.Harding@Sun.COM { 338310506SBarry.Harding@Sun.COM TASK_LOCK(dev); 338410506SBarry.Harding@Sun.COM dev->d_task_flags |= flag; 338510506SBarry.Harding@Sun.COM TASK_SIGNAL(dev); 338610506SBarry.Harding@Sun.COM TASK_UNLOCK(dev); 338710506SBarry.Harding@Sun.COM } 338810506SBarry.Harding@Sun.COM 338910506SBarry.Harding@Sun.COM void 339010506SBarry.Harding@Sun.COM yge_task(void *arg) 339110506SBarry.Harding@Sun.COM { 339210506SBarry.Harding@Sun.COM yge_dev_t *dev = arg; 339310506SBarry.Harding@Sun.COM int flags; 339410506SBarry.Harding@Sun.COM 339510506SBarry.Harding@Sun.COM for (;;) { 339610506SBarry.Harding@Sun.COM 339710506SBarry.Harding@Sun.COM TASK_LOCK(dev); 339810506SBarry.Harding@Sun.COM while ((flags = dev->d_task_flags) == 0) 339910506SBarry.Harding@Sun.COM TASK_WAIT(dev); 340010506SBarry.Harding@Sun.COM 340110506SBarry.Harding@Sun.COM dev->d_task_flags = 0; 340210506SBarry.Harding@Sun.COM TASK_UNLOCK(dev); 340310506SBarry.Harding@Sun.COM 340410506SBarry.Harding@Sun.COM /* 340510506SBarry.Harding@Sun.COM * This should be the first thing after the sleep so if we are 340610506SBarry.Harding@Sun.COM * requested to exit we do that and not waste time doing work 340710506SBarry.Harding@Sun.COM * we will then abandone. 340810506SBarry.Harding@Sun.COM */ 340910506SBarry.Harding@Sun.COM if (flags & YGE_TASK_EXIT) 341010506SBarry.Harding@Sun.COM break; 341110506SBarry.Harding@Sun.COM 341210506SBarry.Harding@Sun.COM /* all processing done without holding locks */ 341310506SBarry.Harding@Sun.COM if (flags & YGE_TASK_RESTART) 341410506SBarry.Harding@Sun.COM yge_restart_task(dev); 341510506SBarry.Harding@Sun.COM } 341610506SBarry.Harding@Sun.COM } 341710506SBarry.Harding@Sun.COM 341810506SBarry.Harding@Sun.COM void 341910506SBarry.Harding@Sun.COM yge_error(yge_dev_t *dev, yge_port_t *port, char *fmt, ...) 342010506SBarry.Harding@Sun.COM { 342110506SBarry.Harding@Sun.COM va_list ap; 342210506SBarry.Harding@Sun.COM char buf[256]; 342311869SVitezslav.Batrla@Sun.COM int ppa; 342410506SBarry.Harding@Sun.COM 342510506SBarry.Harding@Sun.COM va_start(ap, fmt); 342610506SBarry.Harding@Sun.COM (void) vsnprintf(buf, sizeof (buf), fmt, ap); 342710506SBarry.Harding@Sun.COM va_end(ap); 342810506SBarry.Harding@Sun.COM 342911869SVitezslav.Batrla@Sun.COM if (dev == NULL && port == NULL) { 343011869SVitezslav.Batrla@Sun.COM cmn_err(CE_WARN, "yge: %s", buf); 343111869SVitezslav.Batrla@Sun.COM } else { 343211869SVitezslav.Batrla@Sun.COM if (port != NULL) 343311869SVitezslav.Batrla@Sun.COM ppa = port->p_ppa; 343411869SVitezslav.Batrla@Sun.COM else 343511869SVitezslav.Batrla@Sun.COM ppa = ddi_get_instance(dev->d_dip); 343611869SVitezslav.Batrla@Sun.COM cmn_err(CE_WARN, "yge%d: %s", ppa, buf); 343711869SVitezslav.Batrla@Sun.COM } 343810506SBarry.Harding@Sun.COM } 343910506SBarry.Harding@Sun.COM 344010506SBarry.Harding@Sun.COM static int 344110506SBarry.Harding@Sun.COM yge_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 344210506SBarry.Harding@Sun.COM { 344310506SBarry.Harding@Sun.COM yge_dev_t *dev; 344410506SBarry.Harding@Sun.COM int rv; 344510506SBarry.Harding@Sun.COM 344610506SBarry.Harding@Sun.COM switch (cmd) { 344710506SBarry.Harding@Sun.COM case DDI_ATTACH: 344810506SBarry.Harding@Sun.COM dev = kmem_zalloc(sizeof (*dev), KM_SLEEP); 344910506SBarry.Harding@Sun.COM dev->d_port[0] = kmem_zalloc(sizeof (yge_port_t), KM_SLEEP); 345010506SBarry.Harding@Sun.COM dev->d_port[1] = kmem_zalloc(sizeof (yge_port_t), KM_SLEEP); 345110506SBarry.Harding@Sun.COM dev->d_dip = dip; 345210506SBarry.Harding@Sun.COM ddi_set_driver_private(dip, dev); 345310506SBarry.Harding@Sun.COM 345410506SBarry.Harding@Sun.COM dev->d_port[0]->p_port = 0; 345510506SBarry.Harding@Sun.COM dev->d_port[0]->p_dev = dev; 345610506SBarry.Harding@Sun.COM dev->d_port[1]->p_port = 0; 345710506SBarry.Harding@Sun.COM dev->d_port[1]->p_dev = dev; 345810506SBarry.Harding@Sun.COM 345910506SBarry.Harding@Sun.COM rv = yge_attach(dev); 346010506SBarry.Harding@Sun.COM if (rv != DDI_SUCCESS) { 346110506SBarry.Harding@Sun.COM ddi_set_driver_private(dip, 0); 346210506SBarry.Harding@Sun.COM kmem_free(dev->d_port[1], sizeof (yge_port_t)); 346310506SBarry.Harding@Sun.COM kmem_free(dev->d_port[0], sizeof (yge_port_t)); 346410506SBarry.Harding@Sun.COM kmem_free(dev, sizeof (*dev)); 346510506SBarry.Harding@Sun.COM } 346610506SBarry.Harding@Sun.COM return (rv); 346710506SBarry.Harding@Sun.COM 346810506SBarry.Harding@Sun.COM case DDI_RESUME: 346910506SBarry.Harding@Sun.COM dev = ddi_get_driver_private(dip); 347010506SBarry.Harding@Sun.COM ASSERT(dev != NULL); 347110506SBarry.Harding@Sun.COM return (yge_resume(dev)); 347210506SBarry.Harding@Sun.COM 347310506SBarry.Harding@Sun.COM default: 347410506SBarry.Harding@Sun.COM return (DDI_FAILURE); 347510506SBarry.Harding@Sun.COM } 347610506SBarry.Harding@Sun.COM } 347710506SBarry.Harding@Sun.COM 347810506SBarry.Harding@Sun.COM static int 347910506SBarry.Harding@Sun.COM yge_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 348010506SBarry.Harding@Sun.COM { 348110506SBarry.Harding@Sun.COM yge_dev_t *dev; 348210506SBarry.Harding@Sun.COM int rv; 348310506SBarry.Harding@Sun.COM 348410506SBarry.Harding@Sun.COM switch (cmd) { 348510506SBarry.Harding@Sun.COM case DDI_DETACH: 348610506SBarry.Harding@Sun.COM 348710506SBarry.Harding@Sun.COM dev = ddi_get_driver_private(dip); 348810506SBarry.Harding@Sun.COM 348910506SBarry.Harding@Sun.COM /* attempt to unregister MACs from Nemo */ 349010506SBarry.Harding@Sun.COM for (int i = 0; i < dev->d_num_port; i++) { 349110506SBarry.Harding@Sun.COM rv = yge_unregister_port(dev->d_port[i]); 349210506SBarry.Harding@Sun.COM if (rv != DDI_SUCCESS) { 349310506SBarry.Harding@Sun.COM return (DDI_FAILURE); 349410506SBarry.Harding@Sun.COM } 349510506SBarry.Harding@Sun.COM } 349610506SBarry.Harding@Sun.COM 349710506SBarry.Harding@Sun.COM ASSERT(dip == dev->d_dip); 349810506SBarry.Harding@Sun.COM yge_detach(dev); 349910506SBarry.Harding@Sun.COM ddi_set_driver_private(dip, 0); 350010506SBarry.Harding@Sun.COM kmem_free(dev->d_port[1], sizeof (yge_port_t)); 350110506SBarry.Harding@Sun.COM kmem_free(dev->d_port[0], sizeof (yge_port_t)); 350210506SBarry.Harding@Sun.COM kmem_free(dev, sizeof (*dev)); 350310506SBarry.Harding@Sun.COM return (DDI_SUCCESS); 350410506SBarry.Harding@Sun.COM 350510506SBarry.Harding@Sun.COM case DDI_SUSPEND: 350610506SBarry.Harding@Sun.COM dev = ddi_get_driver_private(dip); 350710506SBarry.Harding@Sun.COM ASSERT(dev != NULL); 350810506SBarry.Harding@Sun.COM return (yge_suspend(dev)); 350910506SBarry.Harding@Sun.COM 351010506SBarry.Harding@Sun.COM default: 351110506SBarry.Harding@Sun.COM return (DDI_FAILURE); 351210506SBarry.Harding@Sun.COM } 351310506SBarry.Harding@Sun.COM } 351410506SBarry.Harding@Sun.COM 351510506SBarry.Harding@Sun.COM static int 351610506SBarry.Harding@Sun.COM yge_quiesce(dev_info_t *dip) 351710506SBarry.Harding@Sun.COM { 351810506SBarry.Harding@Sun.COM yge_dev_t *dev; 351910506SBarry.Harding@Sun.COM 352010506SBarry.Harding@Sun.COM dev = ddi_get_driver_private(dip); 352110506SBarry.Harding@Sun.COM ASSERT(dev != NULL); 352210506SBarry.Harding@Sun.COM 352310506SBarry.Harding@Sun.COM /* NB: No locking! We are called in single threaded context */ 352410506SBarry.Harding@Sun.COM for (int i = 0; i < dev->d_num_port; i++) { 352510506SBarry.Harding@Sun.COM yge_port_t *port = dev->d_port[i]; 352610506SBarry.Harding@Sun.COM if (port->p_running) 352710506SBarry.Harding@Sun.COM yge_stop_port(port); 352810506SBarry.Harding@Sun.COM } 352910506SBarry.Harding@Sun.COM 353010506SBarry.Harding@Sun.COM /* Disable all interrupts. */ 353110506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_IMSK, 0); 353210506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B0_IMSK); 353310506SBarry.Harding@Sun.COM CSR_WRITE_4(dev, B0_HWE_IMSK, 0); 353410506SBarry.Harding@Sun.COM (void) CSR_READ_4(dev, B0_HWE_IMSK); 353510506SBarry.Harding@Sun.COM 353610506SBarry.Harding@Sun.COM /* Put hardware into reset. */ 353710506SBarry.Harding@Sun.COM CSR_WRITE_2(dev, B0_CTST, CS_RST_SET); 353810506SBarry.Harding@Sun.COM 353910506SBarry.Harding@Sun.COM return (DDI_SUCCESS); 354010506SBarry.Harding@Sun.COM } 354110506SBarry.Harding@Sun.COM 354210506SBarry.Harding@Sun.COM /* 354310506SBarry.Harding@Sun.COM * Stream information 354410506SBarry.Harding@Sun.COM */ 354510506SBarry.Harding@Sun.COM DDI_DEFINE_STREAM_OPS(yge_devops, nulldev, nulldev, yge_ddi_attach, 354610506SBarry.Harding@Sun.COM yge_ddi_detach, nodev, NULL, D_MP, NULL, yge_quiesce); 354710506SBarry.Harding@Sun.COM 354810506SBarry.Harding@Sun.COM /* 354910506SBarry.Harding@Sun.COM * Module linkage information. 355010506SBarry.Harding@Sun.COM */ 355110506SBarry.Harding@Sun.COM 355210506SBarry.Harding@Sun.COM static struct modldrv yge_modldrv = { 355310506SBarry.Harding@Sun.COM &mod_driverops, /* drv_modops */ 355410506SBarry.Harding@Sun.COM "Yukon 2 Ethernet", /* drv_linkinfo */ 355510506SBarry.Harding@Sun.COM &yge_devops /* drv_dev_ops */ 355610506SBarry.Harding@Sun.COM }; 355710506SBarry.Harding@Sun.COM 355810506SBarry.Harding@Sun.COM static struct modlinkage yge_modlinkage = { 355910506SBarry.Harding@Sun.COM MODREV_1, /* ml_rev */ 356010506SBarry.Harding@Sun.COM &yge_modldrv, /* ml_linkage */ 356110506SBarry.Harding@Sun.COM NULL 356210506SBarry.Harding@Sun.COM }; 356310506SBarry.Harding@Sun.COM 356410506SBarry.Harding@Sun.COM /* 356510506SBarry.Harding@Sun.COM * DDI entry points. 356610506SBarry.Harding@Sun.COM */ 356710506SBarry.Harding@Sun.COM int 356810506SBarry.Harding@Sun.COM _init(void) 356910506SBarry.Harding@Sun.COM { 357010506SBarry.Harding@Sun.COM int rv; 357110506SBarry.Harding@Sun.COM mac_init_ops(&yge_devops, "yge"); 357210506SBarry.Harding@Sun.COM if ((rv = mod_install(&yge_modlinkage)) != DDI_SUCCESS) { 357310506SBarry.Harding@Sun.COM mac_fini_ops(&yge_devops); 357410506SBarry.Harding@Sun.COM } 357510506SBarry.Harding@Sun.COM return (rv); 357610506SBarry.Harding@Sun.COM } 357710506SBarry.Harding@Sun.COM 357810506SBarry.Harding@Sun.COM int 357910506SBarry.Harding@Sun.COM _fini(void) 358010506SBarry.Harding@Sun.COM { 358110506SBarry.Harding@Sun.COM int rv; 358210506SBarry.Harding@Sun.COM if ((rv = mod_remove(&yge_modlinkage)) == DDI_SUCCESS) { 358310506SBarry.Harding@Sun.COM mac_fini_ops(&yge_devops); 358410506SBarry.Harding@Sun.COM } 358510506SBarry.Harding@Sun.COM return (rv); 358610506SBarry.Harding@Sun.COM } 358710506SBarry.Harding@Sun.COM 358810506SBarry.Harding@Sun.COM int 358910506SBarry.Harding@Sun.COM _info(struct modinfo *modinfop) 359010506SBarry.Harding@Sun.COM { 359110506SBarry.Harding@Sun.COM return (mod_info(&yge_modlinkage, modinfop)); 359210506SBarry.Harding@Sun.COM } 3593