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