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